diff --git a/.github/styles/base/Dictionary.txt b/.github/styles/base/Dictionary.txt index a378bd5bc9..38b587804e 100644 --- a/.github/styles/base/Dictionary.txt +++ b/.github/styles/base/Dictionary.txt @@ -145,6 +145,7 @@ crd crds created_at creationTimestamp +CRMs cronjob CrowdStrike cryptocurrency @@ -279,6 +280,7 @@ gojira Golang Goroutine Goroutine +GPUs gbps grafana Grafana @@ -425,6 +427,7 @@ Knatives knep kong kongair +kong_konnect_api_request kong_name kong-ip Kong/kong @@ -735,6 +738,7 @@ serializer serverless serviceaccounts serviceless +service_name shm show_in_api Sigstore diff --git a/api-specs/konnect/metering-and-billing/v3/openapi.yaml b/api-specs/konnect/metering-and-billing/v3/openapi.yaml new file mode 100644 index 0000000000..575618cc91 --- /dev/null +++ b/api-specs/konnect/metering-and-billing/v3/openapi.yaml @@ -0,0 +1,488 @@ +openapi: 3.0.0 +info: + title: Konnect Metering & Billing + version: 0.0.1 + contact: + name: Kong + url: 'https://cloud.konghq.com' + description: Konnect Metering & Billing API. +servers: + - url: 'https://us.api.konghq.com/v3' + description: United-States Production region + - url: 'https://eu.api.konghq.com/v3' + description: Europe Production region + - url: 'https://au.api.konghq.com/v3' + description: Australia Production region + - url: 'https://me.api.konghq.com/v3' + description: Middle-East Production region + - url: 'https://in.api.konghq.com/v3' + description: India Production region + - url: 'https://sg.api.konghq.com/v3' + description: Singapore Production region +paths: + /openmeter/events: + post: + operationId: ingest-metering-events + summary: Ingest metering events + description: Ingests an event or batch of events following the CloudEvents specification. + requestBody: + required: true + content: + application/cloudevents+json: + schema: + $ref: '#/components/schemas/MeteringEvent' + application/cloudevents-batch+json: + schema: + type: array + items: + $ref: '#/components/schemas/MeteringEvent' + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/MeteringEvent' + - type: array + items: + $ref: '#/components/schemas/MeteringEvent' + responses: + '202': + description: The events have been ingested and are being processed asynchronously. + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + tags: + - Metering Events +components: + schemas: + DateTime: + description: '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.' + type: string + format: date-time + example: '2023-01-01T01:01:01.001Z' + title: RFC3339 Date-Time + MeteringEvent: + description: Metering event following the CloudEvents specification. + type: object + properties: + id: + description: Identifies the event. + type: string + example: 5c10fade-1c9e-4d6c-8275-c52c36731d3c + minLength: 1 + source: + description: Identifies the context in which an event happened. + type: string + format: uri-reference + example: service-name + minLength: 1 + specversion: + description: The version of the CloudEvents specification which the event uses. + type: string + example: '1.0' + default: '1.0' + minLength: 1 + type: + description: Contains a value describing the type of event related to the originating occurrence. + type: string + example: com.example.someevent + minLength: 1 + datacontenttype: + description: Content type of the CloudEvents data value. Only the value "application/json" is allowed over HTTP. + type: string + example: application/json + enum: + - application/json + nullable: true + dataschema: + description: Identifies the schema that data adheres to. + type: string + format: uri + minLength: 1 + nullable: true + subject: + description: Describes the subject of the event in the context of the event producer (identified by source). + type: string + example: customer-id + minLength: 1 + time: + description: Timestamp of when the occurrence happened. Must adhere to RFC 3339. + type: string + example: '2023-01-01T01:01:01.001Z' + allOf: + - $ref: '#/components/schemas/DateTime' + nullable: true + data: + description: |- + The event payload. + Optional, if present it must be a JSON object. + type: object + additionalProperties: {} + nullable: true + example: + specversion: '1.0' + id: 5c10fade-1c9e-4d6c-8275-c52c36731d3c + source: service-name + type: prompt + subject: customer-id + time: '2023-01-01T01:01:01.001Z' + data: + prompt: 'Hello, world!' + tokens: 100 + model: gpt-4o + type: input + required: + - id + - source + - specversion + - type + - subject + title: Metering Event + BaseError: + description: standard error + type: object + properties: + status: + description: | + The HTTP status code of the error. Useful when passing the response + body to child properties in a frontend UI. Must be returned as an integer. + type: integer + readOnly: true + title: + description: | + A short, human-readable summary of the problem. It should not + change between occurences of a problem, except for localization. + Should be provided as "Sentence case" for direct use in the UI. + type: string + readOnly: true + type: + description: The error type. + type: string + readOnly: true + instance: + description: | + Used to return the correlation ID back to the user, in the format + kong:trace:. This helps us find the relevant logs + when a customer reports an issue. + type: string + readOnly: true + detail: + description: | + A human readable explanation specific to this occurence of the problem. + This field may contain request/entity data to help the user understand + what went wrong. Enclose variable values in square brackets. Should be + provided as "Sentence case" for direct use in the UI. + type: string + readOnly: true + required: + - status + - title + - instance + - detail + title: Error + InvalidRules: + description: invalid parameters rules + type: string + enum: + - required + - is_array + - is_base64 + - is_boolean + - is_date_time + - is_integer + - is_null + - is_number + - is_object + - is_string + - is_uuid + - is_fqdn + - is_arn + - unknown_property + - missing_reference + - is_label + - matches_regex + - invalid + - is_supported_network_availability_zone_list + - is_supported_network_cidr_block + - is_supported_provider_region + - type + nullable: true + readOnly: true + InvalidParameterStandard: + type: object + properties: + field: + type: string + example: name + readOnly: true + rule: + $ref: '#/components/schemas/InvalidRules' + source: + type: string + example: body + reason: + type: string + example: is a required field + readOnly: true + additionalProperties: false + required: + - field + - reason + InvalidParameterMinimumLength: + type: object + properties: + field: + type: string + example: name + readOnly: true + rule: + description: invalid parameters rules + type: string + enum: + - min_length + - min_digits + - min_lowercase + - min_uppercase + - min_symbols + - min_items + - min + nullable: false + readOnly: true + minimum: + type: integer + example: 8 + source: + type: string + example: body + reason: + type: string + example: must have at least 8 characters + readOnly: true + additionalProperties: false + required: + - field + - reason + - rule + - minimum + InvalidParameterMaximumLength: + type: object + properties: + field: + type: string + example: name + readOnly: true + rule: + description: invalid parameters rules + type: string + enum: + - max_length + - max_items + - max + nullable: false + readOnly: true + maximum: + type: integer + example: 8 + source: + type: string + example: body + reason: + type: string + example: must not have more than 8 characters + readOnly: true + additionalProperties: false + required: + - field + - reason + - rule + - maximum + InvalidParameterChoiceItem: + type: object + properties: + field: + type: string + example: name + readOnly: true + rule: + description: invalid parameters rules + type: string + enum: + - enum + nullable: false + readOnly: true + reason: + type: string + example: is a required field + readOnly: true + choices: + type: array + items: {} + minItems: 1 + nullable: false + readOnly: true + uniqueItems: true + source: + type: string + example: body + additionalProperties: false + required: + - field + - reason + - rule + - choices + InvalidParameterDependentItem: + type: object + properties: + field: + type: string + example: name + readOnly: true + rule: + description: invalid parameters rules + type: string + enum: + - dependent_fields + nullable: true + readOnly: true + reason: + type: string + example: is a required field + readOnly: true + dependents: + type: array + items: {} + nullable: true + readOnly: true + uniqueItems: true + source: + type: string + example: body + additionalProperties: false + required: + - field + - rule + - reason + - dependents + InvalidParameters: + description: invalid parameters + type: array + items: + oneOf: + - $ref: '#/components/schemas/InvalidParameterStandard' + - $ref: '#/components/schemas/InvalidParameterMinimumLength' + - $ref: '#/components/schemas/InvalidParameterMaximumLength' + - $ref: '#/components/schemas/InvalidParameterChoiceItem' + - $ref: '#/components/schemas/InvalidParameterDependentItem' + minItems: 1 + nullable: false + uniqueItems: true + BadRequestError: + allOf: + - $ref: '#/components/schemas/BaseError' + - type: object + required: + - invalid_parameters + properties: + invalid_parameters: + $ref: '#/components/schemas/InvalidParameters' + UnauthorizedError: + allOf: + - $ref: '#/components/schemas/BaseError' + - type: object + properties: + status: + example: 401 + title: + example: Unauthorized + type: + example: 'https://httpstatuses.com/401' + instance: + example: 'kong:trace:1234567890' + detail: + example: Invalid credentials + ForbiddenError: + allOf: + - $ref: '#/components/schemas/BaseError' + - type: object + properties: + status: + example: 403 + title: + example: Forbidden + type: + example: 'https://httpstatuses.com/403' + instance: + example: 'kong:trace:1234567890' + detail: + example: Forbidden + examples: + UnauthorizedExample: + value: + status: 401 + title: Unauthorized + instance: 'kong:trace:8347343766220159418' + detail: Unauthorized + ForbiddenExample: + value: + status: 403 + title: Forbidden + instance: 'kong:trace:2723154947768991354' + detail: You do not have permission to perform this action + responses: + BadRequest: + description: Bad Request + content: + application/problem+json: + schema: + $ref: '#/components/schemas/BadRequestError' + Unauthorized: + description: Unauthorized + content: + application/problem+json: + schema: + $ref: '#/components/schemas/UnauthorizedError' + examples: + UnauthorizedExample: + $ref: '#/components/examples/UnauthorizedExample' + Forbidden: + description: Forbidden + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ForbiddenError' + examples: + UnauthorizedExample: + $ref: '#/components/examples/ForbiddenExample' + securitySchemes: + systemAccountAccessToken: + type: http + scheme: bearer + bearerFormat: Token + description: | + The system account access token is meant for automations and integrations that are not directly associated with a human identity. + You can generate a system account Access Token by creating a system account and then obtaining a system account access token for that account. + The access token must be passed in the header of a request, for example: + `curl -X GET 'https://global.api.konghq.com/v2/users/' --header 'Authorization: Bearer spat_i2Ej...'` + personalAccessToken: + type: http + scheme: bearer + bearerFormat: Token + description: | + The personal access token is meant to be used as an alternative to basic-auth when accessing Konnect via APIs. + You can generate a Personal Access Token (PAT) from the [personal access token page](https://cloud.konghq.com/global/account/tokens/) in the Konnect dashboard. + The PAT token must be passed in the header of a request, for example: + `curl -X GET 'https://global.api.konghq.com/v2/users/' --header 'Authorization: Bearer kpat_xgfT...'` + konnectAccessToken: + type: http + scheme: bearer + bearerFormat: JWT + description: | + The Konnect access token is meant to be used by the Konnect dashboard and the decK CLI authenticate with. +tags: + - name: Metering Events + description: 'Metering events are used to track usage of your product or service. Events are processed asynchronously by the meters, so they may not be immediately available for querying.' +security: + - systemAccountAccessToken: [] + - personalAccessToken: [] + - konnectAccessToken: [] \ No newline at end of file diff --git a/app/_api/konnect/metering-and-billing/_index.md b/app/_api/konnect/metering-and-billing/_index.md new file mode 100644 index 0000000000..848297dd9a --- /dev/null +++ b/app/_api/konnect/metering-and-billing/_index.md @@ -0,0 +1,3 @@ +--- +konnect_product_id: c8038010-4393-4a7e-ae2c-c6f851932a93 +--- \ No newline at end of file diff --git a/app/_assets/icons/products/metering-and-billing.svg b/app/_assets/icons/products/metering-and-billing.svg new file mode 100644 index 0000000000..44de080256 --- /dev/null +++ b/app/_assets/icons/products/metering-and-billing.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/_assets/javascripts/apps/components/ProductIcon.vue b/app/_assets/javascripts/apps/components/ProductIcon.vue index 09c23d63a0..981e8bb2e4 100644 --- a/app/_assets/javascripts/apps/components/ProductIcon.vue +++ b/app/_assets/javascripts/apps/components/ProductIcon.vue @@ -17,6 +17,7 @@ import catalog from '@/icons/products/catalog.svg' import eventGateway from '@/icons/products/event-gateway.svg' import konnect from '@/icons/products/konnect.svg' import referencePlatform from '@/icons/products/konnect-reference-platform.svg' +import meteringBilling from '@/icons/products/metering-and-billing.svg' const productIcons = { 'advanced-analytics': advancedAnalytics, @@ -28,6 +29,7 @@ const productIcons = { 'catalog': catalog, 'konnect': konnect, 'reference-platform': referencePlatform, + 'metering-and-billing': meteringBilling, operator, kic, mesh diff --git a/app/_assets/stylesheets/index.css b/app/_assets/stylesheets/index.css index 00296d6223..b9e226a33e 100644 --- a/app/_assets/stylesheets/index.css +++ b/app/_assets/stylesheets/index.css @@ -110,6 +110,8 @@ --color-operator-background: var(--color-semantic-blue-secondary); --color-api-products-brand: var(--color-semantic-orange-primary); --color-api-products-background: var(--color-semantic-orange-secondary); + --color-metering-and-billing-brand: var(--color-semantic-orange-primary); + --color-metering-and-billing-background: var(--color-semantic-orange-secondary); } .dark { diff --git a/app/_data/konnect_oas_data.json b/app/_data/konnect_oas_data.json index 31c22b63e1..16467307b2 100644 --- a/app/_data/konnect_oas_data.json +++ b/app/_data/konnect_oas_data.json @@ -709,5 +709,26 @@ "registration_configs": [] } ] + }, + { + "id": "c8038010-4393-4a7e-ae2c-c6f851932a93", + "title": "Metering & Billing", + "latestVersion": { + "name": "v3", + "id": "e616488f-8570-4de6-8004-fbbddcd38498" + }, + "description": "Konnect Metering & Billing API", + "documentCount": 0, + "versionCount": 1, + "versions": [ + { + "id": "e616488f-8570-4de6-8004-fbbddcd38498", + "created_at": "2025-12-12T20:56:35.496Z", + "updated_at": "2025-12-12T21:01:14.395Z", + "name": "v3", + "deprecated": false, + "registration_configs": [] + } + ] } ] \ No newline at end of file diff --git a/app/_data/products/metering-and-billing.yml b/app/_data/products/metering-and-billing.yml new file mode 100644 index 0000000000..bd4bc147bd --- /dev/null +++ b/app/_data/products/metering-and-billing.yml @@ -0,0 +1,2 @@ +name: Metering & Billing +icon: /_assets/icons/products/metering-and-billing.svg \ No newline at end of file diff --git a/app/_data/schemas/frontmatter/base.json b/app/_data/schemas/frontmatter/base.json index 619199800a..31658fae82 100644 --- a/app/_data/schemas/frontmatter/base.json +++ b/app/_data/schemas/frontmatter/base.json @@ -43,7 +43,7 @@ "type": "array", "items": { "type": "string", - "enum": ["ai-gateway", "gateway", "insomnia", "mesh", "kic", "catalog", "advanced-analytics", "dev-portal", "operator", "konnect", "event-gateway", "konnect-reference-platform"] + "enum": ["ai-gateway", "gateway", "insomnia", "mesh", "kic", "catalog", "advanced-analytics", "dev-portal", "operator", "konnect", "event-gateway", "konnect-reference-platform", "metering-and-billing"] } }, "tools": { diff --git a/app/_data/top_navigation.yml b/app/_data/top_navigation.yml index b86419e38a..49143ab387 100644 --- a/app/_data/top_navigation.yml +++ b/app/_data/top_navigation.yml @@ -66,6 +66,9 @@ platform: - text: Analytics url: /advanced-analytics/ product: advanced-analytics + - text: Metering & Billing + url: /metering-and-billing/ + product: metering-and-billing - text: Scorecards icon: /assets/icons/monochrome/document.svg url: /catalog/scorecards/ diff --git a/app/_how-tos/get-started-with-metering-and-billing.md b/app/_how-tos/get-started-with-metering-and-billing.md new file mode 100644 index 0000000000..f6db9e4664 --- /dev/null +++ b/app/_how-tos/get-started-with-metering-and-billing.md @@ -0,0 +1,234 @@ +--- +title: Get started with {{site.metering_and_billing}} in {{site.konnect_short_name}} +description: Learn how to meter and monetize API Gateway requests with {{site.konnect_short_name}} and {{site.metering_and_billing}}. +content_type: how_to + +permalink: /metering-and-billing/get-started/ +breadcrumbs: + - /metering-and-billing/ + +products: + - gateway + - metering-and-billing + +works_on: + - konnect + +tags: + - get-started + +tldr: + q: What is {{site.metering_and_billing}} in {{site.konnect_short_name}}, and how can I get started with it? + a: | + [{{site.metering_and_billing}}](/metering-and-billing/) provides flexible billing and metering for AI and DevTool companies. It also includes real-time insights and usage limit enforcement. + + This tutorial will help you get started with {{site.metering_and_billing}} by setting up metering based on {{site.base_gateway}} API requests, turn raw API usage into billable product offerings by defining features and pricing plans, and start subscriptions to assign to customers. + +tools: + - deck + +prereqs: + entities: + services: + - example-service + routes: + - example-route + inline: + - title: "{{site.konnect_short_name}} roles" + content: | + You need the [{{site.metering_and_billing}} Admin role](/konnect-platform/teams-and-roles/#metering-billing) in {{site.konnect_short_name}} to configure {{site.metering_and_billing}}. + icon_url: /assets/icons/kogo-white.svg + +cleanup: + inline: + - title: Clean up Konnect environment + include_content: cleanup/platform/konnect + icon_url: /assets/icons/gateway.svg + +min_version: + gateway: '3.4' +next_steps: + - text: See all {{site.base_gateway}} tutorials + url: /how-to/?products=gateway + - text: Learn about {{site.base_gateway}} entities + url: /gateway/entities/ + - text: Learn about how {{site.base_gateway}} is configured + url: /gateway/configuration/ + - text: See all {{site.base_gateway}} plugins + url: /plugins/ +automated_tests: false +--- + +This getting-started guide shows how you can meter {{site.base_gateway}} API requests and invoice your customers based on their API consumption with {{site.metering_and_billing}} in {{site.konnect_short_name}}. + +In this guide, you'll: +* Create a {{site.base_gateway}} Consumer that you'll map as a customer +* Set up a meter for {{site.base_gateway}} API requests +* Create a premium plan based on API usage +* Start subscriptions for a customer +* Generate an invoice for a customer on the paid premium plan and see their API usage + +The following diagram shows how {{site.base_gateway}} entities and {{site.metering_and_billing}} entities are associated: + +{% mermaid %} +flowchart TB + subgraph gateway["Kong Gateway"] + direction LR + service["example-service"] + route["example-route"] + consumer1["Consumer-Kong Air"] + end + subgraph metering["Konnect {{site.metering_and_billing}}"] + direction LR + meter["Meter"] + subgraph plan["Premium Plan"] + direction LR + feature2["Feature (example-service)"] + rate-card2["Rate card"] + end + subgraph subscription["Premium Subscription"] + direction LR + customer1["Customer (Kong Air)"] + end + end + gateway --> metering + service --> meter + meter --> feature2 + consumer1 --> customer1 + subscription --> plan + +{% endmermaid %} + + +## Create a Consumer + +Before you configure {{site.metering_and_billing}}, you can set up a Consumer, Kong Air. [Consumers](/gateway/entities/consumer/) let you identify the client that's interacting with {{site.base_gateway}}. Later in this guide, you'll be mapping this Consumer to a customer in {{site.metering_and_billing}} and assigning them to a Premium plan. Doing this allows you map existing Consumers that are already consuming your APIs to customers to make them billable. + +You're going to use key [authentication](/gateway/authentication/) in this tutorial, so the Consumer needs an API key to access any {{site.base_gateway}} Services. + + +{% entity_examples %} +entities: + consumers: + - username: kong-air + keyauth_credentials: + - key: air-key +{% endentity_examples %} + + +## Enable authentication + +Authentication lets you identify a Consumer so you can invoice them as customers after they've consumed the resource, in this case, the API request. +This example uses the [Key Authentication](/plugins/key-auth/) plugin, but you can use any [authentication plugin](/plugins/?category=authentication) that you prefer. + +Enable the plugin globally, which means it applies to all {{site.base_gateway}} Services and Routes: + + +{% entity_examples %} +entities: + plugins: + - name: key-auth + config: + key_names: + - apikey +{% endentity_examples %} + + +## Create a meter + +In {{site.metering_and_billing}}, meters track and record the consumption of a resource or service over time. This usage can take various forms, such as API requests, compute time seconds, or tokens consumed. Usage metering is commonly event-based to ensure accuracy and data you can audit. + +In this guide, you'll enable API Gateway requests for metering. This will meter API request traffic in {{site.metering_and_billing}} so that you can charge customers for API traffic usage. + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the API Gateway Requests settings, click **Enable Gateways**. +1. Select the "quickstart" control plane. +1. Click **Enable 1 Gateways**. + + +## Create a feature + +Meters collect raw usage data, but features make that data billable. Without a feature, usage is tracked but not invoiced. Now that you're metering API consumption, you need to associate traffic from the `example-service` Gateway Service with a feature as something you want to price or govern. + +Features are customer-facing, and show up on the invoice for paid plans. Feature examples could include things like flight data requests, GPT-5 input tokens, or available LLM models. + +In this guide, you'll create a feature for the `example-service` you created in the prerequisites. + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the {{site.metering_and_billing}} sidebar, click **Product Catalog**. +1. Click **Create Feature**. +1. In the **Name** field, enter `example-service`. +1. From the **Meter** dropdown menu, select "API Gateway Requests". +1. Click **Add group by filter**. + The group by filter ensures you only bill for traffic to `example-service`, not all {{site.base_gateway}} traffic. This lets you offer different pricing for different APIs. +1. From the **Group by** dropdown menu, select "service_name". +1. From the **Operator** dropdown menu, select "Equals". +1. From the **Value** dropdown menu, select "example-service". +1. Click **Save**. + +## Create a Premium plan + +Plans are the core building blocks of your product catalog. They are a collection of rate cards that define the price and access of a feature. Plans can be assigned to customers by starting a subscription. + +A rate card describes price and usage limits or access control for a feature or item. Rate cards are made up of the associated feature, price, and optional usage limits or access control for the feature, called entitlements. + +In this section, you'll create a Premium plan that grants paying customers access to the `example-service` at a rate of 5,000 requests per month: + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the {{site.metering_and_billing}} sidebar, click **Product Catalog**. +1. Click the **Plans** tab. +1. Click **Create Plan**. +1. In the **Name** field, enter `Premium`. +1. In the **Billing cadence** dropdown menu, select "1 month". +1. Click **Save**. +1. Click **Add Rate Card**. +1. From the **Feature** dropdown menu, select "example-service". +1. Click **Next Step**. +1. From the **Pricing model** dropdown menu, select "Usage based". +1. In the **Price per unit** field, enter `1`. +1. Click **Next Step**. +1. Click **Save Rate Card**. +1. Click **Publish Plan**. + +## Start a subscription + +Customers are the entities who pay for the consumption. In many cases, it's equal to your Consumer. Here you are going to create a customer and map our Consumer to it. + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the {{site.metering_and_billing}} sidebar, click **Billing**. +1. Click **Create Customer**. +1. In the **Name** field, enter `Kong Air`. +1. In the **Include usage from** dropdown, select "kong-air". +1. Click **Save**. +1. Click the **Subscriptions** tab. +1. Click **Create a Subscription**. +1. From the **Subscribed Plan** dropdown, select "Premium". +1. Click **Next Step**. +1. Click **Create Subscription**. + + + +## Validate + +You can run the following command to test the that the Kong Air Consumer is invoiced correctly: + + +```sh +for _ in {1..6}; do + curl -i $KONNECT_PROXY_URL/anything \ + -H "apikey:air-key" + echo +done +``` + + +This will generate six requests. Now, check the invoice that was created in {{site.metering_and_billing}}: + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the {{site.metering_and_billing}} sidebar, click **Billing**. +1. Click the **Invoices** tab. +1. Click **Kong Air**. +1. Click the **Invoicing** tab. +1. Click **Preview Invoice**. + +You'll see in Lines that `example-service` is listed and was used six times. In this guide, you're using the sandbox for invoices. To deploy your subscription in production, configure a payments integration in **{{site.metering_and_billing}}** > **Settings**. \ No newline at end of file diff --git a/app/_includes/konnect/metering-and-billing/discounts.md b/app/_includes/konnect/metering-and-billing/discounts.md new file mode 100644 index 0000000000..c9bd1c825e --- /dev/null +++ b/app/_includes/konnect/metering-and-billing/discounts.md @@ -0,0 +1,22 @@ +## Discounts and commitments + +Rate Cards discounts and commitments allow you to adjust the price of a feature in a plan. + +The following table describes the discounts and commitment types: + +{% table %} +columns: + - title: Discount + key: discount + - title: Description + key: description +rows: + - discount: Percentage discount + description: "Reduces price by a fixed percent across all usage." + - discount: "[Usage discount](#usage-discounts)" + description: "Pricing applies only after the discounted usage value is reached. You can use this to define overage prices." + - discount: Minimum spend + description: "Guarantees a customer pays a specified amount, even if their usage is less. For example, if the minimum spend is set to $10, customers will pay $10 even if they only use $2 worth of the API or LLM token. The minimum spend line only appears on the invoice that includes the end of the line’s billing period." + - discount: Maximum spend + description: "Sets the maximum amount a customer will pay for a feature. For example, if maximum spend is set to $10, customers will only pay $10, even if they have a $100 worth of usage." +{% endtable %} diff --git a/app/_includes/konnect/metering-and-billing/tax.md b/app/_includes/konnect/metering-and-billing/tax.md new file mode 100644 index 0000000000..12a8080a91 --- /dev/null +++ b/app/_includes/konnect/metering-and-billing/tax.md @@ -0,0 +1,39 @@ +{{site.metering_and_billing}} doesn't calculate taxes itself. Instead, it configures external services to do so with Product Catalog. Currently, {{site.metering_and_billing}} supports [Stripe Tax](https://stripe.com/tax). + +{{site.metering_and_billing}} supports the following tax settings: + +* Inclusive: The listed price already includes tax. A 10% inclusive tax on a $500 item still results in a $500 invoice. +* Exclusive: Tax is added on top of the listed price. A 10% exclusive tax on a $500 item raises the invoice total to $550. +* Tax codes: Apply a tax code to a feature. Some payment providers, like Stripe, apply their own default [tax code](https://docs.stripe.com/tax/tax-codes). In those cases, you can leave {{site.metering_and_billing}}'s tax settings blank. + +You can enable tax collection from a [Rate Card](/metering-and-billing/product-catalog/) or the [billing profile settings](https://cloud.konghq.com/metering-billing/billing-profiles). + +In {{site.metering_and_billing}}, you can define the tax behavior on multiple levels, from lowest to highest precedence: + +{% table %} +columns: + - title: Use Case + key: use_case + - title: Setting + key: setting +rows: + - use_case: "Fallback to the tax behavior of the payment provider, like Stripe." + setting: "[Payment provider](https://cloud.konghq.com/metering-billing/apps)" + - use_case: "Define the default tax behavior, if any, for all customers." + setting: "[Billing profile](https://cloud.konghq.com/metering-billing/billing-profiles)" + - use_case: "Override the default tax behavior on a per Rate Card basis." + setting: "[Plan Rate Card](/metering-and-billing/product-catalog/#rate-cards)" + - use_case: "Override the default tax behavior on a per-subscription basis." + setting: "[Subscription Rate Card](/metering-and-billing/product-catalog/#rate-cards)" + - use_case: "Override the tax behavior per invoice line item." + setting: "[Invoice](https://cloud.konghq.com/metering-billing/invoices)" +{% endtable %} + + +We recommend setting the tax behavior on the payment provider level if you use Stripe for tax calculation. Tax behavior is optional at the billing profile, plan rate card, and subscription rate card levels. + +When tax enforcement is enabled, {{site.metering_and_billing}} prevents you from starting a subscription if automatic tax calculation isn't supported. When enforcement is enabled, the following actions are blocked: + +* Creating a paid subscription when tax cannot be calculated +* Finalizing an invoice when tax cannot be calculated +* Validation logic also varies by tax service. For example, with Stripe Tax, {{site.metering_and_billing}} uses Stripe's APIs to verify whether tax calculation is supported for the customer. In that case of Stripe, the customer must have a valid tax location. \ No newline at end of file diff --git a/app/_indices/metering-and-billing.yaml b/app/_indices/metering-and-billing.yaml new file mode 100644 index 0000000000..23bc9ad52e --- /dev/null +++ b/app/_indices/metering-and-billing.yaml @@ -0,0 +1,12 @@ +title: "{{site.metering_and_billing}} Documentation Index" +sections: + - title: Reference + items: + - path: /metering-and-billing/ + - path: /metering-and-billing/**/* + auto_exclude: true + - title: How-Tos + items: + - type: how-to + products: + - metering-and-billing \ No newline at end of file diff --git a/app/_landing_pages/metering-and-billing.yaml b/app/_landing_pages/metering-and-billing.yaml new file mode 100644 index 0000000000..99c4fddb63 --- /dev/null +++ b/app/_landing_pages/metering-and-billing.yaml @@ -0,0 +1,159 @@ +metadata: + title: "{{site.metering_and_billing}}" + content_type: landing_page + description: Learn how to meter and bill for your features with {{site.metering_and_billing}}. + breadcrumbs: + - /metering-and-billing/ + products: + - metering-and-billing + +rows: + - header: + type: h1 + text: "{{site.metering_and_billing}}" + sub_text: Meter, bill, and monetize the entire AI connectivity data path. + columns: + - blocks: + - type: structured_text + config: + blocks: + - type: text + text: | + {{site.konnect_short_name}} {{site.metering_and_billing}} provides a full system for tracking real-time usage, pricing products, enforcing entitlements, and generating invoices. + It is designed for AI and API-first businesses that need accurate usage metering, flexible pricing models, and customer-level billing detail. + + You can meter {{site.base_gateway}} requests, LLM tokens, or any custom event. + You can create and publish pricing plans, manage subscriptions, and automate revenue collection with payment providers like Stripe and ERPs. + - type: button + config: + text: "Start metering and billing API Gateway requests →" + url: /metering-and-billing/get-started/ + + - blocks: + - type: image + config: + url: /assets/images/konnect/metering.png + alt_text: "{{site.metering_and_billing}} Overview" + + + - header: + type: h2 + text: "Learn more" + + columns: + - blocks: + - type: card + config: + title: Metering + description: | + {{site.metering_and_billing}} provides a real-time event based usage metering to aggregate consumption over time precisely. It also provides deduplication and flexible usage attribution of events and consumers to billable customers. + icon: /assets/icons/analytics.svg + cta: + text: Learn more + url: /metering-and-billing/metering/ + - blocks: + - type: card + config: + title: Product Catalog + description: | + {{site.konnect_short_name}} {{site.metering_and_billing}}’s Product Catalog lets you centrally define the different plans and plan features that make up your offering—so you can manage pricing, entitlements, and packaging in one place. + icon: /assets/icons/document-list.svg + cta: + text: Learn more + url: /metering-and-billing/product-catalog/ + - blocks: + - type: card + config: + title: Customers and usage attribution + description: | + Customers represent individuals or organizations that subscribe to plans, gain access to features, and are invoiced for their consumption. + icon: /assets/icons/team.svg + cta: + text: Learn more + url: /metering-and-billing/customer/ + - blocks: + - type: card + config: + title: Billing, invoicing, and subscriptions + description: | + Learn how to set up billing, invoicing, and subscriptions in {{site.konnect_short_name}} {{site.metering_and_billing}}. + icon: /assets/icons/money.svg + cta: + text: Learn more + url: /metering-and-billing/billing-invoicing-subscriptions/ + + - header: + type: h2 + text: "Integrations" + sub_text: "Connect {{site.metering_and_billing}} to external payment, CRM, and invoicing systems" + + column_count: 3 + columns: + - blocks: + - type: card + config: + title: Stripe + description: | + Send invoices, calculate tax, and collect payments. + icon: /assets/icons/third-party/stripe.svg + cta: + text: View integration + url: "https://cloud.konghq.com/us/metering-billing/apps/marketplace/stripe" + + - blocks: + - type: card + config: + title: Custom Invoicing + description: | + Implement custom billing flows using your own invoicing and payment systems. + icon: /assets/icons/third-party/custom.svg + cta: + text: View integration + url: "https://cloud.konghq.com/us/metering-billing/apps/marketplace/custom_invoicing" + + - blocks: + - type: card + config: + title: HubSpot + description: | + Sync customer data and analyze customer interactions through HubSpot CRM. + icon: /assets/icons/third-party/hubspot.svg + cta: + text: Contact Sales + url: "https://konghq.com/contact-sales" + + - blocks: + - type: card + config: + title: Salesforce + description: | + Integrate with Salesforce CRM to manage accounts, subscriptions, and customer insights. + icon: /assets/icons/third-party/salesforce.svg + cta: + text: Contact Sales + url: "https://konghq.com/contact-sales" + + - blocks: + - type: card + config: + title: PayPal + description: | + Accept customer payments using PayPal’s global payment platform. + icon: /assets/icons/third-party/paypal.svg + cta: + text: Contact Sales + url: "https://konghq.com/contact-sales" + + - blocks: + - type: card + config: + title: Adyen + description: | + Process global payments with Adyen’s payment infrastructure. + icon: /assets/icons/third-party/adyen.svg + cta: + text: Contact Sales + url: "https://konghq.com/contact-sales" + + + diff --git a/app/_plugins/blocks/validation.rb b/app/_plugins/blocks/validation.rb index 081610f75d..2e0954ecf8 100644 --- a/app/_plugins/blocks/validation.rb +++ b/app/_plugins/blocks/validation.rb @@ -18,7 +18,7 @@ def render(context) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength products = @page.fetch('products', []) - unless %w[gateway kic ai-gateway operator event-gateway].any? { |p| products.include?(p) } + unless %w[gateway kic ai-gateway operator event-gateway metering-and-billing].any? { |p| products.include?(p) } raise ArgumentError, "Unsupported product for {% validation #{@name} %}" end diff --git a/app/assets/icons/third-party/adyen.svg b/app/assets/icons/third-party/adyen.svg new file mode 100644 index 0000000000..b6e1fb932a --- /dev/null +++ b/app/assets/icons/third-party/adyen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/icons/third-party/custom.svg b/app/assets/icons/third-party/custom.svg new file mode 100644 index 0000000000..c533465dd5 --- /dev/null +++ b/app/assets/icons/third-party/custom.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/icons/third-party/hubspot.svg b/app/assets/icons/third-party/hubspot.svg new file mode 100644 index 0000000000..4be6b49537 --- /dev/null +++ b/app/assets/icons/third-party/hubspot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/icons/third-party/paypal.svg b/app/assets/icons/third-party/paypal.svg new file mode 100644 index 0000000000..f5fe1e8212 --- /dev/null +++ b/app/assets/icons/third-party/paypal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/icons/third-party/salesforce.svg b/app/assets/icons/third-party/salesforce.svg new file mode 100644 index 0000000000..8a15f25559 --- /dev/null +++ b/app/assets/icons/third-party/salesforce.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/icons/third-party/stripe.svg b/app/assets/icons/third-party/stripe.svg new file mode 100644 index 0000000000..f421bbcfe7 --- /dev/null +++ b/app/assets/icons/third-party/stripe.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/images/konnect/metering.png b/app/assets/images/konnect/metering.png new file mode 100644 index 0000000000..2ddcca6d3e Binary files /dev/null and b/app/assets/images/konnect/metering.png differ diff --git a/app/konnect-platform/teams-and-roles.md b/app/konnect-platform/teams-and-roles.md index 362602be1b..a9fc789e5b 100644 --- a/app/konnect-platform/teams-and-roles.md +++ b/app/konnect-platform/teams-and-roles.md @@ -189,6 +189,37 @@ schema: mesh_control_planes {% endkonnect_roles_table %} +#### {{site.metering_and_billing}} + +The following describes the predefined roles for [{{site.metering_and_billing}}](/metering-and-billing/): + +{% table %} +columns: + - title: Role + key: role + - title: Description + key: description +rows: + - role: "`Ingest`" + description: "Ingests events only (intended only for machines)." + - role: "`Admin`" + description: "Can read and write every resource. Includes billing apps, billing profiles, and notifications." + - role: "`Viewer`" + description: "Can read every resource. Includes billing apps, billing profiles, and notifications." + - role: "`Metering Admin`" + description: "Can write any metering resources (includes meters and events)." + - role: "`Metering Viewer`" + description: "Can read any metering resources (includes meters and events)." + - role: "`Product Catalog Admin`" + description: "Can write any Product Catalog resources (includes plans, features, and rate cards)." + - role: "`Product Catalog Viewer`" + description: "Can read any Product Catalog resources (includes plans, features, and rate cards)." + - role: "`Billing Admin`" + description: "Can read and write customer, subscription, entitlement, and invoice resources." + - role: "`Billing Viewer`" + description: "Can read customer, subscription, entitlement, and invoice resources." +{% endtable %} + #### Networks The following describes the predefined roles for networks: diff --git a/app/metering-and-billing/billing-invoicing-subscriptions.md b/app/metering-and-billing/billing-invoicing-subscriptions.md new file mode 100644 index 0000000000..a773ac935d --- /dev/null +++ b/app/metering-and-billing/billing-invoicing-subscriptions.md @@ -0,0 +1,177 @@ +--- +title: "Billing, invoicing, and subscriptions" +content_type: reference +description: "Learn how billing, invoicing, and subscriptions work in {{site.konnect_short_name}} {{site.metering_and_billing}}." +layout: reference +products: + - metering-and-billing +tools: + - konnect-api +works_on: + - konnect +breadcrumbs: + - /metering-and-billing/ +related_resources: + - text: "{{site.konnect_short_name}} {{site.metering_and_billing}}" + url: /metering-and-billing/ +--- + +## Billing profiles + +Billing profiles contain the invoicing, payment, and tax settings for billing and controls invoice generation. An organization can have multiple billing profiles defined. This is useful when you have different billing needs for different customers. For example, you might want some customers to be billed via Stripe and others via bank transfer. + +Each {{site.metering_and_billing}} instance has one default billing profile that all new customers will be assigned to unless otherwise specified. An exception to this is when modifying the default billing profile from Sandbox to a production app, customers with outstanding invoices are automatically retained on the Sandbox-based billing profile to prevent unintended charges from test data. + +A billing profile is linked to a specific App. This association is established during the billing profile's creation and remains immutable. When transitioning to a new app, organizations must [migrate to a new billing profile](#customer-billing-profile-overrides). + +Billing profiles can be managed from the [**Billing Profiles**](https://cloud.konghq.com/metering-billing/billing-profiles) tab in **{{site.metering_and_billing}} > Settings** in the {{site.konnect_short_name}} UI. + +### Invoicing settings + +The invoicing settings define the invoice creation process and lifecycle management parameters, including: + +* Whether invoices are sent automatically for payment collection or if they require approval first +* If intermediate invoices are allowed +* How long to wait for late usage events +* How long to wait before sending the invoice + +You may want to disable auto advance for the following use cases: + +* Initial billing configuration validation: Enables manual verification of charges prior to customer distribution +* Emergency control mechanism: Provides immediate invoice control during system integration issues or event reporting anomalies +* External system integration requirements: Accommodates scenarios requiring synchronization with external systems prior to invoice finalization + +Strategic applications of auto advance with extended draft periods: + +* Facilitates internal review processes by support and sales teams before customer distribution. +* Enables quality assurance checks on high-value accounts. +* Default tax behavior establishes the standard tax handling for invoice line items, unless overridden by subscription-specific Rate Card settings. + +### Payment settings + +Payment method determines the invoice settlement process. {{site.metering_and_billing}} currently supports two payment methods: + +* **Charge automatically:** Processes payment immediately using the customer's stored payment card. +* **Send invoice:** Issues an invoice to the customer for payment via their preferred method (credit card, bank transfer, or other supported payment options). + +Invoice due after/Payment due after specifies the duration allowed for invoice payment after finalization. This grace period applies to all payment methods, including credit card payments which may be declined. If payment is not received within this timeframe, the invoice status will transition to overdue. + +### Customer billing profile overrides + +Customer overrides allows you to assign a different billing profile to customers other than the default. By default customers are pinned to the default billing profile. This is useful when you have different billing needs for different customers. For example, you might want some customers to be billed via Stripe and others via bank transfer. + +Customer overrides can be useful for the following use cases: +* **Enterprise billing**: Set up one billing profile for SaaS customers and another for Enterprise customers (with send invoice for bank transfer selected). +* **Migrating customers billing**: Create a new billing profile that you want to migrate customers to and then assign them to the new profile with a customer override. + +Configure customer overrides by navigating to **{{site.metering_and_billing}}** > [**Billing**](https://cloud.konghq.com/metering-billing/customers), click a customer, then navigate to the **Billing Profile** section of the customer settings. + +## Tax calculations + +{% include_cached /konnect/metering-and-billing/tax.md %} + +## Invoicing + +Invoices are created when a subscription starts and are kept up-to-date with the subscription state. The subscription [Rate Card](/metering-and-billing/product-catalog/#rate-cards) governs the price and the invoicing frequency for the specified feature. For example, a subscription with a single in-advance flat fee billed monthly will generate one invoice per month. + +{{site.metering_and_billing}} invoices follow a well-defined lifecycle that aligns directly with their associated subscription periods. Each invoice serves as an immutable record of billing information, which ensures complete data integrity and audit compliance throughout the billing process. + +The invoice document maintains comprehensive and structured information that is essential for billing transparency. Invoices contain the following information: +* The total amount of lines before discounts and taxes +* The total amount of charges (minimum spend) before discounts and taxes +* The total amount of discounts applied +* The total amount of inclusive and exclusive taxes +* The total amount of taxes +* The total amount after taxes and discounts charged to the customer + +To view invoices in {{site.konnect_short_name}}, navigate to **{{site.metering_and_billing}}** > **Billing** and click the **Invoices** tab. + +### Invoice lifecycle + +The following table describes the different states of the invoice lifecycle: + +{% table %} +columns: + - title: State + key: state + - title: Possible transitions + key: transitions + - title: Description + key: description +rows: + - state: Gathering + transitions: N/A + description: "Gathering the items to be invoiced. Note: for details please see Gathering Invoices, in this page only the other states will be discussed" + - state: Draft + transitions: "Issued, Deleted" + description: "The invoice is created and in draft state. The invoice can only be updated in this state. In later states the invoice can only be voided." + - state: Issued + transitions: Payment Processing + description: "The invoice is issued to the customer." + - state: Payment Processing + transitions: "Overdue, Unable to be collected, Paid, Void" + description: "Payment is being processed." + - state: Overdue + transitions: "Paid, Void, Unable to be collected" + description: "The invoice is overdue." + - state: Unable to be collected + transitions: "Paid, Void" + description: "The invoice has been marked as unable to be collected." + - state: Paid + transitions: N/A + description: "The invoice has been paid." + - state: Void + transitions: N/A + description: "The invoice has been voided." + - state: Deleted + transitions: N/A + description: "The invoice has been deleted and is no longer available." +{% endtable %} + + +### Gathering invoices + +{{site.metering_and_billing}} gathers invoices with upcoming charges for the active running billing cycle. These invoices show current pending charges for the user's current billing period in real-time when fetched or viewed, providing visibility into accruing usage before the final invoice is issued. + +Gathering invoices are automatically deleted when the last item for a subscription has been billed for. + +Given an invoice is always single currency, if the customer was migrated between currencies they might have one gathering invoice per currency. + +{:.warning} +> **Important:** For systematic changes that need to persist across billing cycles, we recommend modifying the subscription directly rather than editing gathering invoices. This ensures consistent billing behavior aligned with the intended subscription terms. + +{% include_cached /konnect/metering-and-billing/discounts.md %} + +## Subscriptions + +Billing and subscriptions in {{site.metering_and_billing}} create relationships between customers and their pricing model. This serves as the bridge between your customers, their usage data, and how that usage translates into billable amounts. + +Subscriptions automate the billing lifecycle by: + +* **Tracking usage** through meters +* **Applying pricing logic** from plans or custom configurations +* **Generating invoices** based on billing cadences +* **Enforcing entitlements** to control feature access + +Subscriptions can be created from predefined plans or fully customized at creation time to accommodate unique customer requirements. This flexibility supports everything from self-serve sign-ups to enterprise contract negotiations. + +To add a subscription to a customer, navigate to **{{site.metering_and_billing}}** > **Billing**, click your customer, and then click the **Subscriptions** tab in the {{site.konnect_short_name}} UI. + +## Plan migration + +Plans in {{site.metering_and_billing}} are versioned. When you update a plan, existing subscriptions remain on their current version. This is known as "grandfathering". Customers keep their existing pricing until they're explicitly migrated. + +Migrating a subscription to a new plan version allows you to: + +* Apply new pricing to existing customers +* Transition customers to improved plan structures +* Deprecate old plan versions +* Standardize customers on current offerings + +Migrations follow the same timing rules as other subscription changes: + +* **Immediate**: Migration takes effect right away +* **Next billing cycle**: Migration occurs at the end of the current period + +Choose timing based on whether the migration is favorable (immediate) or potentially disruptive (next cycle) to the customer. + diff --git a/app/metering-and-billing/customer.md b/app/metering-and-billing/customer.md new file mode 100644 index 0000000000..a6825b4a4c --- /dev/null +++ b/app/metering-and-billing/customer.md @@ -0,0 +1,163 @@ +--- +title: "Customers and usage attribution" +content_type: reference +description: "Learn how Customers and usage attributes work in {{site.konnect_short_name}} {{site.metering_and_billing}} and how they access features." +layout: reference +products: + - metering-and-billing +tools: + - konnect-api +works_on: + - konnect +breadcrumbs: + - /metering-and-billing/ +related_resources: + - text: "{{site.konnect_short_name}} {{site.metering_and_billing}}" + url: /metering-and-billing/ +--- + +## What is a customer? + +Customers represent individuals or organizations that subscribe to plans, gain access to features, and are invoiced for their consumption. + +Billable events ingested into {{site.metering_and_billing}} always include a subject field that represents metered entities within your system, such as {{site.base_gateway}} [Consumers](/gateway/entities/consumer/), [Dev Portal applications](/dev-portal/self-service/), or [subjects](#what-is-a-subject) or entities outside of {{site.konnect_short_name}}. + +A customer can have **one or many** usage attributes assigned, allowing you to group usage and billing. For example, if a customer has multiple departments that are producing usage, you could create two usage attributes for each department that are assigned to one customer. + +{% mermaid %} +flowchart TB + %% Left side + Customer[Customer] + Subject[Subject] + UsageEventsLeft[Usage Events] + + Customer -->|1:n| Subject + Subject -->|1:n| UsageEventsLeft + + %% Right side + ACME[ACME Inc.] + Dept1[Department 1] + Dept2[Department 2] + UsageEvents1[Usage Events] + UsageEvents2[Usage Events] + + ACME --> Dept1 + ACME --> Dept2 + + Dept1 --> UsageEvents1 + Dept2 --> UsageEvents2 +{% endmermaid %} + +Use the following table to help you determine the best way to map your customers to usage attributes: + +{% table %} +columns: + - title: You want to... + key: use-case + - title: Then use... + key: recommendation +rows: + - use-case: | + Attribute Kong AI Gateway token usage to customers. + recommendation: "[Consumers](/gateway/entities/consumer/)" + - use-case: | + Attribute {{site.base_gateway}} API request usage to customers. + recommendation: "[Consumers](/gateway/entities/consumer/)" + - use-case: | + Attribute {{site.konnect_short_name}} Dev Portal application requests to customers. + recommendation: "[Applications](/dev-portal/self-service/)" + - use-case: | + Attribute usage from sources outside of {{site.base_gateway}} and {{site.konnect_short_name}} to customers. + recommendation: "[Subjects](#what-is-a-subject)" +{% endtable %} + +### What is a subject? + +Subjects represent the entity that consumes metered resources in {{site.konnect_short_name}} {{site.metering_and_billing}}. Billable events ingested to {{site.metering_and_billing}} have a subject associated with them. + +A subject can represent any unique event in your system, such as: +* Customer ID or User ID +* Hostname or IP address +* Service or application name +* Device ID + +The subject model is intentionally generic, enabling flexible application across different metering scenarios. + + + +#### Data ingestion + +When shipping data to {{site.konnect_short_name}}, you must include the subject within the events payload: + +```ts +{ + "specversion": "1.0", + "type": "api-calls", + "id": "00002", + "time": "2023-01-01T00:00:00.001Z", + "source": "service-0", + "subject": "customer-1", + "data": {...} +} +``` + +## Create a customer + +To create a customer in {{site.konnect_short_name}}, do the following: + +{% navtabs "customer" %} +{% navtab "Consumer" %} + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the {{site.metering_and_billing}} sidebar, click **Billing**. +1. Click **Create Customer**. +1. In the **Name** field, enter your customer's name. +1. Select **Consumers**. +1. In the **Include usage from** dropdown, search for your Consumer. +1. Click **Save**. + +{% endnavtab %} +{% navtab "Application" %} + +1. In the {{site.konnect_short_name}} sidebar, click **{{site.metering_and_billing}}**. +1. In the {{site.metering_and_billing}} sidebar, click **Billing**. +1. Click **Create Customer**. +1. In the **Name** field, enter your customer's name. +1. Select **Applications**. +1. In the **Include usage from** dropdown, search for the Dev Portal application. +1. Click **Save**. + +{% endnavtab %} +{% navtab "Subject" %} + +{:.warning} +> **Important:** During the billing beta, customers are limited to **one subject**. Support for multiple subjects will be available in the future. + +Subjects are created when you create the customer. To create a customer associated with a subject, send a `POST` request to the `/openmeter/customers` endpoint: + + +{% konnect_api_request %} +url: /v3/openmeter/customers +status_code: 201 +method: POST +body: + name: "ACME Inc." + key: "019ae40f-4258-7f15-9491-842f42a7d6ac" + usageAttribution: + subjectKeys: + - "YOUR-SUBJECT-KEY" +{% endkonnect_api_request %} + + +Replace `$KONNECT_TOKEN` with your [{{site.konnect_short_name}} personal or system access token](/konnect-api/#system-accounts-and-access-tokens) and `YOUR-SUBJECT-KEY` with the subject key from events that are associated with the customer. + +{:.info} +> {{site.konnect_short_name}} {{site.metering_and_billing}} will also automatically create a subject for you when you ingest an usage event for a new subject. + +{% endnavtab %} +{% endnavtabs %} + + +## Schema + +[Insert Schema here](https://openmeter.io/docs/api/cloud#tag/customers) \ No newline at end of file diff --git a/app/metering-and-billing/metering.md b/app/metering-and-billing/metering.md new file mode 100644 index 0000000000..0240d46353 --- /dev/null +++ b/app/metering-and-billing/metering.md @@ -0,0 +1,568 @@ +--- +title: "Metering" +content_type: reference +description: "Learn how metering works in {{site.konnect_short_name}} {{site.metering_and_billing}}." +layout: reference +products: + - metering-and-billing +tools: + - konnect-api +works_on: + - konnect +breadcrumbs: + - /metering-and-billing/ +related_resources: + - text: "{{site.konnect_short_name}} {{site.metering_and_billing}}" + url: /metering-and-billing/ + - text: "Subjects" + url: /metering-and-billing/subjects/ +faqs: + - q: Do I need to bill or create plans for my meters? + a: No, you can use metering on it's own to track customer usage. +--- + +{{site.metering_and_billing}} provides a real-time event based usage metering to aggregate consumption over time precisely. It also provides deduplication and flexible usage attribution of events and consumers to billable customers. + +{{site.metering_and_billing}} metering can help to track various usage: + + +{% table %} +columns: + - title: Use Case + key: use_case + - title: Description + key: description +rows: + - use_case: AI Tokens + description: "Metering AI Tokens consumed by LLMs and AI agents." + - use_case: API Requests + description: "Metering API Requests count and duration." + - use_case: Compute + description: "Metering runtime of VMs, CPUs, GPUs, etc." + - use_case: Seats + description: "Metering number of unique users over sessions." +{% endtable %} + + +You can meter {{site.base_gateway}} events, like API requests and LLM token usage, as well as generic events. + +Each generic meter is comprised from the following attributes: +* Event type: The event type that the meter is tracking. This is used to filter the events that are used to calculate the meter. +* Value type: The JSON path to the property that contains the value to be metered. This is optional when the aggregation is `COUNT`. +* Aggregation type: The [aggregation type](#aggregation-types) to use for the meter. +* Group by: (Optional) A map of JSON paths to group the metered data by. + +## Aggregation types + +Aggregation types determine how usage data is aggregated for generic meters. + +You can configure the following aggregation types for generic meters: + +{% table %} +columns: + - title: Aggregation Type + key: aggregation_type + - title: Description + key: description +rows: + - aggregation_type: COUNT + description: "The `COUNT` aggregation type counts the number of events that occur within a specific time window. This is often used for metrics that are inherently countable, such as the number of transactions processed or API calls made. The `COUNT` aggregation type doesn't have the `valueProperty`." + - aggregation_type: SUM + description: "The `SUM` aggregation type calculates the total sum of the metered values for a specific time window. `SUM` aggregates over the events `valueProperty`. This is useful for accumulating metrics like total LLM tokens used, total data transferred, or total time spent on a service." + - aggregation_type: UNIQUE COUNT + description: "The `UNIQUE_COUNT` aggregation type counts the number of unique events. This is useful when events are unique by a specific field. The `valueProperty` defines the field that makes the ingested event unique. The property's value in the ingested event must be a string or number." + - aggregation_type: LATEST + description: "The `LATEST` aggregation type returns the latest value for a specific time window. This is useful for when you track the size of a resource on your own and report periodically the value of it to {{site.metering_and_billing}}. For example disk size, number of resources or seats. The latest aggregation takes the last value reported for the period." + - aggregation_type: MIN + description: "The `MIN` aggregation type identifies the minimum value among the metered data points within a specific time window. This is useful for metrics where the lowest value is of interest, such as minimum available storage or minimum response time." + - aggregation_type: MAX + description: "The `MAX` aggregation type identifies the maximum value among the metered data points within a specific time window. This is useful for metrics where the highest value is of interest, such as maximum load on a server or maximum transaction value." +{% endtable %} + + +## Event ingestion + +{{site.metering_and_billing}} ingests {{site.konnect_short_name}} API Gateway and LLM events automatically when they're enabled. If you want to configure generic meters, you must use the [CloudEvents](https://cloudevents.io/) format for event ingestion. + +As CloudEvents is generic, here are some best practices for defining events in OpenMeter: + +{% table %} +columns: + - title: Name + key: name + - title: Description + key: description + - title: Examples + key: examples +rows: + - name: "Subject (API Property: `event.subject`)" + description: "Subjects in OpenMeter are entities that consume resources you wish to meter. These can range from users, servers, and services to devices. The design of subjects is intentionally generic, enabling flexible application across various metering scenarios. Typically, a subject acts as a unique identifier within your system for a user or customer." + examples: | + - Customer ID or User ID + - Hostname or IP address + - Service or Application name + - Device ID + - name: "Source Property (API Property: `event.source`)" + description: "The event's source (e.g. the service name). As events are unique by id and source, set different sources if you report the same transaction in multiple applications." + examples: | + - `my-service-name` + - `my-application-name` + - name: "Choosing Event ID" + description: "Events are unique by `id` and `source` properties for idempotency. OpenMeter deduplicates events by uniqueness. Therefore, picking an ID that makes the event unique and resilient to retries is important. For example, in the case of a metering API call, this can be the request ID. You can generate a new UUID if your application doesn't have a unique identifier." + examples: | + - HTTP Request ID, typically in headers: `Request-ID`, `X-Request-ID` + - LLM Chat Completion ID: `id` field in ChatGPT response + - Workflow ID: like activity ID in Temporal + - Generate UUID: Node.js, Python, Go + - name: "Data Property (API Property: `event.data`)" + description: "OpenMeter uses CloudEvents format's data property to ingest values and group bys. Be sure to always include in this data property what the meter requires, like value property and group bys." + examples: | + - Always include value property for non-`COUNT` aggregations. + - Always include group by properties. + - Use string quotation for numbers to preserve precision like `\"123\"`. +{% endtable %} + + +## Create a meter + +To configure a meter in {{site.konnect_short_name}}, do the following: + +{% navtabs "create-meter" %} +{% navtab "{{site.base_gateway}} API requests" %} +To meter {{site.base_gateway}} API requests, you need traffic to a [Gateway Service](/gateway/entities/service/#set-up-a-gateway-service) and[Route](/gateway/entities/route/#set-up-a-route). + +1. In the {{site.konnect_short_name}} sidebar, click **Metering & Billing**. +1. Enable **Gateway**. +1. Select a Gateway +1. Click **Enable Gateway** + +{% endnavtab %} +{% navtab "Kong AI Gateway LLM tokens" %} +To meter Kong AI Gateway LLM token usage, you must have the [AI Proxy plugin](/plugins/ai-proxy/) configured. + +1. In the {{site.konnect_short_name}} sidebar, click **Metering & Billing**. +1. Enable **AI Gateway Tokens**. + +You will see `kong_konnect_llm_tokens` available from the list of available meters. +{% endnavtab %} +{% navtab "Generic meters" %} + +1. In the {{site.konnect_short_name}} sidebar, click **Metering & Billing**. +1. Click **New generic meter**. +1. Configure the meter information as needed. +1. Send a CloudEvent to start collecting meter usage. + +{% endnavtab %} +{% endnavtabs %} + +## Example meter use cases + +The following example show how you can configure meters and usage events for common use cases. + +### LLM token usage + +{:.info} +> If you want to meter Kong AI Gateway LLM token usage, you can enable the built-in integration to meter usage in one click. + +In most cases, AI applications want to count token usage for billing or cost control purposes. As a single AI interaction involves consuming multiple tokens, we define our generic meter with the `SUM` aggregation and report token usage in the data's tokens property. As most LLMs charge differently for input, output and system prompts and different models it makes sense to add model and prompt type to the group by. + +{% navtabs "llm-token-usage" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: tokens_total + description: AI Token Usage + # Filter events by type + eventType: prompt + aggregation: SUM + # JSONPath to parse usage value + valueProperty: $.tokens + groupBy: + # Model used: gpt4-turbo, etc. + model: $.model + # Prompt type: input, output, system + type: $.type +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "prompt", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "chat-app", + "subject": "customer-1", + "data": { + "tokens": "123456", + "model": "gpt4-turbo", + "type": "output" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### GPU time + +Metering GPUs is a common use-case for customer billing, internal charge back and cost control use cases. + +{% navtabs "gpu-time" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: gpu_execution_duration_seconds + description: GPU Time + eventType: gpu_time + aggregation: SUM + valueProperty: $.duration_seconds + groupBy: + hostname: $.hostname + region: $.region + # Type of GPU: e.g. nvidia_A100 + gpu_type: $.gpu_type +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "gpu_time", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "my-image-generator", + "subject": "customer-1", + "data": { + "duration_seconds": "12345", + "hostname": "my-hostname", + "region": "us-east-1", + "gpu_type": "nvidia_A100" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### API request count + +{:.info} +> If you want to meter {{site.base_gateway}} API requests, you can enable the built-in integration to meter usage in one click. + +Products monetizing API usage may want to count the number of requests. With choosing the COUNT aggregation each event will increase the meter by one. For grouping we can add method and route. Note how we report the route template not the actual HTTP path to avoid differences around IDs and dynamic routes. + +{% navtabs "request-count" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: api_requests_total + description: API Requests + # Filter events by type + eventType: request + aggregation: COUNT + groupBy: + # HTTP Method: GET, POST, etc. + method: $.method + # Route: /products/:product_id + route: $.route +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "request", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "api-service", + "subject": "customer-1", + "data": { + "method": "GET", + "route": "/products/:product_id" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### API request duration + +Similar to the API request, you can decide to track the request duration. This is basically how serverless products like AWS Lambda charge their customers. If you want to track both the request count and duration, you can check out our advanced example. + +{% navtabs "request-duration" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: api_request_duration + description: API Request Duration + # Filter events by type + eventType: request + aggregation: SUM + # JSONPath to parse duration value + valueProperty: $.duration_seconds + groupBy: + # HTTP Method: GET, POST, etc. + method: $.method + # Route: /products/:product_id + route: $.route +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "request", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "api-service", + "subject": "customer-1", + "data": { + "method": "GET", + "route": "/products/:product_id", + "duration_seconds": "12345" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### Kubernetes pod execution duration + +To track Kubernetes pod execution duration, use our native Kubernetes collector that already reports usage events in this format. + +{% navtabs "k8s" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: pod_execution_time + description: Pod Execution Time + eventType: kube-pod-exec-time + aggregation: SUM + valueProperty: $.duration_seconds + groupBy: + pod_name: $.pod_name + pod_namespace: $.pod_namespace +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "kube-pod-exec-time", + "id": "f7f11c82-c415-4325-aec7-572606681817", + "time": "2024-01-01T00:00:00.001Z", + "source": "my-app", + "subject": "customer-1", + "data": { + "duration_seconds": "123", + "pod_name": "pod_name", + "pod_namespace": "pod_namespace" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### Counting unique events + +In some cases, you may want to count unique events, such as unique sessions. To achieve this, you can use the `UNIQUE_COUNT` aggregation. + +{% navtabs "count-unique" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: unique_sessions_total + description: Unique Sessions + eventType: login + aggregation: UNIQUE_COUNT + valueProperty: $.session_id +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "auth_check", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "auth-service", + "subject": "customer-1", + "data": { + "session_id": "session_id" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### Moving multiple meters with one event + +In OpenMeter, a single event can move multiple meters if the event type matches. Let's see an example of tracking an API request's occurrence, execution duration, and network usage. + +{% navtabs "moving-meters" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: api_requests_total + description: API Requests + eventType: request + aggregation: COUNT + groupBy: + method: $.method + route: $.route + - slug: api_request_duration_seconds + description: API Request Duration + eventType: request + aggregation: SUM + valueProperty: $.duration_seconds + groupBy: + method: $.method + route: $.route + - slug: api_request_ingress_bytes + description: Request Ingress Bytes + eventType: request + aggregation: SUM + valueProperty: $.ingress_bytes + groupBy: + method: $.method + route: $.route +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "type": "request", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "api-service", + "subject": "customer-1", + "data": { + "method": "GET", + "route": "/products/:product_id", + "duration_seconds": "123", + "ingress_bytes": "456", + "egress_bytes": "789" + } +} +``` +{% endnavtab %} +{% endnavtabs %} + +### Counting state changes + +In some cases you want to count how many states a workflow or task went through as it progresses for example from `created` to `in_progress` and `success`. The challenge is that if you report a usage event for every state change and track state as a group by answering simple questions like how many workflows were in total would always require filtering by states like `created`, which is easy to forget and error-prone. + +The recommended way to model states is to create separate meters per state. + +{% navtabs "state-change" %} +{% navtab "Meter example" %} +```yaml +meters: + - slug: workflow_created + description: Workflows Created + eventType: workflow_create + aggregation: COUNT + groupBy: + task_type: $.task_type + - slug: workflow_succeeded + description: Workflow Succeeded + eventType: workflow_success + aggregation: COUNT + groupBy: + task_type: $.task_type + - slug: workflow_failed + description: Workflow Failed + eventType: workflow_fail + aggregation: COUNT + groupBy: + task_type: $.task_type +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +[ + { + "specversion": "1.0", + "type": "workflow_create", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "task-queue", + "subject": "task-1", + "data": { + "type": "image-generate" + } + }, + { + "specversion": "1.0", + "type": "workflow_success", + "id": "00001", + "time": "2024-01-01T00:00:00.001Z", + "source": "task-queue", + "subject": "task-1", + "data": { + "task_type": "image-generate" + } + } +] +``` +{% endnavtab %} +{% endnavtabs %} + +### Translate AI demo + +Example meters for the imaginary Translate AI product that translates PDF documents between languages. For example, you can use an LLM like GPT-4 to translate a PDF document from German to English. For this use case, you want to track the number of pages, words, and LLM tokens used for each translation. + +{% navtabs "ai-demo" %} +{% navtab "Meter example" %} +Meter to count the number of pages translated: +```yaml +meters: + - slug: pages_total + description: Number of pages translated + eventType: translate + aggregation: SUM + valueProperty: $.pages +``` + +Meter to count the number of words translated: +```yaml +meters: + - slug: words_total + description: Number of words translated + eventType: translate + aggregation: SUM + valueProperty: $.words +``` + +Meter to count the number of LLM tokens used: +```yaml +meters: + - slug: tokens_total + description: Number of LLM tokens used + eventType: translate + aggregation: SUM + valueProperty: $.tokens + groupBy: + model: $.model +``` +{% endnavtab %} +{% navtab "Usage event example" %} +```json +{ + "specversion": "1.0", + "id": "0b8bb322-90c2-4b46-b541-0380bac1b9a5", + "source": "myapp", + "type": "translate", + "subject": "customer-123", + "datacontenttype": "application/json", + "time": "2025-02-18T16:37:44Z", + "data": { + "model": "gpt-4", + "pages": 23, + "tokens": 10200, + "words": 6912 + } +} +``` +{% endnavtab %} +{% endnavtabs %} diff --git a/app/metering-and-billing/product-catalog.md b/app/metering-and-billing/product-catalog.md new file mode 100644 index 0000000000..07f0e98b0d --- /dev/null +++ b/app/metering-and-billing/product-catalog.md @@ -0,0 +1,230 @@ +--- +title: "Product Catalog" +content_type: reference +description: "Learn how the Product Catalog work in {{site.konnect_short_name}} {{site.metering_and_billing}} and how they relate to usage tracking and external billing systems." +layout: reference +products: + - metering-and-billing +tools: + - konnect-api +works_on: + - konnect +breadcrumbs: + - /metering-and-billing/ +related_resources: + - text: "{{site.konnect_short_name}} {{site.metering_and_billing}}" + url: /metering-and-billing/ + - text: "Subjects" + url: /metering-and-billing/subjects/ + +--- + + +{{site.konnect_short_name}} {{site.metering_and_billing}}'s Product Catalog lets you centrally define the different plans and plan features that make up your offering—so you can manage pricing, entitlements, and packaging in one place. + +Each Product Catalog plan consists of: +* [Features](#features) that you want to price or govern. Can be metered or static. +* [Rate cards](#rate-cards) that determine which features ([entitlements](#entitlements)) and how much of the feature a subscriber can access ([pricing models](#pricing-models)) +* Optional [add-ons](#add-ons) that allow customers to purchase additional usage or features on demand + +For example, say you're metering API Gateway requests for your API and you want to charge customers based on API usage, you might configure your plans like the following: + +{% mermaid %} +flowchart TB + subgraph free-plan["Free Plan"] + direction TB + subgraph feature-free["Feature"] + direction TB + meter-free["Meter
(API requests)"] + end + rate-card-free["Rate Card
(10 requests/month)"] + entitlement-free["Entitlement (Metered)"] + end + + subgraph premium-plan["Premium Plan"] + direction TB + subgraph feature-premium["Feature"] + direction TB + meter-premium["Meter
(API requests)"] + end + rate-card-premium["Rate Card
(1000 requests/month)"] + entitlement-premium["Entitlement (Metered)"] + addon["Add-on
(1000 additional requests)"] + end + + meter-free ~~~ rate-card-free + rate-card-free ~~~ entitlement-free + + meter-premium ~~~ rate-card-premium + rate-card-premium ~~~ entitlement-premium + entitlement-premium ~~~ addon +{% endmermaid %} + + +## Features + +Features are part of your product offering and the building blocks of your plans and entitlements. They are the resource you want to govern and invoice for. For example, LLM Models, tokens, storage units. Features are associated with a meter, so that you can connect usage to a feature that you can then charge for. + +Features are the building blocks of your product offering, they represent the various capabilities of your system. Practically speaking, they typically translate to line items on your pricing page and show up on the invoice. + +The feature set between plans can vary in terms of what features are available, what configurations are available for a given feature, and what usage limits are enforced. + +The following table details an example for a fictional AI startup: + +{% table %} +columns: + - title: Feature + key: feature + - title: Free plan + key: plan1 + - title: Premium plan + key: plan2 +rows: + - feature: "GPT Tokens" + plan1: "10,000 /m" + plan2: "1,000,000 /m" + - feature: "Available models" + plan1: gpt-3 + plan2: "gpt-3, gpt-4" + - feature: "SAML SSO auth" + plan1: "-" + plan2: "Yes" +{% endtable %} + +Features can be archived, after which no new entitlements can be created for them, but the existing entitlement are left intact. You can think of this as deprecating a feature, removing it from the pricing page, or migrating it to a new name (key). + +## Plans + +Plans are a core component of the Product Catalog. Plans define the pricing and entitlements your customers receive in {{site.konnect_short_name}} {{site.metering_and_billing}}. They act as reusable templates that describe what a customer gets and how they are charged. Each plan can include multiple phases, prices, and entitlements, and can be versioned. + +Plans can take different forms, for example: + +* $99 per month for 1 million API requests +* 10 GB storage included +* SAML or SSO support + +### Rate cards + +Plans are built from rate cards, which determine which features a plan can access, the price, and how much of a feature they can use (called entitlements). Rate Cards define the configuration of features that subscribers will be entitled to and charged for. + +For example, to set up the previous example plan, you'd use the following rate cards: + +{% table %} +columns: + - title: Feature + key: feature + - title: Price + key: price + - title: Entitlement + key: entitlement +rows: + - feature: AI Tokens + price: "$99/m" + entitlement: "1,000,000 /m" + - feature: Storage + price: "$0/m" + entitlement: "10 GB /m" + - feature: SAML SSO + price: "$0/m" + entitlement: "True" +{% endtable %} + +Rate cards can be configured with or without a feature: + +* **With a feature:** Rate cards with features can be priced as recurring, one-time flat, or usage-based. Rate cards with features can have an entitlement to control access. When the associated feature has a meter, the rate card can describe usage limits. +* **Without a feature:** Rate cards without features can only have a flat-fee price. Rate cards without features don't have an entitlement to control access. + +#### Add-ons + +Add-ons let you extend your plans with optional features or capacity that customers can purchase on demand. They are versioned and consist of one or more rate cards defining pricing, entitlements, and billing cadence independently of the base plan. Add-ons allow you to sell extra features, overage packs, or services without changing the core plan. + +#### Pricing models + +Rate cards offer several different pricing models, listed in the following table: + +{% table %} +columns: + - title: Pricing model + key: model + - title: Description + key: description +rows: + - model: "Free" + description: "Free pricing" + - model: "Flat fee" + description: "A one-time or recurring fee" + - model: "Usage based" + description: "Linear pricing based on metered usage" + - model: "Tiered" + description: "Tiered pricing based on metered usage" + - model: "Package" + description: "Pricing based on fixed-sized usage packages" + - model: "Dynamic" + description: "USD prices created dynamically from meter values" +{% endtable %} + +Besides the **Free** pricing model, other models require configuration that you can see from the {{site.konnect_short_name}} UI. + +#### Tax calculations + +{% include_cached /konnect/metering-and-billing/tax.md %} + +#### Entitlements + +Entitlements are used to control access to different features, they make it possible to implement complex pricing scenarios such as monthly quotas, prepaid billing, and per-customer pricing. + +Entitlements can help you implement various monetization strategies: +* Enforce usage limits, like monthly token allowances. +* Sell plans with various feature sets. +* Offer custom quotes and per-customer pricing. +* Adopt prepaid billing and grant usage, and handle top-ups. +* Define and track pre-purchase commitments. + +There are three different types of entitlements: + +{% table %} +columns: + - title: Type + key: type + - title: Description + key: description +rows: + - type: Metered + description: | + Allow customers to consume features up to a certain usage limit, e.g., 10 million monthly tokens. + + This is useful for example when the underlying resources are expensive, as is the case for most AI products. Metered entitlements leverage the usage information collected by OpenMeter and give you the ability to do real time usage enforcement as well as historical queries and access checks. + - type: Static + description: | + Define customer-specific configurations as a JSON value. e.g. `{ "enabledModels": ["gpt-3", "gpt-4"] }` + + For example, you may only give free users access to a subset of AI models. With static entitlements, you can specify which models the customer can use based on their tier. + - type: Boolean + description: | + Describe access to specific features, like SAML SSO, without needing configuration or metering. + + In cases where you don't need to set up usage limits or configure customer level settings you can use boolean entitlements. These are simple true or false access grants to a feature. +{% endtable %} + +### Plan versions + +Plans are versioned to allow you to make changes without affecting running subscriptions. Each plan can have one published and one draft version. Editing already published plans will create a new draft version. Once you are ready, you can publish the draft version. + +Subscriptions are bound to a specific version of the plan and can be migrated to a new version. + +### Plan phases + +A plan can have multiple phases, such as a free trial for the first 30 days and then converting to a paid plan after the 30 days are up. Each phase can have a different price and entitlement. Phases can be used to create automatic time-based offering changes, like trials, reverse trials, ramp-up phases. + +Example for reverse trials with plan phases: + +* Phase 1 (Trial): limited to 100,000 tokens, premium features included +* Phase 2 (Free): limited to 1,000 tokens + + +{% include_cached /konnect/metering-and-billing/discounts.md %} + + +## Subscriptions + +{{site.konnect_short_name}} {{site.metering_and_billing}} [subscriptions](/metering-and-billing/billing-invoicing-subscriptions/#subscriptions) link your [Customers](/metering-and-billing/customer/) to plans, and [meters](/metering-and-billing/metering/). diff --git a/jekyll.yml b/jekyll.yml index 16a800e2d0..c950fef91d 100644 --- a/jekyll.yml +++ b/jekyll.yml @@ -106,6 +106,7 @@ operator_product_name_short: KO event_gateway: Kong Event Gateway event_gateway_short: Event Gateway konnect_catalog: Catalog +metering_and_billing: Metering & Billing repos: developer: https://github.com/Kong/developer.konghq.com