From 6a4c48ca656f8e985edeae1ac50318a4b0894c8a Mon Sep 17 00:00:00 2001 From: rolosp <6114043+rolosp@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:30:52 +0200 Subject: [PATCH 1/2] feat: add v3 operations to v1 client --- .agents/skills/v3-client-shim/SKILL.md | 187 + .../v3-client-shim/references/add-endpoint.md | 228 + api/client/javascript/orval.v3.config.ts | 41 + api/client/javascript/package.json | 4 +- api/client/javascript/scripts/add-as-const.ts | 8 +- api/client/javascript/scripts/generate-v3.ts | 46 + api/client/javascript/src/client/index.ts | 17 + api/client/javascript/src/v3/addons.ts | 111 + api/client/javascript/src/v3/apps.ts | 41 + .../javascript/src/v3/billing-profiles.ts | 90 + api/client/javascript/src/v3/currencies.ts | 88 + api/client/javascript/src/v3/customers.ts | 366 + api/client/javascript/src/v3/defaults.ts | 43 + api/client/javascript/src/v3/events.ts | 45 + api/client/javascript/src/v3/features.ts | 108 + api/client/javascript/src/v3/governance.ts | 29 + api/client/javascript/src/v3/index.ts | 90 + api/client/javascript/src/v3/llm-cost.ts | 86 + api/client/javascript/src/v3/meters.ts | 105 + api/client/javascript/src/v3/plans.ts | 205 + api/client/javascript/src/v3/schemas.ts | 9154 +++++++++++++++ api/client/javascript/src/v3/subscriptions.ts | 161 + api/client/javascript/src/v3/tax-codes.ts | 87 + api/client/javascript/src/v3/v3.spec.ts | 448 + api/client/javascript/src/v3/zod/index.ts | 9766 +++++++++++++++++ 25 files changed, 21552 insertions(+), 2 deletions(-) create mode 100644 .agents/skills/v3-client-shim/SKILL.md create mode 100644 .agents/skills/v3-client-shim/references/add-endpoint.md create mode 100644 api/client/javascript/orval.v3.config.ts create mode 100644 api/client/javascript/scripts/generate-v3.ts create mode 100644 api/client/javascript/src/v3/addons.ts create mode 100644 api/client/javascript/src/v3/apps.ts create mode 100644 api/client/javascript/src/v3/billing-profiles.ts create mode 100644 api/client/javascript/src/v3/currencies.ts create mode 100644 api/client/javascript/src/v3/customers.ts create mode 100644 api/client/javascript/src/v3/defaults.ts create mode 100644 api/client/javascript/src/v3/events.ts create mode 100644 api/client/javascript/src/v3/features.ts create mode 100644 api/client/javascript/src/v3/governance.ts create mode 100644 api/client/javascript/src/v3/index.ts create mode 100644 api/client/javascript/src/v3/llm-cost.ts create mode 100644 api/client/javascript/src/v3/meters.ts create mode 100644 api/client/javascript/src/v3/plans.ts create mode 100644 api/client/javascript/src/v3/schemas.ts create mode 100644 api/client/javascript/src/v3/subscriptions.ts create mode 100644 api/client/javascript/src/v3/tax-codes.ts create mode 100644 api/client/javascript/src/v3/v3.spec.ts create mode 100644 api/client/javascript/src/v3/zod/index.ts diff --git a/.agents/skills/v3-client-shim/SKILL.md b/.agents/skills/v3-client-shim/SKILL.md new file mode 100644 index 0000000000..df4b532503 --- /dev/null +++ b/.agents/skills/v3-client-shim/SKILL.md @@ -0,0 +1,187 @@ +--- +name: v3-client-shim +description: Add or update an endpoint in the OpenMeter legacy JavaScript client's v3 compatibility shim (api/client/javascript/src/v3/). Use whenever a v3 API operation needs a typed JS client method — a new server endpoint to expose via `om.v3.*`, a changed request/response, regenerating the v3 types or Zod schemas, or wiring a new v3 resource class. Trigger this even if the user only says "add the v3 plans endpoint to the JS SDK", "wire up the new v3 customer call", or "regenerate the v3 client types" without naming the shim. +user-invocable: true +argument-hint: "[v3 endpoint or resource to add]" +allowed-tools: Read, Edit, Write, Bash, Grep, Glob, Agent +--- + +# v3 client shim — adding endpoints + +## What this is + +The legacy JS client at `api/client/javascript` (`@openmeter/sdk`) exposes the +**v3 API** through a compatibility shim under `src/v3/`, reached via a lazy +`om.v3` getter on the `OpenMeter` class: + +```ts +const om = new OpenMeter({ apiKey }) +await om.v3.plans.create({ key: 'starter', name: 'Starter', currency: 'USD', billing_cadence: 'P1M', phases: [] }) +``` + +It reuses the **same generator stack as the v1 client** — `openapi-typescript` +for types, `orval` for Zod, and thin hand-written resource classes over +`openapi-fetch` — but pointed at the v3 OpenAPI spec. It is an interim fallback +to the generated v3 SDK in `api/spec/`; the win is that it's simple and uses +machinery the team already maintains. + +**The one governing principle — "Option A":** the shim surfaces the v3 wire +shape **verbatim**. The v3 wire is `snake_case` (`billing_cadence`, +`created_at`); callers see exactly that. There is **no field renaming and no +per-type transform layer**. The only runtime transform is dates, handled by the +shared v1 `decodeDates`/`encodeDates` walker. If you ever feel the urge to add +camelCase↔snake_case mapping, stop (see Gotchas — it corrupts free-form maps and +rebuilds the exact thing this shim exists to avoid). + +## File map (everything lives in `api/client/javascript`) + +| Path | Role | Edit by hand? | +|---|---|---| +| `scripts/generate-v3.ts` | openapi-typescript → `src/v3/schemas.ts` | rarely | +| `orval.v3.config.ts` | orval → `src/v3/zod/index.ts` | rarely | +| `src/v3/schemas.ts` | generated TS types (committed) | **no — generated** | +| `src/v3/zod/index.ts` | generated Zod schemas (committed) | **no — generated** | +| `src/v3/index.ts` | `V3` class: builds the client, holds resource instances | yes (new classes) | +| `src/v3/.ts` | thin resource classes (plans, features, customers, …) | **yes** | +| `src/v3/v3.spec.ts` | smoke test | yes | +| `src/client/index.ts` | `OpenMeter` class + the `om.v3` getter | rarely | +| `src/client/utils.ts` | shared `transformResponse`, `decodeDates`, `encodeDates` | no | + +## Workflow + +Run all `pnpm`/`node`/`tsc` commands from `api/client/javascript`. + +### 1. Make sure the operation is in the spec + +Both v3 generators read the bundled **`api/v3/openapi.yaml`**. That file is +produced upstream from the TypeSpec in `api/spec/` (via `make gen-api` at the +repo root). If the endpoint was just added on the server and isn't in +`api/v3/openapi.yaml` yet, regenerate the spec first — the shim is strictly +downstream of it. + +### 2. Regenerate the shim's types + Zod + +```bash +pnpm run generate:client:v3 # → src/v3/schemas.ts +pnpm run generate:zod:v3 # → src/v3/zod/index.ts +``` + +(`pnpm run generate` runs all four: v1 client/zod + v3 client/zod.) Commit the +regenerated files — they're tracked, like their v1 counterparts. + +### 3. Look up the operation's exact types + +Open `src/v3/schemas.ts` and find the operation in the `operations` interface. +**The key is the kebab-case `operationId`** — e.g. `create-plan`, `get-customer`, +`ingest-metering-events`. From its block, read: + +- the **path** and any **path params** (`path: { planId: ... }`), +- the **request body** type (`requestBody.content['application/json']` → + `components['schemas']['CreatePlanRequest']`), +- the **2xx response** content type. + +Import the **named component type** (`CreatePlanRequest`, +`BillingSubscriptionCreate`, `CreateCustomerRequest`, …). Look it up — don't +guess from v1 names; v3 uses request-wrapper names (`CreatePlanRequest`, not +`PlanCreate`). + +### 4. Add the method (or a new class) + +Mirror the existing resource classes exactly. Path params are typed as `string` +(they're ULIDs); the body uses the named component type; list query params come +from the `operations` index. **Use the v3 path verbatim** (`/openmeter/...`) — +the `${baseUrl}/api/v3` prefix is already handled by the client. + +```ts +// POST with body +public async create(plan: CreatePlanRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/plans', { body: plan, ...options }) + return transformResponse(resp) +} + +// GET with path param +public async get(planId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/plans/{planId}', { + params: { path: { planId } }, + ...options, + }) + return transformResponse(resp) +} + +// GET list with query +public async list( + params?: operations['list-plans']['parameters']['query'], + options?: RequestOptions, +) { + const resp = await this.client.GET('/openmeter/plans', { params: { query: params }, ...options }) + return transformResponse(resp) +} +``` + +**Extending an existing class** (e.g. add `update`/`delete` to `plans`): just add +the method. **Creating a new resource class**: write `src/v3/.ts` +following the same shape, then in `src/v3/index.ts` import it, declare a public +field, and instantiate it in the `V3` constructor off `this.client`. It is then +automatically reachable as `om.v3.` — no change needed in +`src/client/index.ts`. + +For the full end-to-end walkthrough (extending a class **and** adding a brand-new +one, with the `V3` wiring), read **`references/add-endpoint.md`**. + +### 5. Verify + +```bash +node_modules/.bin/tsc --noEmit # 0 errors +node_modules/.bin/biome check --write src/v3/ # format + lint the hand-written file(s) +node_modules/.bin/vitest --run src/v3/v3.spec.ts # extend the spec with the new op first +``` + +Add a case to `src/v3/v3.spec.ts` covering the new method (request shaping + +response). The spec stubs the transport with `@fetch-mock/vitest`; see the +existing cases and the fetch-mock notes in Gotchas. + +## Gotchas (hard-won — read before editing) + +- **operationIds are kebab-case** in the `operations` interface keys + (`create-plan`), even though the JS methods are camelCase. +- **Don't re-prefix paths.** Use `/openmeter/...` verbatim; the client targets + `${config.baseUrl}/api/v3`, composed in `src/v3/index.ts`. +- **Pagination and errors are free.** v3 `page` is a deepObject query + (`page[size]`/`page[number]`) and works via the reused querySerializer; v3 + errors are `application/problem+json` and throw via the shared + `transformResponse`/`HTTPError`. Nothing to wire. +- **Never re-export `src/v3/schemas.ts` or the v3 Zod from the package root** — + it collides wholesale with the v1 `export *` (`paths`, `operations`, shared + names). If consumers need v3 types, add a dedicated `@openmeter/sdk/v3` subpath + export instead. +- **biome forbids assignment-in-expression.** The lazy `om.v3` getter uses an + `if (!this._v3) { this._v3 = new V3(...) }` guard, not `??=` in a return + (`noAssignInExpressions`). Follow that pattern for any new lazy getter. +- **fetch-mock v12 quirks** (in `v3.spec.ts`): `callHistory.calls()` takes **no** + name filter (passing one is misread as a URL matcher); and a bare URL matcher + requires an exact match, so use a `begin:` matcher when the request + carries a query string. +- **Don't add a transform/rename layer** (Option A). A generic camel↔snake walker + would corrupt free-form `metadata` / event `data` / `additionalProperties` + maps, and a schema-aware one re-creates the per-type transform layer the shim + exists to avoid. +- **`sort` param caveat:** v3 `sort` is `style: form, explode: false` + (comma-joined) but the shared serializer uses `explode: true`. If a list + endpoint actually relies on `sort`, verify the encoding and add a per-param + override if needed. +- **`decodeDates` footgun:** the shared walker coerces any ISO-8601-looking + string to a `Date`, including inside free-form `metadata`/`data`. Pre-existing + behavior; be aware when a payload carries such fields. +- **Only the hand-written `src/v3/*.ts` files are edited by hand.** + `schemas.ts` and `zod/index.ts` are generated and committed. `scripts/*.ts` + and `*.config.ts` are excluded from `tsc`; `*.spec.ts` is excluded from `tsc` + but run by `vitest`. +- **The v3 spec is unstable.** Every v3 operation is flagged `x-unstable: true`, + so paths, types, and verbs can change between spec versions. After + regenerating, expect occasional churn in `schemas.ts` and re-verify the + hand-written methods still compile. +- **Some capabilities are simply absent from the v3 spec** and therefore cannot + be shimmed: notifications, portal tokens, subjects, debug metrics, and the app + marketplace install flow exist in the v1 client but have no v3 operations. If + asked to add one of these to `om.v3.*`, confirm it exists in + `api/v3/openapi.yaml` first — if it doesn't, it belongs on v1. diff --git a/.agents/skills/v3-client-shim/references/add-endpoint.md b/.agents/skills/v3-client-shim/references/add-endpoint.md new file mode 100644 index 0000000000..5055e336bd --- /dev/null +++ b/.agents/skills/v3-client-shim/references/add-endpoint.md @@ -0,0 +1,228 @@ +# Worked examples: adding v3 endpoints + +Two end-to-end walkthroughs against `api/client/javascript`. The first extends an +existing resource class; the second adds a brand-new one and wires it into the +`V3` container. Both assume the operation already exists in `api/v3/openapi.yaml` +and that you've regenerated types/zod (`pnpm run generate:client:v3 && +pnpm run generate:zod:v3`). + +--- + +## Example 1 — extend an existing class: add `update` + `delete` to plans + +### Find the operations + +In `src/v3/schemas.ts`, the `operations` interface has kebab-case keys. The +relevant blocks look like: + +```ts +'update-plan': { + parameters: { path: { planId: components['schemas']['ULID'] } } + requestBody: { content: { 'application/json': components['schemas']['UpsertPlanRequest'] } } + responses: { 200: { content: { 'application/json': components['schemas']['BillingPlan'] } } } +} +'delete-plan': { + parameters: { path: { planId: components['schemas']['ULID'] } } + requestBody?: never + responses: { 204: { content?: never } } +} +``` + +So: `update-plan` is `PUT /openmeter/plans/{planId}` with body `UpsertPlanRequest`; +`delete-plan` is `DELETE /openmeter/plans/{planId}`, no body, 204. + +### Add the methods + +In `src/v3/plans.ts`, add `UpsertPlanRequest` to the type import, then: + +```ts +/** Update (replace) a plan */ +public async update( + planId: string, + plan: UpsertPlanRequest, + options?: RequestOptions, +) { + const resp = await this.client.PUT('/openmeter/plans/{planId}', { + body: plan, + params: { path: { planId } }, + ...options, + }) + return transformResponse(resp) +} + +/** Delete a plan */ +public async delete(planId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/plans/{planId}', { + params: { path: { planId } }, + ...options, + }) + return transformResponse(resp) +} +``` + +That's it — `plans` is already wired into `V3`, so `om.v3.plans.update(...)` +works immediately. + +--- + +## Example 2 — add a new resource class: tax codes + +The tax operations (`create-tax-code`, `get-tax-code`, `list-tax-codes`, +`upsert-tax-code`, `delete-tax-code`) live under `/openmeter/tax/codes` and have +no resource class yet. + +### Look up the types + +From `src/v3/schemas.ts`: +- `create-tax-code`: `POST /openmeter/tax/codes`, body `CreateTaxCodeRequest` +- `list-tax-codes`: `GET /openmeter/tax/codes`, query `operations['list-tax-codes']['parameters']['query']` +- `get-tax-code`: `GET /openmeter/tax/codes/{taxCodeId}` +- `upsert-tax-code`: `PUT /openmeter/tax/codes/{taxCodeId}`, body `UpsertTaxCodeRequest` +- `delete-tax-code`: `DELETE /openmeter/tax/codes/{taxCodeId}` + +(Verify the exact paths and component names in the generated file — the above is +illustrative.) + +### Write `src/v3/tax.ts` + +```ts +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateTaxCodeRequest, + UpsertTaxCodeRequest, + operations, + paths, +} from './schemas.js' + +/** + * Tax codes (v3) + * + * Thin wrapper over the v3 tax endpoints. Bodies use the v3 wire shape verbatim + * (snake_case). + */ +export class Tax { + constructor(private client: Client) {} + + public async createCode(body: CreateTaxCodeRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/tax/codes', { body, ...options }) + return transformResponse(resp) + } + + public async listCodes( + params?: operations['list-tax-codes']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/tax/codes', { + params: { query: params }, + ...options, + }) + return transformResponse(resp) + } + + public async getCode(taxCodeId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/tax/codes/{taxCodeId}', { + params: { path: { taxCodeId } }, + ...options, + }) + return transformResponse(resp) + } + + public async upsertCode( + taxCodeId: string, + body: UpsertTaxCodeRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/tax/codes/{taxCodeId}', { + body, + params: { path: { taxCodeId } }, + ...options, + }) + return transformResponse(resp) + } + + public async deleteCode(taxCodeId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/tax/codes/{taxCodeId}', { + params: { path: { taxCodeId } }, + ...options, + }) + return transformResponse(resp) + } +} +``` + +### Wire it into `V3` (`src/v3/index.ts`) + +Add the import (alphabetical), declare a public field, and instantiate it in the +constructor after `this.client` is built: + +```ts +import { Tax } from './tax.js' +// ... +export class V3 { + public client: Client + // ...existing fields... + public tax: Tax + + constructor(config: Config) { + // ...this.client = createClient(...)... + // ...existing resource instantiations... + this.tax = new Tax(this.client) + } +} +``` + +No change to `src/client/index.ts` is needed — the `om.v3` getter exposes the +whole `V3` instance, so `om.v3.tax.listCodes()` works as soon as the field +exists. + +### Add a smoke test (`src/v3/v3.spec.ts`) + +```ts +it('create tax code: POST /api/v3/openmeter/tax/codes', async ({ + baseUrl, + client, + task, +}) => { + const route = `${baseUrl}/api/v3/openmeter/tax/codes` + const created = { id: '01J...', key: 'standard' } + fetchMock.route(route, { body: created, status: 201 }, { method: 'POST', name: task.name }) + + const resp = await client.v3.tax.createCode({ key: 'standard', /* snake_case fields */ }) + + expect(resp).toMatchObject({ id: created.id }) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + // verify the body went out verbatim (snake_case, no renaming): + const sent = JSON.parse(String(fetchMock.callHistory.calls()[0]?.options?.body)) + expect(sent.key).toBe('standard') +}) +``` + +Note the fetch-mock v12 details: `calls()` takes no name argument, and for a GET +with a query string use a `begin:` matcher instead of the exact URL. + +### Verify + +```bash +node_modules/.bin/tsc --noEmit +node_modules/.bin/biome check --write src/v3/tax.ts src/v3/index.ts src/v3/v3.spec.ts +node_modules/.bin/vitest --run src/v3/v3.spec.ts +``` + +--- + +## Quick reference: openapi-fetch call shapes + +| HTTP | Call | +|---|---| +| POST body | `this.client.POST('/openmeter/x', { body, ...options })` | +| GET path | `this.client.GET('/openmeter/x/{id}', { params: { path: { id } }, ...options })` | +| GET query | `this.client.GET('/openmeter/x', { params: { query: params }, ...options })` | +| PUT path+body | `this.client.PUT('/openmeter/x/{id}', { body, params: { path: { id } }, ...options })` | +| DELETE | `this.client.DELETE('/openmeter/x/{id}', { params: { path: { id } }, ...options })` | +| POST path+body | `this.client.POST('/openmeter/x/{id}/action', { body, params: { path: { id } }, ...options })` | + +Every method ends with `return transformResponse(resp)` — it throws `HTTPError` +on ≥400 and runs `decodeDates` on the body. Path params: `string`. Body: named +component type from `schemas.ts`. Query: `operations['']['parameters']['query']`. diff --git a/api/client/javascript/orval.v3.config.ts b/api/client/javascript/orval.v3.config.ts new file mode 100644 index 0000000000..7114db56ef --- /dev/null +++ b/api/client/javascript/orval.v3.config.ts @@ -0,0 +1,41 @@ +import { defineConfig } from 'orval' + +// v3 compatibility shim — Zod schema generator. Mirrors orval.config.ts but +// reads the v3 OpenAPI spec (api/v3/openapi.yaml) and writes src/v3/zod/index.ts. +// See V3_SHIM_PLAN.md. +export default defineConfig({ + openmeter: { + input: { + target: '../../v3/openapi.yaml', + }, + output: { + formatter: 'biome', + clean: true, + client: 'zod', + mode: 'single', + namingConvention: 'PascalCase', + override: { + useDates: true, + zod: { + coerce: { + body: true, + header: false, + param: true, + query: true, + response: false, + }, + generate: { + body: true, + header: false, + param: true, + query: true, + response: false, + }, + }, + }, + propertySortOrder: 'Alphabetical', + target: './src/v3/zod/index.ts', + tsconfig: './tsconfig.json', + }, + }, +}) diff --git a/api/client/javascript/package.json b/api/client/javascript/package.json index 8ebee02f24..0608ab4437 100644 --- a/api/client/javascript/package.json +++ b/api/client/javascript/package.json @@ -57,9 +57,11 @@ "scripts": { "build": "duel", "format": "biome format --write .", - "generate": "pnpm run generate:client && pnpm run generate:zod", + "generate": "pnpm run generate:client && pnpm run generate:zod && pnpm run generate:client:v3 && pnpm run generate:zod:v3", "generate:client": "tsx scripts/generate.ts && biome format --write ./src/client/schemas.ts", "generate:zod": "orval && tsx scripts/add-as-const.ts && biome lint --write ./src/zod/index.ts && biome format --write ./src/zod/index.ts", + "generate:client:v3": "tsx scripts/generate-v3.ts && biome format --write ./src/v3/schemas.ts", + "generate:zod:v3": "orval --config orval.v3.config.ts && tsx scripts/add-as-const.ts src/v3/zod/index.ts && biome lint --write ./src/v3/zod/index.ts && biome format --write ./src/v3/zod/index.ts", "lint": "tsc --noEmit && biome lint .", "prepublishOnly": "pnpm run generate && pnpm run build && pnpm run lint && pnpm run test", "pretest": "pnpm run build", diff --git a/api/client/javascript/scripts/add-as-const.ts b/api/client/javascript/scripts/add-as-const.ts index c61aa8fd41..df8e877d62 100644 --- a/api/client/javascript/scripts/add-as-const.ts +++ b/api/client/javascript/scripts/add-as-const.ts @@ -1,4 +1,5 @@ import { readFileSync, writeFileSync } from 'node:fs' +import { fileURLToPath } from 'node:url' /** * Post-generation workaround for orval's zod output: object-literal defaults @@ -6,8 +7,13 @@ import { readFileSync, writeFileSync } from 'node:fs' * fail Zod's `.default()` signature when the schema expects a literal type. * Remove this script once orval emits `as const` for object-literal defaults. * See: https://github.com/orval-labs/orval/issues/3244 + * + * Optional first CLI arg is the target file (resolved from cwd), used by the v3 + * shim to point at src/v3/zod/index.ts. Defaults to the v1 zod output. */ -const file = new URL('../src/zod/index.ts', import.meta.url) +const file = + process.argv[2] ?? + fileURLToPath(new URL('../src/zod/index.ts', import.meta.url)) const src = readFileSync(file, 'utf8') const fixed = src.replace( /(^export const \w+Default =\s*\{[^{}]*\})/gm, diff --git a/api/client/javascript/scripts/generate-v3.ts b/api/client/javascript/scripts/generate-v3.ts new file mode 100644 index 0000000000..2a7e3869a8 --- /dev/null +++ b/api/client/javascript/scripts/generate-v3.ts @@ -0,0 +1,46 @@ +import fs from 'node:fs' +import openapiTS, { astToString } from 'openapi-typescript' +import { factory, SyntaxKind } from 'typescript' + +// v3 compatibility shim — types generator. Mirrors scripts/generate.ts but +// points at the v3 OpenAPI spec (api/v3/openapi.yaml) and writes src/v3/schemas.ts. +// See V3_SHIM_PLAN.md. The v1 `#/components/schemas/Event` optional-field hack is +// intentionally omitted: the v3 MeteringEvent schema already expresses optionality +// correctly, so only the date-time transform is needed. + +const DATE = factory.createTypeReferenceNode(factory.createIdentifier('Date')) // `Date` +const NULL = factory.createLiteralTypeNode(factory.createNull()) // `null` +const STRING = factory.createKeywordTypeNode(SyntaxKind.StringKeyword) // `string` + +const schema = new URL('../../../v3/openapi.yaml', import.meta.url) + +const ast = await openapiTS(schema, { + defaultNonNullable: false, + rootTypes: true, + rootTypesNoSchemaPrefix: true, + transform(schemaObject, metadata) { + if (schemaObject.format === 'date-time') { + const allowString = + (metadata.schema && + 'in' in metadata.schema && + metadata.schema.in === 'query') || + metadata.path?.includes('/parameters/query') + + // allow string in query parameters + if (allowString) { + return schemaObject.nullable + ? factory.createUnionTypeNode([DATE, NULL, STRING]) + : factory.createUnionTypeNode([DATE, STRING]) + } + + return schemaObject.nullable + ? factory.createUnionTypeNode([DATE, NULL]) + : DATE + } + }, +}) + +const contents = astToString(ast) + +fs.mkdirSync('./src/v3', { recursive: true }) +fs.writeFileSync('./src/v3/schemas.ts', contents) diff --git a/api/client/javascript/src/client/index.ts b/api/client/javascript/src/client/index.ts index c9de2bbd9e..7b561242d2 100644 --- a/api/client/javascript/src/client/index.ts +++ b/api/client/javascript/src/client/index.ts @@ -3,6 +3,7 @@ import createClient, { type ClientOptions, createQuerySerializer, } from 'openapi-fetch' +import { V3 } from '../v3/index.js' import { Addons } from './addons.js' import { Apps } from './apps.js' import { Billing } from './billing.js' @@ -104,4 +105,20 @@ export class OpenMeter { this.subscriptionAddons = new SubscriptionAddons(this.client) this.subscriptions = new Subscriptions(this.client) } + + private _v3?: V3 + + /** + * v3 API compatibility shim — `om.v3.plans.create(...)`, etc. + * + * Lazily constructs a dedicated client for the v3 surface (`/api/v3`) + * sharing this client's config/auth. Interim fallback to the generated v3 SDK + * in `api/spec/`; surfaces snake_case wire shapes verbatim. + */ + get v3(): V3 { + if (!this._v3) { + this._v3 = new V3(this.config) + } + return this._v3 + } } diff --git a/api/client/javascript/src/v3/addons.ts b/api/client/javascript/src/v3/addons.ts new file mode 100644 index 0000000000..425e52ebd9 --- /dev/null +++ b/api/client/javascript/src/v3/addons.ts @@ -0,0 +1,111 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateAddonRequest, + operations, + paths, + UpsertAddonRequest, +} from './schemas.js' + +/** + * Addons (v3) + * + * Thin wrapper over the v3 add-on endpoints. Request/response bodies use the v3 + * wire shape verbatim (snake_case); no field renaming (Option A). + */ +export class Addons { + constructor(private client: Client) {} + + /** + * Create an add-on + */ + public async create(addon: CreateAddonRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/addons', { + body: addon, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List add-ons + */ + public async list( + params?: operations['list-addons']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/addons', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get an add-on by ID + */ + public async get(addonId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/addons/{addonId}', { + params: { path: { addonId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Update (replace) an add-on + */ + public async update( + addonId: string, + addon: UpsertAddonRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/addons/{addonId}', { + body: addon, + params: { path: { addonId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete an add-on + */ + public async delete(addonId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/addons/{addonId}', { + params: { path: { addonId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Publish an add-on version + */ + public async publish(addonId: string, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/addons/{addonId}/publish', { + params: { path: { addonId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Archive an add-on version + */ + public async archive(addonId: string, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/addons/{addonId}/archive', { + params: { path: { addonId } }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/apps.ts b/api/client/javascript/src/v3/apps.ts new file mode 100644 index 0000000000..22260286cf --- /dev/null +++ b/api/client/javascript/src/v3/apps.ts @@ -0,0 +1,41 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { operations, paths } from './schemas.js' + +/** + * Apps (v3) + * + * Thin wrapper over the v3 app endpoints. Responses use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Apps { + constructor(private client: Client) {} + + /** + * Get an installed app by ID + */ + public async get(appId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/apps/{appId}', { + params: { path: { appId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List installed apps + */ + public async list( + params?: operations['list-apps']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/apps', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/billing-profiles.ts b/api/client/javascript/src/v3/billing-profiles.ts new file mode 100644 index 0000000000..b8be4e781f --- /dev/null +++ b/api/client/javascript/src/v3/billing-profiles.ts @@ -0,0 +1,90 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateBillingProfileRequest, + operations, + paths, + UpsertBillingProfileRequest, +} from './schemas.js' + +/** + * Billing profiles (v3) + * + * Thin wrapper over the v3 billing profile endpoints. Bodies use the v3 wire + * shape verbatim (snake_case); no field renaming (Option A). + */ +export class BillingProfiles { + constructor(private client: Client) {} + + /** + * Create a billing profile + */ + public async create( + body: CreateBillingProfileRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/profiles', { + body, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List billing profiles + */ + public async list( + params?: operations['list-billing-profiles']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/profiles', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a billing profile by ID + */ + public async get(id: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/profiles/{id}', { + params: { path: { id } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Update a billing profile + */ + public async update( + id: string, + body: UpsertBillingProfileRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/profiles/{id}', { + body, + params: { path: { id } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete a billing profile + */ + public async delete(id: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/profiles/{id}', { + params: { path: { id } }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/currencies.ts b/api/client/javascript/src/v3/currencies.ts new file mode 100644 index 0000000000..3a86addef2 --- /dev/null +++ b/api/client/javascript/src/v3/currencies.ts @@ -0,0 +1,88 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateCostBasisRequest, + CreateCurrencyCustomRequest, + operations, + paths, +} from './schemas.js' + +/** + * Currencies (v3) + * + * Thin wrapper over the v3 currency endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Currencies { + constructor(private client: Client) {} + + /** + * Create a custom currency + */ + public async createCustom( + body: CreateCurrencyCustomRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/currencies/custom', { + body, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List currencies + */ + public async list( + params?: operations['list-currencies']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/currencies', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Create a cost basis for a custom currency + */ + public async createCostBasis( + currencyId: string, + body: CreateCostBasisRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/currencies/custom/{currencyId}/cost-bases', + { + body, + params: { path: { currencyId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * List cost bases for a custom currency + */ + public async listCostBases( + currencyId: string, + params?: operations['list-cost-bases']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/currencies/custom/{currencyId}/cost-bases', + { + params: { path: { currencyId }, query: params }, + ...options, + }, + ) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/customers.ts b/api/client/javascript/src/v3/customers.ts new file mode 100644 index 0000000000..f0b780a636 --- /dev/null +++ b/api/client/javascript/src/v3/customers.ts @@ -0,0 +1,366 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + BillingCustomerStripeCreateCheckoutSessionRequest, + BillingCustomerStripeCreateCustomerPortalSessionRequest, + CreateCreditAdjustmentRequest, + CreateCreditGrantRequest, + CreateCustomerRequest, + operations, + paths, + UpdateCreditGrantExternalSettlementRequest, + UpsertAppCustomerDataRequest, + UpsertCustomerBillingDataRequest, + UpsertCustomerRequest, +} from './schemas.js' + +/** + * Customers (v3) + * + * Thin wrapper over the v3 customers endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Customers { + constructor(private client: Client) {} + + /** + * Create a customer + */ + public async create( + customer: CreateCustomerRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/customers', { + body: customer, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List customers + */ + public async list( + params?: operations['list-customers']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/customers', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a customer by ID + */ + public async get(customerId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/customers/{customerId}', { + params: { path: { customerId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Upsert (replace) a customer + */ + public async upsert( + customerId: string, + customer: UpsertCustomerRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/customers/{customerId}', { + body: customer, + params: { path: { customerId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete a customer by ID + */ + public async delete(customerId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/customers/{customerId}', { + params: { path: { customerId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List credit grants for a customer + */ + public async listCreditGrants( + customerId: string, + params?: operations['list-credit-grants']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/credits/grants', + { + params: { path: { customerId }, query: params }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Create a credit grant for a customer + */ + public async createCreditGrant( + customerId: string, + body: CreateCreditGrantRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/customers/{customerId}/credits/grants', + { + body, + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Get a credit grant for a customer + */ + public async getCreditGrant( + customerId: string, + creditGrantId: string, + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/credits/grants/{creditGrantId}', + { + params: { path: { creditGrantId, customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * List credit transactions for a customer + */ + public async listCreditTransactions( + customerId: string, + params?: operations['list-credit-transactions']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/credits/transactions', + { + params: { path: { customerId }, query: params }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Create a credit adjustment for a customer + */ + public async createCreditAdjustment( + customerId: string, + body: CreateCreditAdjustmentRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/customers/{customerId}/credits/adjustments', + { + body, + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Get a customer's credit balance + */ + public async getCreditBalance( + customerId: string, + params?: operations['get-customer-credit-balance']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/credits/balance', + { + params: { path: { customerId }, query: params }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Update the external settlement status of a credit grant + */ + public async updateCreditGrantExternalSettlement( + customerId: string, + creditGrantId: string, + body: UpdateCreditGrantExternalSettlementRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/customers/{customerId}/credits/grants/{creditGrantId}/settlement/external', + { + body, + params: { path: { creditGrantId, customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Get customer billing data + */ + public async getBilling(customerId: string, options?: RequestOptions) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/billing', + { + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Update customer billing data + */ + public async updateBilling( + customerId: string, + body: UpsertCustomerBillingDataRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT( + '/openmeter/customers/{customerId}/billing', + { + body, + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Update customer billing app data + */ + public async updateBillingAppData( + customerId: string, + body: UpsertAppCustomerDataRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT( + '/openmeter/customers/{customerId}/billing/app-data', + { + body, + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Create a Stripe Checkout Session for the customer + */ + public async createStripeCheckoutSession( + customerId: string, + body: BillingCustomerStripeCreateCheckoutSessionRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/customers/{customerId}/billing/stripe/checkout-sessions', + { + body, + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Create a Stripe Customer Portal Session for the customer + */ + public async createStripePortalSession( + customerId: string, + body: BillingCustomerStripeCreateCustomerPortalSessionRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/customers/{customerId}/billing/stripe/portal-sessions', + { + body, + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * List customer charges + */ + public async listCharges( + customerId: string, + params?: operations['list-customer-charges']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/charges', + { + params: { path: { customerId }, query: params }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * List the customer's active features and their access + */ + public async listEntitlementAccess( + customerId: string, + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/customers/{customerId}/entitlement-access', + { + params: { path: { customerId } }, + ...options, + }, + ) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/defaults.ts b/api/client/javascript/src/v3/defaults.ts new file mode 100644 index 0000000000..dbc8af7fdb --- /dev/null +++ b/api/client/javascript/src/v3/defaults.ts @@ -0,0 +1,43 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + paths, + UpdateOrganizationDefaultTaxCodesRequest, +} from './schemas.js' + +/** + * Defaults (v3) + * + * Thin wrapper over the v3 organization defaults endpoints. Bodies use the v3 + * wire shape verbatim (snake_case); no field renaming (Option A). + */ +export class Defaults { + constructor(private client: Client) {} + + /** + * Get organization default tax codes + */ + public async getOrganizationTaxCodes(options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/defaults/tax-codes', { + ...options, + }) + + return transformResponse(resp) + } + + /** + * Update organization default tax codes + */ + public async updateOrganizationTaxCodes( + body: UpdateOrganizationDefaultTaxCodesRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/defaults/tax-codes', { + body, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/events.ts b/api/client/javascript/src/v3/events.ts new file mode 100644 index 0000000000..26cf8a8d91 --- /dev/null +++ b/api/client/javascript/src/v3/events.ts @@ -0,0 +1,45 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { MeteringEvent, operations, paths } from './schemas.js' + +/** + * Metering Events (v3) + * + * Thin wrapper over the v3 events endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Events { + constructor(private client: Client) {} + + /** + * Ingest a metering event or batch of events (CloudEvents). Returns 202 with + * no body on success. + */ + public async ingest( + events: MeteringEvent | MeteringEvent[], + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/events', { + body: events, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List ingested metering events + */ + public async list( + params?: operations['list-metering-events']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/events', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/features.ts b/api/client/javascript/src/v3/features.ts new file mode 100644 index 0000000000..264b589ffe --- /dev/null +++ b/api/client/javascript/src/v3/features.ts @@ -0,0 +1,108 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateFeatureRequest, + MeterQueryRequest, + operations, + paths, + UpdateFeatureRequest, +} from './schemas.js' + +/** + * Features (v3) + * + * Thin wrapper over the v3 features endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Features { + constructor(private client: Client) {} + + /** + * Create a feature + */ + public async create(feature: CreateFeatureRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/features', { + body: feature, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List features + */ + public async list( + params?: operations['list-features']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/features', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a feature by ID + */ + public async get(featureId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/features/{featureId}', { + params: { path: { featureId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete a feature by ID + */ + public async delete(featureId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/features/{featureId}', { + params: { path: { featureId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Update a feature + */ + public async update( + featureId: string, + feature: UpdateFeatureRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PATCH('/openmeter/features/{featureId}', { + body: feature, + params: { path: { featureId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Query a feature's cost + */ + public async queryCost( + featureId: string, + body?: MeterQueryRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/features/{featureId}/cost/query', + { + body, + params: { path: { featureId } }, + ...options, + }, + ) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/governance.ts b/api/client/javascript/src/v3/governance.ts new file mode 100644 index 0000000000..e2386e9457 --- /dev/null +++ b/api/client/javascript/src/v3/governance.ts @@ -0,0 +1,29 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { GovernanceQueryRequest, paths } from './schemas.js' + +/** + * Governance (v3) + * + * Thin wrapper over the v3 governance endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Governance { + constructor(private client: Client) {} + + /** + * Query feature access for a list of customers + */ + public async queryAccess( + body: GovernanceQueryRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/governance/query', { + body, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/index.ts b/api/client/javascript/src/v3/index.ts new file mode 100644 index 0000000000..28f3967888 --- /dev/null +++ b/api/client/javascript/src/v3/index.ts @@ -0,0 +1,90 @@ +import createClient, { type Client, createQuerySerializer } from 'openapi-fetch' +import type { Config } from '../client/index.js' +import { encodeDates } from '../client/utils.js' +import { Addons } from './addons.js' +import { Apps } from './apps.js' +import { BillingProfiles } from './billing-profiles.js' +import { Currencies } from './currencies.js' +import { Customers } from './customers.js' +import { Defaults } from './defaults.js' +import { Events } from './events.js' +import { Features } from './features.js' +import { Governance } from './governance.js' +import { LlmCost } from './llm-cost.js' +import { Meters } from './meters.js' +import { Plans } from './plans.js' +import type { paths } from './schemas.js' +import { Subscriptions } from './subscriptions.js' +import { TaxCodes } from './tax-codes.js' + +/** + * v3 compatibility shim. + * + * Wraps a dedicated `openapi-fetch` client pointed at the v3 API surface and + * exposes the v3 resource classes. Reached via `OpenMeter.v3`. This is an + * interim fallback to the generated v3 SDK in `api/spec/`; it surfaces the + * snake_case wire shapes verbatim (no field renaming). + * + * Base URL: the v3 servers are `/api/v3` and paths are `/openmeter/...`, + * whereas the v1 `Config.baseUrl` is the bare host. So the v3 client targets + * `${config.baseUrl}/api/v3`. Auth header and query serialization are reused + * from the v1 client (deepObject objects cover the `page[...]` pagination + * params for free). + */ +export class V3 { + public client: Client + + public addons: Addons + public plans: Plans + public features: Features + public customers: Customers + public subscriptions: Subscriptions + public meters: Meters + public events: Events + public billingProfiles: BillingProfiles + public currencies: Currencies + public taxCodes: TaxCodes + public llmCost: LlmCost + public apps: Apps + public governance: Governance + public defaults: Defaults + + constructor(config: Config) { + const baseUrl = `${(config.baseUrl ?? '').replace(/\/$/, '')}/api/v3` + + this.client = createClient({ + ...config, + baseUrl, + headers: { + ...config.headers, + Authorization: config.apiKey ? `Bearer ${config.apiKey}` : undefined, + }, + querySerializer: (q) => + createQuerySerializer({ + array: { + explode: true, + style: 'form', + }, + object: { + explode: true, + style: 'deepObject', + }, + })(encodeDates(q)), + }) + + this.addons = new Addons(this.client) + this.plans = new Plans(this.client) + this.features = new Features(this.client) + this.customers = new Customers(this.client) + this.subscriptions = new Subscriptions(this.client) + this.meters = new Meters(this.client) + this.events = new Events(this.client) + this.billingProfiles = new BillingProfiles(this.client) + this.currencies = new Currencies(this.client) + this.taxCodes = new TaxCodes(this.client) + this.llmCost = new LlmCost(this.client) + this.apps = new Apps(this.client) + this.governance = new Governance(this.client) + this.defaults = new Defaults(this.client) + } +} diff --git a/api/client/javascript/src/v3/llm-cost.ts b/api/client/javascript/src/v3/llm-cost.ts new file mode 100644 index 0000000000..435bc05529 --- /dev/null +++ b/api/client/javascript/src/v3/llm-cost.ts @@ -0,0 +1,86 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { LlmCostOverrideCreate, operations, paths } from './schemas.js' + +/** + * LLM cost (v3) + * + * Thin wrapper over the v3 LLM cost endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class LlmCost { + constructor(private client: Client) {} + + /** + * Create an LLM cost override + */ + public async createOverride( + body: LlmCostOverrideCreate, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/llm-cost/overrides', { + body, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete an LLM cost override + */ + public async deleteOverride(priceId: string, options?: RequestOptions) { + const resp = await this.client.DELETE( + '/openmeter/llm-cost/overrides/{priceId}', + { + params: { path: { priceId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * List LLM cost overrides + */ + public async listOverrides( + params?: operations['list-llm-cost-overrides']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/llm-cost/overrides', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get an LLM cost price by ID + */ + public async getPrice(priceId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/llm-cost/prices/{priceId}', { + params: { path: { priceId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List LLM cost prices + */ + public async listPrices( + params?: operations['list-llm-cost-prices']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/llm-cost/prices', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/meters.ts b/api/client/javascript/src/v3/meters.ts new file mode 100644 index 0000000000..3a61be431f --- /dev/null +++ b/api/client/javascript/src/v3/meters.ts @@ -0,0 +1,105 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateMeterRequest, + MeterQueryRequest, + operations, + paths, + UpdateMeterRequest, +} from './schemas.js' + +/** + * Meters (v3) + * + * Thin wrapper over the v3 meters endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class Meters { + constructor(private client: Client) {} + + /** + * Create a meter + */ + public async create(meter: CreateMeterRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/meters', { + body: meter, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List meters + */ + public async list( + params?: operations['list-meters']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/meters', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a meter by ID + */ + public async get(meterId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/meters/{meterId}', { + params: { path: { meterId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Query a meter's usage + */ + public async query( + meterId: string, + body: MeterQueryRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/meters/{meterId}/query', { + body, + params: { path: { meterId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Update a meter + */ + public async update( + meterId: string, + meter: UpdateMeterRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/meters/{meterId}', { + body: meter, + params: { path: { meterId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete a meter by ID + */ + public async delete(meterId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/meters/{meterId}', { + params: { path: { meterId } }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/plans.ts b/api/client/javascript/src/v3/plans.ts new file mode 100644 index 0000000000..78de539da3 --- /dev/null +++ b/api/client/javascript/src/v3/plans.ts @@ -0,0 +1,205 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreatePlanAddonRequest, + CreatePlanRequest, + operations, + paths, + UpsertPlanAddonRequest, + UpsertPlanRequest, +} from './schemas.js' + +/** + * Plans (v3) + * + * Thin wrapper over the v3 plans endpoints. Request/response bodies use the v3 + * wire shape verbatim (snake_case); no field renaming (Option A). + */ +export class Plans { + constructor(private client: Client) {} + + /** + * Create a plan + */ + public async create(plan: CreatePlanRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/plans', { + body: plan, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List plans + */ + public async list( + params?: operations['list-plans']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/plans', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a plan by ID + */ + public async get(planId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/plans/{planId}', { + params: { path: { planId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Publish a plan + */ + public async publish(planId: string, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/plans/{planId}/publish', { + params: { path: { planId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Update (replace) a plan + */ + public async update( + planId: string, + plan: UpsertPlanRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/plans/{planId}', { + body: plan, + params: { path: { planId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete a plan + */ + public async delete(planId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/plans/{planId}', { + params: { path: { planId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Archive a plan + */ + public async archive(planId: string, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/plans/{planId}/archive', { + params: { path: { planId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List add-ons associated with a plan + */ + public async listAddons( + planId: string, + params?: operations['list-plan-addons']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/plans/{planId}/addons', { + params: { path: { planId }, query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Add an add-on to a plan + */ + public async createAddon( + planId: string, + addon: CreatePlanAddonRequest, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/plans/{planId}/addons', { + body: addon, + params: { path: { planId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get an add-on association for a plan + */ + public async getAddon( + planId: string, + planAddonId: string, + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/plans/{planId}/addons/{planAddonId}', + { + params: { path: { planAddonId, planId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Update an add-on association for a plan + */ + public async updateAddon( + planId: string, + planAddonId: string, + addon: UpsertPlanAddonRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT( + '/openmeter/plans/{planId}/addons/{planAddonId}', + { + body: addon, + params: { path: { planAddonId, planId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Remove an add-on from a plan + */ + public async deleteAddon( + planId: string, + planAddonId: string, + options?: RequestOptions, + ) { + const resp = await this.client.DELETE( + '/openmeter/plans/{planId}/addons/{planAddonId}', + { + params: { path: { planAddonId, planId } }, + ...options, + }, + ) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/schemas.ts b/api/client/javascript/src/v3/schemas.ts new file mode 100644 index 0000000000..9defddff23 --- /dev/null +++ b/api/client/javascript/src/v3/schemas.ts @@ -0,0 +1,9154 @@ +export interface paths { + '/openmeter/addons': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List add-ons + * @description List all add-ons. + */ + get: operations['list-addons'] + put?: never + /** + * Create add-on + * @description Create a new add-on. + */ + post: operations['create-addon'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/addons/{addonId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get add-on + * @description Get add-on by id. + */ + get: operations['get-addon'] + /** + * Update add-on + * @description Update an add-on by id. + */ + put: operations['update-addon'] + post?: never + /** + * Soft delete add-on + * @description Soft delete add-on by id. + */ + delete: operations['delete-addon'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/addons/{addonId}/archive': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Archive add-on version + * @description Archive an add-on version. + */ + post: operations['archive-addon'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/addons/{addonId}/publish': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Publish add-on version + * @description Publish an add-on version. + */ + post: operations['publish-addon'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/apps': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List apps + * @description List installed apps. + */ + get: operations['list-apps'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/apps/{appId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get app + * @description Get an installed app. + */ + get: operations['get-app'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/currencies': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List currencies + * @description List currencies supported by the billing system. + */ + get: operations['list-currencies'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/currencies/custom': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Create custom currency + * @description Create a custom currency. This operation allows defining your own custom + * currency for billing purposes. + */ + post: operations['create-custom-currency'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/currencies/custom/{currencyId}/cost-bases': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List cost bases + * @description List cost bases for a currency. For custom currencies, there can be multiple + * cost bases with different `effective_from` dates. + */ + get: operations['list-cost-bases'] + put?: never + /** + * Create cost basis + * @description Create a cost basis for a currency. + */ + post: operations['create-cost-basis'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List customers */ + get: operations['list-customers'] + put?: never + /** Create customer */ + post: operations['create-customer'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get customer */ + get: operations['get-customer'] + /** Upsert customer */ + put: operations['upsert-customer'] + post?: never + /** Delete customer */ + delete: operations['delete-customer'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/billing': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get customer billing data */ + get: operations['get-customer-billing'] + /** Update customer billing data */ + put: operations['update-customer-billing'] + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/billing/app-data': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + /** Update customer billing app data */ + put: operations['update-customer-billing-app-data'] + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/billing/stripe/checkout-sessions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Create Stripe Checkout Session + * @description Create a [Stripe Checkout Session](https://docs.stripe.com/payments/checkout) + * for the customer. + * + * Creates a Checkout Session for collecting payment method information from + * customers. The session operates in "setup" mode, which collects payment details + * without charging the customer immediately. The collected payment method can be + * used for future subscription billing. + * + * For hosted checkout sessions, redirect customers to the returned URL. For + * embedded sessions, use the client_secret to initialize Stripe.js in your + * application. + */ + post: operations['create-customer-stripe-checkout-session'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/billing/stripe/portal-sessions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Create Stripe customer portal session + * @description Create Stripe Customer Portal Session. + * + * Useful to redirect the customer to the Stripe Customer Portal to manage their + * payment methods, change their billing address and access their invoice history. + * Only returns URL if the customer billing profile is linked to a stripe app and + * customer. + */ + post: operations['create-customer-stripe-portal-session'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/charges': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List customer charges + * @description List customer charges. + * + * Returns the customer's charges that are represented as either flat fee or + * usage-based charges. + */ + get: operations['list-customer-charges'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/credits/adjustments': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Create a credit adjustment + * @description A credit adjustment can be used to make manual adjustments to a customer's + * credit balance. + * + * Supported use-cases: + * + * - Usage correction + */ + post: operations['create-credit-adjustment'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/credits/balance': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get a customer's credit balance + * @description Get a credit balance. + */ + get: operations['get-customer-credit-balance'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/credits/grants': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List credit grants + * @description List credit grants. + */ + get: operations['list-credit-grants'] + put?: never + /** + * Create a new credit grant + * @description Create a new credit grant. A credit grant represents an allocation of prepaid + * credits to a customer. + */ + post: operations['create-credit-grant'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/credits/grants/{creditGrantId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get a credit grant + * @description Get a credit grant. + */ + get: operations['get-credit-grant'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/credits/grants/{creditGrantId}/settlement/external': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Update credit grant external settlement status + * @description Update the payment settlement status of an externally funded credit grant. + * + * Use this endpoint to synchronize the payment state of an external payment with + * the system so that revenue recognition and credit availability work as expected. + */ + post: operations['update-credit-grant-external-settlement'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/credits/transactions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List credit transactions + * @description List credit transactions for a customer. + * + * Returns an immutable, chronological record of credit movements: funded credits + * and consumed credits. Transactions are returned in reverse chronological order + * by default. + */ + get: operations['list-credit-transactions'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/customers/{customerId}/entitlement-access': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List customer entitlement access */ + get: operations['list-customer-entitlement-access'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/defaults/tax-codes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get organization default tax codes */ + get: operations['get-organization-default-tax-codes'] + /** Update organization default tax codes */ + put: operations['update-organization-default-tax-codes'] + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/events': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List metering events + * @description List ingested events. + */ + get: operations['list-metering-events'] + put?: never + /** + * Ingest metering events + * @description Ingests an event or batch of events following the CloudEvents specification. + */ + post: operations['ingest-metering-events'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/features': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List features + * @description List all features. + */ + get: operations['list-features'] + put?: never + /** + * Create feature + * @description Create a feature. + */ + post: operations['create-feature'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/features/{featureId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get feature + * @description Get a feature by id. + */ + get: operations['get-feature'] + put?: never + post?: never + /** + * Delete feature + * @description Delete a feature by id. + */ + delete: operations['delete-feature'] + options?: never + head?: never + /** + * Update feature + * @description Update a feature by id. Currently only the unit_cost field can be updated. + */ + patch: operations['update-feature'] + trace?: never + } + '/openmeter/features/{featureId}/cost/query': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Query feature cost + * @description Query the cost of a feature. + */ + post: operations['query-feature-cost'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/governance/query': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Query governance access + * @description Query feature access for a list of customers. + * + * The endpoint resolves each provided identifier to a customer and returns the + * access status for the requested features, plus optional credit balance + * availability. + * + * _Designed to be called on a fixed refresh interval and the query response is + * intended to be cached._ + */ + post: operations['query-governance-access'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/llm-cost/overrides': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List LLM cost overrides + * @description List per-namespace price overrides. + */ + get: operations['list-llm-cost-overrides'] + put?: never + /** + * Create LLM cost override + * @description Create a per-namespace price override. + */ + post: operations['create-llm-cost-override'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/llm-cost/overrides/{priceId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + post?: never + /** + * Delete LLM cost override + * @description Delete a per-namespace price override. + */ + delete: operations['delete-llm-cost-override'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/llm-cost/prices': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List LLM cost prices + * @description List global LLM cost prices. Returns prices with overrides applied if any. + */ + get: operations['list-llm-cost-prices'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/llm-cost/prices/{priceId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get LLM cost price + * @description Get a specific LLM cost price by ID. Returns the price with overrides applied if + * any. + */ + get: operations['get-llm-cost-price'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/meters': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List meters + * @description List meters. + */ + get: operations['list-meters'] + put?: never + /** + * Create meter + * @description Create a meter. + */ + post: operations['create-meter'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/meters/{meterId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get meter + * @description Get a meter by ID. + */ + get: operations['get-meter'] + /** + * Update meter + * @description Update a meter. + */ + put: operations['update-meter'] + post?: never + /** + * Delete meter + * @description Delete a meter. + */ + delete: operations['delete-meter'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/meters/{meterId}/query': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Query meter + * @description Query a meter for usage. + * + * Set `Accept: application/json` (the default) to get a structured JSON response. + * Set `Accept: text/csv` to download the same data as a CSV file suitable for + * spreadsheets. The CSV columns, in order, are: + * + * `from, to, [subject,] [customer_id, customer_key, customer_name,] , value` + * + * The `subject` column is emitted only when `subject` is in the query's + * `group_by_dimensions`. The three `customer_*` columns are emitted together only + * when `customer_id` is in the query's `group_by_dimensions`. + */ + post: operations['query-meter'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/plans': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List plans + * @description List all plans. + */ + get: operations['list-plans'] + put?: never + /** + * Create plan + * @description Create a new plan. + */ + post: operations['create-plan'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/plans/{planId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get plan + * @description Get a plan by id. + */ + get: operations['get-plan'] + /** + * Update plan + * @description Update a plan by id. + */ + put: operations['update-plan'] + post?: never + /** + * Delete plan + * @description Delete a plan by id. + */ + delete: operations['delete-plan'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/plans/{planId}/addons': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List add-ons for plan + * @description List add-ons associated with a plan. + */ + get: operations['list-plan-addons'] + put?: never + /** + * Add add-on to plan + * @description Add an add-on to a plan. + */ + post: operations['create-plan-addon'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/plans/{planId}/addons/{planAddonId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get add-on association for plan + * @description Get an add-on association for a plan. + */ + get: operations['get-plan-addon'] + /** + * Update add-on association for plan + * @description Update an add-on association for a plan. + */ + put: operations['update-plan-addon'] + post?: never + /** + * Remove add-on from plan + * @description Remove an add-on from a plan. + */ + delete: operations['delete-plan-addon'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/plans/{planId}/archive': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Archive plan version + * @description Archive a plan version. + */ + post: operations['archive-plan'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/plans/{planId}/publish': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Publish plan version + * @description Publish a plan version. + */ + post: operations['publish-plan'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/profiles': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List billing profiles + * @description List billing profiles. + */ + get: operations['list-billing-profiles'] + put?: never + /** + * Create a new billing profile + * @description Create a new billing profile. + * + * Billing profiles contain the settings for billing and controls invoice + * generation. An organization can have multiple billing profiles defined. A + * billing profile is linked to a specific app. This association is established + * during the billing profile's creation and remains immutable. + */ + post: operations['create-billing-profile'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/profiles/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get a billing profile + * @description Get a billing profile. + */ + get: operations['get-billing-profile'] + /** + * Update a billing profile + * @description Update a billing profile. + */ + put: operations['update-billing-profile'] + post?: never + /** + * Delete a billing profile + * @description Delete a billing profile. + * + * Only such billing profiles can be deleted that are: + * + * - not the default profile + * - not pinned to any customer using customer overrides + * - only have finalized invoices + */ + delete: operations['delete-billing-profile'] + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List subscriptions */ + get: operations['list-subscriptions'] + put?: never + /** Create subscription */ + post: operations['create-subscription'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions/{subscriptionId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get subscription */ + get: operations['get-subscription'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions/{subscriptionId}/addons': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * List subscription addons + * @description List the addons of a subscription. + */ + get: operations['list-subscription-addons'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions/{subscriptionId}/addons/{subscriptionAddonId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get add-on association for subscription + * @description Get an add-on association for a subscription. + */ + get: operations['get-subscription-addon'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions/{subscriptionId}/cancel': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Cancel subscription + * @description Cancels the subscription. Will result in a scheduling conflict if there are + * other subscriptions scheduled to start after the cancelation time. + */ + post: operations['cancel-subscription'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions/{subscriptionId}/change': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Change subscription + * @description Closes a running subscription and starts a new one according to the + * specification. Can be used for upgrades, downgrades, and plan changes. + */ + post: operations['change-subscription'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/subscriptions/{subscriptionId}/unschedule-cancelation': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Unschedule subscription cancelation + * @description Unschedules the subscription cancelation. + */ + post: operations['unschedule-cancelation'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/tax-codes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List tax codes */ + get: operations['list-tax-codes'] + put?: never + /** Create tax code */ + post: operations['create-tax-code'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/openmeter/tax-codes/{taxCodeId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get tax code */ + get: operations['get-tax-code'] + /** Upsert tax code */ + put: operations['upsert-tax-code'] + post?: never + /** Delete tax code */ + delete: operations['delete-tax-code'] + options?: never + head?: never + patch?: never + trace?: never + } +} +export type webhooks = Record +export interface components { + schemas: { + /** + * @description Add-on allows extending subscriptions with compatible plans with additional + * ratecards. + */ + Addon: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * Key + * @description A key is a semi-unique string that is used to identify the add-on. It is used to + * reference the latest `active` version of the add-on and is unique with the + * version number. + */ + key: components['schemas']['ResourceKey'] + /** + * Version + * @description Version of the add-on. Incremented when the add-on is updated. + * @default 1 + */ + readonly version: number + /** + * The InstanceType of the add-ons. Can be "single" or "multiple". + * @description The InstanceType of the add-ons. Can be "single" or "multiple". + */ + instance_type: components['schemas']['AddonInstanceType'] + /** + * Currency + * @description The currency code of the add-on. + */ + currency: components['schemas']['BillingCurrencyCode'] + /** + * Effective start date + * @description The date and time when the add-on becomes effective. When not specified, the + * add-on is a draft. + */ + readonly effective_from?: components['schemas']['DateTime'] + /** + * Effective end date + * @description The date and time when the add-on is no longer effective. When not specified, + * the add-on is effective indefinitely. + */ + readonly effective_to?: components['schemas']['DateTime'] + /** + * Status + * @description The status of the add-on. Computed based on the effective start and end dates: + * + * - `draft`: `effective_from` is not set. + * - `active`: `effective_from <= now` and (`effective_to` is not set or + * `now < effective_to`). + * - `archived`: `effective_to <= now`. + */ + readonly status: components['schemas']['AddonStatus'] + /** + * Rate cards + * @description The rate cards of the add-on. + */ + rate_cards: components['schemas']['BillingRateCard'][] + /** + * Validation errors + * @description List of validation errors. + */ + readonly validation_errors?: components['schemas']['ProductCatalogValidationError'][] + } + /** + * @description The instanceType of the add-on. + * + * - `single`: Can be added to a subscription only once. + * - `multiple`: Can be added to a subscription more than once. + * @enum {string} + */ + AddonInstanceType: 'single' | 'multiple' + /** @description Page paginated response. */ + AddonPagePaginatedResponse: { + data: components['schemas']['Addon'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Addon reference. */ + AddonReference: { + id: components['schemas']['ULID'] + } + /** @description Addon reference. */ + AddonReferenceItem: { + id: components['schemas']['ULID'] + } + /** + * @description The status of the add-on defined by the `effective_from` and `effective_to` + * properties. + * + * - `draft`: The add-on has not yet been published and can be edited. + * - `active`: The add-on is published and available for use. + * - `archived`: The add-on is no longer available for use. + * @enum {string} + */ + AddonStatus: 'draft' | 'active' | 'archived' + /** @description Address */ + Address: { + /** + * Country + * @description Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) + * alpha-2 format. + */ + country?: components['schemas']['CountryCode'] + /** + * Postal Code + * @description Postal code. + */ + postal_code?: string + /** + * State + * @description State or province. + */ + state?: string + /** + * City + * @description City. + */ + city?: string + /** + * Line 1 + * @description First line of the address. + */ + line1?: string + /** + * Line 2 + * @description Second line of the address. + */ + line2?: string + /** + * Phone Number + * @description Phone number. + */ + phone_number?: string + } + /** @description Page paginated response. */ + AppPagePaginatedResponse: { + data: components['schemas']['BillingApp'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Address */ + BillingAddress: { + /** + * Country + * @description Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) + * alpha-2 format. + */ + country?: components['schemas']['CountryCode'] + /** + * Postal Code + * @description Postal code. + */ + postal_code?: string + /** + * State + * @description State or province. + */ + state?: string + /** + * City + * @description City. + */ + city?: string + /** + * Line 1 + * @description First line of the address. + */ + line1?: string + /** + * Line 2 + * @description Second line of the address. + */ + line2?: string + /** + * Phone Number + * @description Phone number. + */ + phone_number?: string + } + /** @description Installed application. */ + BillingApp: + | components['schemas']['BillingAppStripe'] + | components['schemas']['BillingAppSandbox'] + | components['schemas']['BillingAppExternalInvoicing'] + /** + * @description Available apps for billing integrations to connect with third-party services. + * Apps can have various capabilities like syncing data from or to external + * systems, integrating with third-party services for tax calculation, delivery of + * invoices, collection of payments, etc. + * @example { + * "type": "stripe", + * "name": "Stripe", + * "description": "Stripe integration allows you to collect payments with Stripe." + * } + */ + BillingAppCatalogItem: { + /** @description Type of the app. */ + readonly type: components['schemas']['BillingAppType'] + /** @description Name of the app. */ + readonly name: string + /** @description Description of the app. */ + readonly description: string + } + /** @description App customer data. */ + BillingAppCustomerData: { + /** + * Stripe + * @description Used if the customer has a linked Stripe app. + */ + stripe?: components['schemas']['BillingAppCustomerDataStripe'] + /** + * External invoicing + * @description Used if the customer has a linked external invoicing app. + */ + external_invoicing?: components['schemas']['BillingAppCustomerDataExternalInvoicing'] + } + /** @description External invoicing customer data. */ + BillingAppCustomerDataExternalInvoicing: { + /** + * Labels + * @description Labels for this external invoicing integration on the customer. + */ + labels?: components['schemas']['Labels'] + } + /** @description Stripe customer data. */ + BillingAppCustomerDataStripe: { + /** + * Stripe customer ID + * @description The Stripe customer ID used. + * @example cus_1234567890 + */ + customer_id?: string + /** + * Stripe default payment method ID + * @description The Stripe default payment method ID. + * @example pm_1234567890 + */ + default_payment_method_id?: string + /** + * Labels + * @description Labels for this Stripe integration on the customer. + */ + labels?: components['schemas']['Labels'] + } + /** + * @description External Invoicing app enables integration with third-party invoicing or payment + * system. + * + * The app supports a bi-directional synchronization pattern where OpenMeter + * Billing manages the invoice lifecycle while the external system handles invoice + * presentation and payment collection. + * + * Integration workflow: + * + * 1. The billing system creates invoices and transitions them through lifecycle + * states (draft → issuing → issued) + * 2. The integration receives webhook notifications about invoice state changes + * 3. The integration calls back to provide external system IDs and metadata + * 4. The integration reports payment events back via the payment status API + * + * State synchronization is controlled by hooks that pause invoice progression + * until the external system confirms synchronization via API callbacks. + */ + BillingAppExternalInvoicing: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * @description The app type. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'external_invoicing' + /** @description The app catalog definition that this installed app is based on. */ + readonly definition: components['schemas']['BillingAppCatalogItem'] + /** @description Status of the app connection. */ + readonly status: components['schemas']['BillingAppStatus'] + /** + * @description Enable draft synchronization hook. + * + * When enabled, invoices will pause at the draft state and wait for the + * integration to call the draft synchronized endpoint before progressing to the + * issuing state. This allows the external system to validate and prepare the + * invoice data. + * + * When disabled, invoices automatically progress through the draft state based on + * the configured workflow timing. + */ + enable_draft_sync_hook: boolean + /** + * @description Enable issuing synchronization hook. + * + * When enabled, invoices will pause at the issuing state and wait for the + * integration to call the issuing synchronized endpoint before progressing to the + * issued state. This ensures the external invoicing system has successfully + * created and finalized the invoice before it is marked as issued. + * + * When disabled, invoices automatically progress through the issuing state and are + * immediately marked as issued. + */ + enable_issuing_sync_hook: boolean + } + /** @description App reference. */ + BillingAppReference: { + /** @description The ID of the app. */ + id: components['schemas']['ULID'] + } + /** @description Sandbox app can be used for testing billing features. */ + BillingAppSandbox: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * @description The app type. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'sandbox' + /** @description The app catalog definition that this installed app is based on. */ + readonly definition: components['schemas']['BillingAppCatalogItem'] + /** @description Status of the app connection. */ + readonly status: components['schemas']['BillingAppStatus'] + } + /** + * @description Connection status of an installed app. + * @enum {string} + */ + BillingAppStatus: 'ready' | 'unauthorized' + /** @description Stripe app. */ + BillingAppStripe: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * @description The app type. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'stripe' + /** @description The app catalog definition that this installed app is based on. */ + readonly definition: components['schemas']['BillingAppCatalogItem'] + /** @description Status of the app connection. */ + readonly status: components['schemas']['BillingAppStatus'] + /** @description The Stripe account ID associated with the connected Stripe account. */ + readonly account_id: string + /** @description Indicates whether the app is connected to a live Stripe account. */ + readonly livemode: boolean + /** @description The masked Stripe API key that only exposes the first and last few characters. */ + readonly masked_api_key: string + } + /** @description Custom text displayed at various stages of the checkout flow. */ + BillingAppStripeCheckoutSessionCustomTextParams: { + /** @description Text displayed after the payment confirmation button. */ + after_submit?: { + /** @description The custom message text (max 1200 characters). */ + message?: string + } + /** @description Text displayed alongside shipping address collection. */ + shipping_address?: { + /** @description The custom message text (max 1200 characters). */ + message?: string + } + /** @description Text displayed alongside the payment confirmation button. */ + submit?: { + /** @description The custom message text (max 1200 characters). */ + message?: string + } + /** @description Text replacing the default terms of service agreement text. */ + terms_of_service_acceptance?: { + /** @description The custom message text (max 1200 characters). */ + message?: string + } + } + /** + * @description Stripe Checkout Session mode. + * + * Determines the primary purpose of the checkout session. + * @enum {string} + */ + BillingAppStripeCheckoutSessionMode: 'setup' + /** + * @description Checkout Session UI mode. + * @enum {string} + */ + BillingAppStripeCheckoutSessionUIMode: 'embedded' | 'hosted' + /** + * @description Controls whether Checkout collects the customer's billing address. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionBillingAddressCollection: + | 'auto' + | 'required' + /** @description Checkout Session consent collection configuration. */ + BillingAppStripeCreateCheckoutSessionConsentCollection: { + /** @description Controls the visibility of payment method reuse agreement. */ + payment_method_reuse_agreement?: components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreement'] + /** + * @description Enables collection of promotional communication consent. + * + * Only available to US merchants. When set to "auto", Checkout determines whether + * to show the option based on the customer's locale. + */ + promotions?: components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionPromotions'] + /** + * @description Requires customers to accept terms of service before payment. + * + * Requires a valid terms of service URL in your Stripe Dashboard settings. + */ + terms_of_service?: components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionTermsOfService'] + } + /** @description Payment method reuse agreement configuration. */ + BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreement: { + /** @description Position and visibility of the payment method reuse agreement. */ + position?: components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreementPosition'] + } + /** + * @description Position of payment method reuse agreement in the UI. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreementPosition: + | 'auto' + | 'hidden' + /** + * @description Promotional communication consent collection setting. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionConsentCollectionPromotions: + | 'auto' + | 'none' + /** + * @description Terms of service acceptance requirement. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionConsentCollectionTermsOfService: + | 'none' + | 'required' + /** @description Controls which customer fields can be updated by the checkout session. */ + BillingAppStripeCreateCheckoutSessionCustomerUpdate: { + /** + * @description Whether to save the billing address to customer.address. + * + * Defaults to "never". + * @default never + */ + address?: components['schemas']['BillingAppStripeCreateCheckoutSessionCustomerUpdateBehavior'] + /** + * @description Whether to save the customer name to customer.name. + * + * Defaults to "never". + * @default never + */ + name?: components['schemas']['BillingAppStripeCreateCheckoutSessionCustomerUpdateBehavior'] + /** + * @description Whether to save shipping information to customer.shipping. + * + * Defaults to "never". + * @default never + */ + shipping?: components['schemas']['BillingAppStripeCreateCheckoutSessionCustomerUpdateBehavior'] + } + /** + * @description Behavior for updating customer fields from checkout session. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionCustomerUpdateBehavior: + | 'auto' + | 'never' + /** + * @description Redirect behavior for embedded checkout sessions. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionRedirectOnCompletion: + | 'always' + | 'if_required' + | 'never' + /** + * @description Configuration options for creating a Stripe Checkout Session. + * + * Based on Stripe's + * [Checkout Session API parameters](https://docs.stripe.com/api/checkout/sessions/create). + */ + BillingAppStripeCreateCheckoutSessionRequestOptions: { + /** + * @description Whether to collect the customer's billing address. + * + * Defaults to auto, which only collects the address when necessary for tax + * calculation. + * @default auto + */ + billing_address_collection?: components['schemas']['BillingAppStripeCreateCheckoutSessionBillingAddressCollection'] + /** + * @description URL to redirect customers who cancel the checkout session. + * + * Not allowed when ui_mode is "embedded". + */ + cancel_url?: string + /** + * @description Unique reference string for reconciling sessions with internal systems. + * + * Can be a customer ID, cart ID, or any other identifier. + */ + client_reference_id?: string + /** @description Controls which customer fields can be updated by the checkout session. */ + customer_update?: components['schemas']['BillingAppStripeCreateCheckoutSessionCustomerUpdate'] + /** @description Configuration for collecting customer consent during checkout. */ + consent_collection?: components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollection'] + /** + * @description Three-letter ISO 4217 currency code in uppercase. + * + * Required for payment mode sessions. Optional for setup mode sessions. + */ + currency?: components['schemas']['CurrencyCode'] + /** @description Custom text to display during checkout at various stages. */ + custom_text?: components['schemas']['BillingAppStripeCheckoutSessionCustomTextParams'] + /** + * Format: int64 + * @description Unix timestamp when the checkout session expires. + * + * Can be 30 minutes to 24 hours from creation. Defaults to 24 hours. + */ + expires_at?: number + /** + * @description IETF language tag for the checkout UI locale. + * + * If blank or "auto", uses the browser's locale. Example: "en", "fr", "de". + */ + locale?: string + /** + * @description Set of key-value pairs to attach to the checkout session. + * + * Useful for storing additional structured information. + */ + metadata?: { + [key: string]: string + } + /** + * @description Return URL for embedded checkout sessions after payment authentication. + * + * Required if ui_mode is "embedded" and redirect-based payment methods are + * enabled. + */ + return_url?: string + /** + * @description Success URL to redirect customers after completing payment or setup. + * + * Not allowed when ui_mode is "embedded". See: + * https://docs.stripe.com/payments/checkout/custom-success-page + */ + success_url?: string + /** + * @description The UI mode for the checkout session. + * + * "hosted" displays a Stripe-hosted page. "embedded" integrates directly into your + * app. Defaults to "hosted". + * @default hosted + */ + ui_mode?: components['schemas']['BillingAppStripeCheckoutSessionUIMode'] + /** + * @description List of payment method types to enable (e.g., "card", "us_bank_account"). + * + * If not specified, Stripe enables all relevant payment methods. + */ + payment_method_types?: string[] + /** + * @description Redirect behavior for embedded checkout sessions. + * + * Controls when to redirect users after completion. See: + * https://docs.stripe.com/payments/checkout/custom-success-page?payment-ui=embedded-form + */ + redirect_on_completion?: components['schemas']['BillingAppStripeCreateCheckoutSessionRedirectOnCompletion'] + /** @description Configuration for collecting tax IDs during checkout. */ + tax_id_collection?: components['schemas']['BillingAppStripeCreateCheckoutSessionTaxIdCollection'] + } + /** + * @description Result of creating a Stripe Checkout Session. + * + * Contains all the information needed to redirect customers to the checkout or + * initialize an embedded checkout flow. + */ + BillingAppStripeCreateCheckoutSessionResult: { + /** @description The customer ID in the billing system. */ + customer_id: components['schemas']['ULID'] + /** @description The Stripe customer ID. */ + stripe_customer_id: string + /** @description The Stripe checkout session ID. */ + session_id: string + /** @description The setup intent ID created for collecting the payment method. */ + setup_intent_id: string + /** + * @description Client secret for initializing Stripe.js on the client side. + * + * Required for embedded checkout sessions. See: + * https://docs.stripe.com/payments/checkout/custom-success-page + */ + client_secret?: string + /** + * @description The client reference ID provided in the request. + * + * Useful for reconciling the session with your internal systems. + */ + client_reference_id?: string + /** @description Customer's email address if provided to Stripe. */ + customer_email?: string + /** @description Currency code for the checkout session. */ + currency?: components['schemas']['CurrencyCode'] + /** @description Timestamp when the checkout session was created. */ + created_at: components['schemas']['DateTime'] + /** @description Timestamp when the checkout session will expire. */ + expires_at?: components['schemas']['DateTime'] + /** @description Metadata attached to the checkout session. */ + metadata?: { + [key: string]: string + } + /** + * @description The status of the checkout session. + * + * See: + * https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-status + */ + status?: string + /** @description URL to redirect customers to the checkout page (for hosted mode). */ + url?: string + /** + * @description Mode of the checkout session. + * + * Currently only "setup" mode is supported for collecting payment methods. + */ + mode: components['schemas']['BillingAppStripeCheckoutSessionMode'] + /** @description The cancel URL where customers are redirected if they cancel. */ + cancel_url?: string + /** @description The success URL where customers are redirected after completion. */ + success_url?: string + /** @description The return URL for embedded sessions after authentication. */ + return_url?: string + } + /** @description Tax ID collection configuration for checkout sessions. */ + BillingAppStripeCreateCheckoutSessionTaxIdCollection: { + /** + * @description Enable tax ID collection during checkout. + * + * Defaults to false. + * @default false + */ + enabled?: boolean + /** + * @description Whether tax ID collection is required. + * + * Defaults to "never". + * @default never + */ + required?: components['schemas']['BillingAppStripeCreateCheckoutSessionTaxIdCollectionRequired'] + } + /** + * @description Tax ID collection requirement level. + * @enum {string} + */ + BillingAppStripeCreateCheckoutSessionTaxIdCollectionRequired: + | 'if_supported' + | 'never' + /** @description Request to create a Stripe Customer Portal Session. */ + BillingAppStripeCreateCustomerPortalSessionOptions: { + /** + * @description The ID of an existing + * [Stripe configuration](https://docs.stripe.com/api/customer_portal/configurations) + * to use for this session, describing its functionality and features. If not + * specified, the session uses the default configuration. + */ + configuration_id?: string + /** + * @description The IETF + * [language tag](https://docs.stripe.com/api/customer_portal/sessions/create#create_portal_session-locale) + * of the locale customer portal is displayed in. If blank or `auto`, the + * customer's preferred_locales or browser's locale is used. + */ + locale?: string + /** + * @description The + * [URL to redirect](https://docs.stripe.com/api/customer_portal/sessions/create#create_portal_session-return_url) + * the customer to after they have completed their requested actions. + */ + return_url?: string + } + /** + * @description Result of creating a + * [Stripe Customer Portal Session](https://docs.stripe.com/api/customer_portal/sessions/object). + * + * Contains all the information needed to redirect the customer to the Stripe + * Customer Portal. + */ + BillingAppStripeCreateCustomerPortalSessionResult: { + /** + * @description The ID of the customer portal session. + * + * See: + * https://docs.stripe.com/api/customer_portal/sessions/object#portal_session_object-id + */ + id: string + /** @description The ID of the stripe customer. */ + stripe_customer_id: string + /** + * @description Configuration used to customize the customer portal. + * + * See: + * https://docs.stripe.com/api/customer_portal/sessions/object#portal_session_object-configuration + */ + configuration_id: string + /** + * @description Livemode. + * + * See: + * https://docs.stripe.com/api/customer_portal/sessions/object#portal_session_object-livemode + */ + livemode: boolean + /** + * @description Created at. + * + * See: + * https://docs.stripe.com/api/customer_portal/sessions/object#portal_session_object-created + */ + created_at: components['schemas']['DateTime'] + /** + * @description Return URL. + * + * See: + * https://docs.stripe.com/api/customer_portal/sessions/object#portal_session_object-return_url + */ + return_url: string + /** + * @description The IETF language tag of the locale customer portal is displayed in. + * + * See: + * https://docs.stripe.com/api/customer_portal/sessions/object#portal_session_object-locale + */ + locale: string + /** + * @description The URL to redirect the customer to after they have completed their requested + * actions. + */ + url: string + } + /** + * @description The type of the app. + * @enum {string} + */ + BillingAppType: 'sandbox' | 'stripe' | 'external_invoicing' + /** + * Customer charge + * @description Customer charge. + */ + BillingCharge: + | components['schemas']['BillingFlatFeeCharge'] + | components['schemas']['BillingUsageBasedCharge'] + /** + * Charge status + * @description Lifecycle status of a charge. + * + * Values: + * + * - `created`: The charge has been created but is not active yet. + * - `active`: The charge is active. + * - `final`: The charge is fully finalized and no further changes are expected. + * - `deleted`: The charge has been deleted. + * @enum {string} + */ + BillingChargeStatus: 'created' | 'active' | 'final' | 'deleted' + /** + * @description The totals of a change. + * + * RealTime is only expanded when the `real_time_usage` expand is used. + */ + BillingChargeTotals: { + /** + * Booked + * @description The amount of the charge already booked to the internal accounting system. + */ + readonly booked: components['schemas']['BillingTotals'] + /** + * Realtime totals + * @description The realtime amount of the charge. + * + * Requires the `realtime_usage` expand. + */ + readonly realtime?: components['schemas']['BillingTotals'] + } + /** + * Customer charge expands + * @description Expands for customer charges. + * + * Values: + * + * - `real_time_usage`: The charge's real-time usage. + * @enum {string} + */ + BillingChargesExpand: 'real_time_usage' + /** @description Describes currency basis supported by billing system. */ + BillingCostBasis: { + readonly id: components['schemas']['ULID'] + /** @description The fiat currency code for the cost basis. */ + fiat_code: components['schemas']['CurrencyCode'] + /** @description The cost rate for the currency. */ + rate: components['schemas']['Numeric'] + /** + * @description An ISO-8601 timestamp representation of the date from which the cost basis is + * effective. If not provided, it will be effective immediately and will be set to + * `now` by the system. + */ + effective_from?: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + } + /** + * Credit adjustment + * @description A credit adjustment can be used to make manual adjustments to a customer's + * credit balance. + * + * Supported use-cases: + * + * - Usage correction + */ + BillingCreditAdjustment: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + } + /** + * Credit availability policy + * @description When credits become available for consumption. + * + * - `on_creation`: Credits are available as soon as the grant is created. + * - `on_authorization`: Credits are available once the payment is authorized. + * - `on_settlement`: Credits are available once the payment is settled. + * @enum {string} + */ + BillingCreditAvailabilityPolicy: 'on_creation' + /** + * Credit balances + * @description The balances of the credits of a customer. + */ + BillingCreditBalances: { + /** @description The timestamp of the balance retrieval. */ + readonly retrieved_at: components['schemas']['DateTime'] + /** @description The balances by currencies. */ + readonly balances: components['schemas']['CreditBalance'][] + } + /** + * Credit funding method + * @description The funding method describes how the grant is funded. + * + * - `none`: No funding workflow applies, for example promotional grants + * - `invoice`: The grant is funded by an in-system invoice flow + * - `external`: The grant is funded outside the system (e.g., wire transfer, + * external invoice, or manual reconciliation) + * @enum {string} + */ + BillingCreditFundingMethod: 'none' | 'invoice' | 'external' + /** + * Credit grant + * @description A credit grant allocates credits to a customer. + * + * Credits are drawn down against charges according to the settlement mode + * configured on the rate card. + */ + BillingCreditGrant: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** @description Funding method of the grant. */ + funding_method: components['schemas']['BillingCreditFundingMethod'] + /** @description The currency of the granted credits. */ + currency: components['schemas']['BillingCurrencyCode'] + /** @description Granted credit amount. */ + amount: components['schemas']['Numeric'] + /** @description Present when a funding workflow applies (funding_method is not `none`). */ + purchase?: components['schemas']['BillingCreditGrantPurchase'] + /** + * @description Tax configuration for the grant. + * + * For `invoice` and `external` funding methods, tax configuration should be + * provided to ensure correct revenue recognition. When not provided, the default + * credit grant tax code is applied, if that's not set the global default taxcode + * is used. + */ + tax_config?: components['schemas']['BillingCreditGrantTaxConfig'] + /** @description Available when `funding_method` is `invoice`. */ + readonly invoice?: components['schemas']['BillingCreditGrantInvoiceReference'] + filters?: components['schemas']['BillingCreditGrantFilters'] + /** + * Format: int16 + * @description Draw-down priority of the grant. Lower values have higher priority. + * @default 10 + */ + priority?: number + /** + * @description The timestamp when the credit grant expires. + * + * Calculated from the grant effective time and `expires_after` if provided. + */ + readonly expires_at?: components['schemas']['DateTime'] + /** @description Timestamp when the grant was voided. */ + readonly voided_at?: components['schemas']['DateTime'] + /** @description Current lifecycle status of the grant. */ + readonly status: components['schemas']['BillingCreditGrantStatus'] + } + /** @description Filters for the credit grant. */ + BillingCreditGrantFilters: { + /** + * @description Limit the credit grant to specific features. If no features are specified, the + * credit grant can be used for any feature. + * @example [ + * "input_tokens", + * "output_tokens" + * ] + */ + features?: components['schemas']['ResourceKey'][] + } + /** @description Invoice references for the grant. */ + BillingCreditGrantInvoiceReference: { + /** @description Identifier of the invoice associated with the grant. */ + readonly id?: components['schemas']['ULID'] + /** @description Identifier of the invoice line associated with the grant. */ + readonly line?: { + id: components['schemas']['ULID'] + } + } + /** @description Purchase and payment terms of the grant. */ + BillingCreditGrantPurchase: { + /** @description Currency of the purchase amount. */ + currency: components['schemas']['CurrencyCode'] + /** + * @description Cost basis per credit unit used to calculate the purchase amount. + * + * If `per_unit_cost_basis` is 0.50 and credit amount is $100.00, the total charge + * is $50.00. The value must be greater than 0. If the cost basis is 0, use + * `funding_method=none` instead. + * + * Defaults to 1.0. + * @default 1.0 + */ + per_unit_cost_basis?: components['schemas']['Numeric'] + /** @description The purchase amount. Calculated from `per_unit_cost_basis` and credit `amount`. */ + readonly amount: components['schemas']['Numeric'] + /** + * @description Controls when credits become available for consumption. + * + * Defaults to `on_creation`. + * @default on_creation + */ + availability_policy?: components['schemas']['BillingCreditAvailabilityPolicy'] + /** @description Current payment settlement status. */ + readonly settlement_status?: components['schemas']['BillingCreditPurchasePaymentSettlementStatus'] + } + /** + * Credit grant lifecycle status + * @description Credit grant lifecycle status. + * + * - `pending`: The credit block has been created but is not yet valid. + * (`effective_at` is in the future or availability_policy is not met) + * - `active`: The credit block is currently valid and eligible for consumption. + * (`effective_at` is in the past, `expires_at` is in the future and + * availability_policy is met) + * - `expired`: The credit block expired with remaining unused balance, + * `expires_at` time has passed. + * - `voided`: The credit block was voided. Remaining balance is forfeited. + * @enum {string} + */ + BillingCreditGrantStatus: 'pending' | 'active' | 'expired' | 'voided' + /** + * Tax configuration for a credit grant + * @description Tax configuration for a credit grant. + * + * Tax configuration should be provided to ensure correct revenue recognition, + * including for externally funded grants. + */ + BillingCreditGrantTaxConfig: { + /** @description Tax behavior applied to the invoice line item. */ + behavior?: components['schemas']['BillingTaxBehavior'] + /** @description Tax code applied to the invoice line item. */ + tax_code?: components['schemas']['TaxCodeReference'] + } + /** + * Credit purchase payment settlement status + * @description Credit purchase payment settlement status. + * + * - `pending`: Payment has been initiated and is not yet authorized. + * - `authorized`: Payment has been authorized. + * - `settled`: Payment has been settled. + * @enum {string} + */ + BillingCreditPurchasePaymentSettlementStatus: + | 'pending' + | 'authorized' + | 'settled' + /** + * Credit transaction + * @description A credit transaction represents a single credit movement on the customer's + * balance. + * + * Credit transactions are immutable. + */ + BillingCreditTransaction: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description The date and time the transaction was booked. */ + readonly booked_at: components['schemas']['DateTime'] + /** @description The type of credit transaction. */ + readonly type: components['schemas']['BillingCreditTransactionType'] + /** @description Currency of the balance affected by the transaction. */ + readonly currency: components['schemas']['BillingCurrencyCode'] + /** + * @description Signed amount of the credit movement. Positive values add balance, negative + * values reduce balance. + */ + readonly amount: components['schemas']['Numeric'] + /** @description The available balance before and after the transaction. */ + readonly available_balance: { + before: components['schemas']['Numeric'] + after: components['schemas']['Numeric'] + } + } + /** + * @description The type of the credit transaction. + * + * - `funded`: Credit granted and available for consumption. + * - `consumed`: Credit consumed by usage or fees. + * - `expired`: Credit removed because it expired before being used. + * @enum {string} + */ + BillingCreditTransactionType: 'funded' | 'consumed' | 'expired' + /** @description Fiat or custom currency. */ + BillingCurrency: + | components['schemas']['BillingCurrencyFiat'] + | components['schemas']['BillingCurrencyCustom'] + /** @description Fiat or custom currency code. */ + BillingCurrencyCode: string & components['schemas']['CurrencyCode'] + /** + * @description Custom currency code. It should be a unique code but not conflicting with any + * existing fiat currency codes. + */ + BillingCurrencyCodeCustom: string + /** @description Describes custom currency. */ + BillingCurrencyCustom: { + readonly id: components['schemas']['ULID'] + /** + * @description The type of the currency. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'custom' + /** + * @description The name of the currency. It should be a human-readable string that represents + * the name of the currency, such as "US Dollar" or "Euro". + */ + name: string + /** @description Description of the currency. */ + description?: string + /** + * @description The symbol of the currency. It should be a string that represents the symbol of + * the currency, such as "$" for US Dollar or "€" for Euro. + */ + symbol?: string + code: components['schemas']['BillingCurrencyCodeCustom'] + /** @description An ISO-8601 timestamp representation of the custom currency creation date. */ + readonly created_at: components['schemas']['DateTime'] + } + /** @description Currency describes a currency supported by the billing system. */ + BillingCurrencyFiat: { + readonly id: components['schemas']['ULID'] + /** + * @description The type of the currency. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'fiat' + /** + * @description The name of the currency. It should be a human-readable string that represents + * the name of the currency, such as "US Dollar" or "Euro". + */ + name: string + /** @description Description of the currency. */ + description?: string + /** + * @description The symbol of the currency. It should be a string that represents the symbol of + * the currency, such as "$" for US Dollar or "€" for Euro. + */ + symbol?: string + readonly code: components['schemas']['CurrencyCode'] + } + /** + * @description Currency type for custom currencies. It should be a unique code but not + * conflicting with any existing standard currency codes. + * @enum {string} + */ + BillingCurrencyType: 'fiat' | 'custom' + /** + * @description Customers can be individuals or organizations that can subscribe to plans and + * have access to features. + */ + BillingCustomer: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + key: components['schemas']['ExternalResourceKey'] + /** + * Usage Attribution + * @description Mapping to attribute metered usage to the customer by the event subject. + */ + usage_attribution?: components['schemas']['BillingCustomerUsageAttribution'] + /** + * Primary Email + * @description The primary email address of the customer. + */ + primary_email?: string + /** + * Currency + * @description Currency of the customer. Used for billing, tax and invoicing. + */ + currency?: components['schemas']['CurrencyCode'] + /** + * Billing Address + * @description The billing address of the customer. Used for tax and invoicing. + */ + billing_address?: components['schemas']['BillingAddress'] + } + /** @description Billing customer data. */ + BillingCustomerData: { + /** + * Billing profile + * @description The billing profile for the customer. + * + * If not provided, the default billing profile will be used. + */ + billing_profile?: components['schemas']['BillingProfileReference'] + /** + * App customer data + * @description App customer data. + */ + app_data?: components['schemas']['BillingAppCustomerData'] + } + /** @description Customer reference. */ + BillingCustomerReference: { + /** @description The ID of the customer. */ + id: components['schemas']['ULID'] + } + /** + * @description Request to create a Stripe Checkout Session for the customer. + * + * Checkout Sessions are used to collect payment method information from customers + * in a secure, Stripe-hosted interface. This integration uses setup mode to + * collect payment methods that can be charged later for subscription billing. + */ + BillingCustomerStripeCreateCheckoutSessionRequest: { + /** + * @description Options for configuring the Stripe Checkout Session. + * + * These options are passed directly to Stripe's + * [checkout session creation API](https://docs.stripe.com/api/checkout/sessions/create). + */ + stripe_options: components['schemas']['BillingAppStripeCreateCheckoutSessionRequestOptions'] + } + /** + * @description Request to create a Stripe Customer Portal Session for the customer. + * + * Useful to redirect the customer to the Stripe Customer Portal to manage their + * payment methods, change their billing address and access their invoice history. + * Only returns URL if the customer billing profile is linked to a stripe app and + * customer. + */ + BillingCustomerStripeCreateCustomerPortalSessionRequest: { + /** @description Options for configuring the Stripe Customer Portal Session. */ + stripe_options: components['schemas']['BillingAppStripeCreateCustomerPortalSessionOptions'] + } + /** + * @description Mapping to attribute metered usage to the customer. One customer can have zero + * or more subjects, but one subject can only belong to one customer. + */ + BillingCustomerUsageAttribution: { + /** + * Subject Keys + * @description The subjects that are attributed to the customer. Can be empty when no usage + * event subjects are associated with the customer. + */ + subject_keys: components['schemas']['UsageAttributionSubjectKey'][] + } + /** @description Entitlement access result. */ + BillingEntitlementAccessResult: { + /** + * @description The type of the entitlement. + * @example static + */ + readonly type: components['schemas']['BillingEntitlementType'] + /** + * @description The feature key of the entitlement. + * @example available_models + */ + readonly feature_key: components['schemas']['ResourceKey'] + /** + * @description Whether the customer has access to the feature. Always true for `boolean` and + * `static` entitlements. Depends on balance for `metered` entitlements. + * @example true + */ + readonly has_access: boolean + /** + * @description Only available for static entitlements. Config is the JSON parsable + * configuration of the entitlement. Useful to describe per customer configuration. + * @example { "availableModels": ["gpt-5", "gpt-4o"] } + */ + readonly config?: string + } + /** + * @description The type of the entitlement. + * @enum {string} + */ + BillingEntitlementType: 'metered' | 'static' | 'boolean' + /** + * @description Token type for LLM cost lookup. + * @enum {string} + */ + BillingFeatureLLMTokenType: + | 'input' + | 'output' + | 'cache_read' + | 'cache_write' + | 'reasoning' + | 'request' + | 'response' + /** + * @description LLM cost lookup configuration. Each dimension (provider, model, token type) can + * be specified as either a static value or a meter group-by property name + * (mutually exclusive). + */ + BillingFeatureLLMUnitCost: { + /** + * @description The type discriminator for LLM unit cost. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'llm' + /** + * Provider property + * @description Meter group-by property that holds the LLM provider. Use this when the meter has + * a group-by dimension for provider. Mutually exclusive with `provider`. + */ + provider_property?: string + /** + * Provider + * @description Static LLM provider value (e.g., "openai", "anthropic"). Use this when the + * feature tracks a single provider. Mutually exclusive with `provider_property`. + */ + provider?: string + /** + * Model property + * @description Meter group-by property that holds the model ID. Use this when the meter has a + * group-by dimension for model. Mutually exclusive with `model`. + */ + model_property?: string + /** + * Model + * @description Static model ID value (e.g., "gpt-4", "claude-3-5-sonnet"). Use this when the + * feature tracks a single model. Mutually exclusive with `model_property`. + */ + model?: string + /** + * Token type property + * @description Meter group-by property that holds the token type. Use this when the meter has a + * group-by dimension for token type. Mutually exclusive with `token_type`. + */ + token_type_property?: string + /** + * Token type + * @description Static token type value. Use this when the feature tracks a single token type + * (e.g., only input tokens). `request` is an alias for `input`, `response` is an + * alias for `output`. Mutually exclusive with `token_type_property`. + */ + token_type?: components['schemas']['BillingFeatureLLMTokenType'] + /** + * Resolved pricing + * @description Resolved per-token pricing from the LLM cost database. Populated in responses + * when the provider and model can be determined, either from static values or from + * meter group-by filters with exact matches. + */ + readonly pricing?: components['schemas']['BillingFeatureLLMUnitCostPricing'] + } + /** @description Resolved per-token pricing from the LLM cost database. */ + BillingFeatureLLMUnitCostPricing: { + /** + * Input per token + * @description Cost per input token in USD. + */ + input_per_token: components['schemas']['Numeric'] + /** + * Output per token + * @description Cost per output token in USD. + */ + output_per_token: components['schemas']['Numeric'] + /** + * Cache read per token + * @description Cost per cache read token in USD. + */ + cache_read_per_token?: components['schemas']['Numeric'] + /** + * Reasoning per token + * @description Cost per reasoning token in USD. + */ + reasoning_per_token?: components['schemas']['Numeric'] + /** + * Cache write per token + * @description Cost per cache write token in USD. + */ + cache_write_per_token?: components['schemas']['Numeric'] + } + /** @description A fixed per-unit cost amount. */ + BillingFeatureManualUnitCost: { + /** + * @description The type discriminator for manual unit cost. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'manual' + /** @description Fixed per-unit cost amount in USD. */ + amount: components['schemas']['Numeric'] + } + /** + * @description Per-unit cost configuration for a feature. Either a fixed manual amount or a + * dynamic LLM cost lookup. + */ + BillingFeatureUnitCost: + | components['schemas']['BillingFeatureManualUnitCost'] + | components['schemas']['BillingFeatureLLMUnitCost'] + /** + * Flat fee charge + * @description A flat fee charge for a customer. + */ + BillingFlatFeeCharge: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * @description The type of the charge. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'flat_fee' + /** + * Customer + * @description The customer owning the charge. + */ + readonly customer: components['schemas']['BillingCustomerReference'] + /** + * Managed by + * @description The charge is managed by the following entity. + */ + readonly managed_by: components['schemas']['ResourceManagedBy'] + /** + * Subscription + * @description The subscription that originated the charge, when the charge was created from a + * subscription item. + */ + readonly subscription?: components['schemas']['BillingSubscriptionReference'] + /** + * Currency + * @description The currency of the charge. + */ + readonly currency: components['schemas']['CurrencyCode'] + /** + * Status + * @description The lifecycle status of the charge. + */ + readonly status: components['schemas']['BillingChargeStatus'] + /** + * Invoice at + * @description The timestamp when the charge is intended to be invoiced. + */ + readonly invoice_at: components['schemas']['DateTime'] + /** + * Service period + * @description The effective service period covered by the charge. + */ + readonly service_period: components['schemas']['ClosedPeriod'] + /** + * Full service period + * @description The full, unprorated service period of the charge. + */ + readonly full_service_period: components['schemas']['ClosedPeriod'] + /** + * Billing period + * @description The billing period the charge belongs to. + */ + readonly billing_period: components['schemas']['ClosedPeriod'] + /** + * Advance after + * @description The earliest time when the charge should be advanced again by background + * processing. + */ + readonly advance_after?: components['schemas']['DateTime'] + /** + * Price + * @description The price of the charge. + */ + readonly price: components['schemas']['BillingPrice'] + /** + * Unique reference ID + * @description Unique reference ID of the charge. + */ + readonly unique_reference_id?: string + /** + * Settlement mode + * @description Settlement mode of the charge. + */ + readonly settlement_mode: components['schemas']['BillingSettlementMode'] + /** + * Tax configuration + * @description Tax configuration of the charge. + */ + readonly tax_config?: components['schemas']['BillingTaxConfig'] + /** + * Payment term + * @description Payment term of the flat fee charge. + */ + payment_term: components['schemas']['BillingPricePaymentTerm'] + /** + * Discounts + * @description The discounts applied to the charge. + */ + discounts?: components['schemas']['BillingFlatFeeDiscounts'] + /** + * Feature key + * @description The feature associated with the charge, when applicable. + */ + feature_key?: string + /** + * Proration configuration + * @description The proration configuration of the charge. + */ + proration_configuration: components['schemas']['BillingRateCardProrationConfiguration'] + /** + * Amount after proration + * @description The amount after proration of the charge. + */ + readonly amount_after_proration: components['schemas']['CurrencyAmount'] + } + /** + * Flat fee charge discounts + * @description Discounts applicable to flat fee charges. + * + * This is the same as `ProductCatalog.Discounts` but without the `usage` field, + * which is not applicable to flat fee charges. + */ + BillingFlatFeeDiscounts: { + /** @description Percentage discount applied to the price (0–100). */ + percentage?: number + } + /** @description Party represents a person or business entity. */ + BillingParty: { + /** @description Unique identifier for the party. */ + readonly id?: string + /** @description An optional unique key of the party. */ + key?: components['schemas']['ExternalResourceKey'] + /** @description Legal name or representation of the party. */ + name?: string + /** + * @description The entity's legal identification used for tax purposes. They may have other + * numbers, but we're only interested in those valid for tax purposes. + */ + tax_id?: components['schemas']['BillingPartyTaxIdentity'] + /** @description Address for where information should be sent if needed. */ + addresses?: components['schemas']['BillingPartyAddresses'] + } + /** @description A collection of addresses for the party. */ + BillingPartyAddresses: { + /** @description Billing address. */ + billing_address: components['schemas']['Address'] + } + /** + * @description Identity stores the details required to identify an entity for tax purposes in a + * specific country. + */ + BillingPartyTaxIdentity: { + /** @description Normalized tax identification code shown on the original identity document. */ + code?: components['schemas']['BillingTaxIdentificationCode'] + } + /** @description Plans provide a template for subscriptions. */ + BillingPlan: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * Key + * @description A key is a semi-unique string that is used to identify the plan. It is used to + * reference the latest `active` version of the plan and is unique with the version + * number. + */ + key: components['schemas']['ResourceKey'] + /** + * Version + * @description Plans are versioned to allow you to make changes without affecting running + * subscriptions. + * @default 1 + */ + readonly version: number + /** + * Currency + * @description The currency code of the plan. + */ + currency: components['schemas']['CurrencyCode'] + /** + * Billing cadence + * @description The billing cadence for subscriptions using this plan. + */ + billing_cadence: components['schemas']['ISO8601Duration'] + /** + * Pro-rating enabled + * @description Whether pro-rating is enabled for this plan. + * @default true + */ + pro_rating_enabled?: boolean + /** + * Effective start date + * @description The date and time when the plan becomes `active`. When not specified, the plan + * is in `draft` status. + */ + readonly effective_from?: components['schemas']['DateTime'] + /** + * Effective end date + * @description A scheduled date and time when the plan becomes `archived`. When not specified, + * the plan is in `active` status indefinitely. + */ + readonly effective_to?: components['schemas']['DateTime'] + /** + * Status + * @description The status of the plan. Computed based on the effective start and end dates: + * + * - `draft`: `effective_from` is not set. + * - `scheduled`: `now < effective_from`. + * - `active`: `effective_from <= now` and (`effective_to` is not set or + * `now < effective_to`). + * - `archived`: `effective_to <= now`. + */ + readonly status: components['schemas']['BillingPlanStatus'] + /** + * Plan phases + * @description The plan phases define the pricing ramp for a subscription. A phase switch + * occurs only at the end of a billing period. At least one phase is required. + */ + phases: components['schemas']['BillingPlanPhase'][] + /** + * Validation errors + * @description List of validation errors in `draft` state that prevent the plan from being + * published. + */ + readonly validation_errors?: components['schemas']['ProductCatalogValidationError'][] + } + /** + * @description The plan phase or pricing ramp allows changing a plan's rate cards over time as + * a subscription progresses. + */ + BillingPlanPhase: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + key: components['schemas']['ResourceKey'] + /** + * Duration + * @description The duration of the phase. When not specified, the phase runs indefinitely. Only + * the last phase may omit the duration. + */ + duration?: components['schemas']['ISO8601Duration'] + /** + * Rate cards + * @description The rate cards of the plan. + */ + rate_cards: components['schemas']['BillingRateCard'][] + } + /** + * @description The status of a plan. + * + * - `draft`: The plan has not yet been published and can be edited. + * - `active`: The plan is published and can be used in subscriptions. + * - `archived`: The plan is no longer available for use. + * - `scheduled`: The plan is scheduled to be published at a future date. + * @enum {string} + */ + BillingPlanStatus: 'draft' | 'active' | 'archived' | 'scheduled' + /** @description Price. */ + BillingPrice: + | components['schemas']['BillingPriceFree'] + | components['schemas']['BillingPriceFlat'] + | components['schemas']['BillingPriceUnit'] + | components['schemas']['BillingPriceGraduated'] + | components['schemas']['BillingPriceVolume'] + /** @description Flat price. */ + BillingPriceFlat: { + /** + * @description The type of the price. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'flat' + /** + * Amount + * @description The amount of the flat price. + */ + amount: components['schemas']['Numeric'] + } + /** @description Free price. */ + BillingPriceFree: { + /** + * @description The type of the price. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'free' + } + /** + * @description Graduated tiered price. + * + * Each tier's rate applies only to the usage within that tier. Pricing can change + * as cumulative usage crosses tier boundaries. + * + * When UnitConfig is present on the rate card, tier boundaries (up_to_amount) are + * expressed in converted billing units. + */ + BillingPriceGraduated: { + /** + * @description The type of the price. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'graduated' + /** + * Tiers + * @description The tiers of the graduated price. At least one tier is required. + */ + tiers: components['schemas']['BillingPriceTier'][] + } + /** + * @description The payment term of a flat price. + * @enum {string} + */ + BillingPricePaymentTerm: 'in_advance' | 'in_arrears' + /** + * @description A price tier used in graduated and volume pricing. + * + * At least one price component (flat_price or unit_price) must be set. When + * UnitConfig is present on the rate card, up_to_amount is expressed in converted + * billing units. + */ + BillingPriceTier: { + /** + * Up to quantity + * @description Up to and including this quantity will be contained in the tier. If undefined, + * the tier is open-ended (the last tier). + */ + up_to_amount?: components['schemas']['Numeric'] + /** + * Flat price component + * @description The flat price component of the tier. Charged once when the tier is entered. + */ + flat_price?: components['schemas']['BillingPriceFlat'] + /** + * Unit price component + * @description The unit price component of the tier. Charged per billing unit within the tier. + */ + unit_price?: components['schemas']['BillingPriceUnit'] + } + /** + * @description Unit price. + * + * Charges a fixed rate per billing unit. When UnitConfig is present on the rate + * card, billing units are the converted quantities (e.g. GB instead of bytes). + */ + BillingPriceUnit: { + /** + * @description The type of the price. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'unit' + /** + * Amount + * @description The amount of the unit price. + */ + amount: components['schemas']['Numeric'] + } + /** + * @description Volume tiered price. + * + * The maximum quantity within a period determines the per-unit price for all units + * in that period. + * + * When UnitConfig is present on the rate card, tier boundaries (up_to_amount) are + * expressed in converted billing units. + */ + BillingPriceVolume: { + /** + * @description The type of the price. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'volume' + /** + * Tiers + * @description The tiers of the volume price. At least one tier is required. + */ + tiers: components['schemas']['BillingPriceTier'][] + } + /** + * @description Billing profiles contain the settings for billing and controls invoice + * generation. + */ + BillingProfile: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * @description The name and contact information for the supplier this billing profile + * represents + */ + supplier: components['schemas']['BillingParty'] + /** @description The billing workflow settings for this profile */ + workflow: components['schemas']['BillingWorkflow'] + /** @description The applications used by this billing profile. */ + apps: components['schemas']['BillingProfileAppReferences'] + /** @description Whether this is the default profile. */ + default: boolean + } + /** @description References to the applications used by a billing profile. */ + BillingProfileAppReferences: { + /** @description The tax app used for this workflow. */ + tax: components['schemas']['BillingAppReference'] + /** @description The invoicing app used for this workflow. */ + invoicing: components['schemas']['BillingAppReference'] + /** @description The payment app used for this workflow. */ + payment: components['schemas']['BillingAppReference'] + } + /** @description Page paginated response. */ + BillingProfilePagePaginatedResponse: { + data: components['schemas']['BillingProfile'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Billing profile reference. */ + BillingProfileReference: { + /** @description The ID of the billing profile. */ + id: components['schemas']['ULID'] + } + /** @description A rate card defines the pricing and entitlement of a feature or service. */ + BillingRateCard: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + key: components['schemas']['ResourceKey'] + /** + * Feature reference + * @description The feature associated with the rate card. + */ + feature?: components['schemas']['FeatureReferenceItem'] + /** + * Billing cadence + * @description The billing cadence of the rate card. When null, the charge is one-time + * (non-recurring). Only valid for flat prices. + */ + billing_cadence?: components['schemas']['ISO8601Duration'] + /** + * Price + * @description The price of the rate card. + */ + price: components['schemas']['BillingPrice'] + /** + * Payment term + * @description The payment term of the rate card. In advance payment term can only be used for + * flat prices. + * @default in_arrears + */ + payment_term?: components['schemas']['BillingPricePaymentTerm'] + /** + * Commitments + * @description Spend commitments for this rate card. Only applicable to usage-based prices + * (unit, graduated, volume). + */ + commitments?: components['schemas']['BillingSpendCommitments'] + /** + * Discounts + * @description The discounts of the rate card. + */ + discounts?: components['schemas']['BillingRateCardDiscounts'] + /** + * Tax config + * @description The tax config of the rate card. + */ + tax_config?: components['schemas']['BillingRateCardTaxConfig'] + } + /** @description Discount configuration for a rate card. */ + BillingRateCardDiscounts: { + /** @description Percentage discount applied to the price (0–100). */ + percentage?: number + /** + * @description Number of usage units granted free before billing starts. Only applies to + * usage-based lines (not flat fees). Usage is treated as zero until this amount is + * exhausted. + */ + usage?: components['schemas']['Numeric'] + } + /** @description The proration configuration of the rate card. */ + BillingRateCardProrationConfiguration: { + /** + * Proration mode + * @description The proration mode of the rate card. + */ + mode: components['schemas']['BillingRateCardProrationMode'] + } + /** + * @description The proration mode of the rate card. + * + * Values: + * + * - `no_proration`: No proration. + * - `prorate_prices`: Prorate the price based on the time remaining in the billing + * period. + * @enum {string} + */ + BillingRateCardProrationMode: 'no_proration' | 'prorate_prices' + /** @description The tax config of the rate card. */ + BillingRateCardTaxConfig: { + behavior?: components['schemas']['BillingTaxBehavior'] + code: components['schemas']['TaxCodeReferenceItem'] + } + /** + * Settlement mode + * @description Settlement mode for billing. + * + * Values: + * + * - `credit_then_invoice`: Credits are applied first, then any remainder is + * invoiced. + * - `credit_only`: Usage is settled exclusively against credits. + * @enum {string} + */ + BillingSettlementMode: 'credit_then_invoice' | 'credit_only' + /** + * @description Spend commitments for a rate card. The customer is committed to spend at least + * the minimum amount and at most the maximum amount. + */ + BillingSpendCommitments: { + /** + * Minimum amount + * @description The customer is committed to spend at least the amount. + */ + minimum_amount?: components['schemas']['Numeric'] + /** + * Maximum amount + * @description The customer is limited to spend at most the amount. + */ + maximum_amount?: components['schemas']['Numeric'] + } + /** @description Subscription. */ + BillingSubscription: { + readonly id: components['schemas']['ULID'] + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * Customer ID + * @description The customer ID of the subscription. + */ + readonly customer_id: components['schemas']['ULID'] + /** + * Plan ID + * @description The plan ID of the subscription. Set if subscription is created from a plan. + */ + readonly plan_id?: components['schemas']['ULID'] + /** + * Billing anchor + * @description A billing anchor is the fixed point in time that determines the subscription's + * recurring billing cycle. It affects when charges occur and how prorations are + * calculated. Common anchors: + * + * - Calendar month (1st of each month): `2025-01-01T00:00:00Z` + * - Subscription anniversary (day customer signed up) + * - Custom date (customer-specified day) + */ + readonly billing_anchor: components['schemas']['DateTime'] + /** + * Status + * @description The status of the subscription. + */ + readonly status: components['schemas']['BillingSubscriptionStatus'] + } + /** @description Request for canceling a subscription. */ + BillingSubscriptionCancel: { + /** + * @description If not provided the subscription is canceled immediately. + * @default immediate + */ + timing?: components['schemas']['BillingSubscriptionEditTiming'] + } + /** @description Request for changing a subscription. */ + BillingSubscriptionChange: { + labels?: components['schemas']['Labels'] + /** @description The customer to create the subscription for. */ + customer: { + /** + * Customer ID + * @description The ID of the customer to create the subscription for. + * + * Either customer ID or customer key must be provided. If both are provided, the + * ID will be used. + */ + id?: components['schemas']['ULID'] + /** + * Customer Key + * @description The key of the customer to create the subscription for. + * + * Either customer ID or customer key must be provided. If both are provided, the + * ID will be used. + */ + key?: components['schemas']['ExternalResourceKey'] + } + /** @description The plan reference of the subscription. */ + plan: { + /** + * Plan ID + * @description The plan ID of the subscription. Set if subscription is created from a plan. + * + * ID or Key of the plan is required if creating a subscription from a plan. If + * both are provided, the ID will be used. + */ + id?: components['schemas']['ULID'] + /** + * Plan Key + * @description The plan Key of the subscription, if any. Set if subscription is created from a + * plan. + * + * ID or Key of the plan is required if creating a subscription from a plan. If + * both are provided, the ID will be used. + */ + key?: components['schemas']['ResourceKey'] + /** + * Plan Version + * @description The plan version of the subscription, if any. If not provided, the latest + * version of the plan will be used. + */ + version?: number + } + /** + * Billing anchor + * @description A billing anchor is the fixed point in time that determines the subscription's + * recurring billing cycle. It affects when charges occur and how prorations are + * calculated. Common anchors: + * + * - Calendar month (1st of each month): `2025-01-01T00:00:00Z` + * - Subscription anniversary (day customer signed up) + * - Custom date (customer-specified day) + * + * If not provided, the subscription will be created with the subscription's + * creation time as the billing anchor. + */ + billing_anchor?: components['schemas']['DateTime'] + /** + * @description Timing configuration for the change, when the change should take effect. For + * changing a subscription, the accepted values depend on the subscription + * configuration. + */ + timing: components['schemas']['BillingSubscriptionEditTiming'] + } + /** @description Response for changing a subscription. */ + BillingSubscriptionChangeResponse: { + /** @description The current subscription before the change. */ + current: components['schemas']['BillingSubscription'] + /** @description The new state of the subscription after the change. */ + next: components['schemas']['BillingSubscription'] + } + /** @description Subscription create request. */ + BillingSubscriptionCreate: { + labels?: components['schemas']['Labels'] + /** @description The customer to create the subscription for. */ + customer: { + /** + * Customer ID + * @description The ID of the customer to create the subscription for. + * + * Either customer ID or customer key must be provided. If both are provided, the + * ID will be used. + */ + id?: components['schemas']['ULID'] + /** + * Customer Key + * @description The key of the customer to create the subscription for. + * + * Either customer ID or customer key must be provided. If both are provided, the + * ID will be used. + */ + key?: components['schemas']['ExternalResourceKey'] + } + /** @description The plan reference of the subscription. */ + plan: { + /** + * Plan ID + * @description The plan ID of the subscription. Set if subscription is created from a plan. + * + * ID or Key of the plan is required if creating a subscription from a plan. If + * both are provided, the ID will be used. + */ + id?: components['schemas']['ULID'] + /** + * Plan Key + * @description The plan Key of the subscription, if any. Set if subscription is created from a + * plan. + * + * ID or Key of the plan is required if creating a subscription from a plan. If + * both are provided, the ID will be used. + */ + key?: components['schemas']['ResourceKey'] + /** + * Plan Version + * @description The plan version of the subscription, if any. If not provided, the latest + * version of the plan will be used. + */ + version?: number + } + /** + * Billing anchor + * @description A billing anchor is the fixed point in time that determines the subscription's + * recurring billing cycle. It affects when charges occur and how prorations are + * calculated. Common anchors: + * + * - Calendar month (1st of each month): `2025-01-01T00:00:00Z` + * - Subscription anniversary (day customer signed up) + * - Custom date (customer-specified day) + * + * If not provided, the subscription will be created with the subscription's + * creation time as the billing anchor. + */ + billing_anchor?: components['schemas']['DateTime'] + } + /** + * @description Subscription edit timing defined when the changes should take effect. If the + * provided configuration is not supported by the subscription, an error will be + * returned. + * @example immediate + */ + BillingSubscriptionEditTiming: + | components['schemas']['BillingSubscriptionEditTimingEnum'] + | components['schemas']['DateTime'] + /** + * @description Subscription edit timing. When immediate, the requested changes take effect + * immediately. When next_billing_cycle, the requested changes take effect at the + * next billing cycle. + * @enum {string} + */ + BillingSubscriptionEditTimingEnum: 'immediate' | 'next_billing_cycle' + /** + * @description Subscription reference represents a reference to the specific subscription item + * this entity represents. + */ + BillingSubscriptionReference: { + /** + * Subscription ID + * @description The ID of the subscription. + */ + readonly id: components['schemas']['ULID'] + /** + * Phase ID + * @description The phase of the subscription. + */ + readonly phase: { + /** + * Phase ID + * @description The ID of the phase. + */ + readonly id: components['schemas']['ULID'] + /** + * Item ID + * @description The item of the phase. + */ + readonly item: { + /** + * Item ID + * @description The ID of the item. + */ + readonly id: components['schemas']['ULID'] + } + } + } + /** + * @description Subscription status. + * @enum {string} + */ + BillingSubscriptionStatus: 'active' | 'inactive' | 'canceled' | 'scheduled' + /** + * @description Tax behavior. + * + * This enum is used to specify whether tax is included in the price or excluded + * from the price. + * @enum {string} + */ + BillingTaxBehavior: 'inclusive' | 'exclusive' + /** @description Tax codes by provider. */ + BillingTaxCode: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + key: components['schemas']['ResourceKey'] + /** + * App type to tax code mappings + * @description Mapping of app types to tax codes. + */ + app_mappings: components['schemas']['BillingTaxCodeAppMapping'][] + } + /** @description Mapping of app types to tax codes. */ + BillingTaxCodeAppMapping: { + /** + * App type + * @description The app type that the tax code is associated with. + */ + app_type: components['schemas']['BillingAppType'] + /** + * Tax code + * @description Tax code. + */ + tax_code: string + } + /** @description Set of provider specific tax configs. */ + BillingTaxConfig: { + /** + * Tax behavior + * @description Tax behavior. + * + * If not specified the billing profile is used to determine the tax behavior. If + * not specified in the billing profile, the provider's default behavior is used. + */ + behavior?: components['schemas']['BillingTaxBehavior'] + /** + * Stripe tax config + * @deprecated + * @description Stripe tax config. + */ + stripe?: components['schemas']['BillingTaxConfigStripe'] + /** + * External invoicing tax config + * @deprecated + * @description External invoicing tax config. + */ + external_invoicing?: components['schemas']['BillingTaxConfigExternalInvoicing'] + /** + * Tax code ID + * @deprecated + * @description Tax code ID. + */ + tax_code_id?: components['schemas']['ULID'] + /** + * Tax code + * @description Tax code reference. + * + * When both `tax_code` and `tax_code_id` are provided, `tax_code` takes + * precedence. When `stripe.code` is also provided, `tax_code` still wins and + * `stripe.code` is ignored. + */ + tax_code?: components['schemas']['TaxCodeReference'] + } + /** @description External invoicing tax config. */ + BillingTaxConfigExternalInvoicing: { + /** + * Tax code + * @description The tax code should be interpreted by the external invoicing provider. + */ + code: string + } + /** @description The tax config for Stripe. */ + BillingTaxConfigStripe: { + /** + * Tax code + * @description Product [tax code](https://docs.stripe.com/tax/tax-codes). + * @example txcd_10000000 + */ + code: string + } + /** + * @description Tax identifier code is a normalized tax code shown on the original identity + * document. + */ + BillingTaxIdentificationCode: string + /** @description Totals contains the summaries of all calculations for a billing resource. */ + BillingTotals: { + /** + * Amount + * @description The total value of the resource before taxes, discounts and commitments. + */ + readonly amount: components['schemas']['Numeric'] + /** + * Taxes total + * @description The total tax amount applied to the resource. + */ + readonly taxes_total: components['schemas']['Numeric'] + /** + * Inclusive taxes total + * @description The total tax amount already included in the resource amount. + */ + readonly taxes_inclusive_total: components['schemas']['Numeric'] + /** + * Exclusive taxes total + * @description The total tax amount added on top of the resource amount. + */ + readonly taxes_exclusive_total: components['schemas']['Numeric'] + /** + * Charges total + * @description The total amount contributed by additional charges. + */ + readonly charges_total: components['schemas']['Numeric'] + /** + * Discounts total + * @description The total amount deducted through discounts. + */ + readonly discounts_total: components['schemas']['Numeric'] + /** + * Credits total + * @description The total amount deducted through credits before taxes are applied. + */ + readonly credits_total: components['schemas']['Numeric'] + /** + * Total + * @description The final total value of the resource after taxes, discounts and commitments. + */ + readonly total: components['schemas']['Numeric'] + } + /** + * Usage-based charge + * @description A usage-based charge for a customer. + */ + BillingUsageBasedCharge: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * @description The type of the charge. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'usage_based' + /** + * Customer + * @description The customer owning the charge. + */ + readonly customer: components['schemas']['BillingCustomerReference'] + /** + * Managed by + * @description The charge is managed by the following entity. + */ + readonly managed_by: components['schemas']['ResourceManagedBy'] + /** + * Subscription + * @description The subscription that originated the charge, when the charge was created from a + * subscription item. + */ + readonly subscription?: components['schemas']['BillingSubscriptionReference'] + /** + * Currency + * @description The currency of the charge. + */ + readonly currency: components['schemas']['CurrencyCode'] + /** + * Status + * @description The lifecycle status of the charge. + */ + readonly status: components['schemas']['BillingChargeStatus'] + /** + * Invoice at + * @description The timestamp when the charge is intended to be invoiced. + */ + readonly invoice_at: components['schemas']['DateTime'] + /** + * Service period + * @description The effective service period covered by the charge. + */ + readonly service_period: components['schemas']['ClosedPeriod'] + /** + * Full service period + * @description The full, unprorated service period of the charge. + */ + readonly full_service_period: components['schemas']['ClosedPeriod'] + /** + * Billing period + * @description The billing period the charge belongs to. + */ + readonly billing_period: components['schemas']['ClosedPeriod'] + /** + * Advance after + * @description The earliest time when the charge should be advanced again by background + * processing. + */ + readonly advance_after?: components['schemas']['DateTime'] + /** + * Price + * @description The price of the charge. + */ + readonly price: components['schemas']['BillingPrice'] + /** + * Unique reference ID + * @description Unique reference ID of the charge. + */ + readonly unique_reference_id?: string + /** + * Settlement mode + * @description Settlement mode of the charge. + */ + readonly settlement_mode: components['schemas']['BillingSettlementMode'] + /** + * Tax configuration + * @description Tax configuration of the charge. + */ + readonly tax_config?: components['schemas']['BillingTaxConfig'] + /** + * Discounts + * @description Discounts applied to the usage-based charge. + */ + discounts?: components['schemas']['BillingRateCardDiscounts'] + /** + * Feature key + * @description The feature associated with the charge. + */ + feature_key: string + /** + * Totals for the charge + * @description Aggregated booked and realtime totals for the charge. + */ + readonly totals: components['schemas']['BillingChargeTotals'] + } + /** @description Billing workflow settings. */ + BillingWorkflow: { + /** @description The collection settings for this workflow */ + collection?: components['schemas']['BillingWorkflowCollectionSettings'] + /** @description The invoicing settings for this workflow */ + invoicing?: components['schemas']['BillingWorkflowInvoicingSettings'] + /** @description The payment settings for this workflow */ + payment?: components['schemas']['BillingWorkflowPaymentSettings'] + /** @description The tax settings for this workflow */ + tax?: components['schemas']['BillingWorkflowTaxSettings'] + } + /** + * @description The alignment for collecting the pending line items into an invoice. + * + * Defaults to subscription, which means that we are to create a new invoice every + * time the a subscription period starts (for in advance items) or ends (for in + * arrears items). + */ + BillingWorkflowCollectionAlignment: + | components['schemas']['BillingWorkflowCollectionAlignmentSubscription'] + | components['schemas']['BillingWorkflowCollectionAlignmentAnchored'] + /** + * @description BillingWorkflowCollectionAlignmentAnchored specifies the alignment for + * collecting the pending line items into an invoice. + */ + BillingWorkflowCollectionAlignmentAnchored: { + /** + * @description The type of alignment. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'anchored' + /** @description The recurring period for the alignment. */ + recurring_period: components['schemas']['RecurringPeriod'] + } + /** + * @description BillingWorkflowCollectionAlignmentSubscription specifies the alignment for + * collecting the pending line items into an invoice. + */ + BillingWorkflowCollectionAlignmentSubscription: { + /** + * @description The type of alignment. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'subscription' + } + /** + * Workflow collection settings + * @description Workflow collection specifies how to collect the pending line items for an + * invoice. + */ + BillingWorkflowCollectionSettings: { + /** + * @description The alignment for collecting the pending line items into an invoice. + * @default { + * "type": "subscription" + * } + */ + alignment?: components['schemas']['BillingWorkflowCollectionAlignment'] + /** + * Format: ISO8601 + * @description This grace period can be used to delay the collection of the pending line items + * specified in alignment. + * + * This is useful, in case of multiple subscriptions having slightly different + * billing periods. + * @default PT1H + * @example P1D + */ + interval?: string + } + /** + * Workflow invoice settings + * @description Invoice settings for a billing workflow. + */ + BillingWorkflowInvoicingSettings: { + /** + * @description Whether to automatically issue the invoice after the draftPeriod has passed. + * @default true + */ + auto_advance?: boolean + /** + * Format: ISO8601 + * @description The period for the invoice to be kept in draft status for manual reviews. + * @default P0D + * @example P1D + */ + draft_period?: string + /** + * @description Should progressive billing be allowed for this workflow? + * @default true + */ + progressive_billing?: boolean + } + /** + * @description Payment settings for a billing workflow when the collection method is charge + * automatically. + */ + BillingWorkflowPaymentChargeAutomaticallySettings: { + /** + * @description The collection method for the invoice. (enum property replaced by openapi-typescript) + * @enum {string} + */ + collection_method: 'charge_automatically' + } + /** + * @description Payment settings for a billing workflow when the collection method is send + * invoice. + */ + BillingWorkflowPaymentSendInvoiceSettings: { + /** + * @description The collection method for the invoice. (enum property replaced by openapi-typescript) + * @enum {string} + */ + collection_method: 'send_invoice' + /** + * Format: ISO8601 + * @description The period after which the invoice is due. With some payment solutions it's only + * applicable for manual collection method. + * @default P30D + * @example P30D + */ + due_after?: string + } + /** @description Payment settings for a billing workflow. */ + BillingWorkflowPaymentSettings: + | components['schemas']['BillingWorkflowPaymentChargeAutomaticallySettings'] + | components['schemas']['BillingWorkflowPaymentSendInvoiceSettings'] + /** + * Workflow tax settings + * @description Tax settings for a billing workflow. + */ + BillingWorkflowTaxSettings: { + /** + * @description Enable automatic tax calculation when tax is supported by the app. For example, + * with Stripe Invoicing when enabled, tax is calculated via Stripe Tax. + * @default true + */ + enabled?: boolean + /** + * @description Enforce tax calculation when tax is supported by the app. When enabled, the + * billing system will not allow to create an invoice without tax calculation. + * Enforcement is different per apps, for example, Stripe app requires customer to + * have a tax location when starting a paid subscription. + * @default false + */ + enforced?: boolean + /** @description Default tax configuration to apply to the invoices for line items. */ + default_tax_config?: components['schemas']['BillingTaxConfig'] + } + /** @description Page paginated response. */ + ChargePagePaginatedResponse: { + data: components['schemas']['BillingCharge'][] + meta: components['schemas']['PaginatedMeta'] + } + /** + * @description A period with defined start and end dates. + * + * The period is always inclusive at the start and exclusive at the end. + */ + ClosedPeriod: { + /** + * Start + * @description The start of the period. + * + * The period is inclusive at the start. + * @example 2023-01-01T01:01:01.001Z + */ + from: components['schemas']['DateTime'] + /** + * End + * @description The end of the period. + * + * The period is exclusive at the end. + * @example 2023-01-01T01:01:01.001Z + */ + to: components['schemas']['DateTime'] + } + /** @description Page paginated response. */ + CostBasisPagePaginatedResponse: { + data: components['schemas']['BillingCostBasis'][] + meta: components['schemas']['PaginatedMeta'] + } + /** + * @description [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 country + * code. Custom two-letter country codes are also supported for convenience. + * @example US + */ + CountryCode: string + /** @description Addon create request. */ + CreateAddonRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * Key + * @description A key is a semi-unique string that is used to identify the add-on. It is used to + * reference the latest `active` version of the add-on and is unique with the + * version number. + */ + key: components['schemas']['ResourceKey'] + /** + * The InstanceType of the add-ons. Can be "single" or "multiple". + * @description The InstanceType of the add-ons. Can be "single" or "multiple". + */ + instance_type: components['schemas']['AddonInstanceType'] + /** + * Currency + * @description The currency code of the add-on. + */ + currency: components['schemas']['BillingCurrencyCode'] + /** + * Rate cards + * @description The rate cards of the add-on. + */ + rate_cards: components['schemas']['BillingRateCard'][] + } + /** @description BillingProfile create request. */ + CreateBillingProfileRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * @description The name and contact information for the supplier this billing profile + * represents + */ + supplier: components['schemas']['BillingParty'] + /** @description The billing workflow settings for this profile */ + workflow: components['schemas']['BillingWorkflow'] + /** @description The applications used by this billing profile. */ + apps: components['schemas']['BillingProfileAppReferences'] + /** @description Whether this is the default profile. */ + default: boolean + } + /** @description CostBasis create request. */ + CreateCostBasisRequest: { + /** @description The fiat currency code for the cost basis. */ + fiat_code: components['schemas']['CurrencyCode'] + /** @description The cost rate for the currency. */ + rate: components['schemas']['Numeric'] + /** + * @description An ISO-8601 timestamp representation of the date from which the cost basis is + * effective. If not provided, it will be effective immediately and will be set to + * `now` by the system. + */ + effective_from?: components['schemas']['DateTime'] + } + /** @description CreditAdjustment create request. */ + CreateCreditAdjustmentRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description The currency of the granted credits. */ + currency: components['schemas']['BillingCurrencyCode'] + /** @description Granted credit amount. */ + amount: components['schemas']['Numeric'] + } + /** @description Filters for the credit grant. */ + CreateCreditGrantFilters: { + /** + * @description Limit the credit grant to specific features. If no features are specified, the + * credit grant can be used for any feature. + * @example [ + * "input_tokens", + * "output_tokens" + * ] + */ + features?: components['schemas']['ResourceKey'][] + } + /** @description Purchase and payment terms of the grant. */ + CreateCreditGrantPurchase: { + /** @description Currency of the purchase amount. */ + currency: components['schemas']['CurrencyCode'] + /** + * @description Cost basis per credit unit used to calculate the purchase amount. + * + * If `per_unit_cost_basis` is 0.50 and credit amount is $100.00, the total charge + * is $50.00. The value must be greater than 0. If the cost basis is 0, use + * `funding_method=none` instead. + * + * Defaults to 1.0. + * @default 1.0 + */ + per_unit_cost_basis?: components['schemas']['Numeric'] + /** + * @description Controls when credits become available for consumption. + * + * Defaults to `on_creation`. + * @default on_creation + */ + availability_policy?: components['schemas']['BillingCreditAvailabilityPolicy'] + } + /** @description CreditGrant create request. */ + CreateCreditGrantRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description Funding method of the grant. */ + funding_method: components['schemas']['BillingCreditFundingMethod'] + /** @description The currency of the granted credits. */ + currency: components['schemas']['CreateCurrencyCode'] + /** @description Granted credit amount. */ + amount: components['schemas']['Numeric'] + /** @description Present when a funding workflow applies (funding_method is not `none`). */ + purchase?: components['schemas']['CreateCreditGrantPurchase'] + /** + * @description Tax configuration for the grant. + * + * For `invoice` and `external` funding methods, tax configuration should be + * provided to ensure correct revenue recognition. When not provided, the default + * credit grant tax code is applied, if that's not set the global default taxcode + * is used. + */ + tax_config?: components['schemas']['CreateCreditGrantTaxConfig'] + filters?: components['schemas']['CreateCreditGrantFilters'] + /** + * Format: int16 + * @description Draw-down priority of the grant. Lower values have higher priority. + * @default 10 + */ + priority?: number + /** + * @description The duration after which the credit grant expires. + * + * Defaults to never expiring. + */ + expires_after?: components['schemas']['ISO8601Duration'] + } + /** + * Tax configuration for a credit grant + * @description Tax configuration for a credit grant. + * + * Tax configuration should be provided to ensure correct revenue recognition, + * including for externally funded grants. + */ + CreateCreditGrantTaxConfig: { + /** @description Tax behavior applied to the invoice line item. */ + behavior?: components['schemas']['BillingTaxBehavior'] + /** @description Tax code applied to the invoice line item. */ + tax_code?: components['schemas']['CreateResourceReference'] + } + /** @description Fiat or custom currency code. */ + CreateCurrencyCode: string & components['schemas']['CurrencyCode'] + /** @description CurrencyCustom create request. */ + CreateCurrencyCustomRequest: { + /** + * @description The name of the currency. It should be a human-readable string that represents + * the name of the currency, such as "US Dollar" or "Euro". + */ + name: string + /** @description Description of the currency. */ + description?: string + /** + * @description The symbol of the currency. It should be a string that represents the symbol of + * the currency, such as "$" for US Dollar or "€" for Euro. + */ + symbol?: string + code: components['schemas']['BillingCurrencyCodeCustom'] + } + /** @description Customer create request. */ + CreateCustomerRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + key: components['schemas']['ExternalResourceKey'] + /** + * Usage Attribution + * @description Mapping to attribute metered usage to the customer by the event subject. + */ + usage_attribution?: components['schemas']['BillingCustomerUsageAttribution'] + /** + * Primary Email + * @description The primary email address of the customer. + */ + primary_email?: string + /** + * Currency + * @description Currency of the customer. Used for billing, tax and invoicing. + */ + currency?: components['schemas']['CurrencyCode'] + /** + * Billing Address + * @description The billing address of the customer. Used for tax and invoicing. + */ + billing_address?: components['schemas']['BillingAddress'] + } + /** @description Feature create request. */ + CreateFeatureRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + key: components['schemas']['ResourceKey'] + /** + * Meter reference + * @description The meter that the feature is associated with and based on which usage is + * calculated. If not specified, the feature is static. + */ + meter?: components['schemas']['FeatureMeterReference'] + /** + * Unit cost + * @description Optional per-unit cost configuration. Use "manual" for a fixed per-unit cost, or + * "llm" to look up cost from the LLM cost database based on meter group-by + * properties. + */ + unit_cost?: components['schemas']['BillingFeatureUnitCost'] + } + /** @description Meter create request. */ + CreateMeterRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + key: components['schemas']['ResourceKey'] + /** @description The aggregation type to use for the meter. */ + aggregation: components['schemas']['MeterAggregation'] + /** + * @description The event type to include in the aggregation. + * @example prompt + */ + event_type: string + /** + * @description The date since the meter should include events. Useful to skip old events. If + * not specified, all historical events are included. + */ + events_from?: components['schemas']['DateTime'] + /** + * @description JSONPath expression to extract the value from the ingested event's data + * property. + * + * The ingested value for sum, avg, min, and max aggregations is a number or a + * string that can be parsed to a number. + * + * For unique_count aggregation, the ingested value must be a string. For count + * aggregation the value_property is ignored. + * @example $.tokens + */ + value_property?: string + /** + * @description Named JSONPath expressions to extract the group by values from the event data. + * + * Keys must be unique and consist only alphanumeric and underscore characters. + * @example { + * "type": "$.type" + * } + */ + dimensions?: { + [key: string]: string + } + } + /** @description PlanAddon create request. */ + CreatePlanAddonRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * Add-on + * @description The add-on associated with the plan. + */ + addon: components['schemas']['AddonReference'] + /** + * From plan phase + * @description The key of the plan phase from which the add-on becomes available for purchase. + */ + from_plan_phase: components['schemas']['ResourceKey'] + /** + * Max quantity + * @description The maximum number of times the add-on can be purchased for the plan. For + * single-instance add-ons this field must be omitted. For multi-instance add-ons + * when omitted, unlimited quantity can be purchased. + */ + max_quantity?: number + } + /** @description Plan create request. */ + CreatePlanRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * Key + * @description A key is a semi-unique string that is used to identify the plan. It is used to + * reference the latest `active` version of the plan and is unique with the version + * number. + */ + key: components['schemas']['ResourceKey'] + /** + * Currency + * @description The currency code of the plan. + */ + currency: components['schemas']['CurrencyCode'] + /** + * Billing cadence + * @description The billing cadence for subscriptions using this plan. + */ + billing_cadence: components['schemas']['ISO8601Duration'] + /** + * Pro-rating enabled + * @description Whether pro-rating is enabled for this plan. + * @default true + */ + pro_rating_enabled?: boolean + /** + * Plan phases + * @description The plan phases define the pricing ramp for a subscription. A phase switch + * occurs only at the end of a billing period. At least one phase is required. + */ + phases: components['schemas']['BillingPlanPhase'][] + } + /** @description TaxCode reference. */ + CreateResourceReference: { + id: components['schemas']['ULID'] + } + /** @description TaxCode create request. */ + CreateTaxCodeRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + key: components['schemas']['ResourceKey'] + /** + * App type to tax code mappings + * @description Mapping of app types to tax codes. + */ + app_mappings: components['schemas']['BillingTaxCodeAppMapping'][] + } + /** + * Credit balance + * @description The credit balance by currency. + */ + CreditBalance: { + readonly currency: components['schemas']['BillingCurrencyCode'] + /** + * @description Credits that have been granted but cannot yet be consumed. Includes grants + * awaiting payment clearance or with a future effective date. + * @example 200.00 + */ + readonly pending: components['schemas']['Numeric'] + /** + * @description Credits that can be consumed right now. Derived from cleared grants after + * applying eligibility and restriction rules. + * @example 150.00 + */ + readonly available: components['schemas']['Numeric'] + } + /** @description Page paginated response. */ + CreditGrantPagePaginatedResponse: { + data: components['schemas']['BillingCreditGrant'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Cursor paginated response. */ + CreditTransactionPaginatedResponse: { + data: components['schemas']['BillingCreditTransaction'][] + meta: components['schemas']['CursorMeta'] + } + /** @description Monetary amount in a specific currency. */ + CurrencyAmount: { + amount: components['schemas']['Numeric'] + currency: components['schemas']['CurrencyCode'] + } + /** + * @description Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html) + * currency code. Custom three-letter currency codes are also supported for + * convenience. + * @example USD + */ + CurrencyCode: string + /** @description Page paginated response. */ + CurrencyPagePaginatedResponse: { + data: components['schemas']['BillingCurrency'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Determines which page of the collection to retrieve. */ + CursorPaginationQueryPage: { + /** @description The number of items to include per page. */ + size?: number + /** @description Request the next page of data, starting with the item after this parameter. */ + after?: string + /** @description Request the previous page of data, starting with the item before this parameter. */ + before?: string + } + /** @description Page paginated response. */ + CustomerPagePaginatedResponse: { + data: components['schemas']['BillingCustomer'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Customer reference. */ + CustomerReference: { + id: components['schemas']['ULID'] + } + /** + * RFC3339 Date-Time + * Format: date-time + * @description [RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in + * UTC. + * @example 2023-01-01T01:01:01.001Z + */ + DateTime: Date + /** + * DateTime Field Filter + * @description Filters on the given datetime (RFC-3339) field value. All properties are + * optional; provide exactly one to specify the comparison. + */ + DateTimeFieldFilter: + | components['schemas']['DateTime'] + | { + /** @description Value strictly equals given RFC-3339 formatted timestamp in UTC. */ + eq?: components['schemas']['DateTime'] + /** @description Value is less than the given RFC-3339 formatted timestamp in UTC. */ + lt?: components['schemas']['DateTime'] + /** @description Value is less than or equal to the given RFC-3339 formatted timestamp in UTC. */ + lte?: components['schemas']['DateTime'] + /** @description Value is greater than the given RFC-3339 formatted timestamp in UTC. */ + gt?: components['schemas']['DateTime'] + /** @description Value is greater than or equal to the given RFC-3339 formatted timestamp in UTC. */ + gte?: components['schemas']['DateTime'] + } + /** + * External Resource Key + * @description ExternalResourceKey is a unique string that is used to identify a resource in an + * external system. + * @example 019ae40f-4258-7f15-9491-842f42a7d6ac + */ + ExternalResourceKey: string + /** @description A capability or billable dimension offered by a provider. */ + Feature: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + key: components['schemas']['ResourceKey'] + /** + * Meter reference + * @description The meter that the feature is associated with and based on which usage is + * calculated. If not specified, the feature is static. + */ + meter?: components['schemas']['FeatureMeterReference'] + /** + * Unit cost + * @description Optional per-unit cost configuration. Use "manual" for a fixed per-unit cost, or + * "llm" to look up cost from the LLM cost database based on meter group-by + * properties. + */ + unit_cost?: components['schemas']['BillingFeatureUnitCost'] + } + /** @description Result of a feature cost query. */ + FeatureCostQueryResult: { + /** @description Start of the queried period. */ + from?: components['schemas']['DateTime'] + /** @description End of the queried period. */ + to?: components['schemas']['DateTime'] + /** @description The cost data rows. */ + data: components['schemas']['FeatureCostQueryRow'][] + } + /** @description A row in the result of a feature cost query. */ + FeatureCostQueryRow: { + /** @description The metered usage value for the period. */ + usage: components['schemas']['Numeric'] + /** + * @description The computed cost amount (usage × unit cost). Null when pricing is not available + * for the given combination of dimensions. + */ + cost: (string & components['schemas']['Numeric']) | null + /** @description The currency code of the cost amount. */ + currency: components['schemas']['CurrencyCode'] + /** + * @description Detail message when cost amount is null, explaining why the cost could not be + * resolved. + */ + detail?: string + /** @description The start of the time bucket the value is aggregated over. */ + from: components['schemas']['DateTime'] + /** @description The end of the time bucket the value is aggregated over. */ + to: components['schemas']['DateTime'] + /** + * @description The dimensions the value is aggregated over. `subject` and `customer_id` are + * reserved dimensions. + */ + dimensions: { + [key: string]: string + } + } + /** @description Reference to a meter associated with a feature. */ + FeatureMeterReference: { + /** + * Meter ID + * @description The ID of the meter to associate with this feature. + */ + id: components['schemas']['ULID'] + /** + * Meter dimensions filters + * @description Filters to apply to the dimensions of the meter. + */ + filters?: { + [key: string]: components['schemas']['QueryFilterStringMapItem'] + } + } + /** @description Page paginated response. */ + FeaturePagePaginatedResponse: { + data: components['schemas']['Feature'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Feature reference. */ + FeatureReferenceItem: { + id: components['schemas']['ULID'] + } + /** @description Filter options for getting a credit balance. */ + GetCreditBalanceParamsFilter: { + /** @description Filter credit balance by currency. */ + currency?: components['schemas']['StringFieldFilterExact'] + } + /** @description Access status for a single feature. */ + GovernanceFeatureAccess: { + /** + * Has access + * @description Whether the customer currently has access to the feature. + * + * `true` for boolean and static entitlements that are available, and for metered + * entitlements with remaining balance. `false` when the feature is unavailable, + * the usage limit has been reached, or (when applicable) credits have been + * exhausted. + */ + readonly has_access: boolean + /** + * Reason + * @description Optional reason when the customer does not have access to the feature. Populated + * when `has_access` is `false`. + */ + readonly reason?: components['schemas']['GovernanceFeatureAccessReason'] + } + /** @description Reason a feature is not accessible to a customer. */ + GovernanceFeatureAccessReason: { + /** + * Code + * @description Machine-readable error code. + */ + readonly code: components['schemas']['GovernanceFeatureAccessReasonCode'] + /** + * Message + * @description Human-readable description of the error. + */ + readonly message: string + /** + * Attributes + * @description Additional structured context. + */ + readonly attributes?: { + [key: string]: unknown + } + } + /** + * @description Machine-readable reason code for denied feature access. + * @enum {string} + */ + GovernanceFeatureAccessReasonCode: + | 'unknown' + | 'usage_limit_reached' + | 'feature_unavailable' + | 'feature_not_found' + | 'no_credit_available' + /** @description Query error within a partially successful governance query response. */ + GovernanceQueryError: { + /** + * Code + * @description Machine-readable error code. + */ + readonly code: components['schemas']['GovernanceQueryErrorCode'] + /** + * Message + * @description Human-readable description of the error. + */ + readonly message: string + /** + * Attributes + * @description Additional structured context. + */ + readonly attributes?: { + [key: string]: unknown + } + /** + * Customer identifier + * @description The customer identifier from the request that produced this error. + */ + readonly customer?: string + } + /** + * @description Error code for a governance query failure. + * @enum {string} + */ + GovernanceQueryErrorCode: 'unknown' | 'customer_not_found' + /** @description Query to evaluate feature access for a list of customers. */ + GovernanceQueryRequest: { + /** + * Include credits + * @description Whether to include credit balance availability for each resolved customer. When + * true, each feature evaluation includes credit balance checks. + * + * Defaults to `false`. + * @default false + */ + include_credits?: boolean + /** Customer */ + customer: components['schemas']['GovernanceQueryRequestCustomers'] + /** Feature */ + feature?: components['schemas']['GovernanceQueryRequestFeatures'] + } + /** @description List of customer identifiers to evaluate access for. */ + GovernanceQueryRequestCustomers: { + /** + * Customer keys and usage-attribution subjects + * @description Each entry can be a customer `key` or a usage-attribution subject `key`. + * Identifiers that cannot be resolved to a customer are reported in the response + * `errors` array. + */ + keys: string[] + } + /** + * @description Optional list of feature keys to evaluate access for. If omitted, all features + * available in the organization are returned. Providing this list is recommended + * to reduce the response size and the load on the backend services. + */ + GovernanceQueryRequestFeatures: { + /** + * Feature Keys + * @description List of feature keys to evaluate access for. + */ + keys: string[] + } + /** @description Response of the governance query. */ + GovernanceQueryResponse: { + /** + * Data + * @description Access evaluation results, one entry per resolved customer. + */ + readonly data: components['schemas']['GovernanceQueryResult'][] + /** + * Errors + * @description Partial errors encountered while processing the request. + */ + readonly errors: components['schemas']['GovernanceQueryError'][] + /** + * Meta + * @description Pagination metadata. The endpoint may return a partial response if the full + * response would exceed server-side limits. + */ + readonly meta: components['schemas']['CursorMeta'] + } + /** @description Access evaluation result for a single resolved customer. */ + GovernanceQueryResult: { + /** + * Matched identifiers + * @description The list of identifiers from the request that resolved to this customer. Each + * entry is either the customer `key` or one of its usage-attribution subject + * `key`s. + * + * Duplicate or aliased identifiers that resolve to the same customer collapse to a + * single result entry, with every requested identifier listed here. + */ + readonly matched: string[] + /** + * Customer + * @description The customer the matched identifiers resolved to. + */ + readonly customer: components['schemas']['BillingCustomer'] + /** + * Features + * @description Map of features with their access status. + * + * Map keys are the feature keys requested in `feature.keys`, or every feature + * `key` available in the organization when the feature filter was omitted. + */ + readonly features: { + [key: string]: components['schemas']['GovernanceFeatureAccess'] + } + /** + * Updated at + * @description Timestamp of the most recent change to the customer's access state reflected in + * this result. + */ + readonly updated_at: components['schemas']['DateTime'] + } + /** + * ISO 8601 Duration + * Format: ISO8601 + * @description [ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm) + * string. + * @example P1Y + */ + ISO8601Duration: string + /** @description Cursor paginated response. */ + IngestedEventPaginatedResponse: { + data: components['schemas']['MeteringIngestedEvent'][] + meta: components['schemas']['CursorMeta'] + } + /** @description LLM Model */ + LLMCostModel: { + /** @description Identifier of the model, e.g., "gpt-4", "claude-3-5-sonnet". */ + id: string + /** @description Name of the model, e.g., "GPT-4", "Claude 3.5 Sonnet". */ + name: string + } + /** @description Token pricing for an LLM model, denominated per token. */ + LLMCostModelPricing: { + /** @description Input price per token (USD). */ + input_per_token: components['schemas']['Numeric'] + /** @description Output price per token (USD). */ + output_per_token: components['schemas']['Numeric'] + /** @description Cache read price per token (USD). */ + cache_read_per_token?: components['schemas']['Numeric'] + /** @description Cache write price per token (USD). */ + cache_write_per_token?: components['schemas']['Numeric'] + /** @description Reasoning output price per token (USD). */ + reasoning_per_token?: components['schemas']['Numeric'] + } + /** + * @description Input for creating a per-namespace price override. Unique per provider, model + * and currency. If an override already exists for the given provider, model and + * currency, it will be updated. If an override does not exist, it will be created. + */ + LLMCostOverrideCreate: { + /** @description Provider/vendor of the model. */ + provider: string + /** @description Canonical model identifier. */ + model_id: string + /** @description Human-readable model name. */ + model_name?: string + /** @description Token pricing data. */ + pricing: components['schemas']['LLMCostModelPricing'] + /** @description Currency code. */ + currency: components['schemas']['CurrencyCode'] + /** @description When this override becomes effective. */ + effective_from: components['schemas']['DateTime'] + /** @description When this override expires. */ + effective_to?: components['schemas']['DateTime'] + } + /** + * @description An LLM cost price record, representing the cost per token for a specific model + * from a specific provider. + */ + LLMCostPrice: { + /** @description Unique identifier. */ + readonly id: components['schemas']['ULID'] + /** @description Provider of the model. */ + readonly provider: components['schemas']['LLMCostProvider'] + /** @description The model. */ + readonly model: components['schemas']['LLMCostModel'] + /** @description Token pricing data. */ + readonly pricing: components['schemas']['LLMCostModelPricing'] + /** @description Currency code (currently always "USD"). */ + readonly currency: components['schemas']['CurrencyCode'] + /** @description Where this price came from. */ + readonly source: components['schemas']['LLMCostPriceSource'] + /** @description When this price becomes effective. */ + readonly effective_from: components['schemas']['DateTime'] + /** @description When this price expires. Omitted when the price is currently effective. */ + readonly effective_to?: components['schemas']['DateTime'] + /** @description Creation timestamp. */ + readonly created_at: components['schemas']['DateTime'] + /** @description Last update timestamp. */ + readonly updated_at: components['schemas']['DateTime'] + } + /** + * @description Identifies where an LLM cost price came from. + * @enum {string} + */ + LLMCostPriceSource: 'manual' | 'system' + /** @description LLM Provider */ + LLMCostProvider: { + /** @description Identifier of the provider, e.g., "openai", "anthropic". */ + id: string + /** @description Name of the provider, e.g., "OpenAI", "Anthropic". */ + name: string + } + /** @description Filter options for listing add-ons. */ + ListAddonsParamsFilter: { + id?: components['schemas']['ULIDFieldFilter'] + key?: components['schemas']['StringFieldFilter'] + name?: components['schemas']['StringFieldFilter'] + status?: components['schemas']['StringFieldFilterExact'] + currency?: components['schemas']['StringFieldFilterExact'] + } + /** @description Filter options for listing charges. */ + ListChargesParamsFilter: { + /** + * @description Filter charges by status. + * + * Supported statuses are: + * + * - `created` + * - `active` + * - `final` + * - `deleted` + * + * If omitted, all statuses are returned except for `deleted`. + */ + status?: components['schemas']['StringFieldFilterExact'] + } + /** @description Filter options for listing cost bases. */ + ListCostBasesParamsFilter: { + /** @description Filter cost bases by fiat currency code. */ + fiat_code?: components['schemas']['CurrencyCode'] + } + /** @description Filter options for listing credit grants. */ + ListCreditGrantsParamsFilter: { + /** @description Filter credit grants by status. */ + status?: components['schemas']['BillingCreditGrantStatus'] + /** @description Filter credit grants by currency. */ + currency?: components['schemas']['CurrencyCode'] + } + /** @description Filter options for listing credit transactions. */ + ListCreditTransactionsParamsFilter: { + /** @description Filter credit transactions by type. */ + type?: components['schemas']['BillingCreditTransactionType'] + /** @description Filter credit transactions by currency. */ + currency?: components['schemas']['BillingCurrencyCode'] + } + /** @description Filter options for listing currencies. */ + ListCurrenciesParamsFilter: { + type?: components['schemas']['BillingCurrencyType'] + code?: components['schemas']['StringFieldFilter'] + } + /** @description List customer entitlement access response data. */ + ListCustomerEntitlementAccessResponseData: { + /** @description The list of entitlement access results. */ + readonly data: components['schemas']['BillingEntitlementAccessResult'][] + } + /** @description Filter options for listing customers. */ + ListCustomersParamsFilter: { + key?: components['schemas']['StringFieldFilter'] + name?: components['schemas']['StringFieldFilter'] + primary_email?: components['schemas']['StringFieldFilter'] + usage_attribution_subject_key?: components['schemas']['StringFieldFilter'] + plan_key?: components['schemas']['StringFieldFilter'] + billing_profile_id?: components['schemas']['ULIDFieldFilter'] + } + /** @description Filter options for listing ingested events. */ + ListEventsParamsFilter: { + /** @description Filter events by ID. */ + id?: components['schemas']['StringFieldFilter'] + /** @description Filter events by source. */ + source?: components['schemas']['StringFieldFilter'] + /** @description Filter events by subject. */ + subject?: components['schemas']['StringFieldFilter'] + /** @description Filter events by type. */ + type?: components['schemas']['StringFieldFilter'] + /** @description Filter events by the associated customer ID. */ + customer_id?: components['schemas']['ULIDFieldFilter'] + /** @description Filter events by event time. */ + time?: components['schemas']['DateTimeFieldFilter'] + /** @description Filter events by the time the event was ingested. */ + ingested_at?: components['schemas']['DateTimeFieldFilter'] + /** @description Filter events by the time the event was stored. */ + stored_at?: components['schemas']['DateTimeFieldFilter'] + } + /** @description Filter options for listing features. */ + ListFeatureParamsFilter: { + meter_id?: components['schemas']['ULIDFieldFilter'] + key?: components['schemas']['StringFieldFilter'] + name?: components['schemas']['StringFieldFilter'] + } + /** @description Filter options for listing LLM cost prices. */ + ListLLMCostPricesParamsFilter: { + /** @description Filter by provider. e.g. ?filter[provider][eq]=openai */ + provider?: components['schemas']['StringFieldFilter'] + /** @description Filter by model ID. e.g. ?filter[model_id][eq]=gpt-4 */ + model_id?: components['schemas']['StringFieldFilter'] + /** @description Filter by model name. e.g. ?filter[model_name][contains]=gpt */ + model_name?: components['schemas']['StringFieldFilter'] + /** @description Filter by currency code. e.g. ?filter[currency][eq]=USD */ + currency?: components['schemas']['StringFieldFilter'] + /** @description Filter by source. e.g. ?filter[source][eq]=system */ + source?: components['schemas']['StringFieldFilter'] + } + /** @description Filter options for listing meters. */ + ListMetersParamsFilter: { + /** @description Filter meters by key. */ + key?: components['schemas']['StringFieldFilter'] + /** @description Filter meters by name. */ + name?: components['schemas']['StringFieldFilter'] + } + /** @description Filter options for listing plans. */ + ListPlansParamsFilter: { + key?: components['schemas']['StringFieldFilter'] + name?: components['schemas']['StringFieldFilter'] + status?: components['schemas']['StringFieldFilterExact'] + currency?: components['schemas']['StringFieldFilterExact'] + } + /** @description Filter options for listing subscriptions. */ + ListSubscriptionsParamsFilter: { + id?: components['schemas']['ULIDFieldFilter'] + customer_id?: components['schemas']['ULIDFieldFilter'] + status?: components['schemas']['StringFieldFilterExact'] + plan_id?: components['schemas']['ULIDFieldFilter'] + plan_key?: components['schemas']['StringFieldFilterExact'] + } + /** + * @description A meter is a configuration that defines how to match and aggregate events. + * @example { + * "id": "01G65Z755AFWAKHE12NY0CQ9FH", + * "key": "tokens_total", + * "name": "Tokens Total", + * "description": "AI Token Usage", + * "aggregation": "sum", + * "event_type": "prompt", + * "value_property": "$.tokens", + * "dimensions": { + * "model": "$.model", + * "type": "$.type" + * }, + * "created_at": "2024-01-01T01:01:01.001Z", + * "updated_at": "2024-01-01T01:01:01.001Z" + * } + */ + Meter: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + key: components['schemas']['ResourceKey'] + /** @description The aggregation type to use for the meter. */ + aggregation: components['schemas']['MeterAggregation'] + /** + * @description The event type to include in the aggregation. + * @example prompt + */ + event_type: string + /** + * @description The date since the meter should include events. Useful to skip old events. If + * not specified, all historical events are included. + */ + events_from?: components['schemas']['DateTime'] + /** + * @description JSONPath expression to extract the value from the ingested event's data + * property. + * + * The ingested value for sum, avg, min, and max aggregations is a number or a + * string that can be parsed to a number. + * + * For unique_count aggregation, the ingested value must be a string. For count + * aggregation the value_property is ignored. + * @example $.tokens + */ + value_property?: string + /** + * @description Named JSONPath expressions to extract the group by values from the event data. + * + * Keys must be unique and consist only alphanumeric and underscore characters. + * @example { + * "type": "$.type" + * } + */ + dimensions?: { + [key: string]: string + } + } + /** + * @description The aggregation type to use for the meter. + * @enum {string} + */ + MeterAggregation: + | 'sum' + | 'count' + | 'unique_count' + | 'avg' + | 'min' + | 'max' + | 'latest' + /** @description Page paginated response. */ + MeterPagePaginatedResponse: { + data: components['schemas']['Meter'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Filters to apply to a meter query. */ + MeterQueryFilters: { + /** + * @description Filters to apply to the dimensions of the query. For `subject` and `customer_id` + * only equals ("eq", "in") comparisons are supported. + */ + dimensions?: { + [key: string]: components['schemas']['QueryFilterStringMapItem'] + } + } + /** + * @description The granularity of the time grouping. Time durations are specified in ISO 8601 + * format. + * @enum {string} + */ + MeterQueryGranularity: 'PT1M' | 'PT1H' | 'P1D' | 'P1M' + /** + * @description A meter query request. + * @example { + * "from": "2023-01-01T00:00:00Z", + * "to": "2023-01-02T00:00:00Z", + * "granularity": "P1D", + * "time_zone": "UTC" + * } + */ + MeterQueryRequest: { + /** @description The start of the period the usage is queried from. */ + from?: components['schemas']['DateTime'] + /** @description The end of the period the usage is queried to. */ + to?: components['schemas']['DateTime'] + /** + * @description The size of the time buckets to group the usage into. If not specified, the + * usage is aggregated over the entire period. + */ + granularity?: components['schemas']['MeterQueryGranularity'] + /** + * @description The value is the name of the time zone as defined in the IANA Time Zone Database + * (http://www.iana.org/time-zones). The time zone is used to determine the start + * and end of the time buckets. If not specified, the UTC timezone will be used. + * @default UTC + */ + time_zone?: string + /** + * @description The dimensions to group the results by. + * @example [ + * "model", + * "type" + * ] + */ + group_by_dimensions?: string[] + /** @description Filters to apply to the query. */ + filters?: components['schemas']['MeterQueryFilters'] + } + /** + * @description Meter query result. + * @example { + * "from": "2023-01-01T00:00:00Z", + * "to": "2023-01-02T00:00:00Z", + * "data": [ + * { + * "value": "12.3456", + * "from": "2023-01-01T00:00:00Z", + * "to": "2023-01-02T00:00:00Z", + * "dimensions": { + * "customer_id": "01G65Z755AFWAKHE12NY0CQ9FH", + * "model": "gpt-4-turbo", + * "type": "input" + * } + * } + * ] + * } + */ + MeterQueryResult: { + /** @description The start of the period the usage is queried from. */ + from?: components['schemas']['DateTime'] + /** @description The end of the period the usage is queried to. */ + to?: components['schemas']['DateTime'] + /** @description The usage data. If no data is available, an empty array is returned. */ + data: components['schemas']['MeterQueryRow'][] + } + /** + * @description A row in the result of a meter query. + * @example { + * "value": "12.3456", + * "from": "2023-01-01T00:00:00Z", + * "to": "2023-01-02T00:00:00Z", + * "dimensions": { + * "customer_id": "01G65Z755AFWAKHE12NY0CQ9FH", + * "model": "gpt-4-turbo", + * "type": "input" + * } + * } + */ + MeterQueryRow: { + /** @description The aggregated value. */ + value: components['schemas']['Numeric'] + /** @description The start of the time bucket the value is aggregated over. */ + from: components['schemas']['DateTime'] + /** @description The end of the time bucket the value is aggregated over. */ + to: components['schemas']['DateTime'] + /** + * @description The dimensions the value is aggregated over. `subject` and `customer_id` are + * reserved dimensions. + */ + dimensions: { + [key: string]: string + } + } + /** + * Metering Event + * @description Metering event following the CloudEvents specification. + * @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" + * } + * } + */ + MeteringEvent: { + /** + * @description Identifies the event. + * @example 5c10fade-1c9e-4d6c-8275-c52c36731d3c + */ + id: string + /** + * Format: uri-reference + * @description Identifies the context in which an event happened. + * @example service-name + */ + source: string + /** + * @description The version of the CloudEvents specification which the event uses. + * @default 1.0 + * @example 1.0 + */ + specversion: string + /** + * @description Contains a value describing the type of event related to the originating + * occurrence. + * @example com.example.someevent + */ + type: string + /** + * @description Content type of the CloudEvents data value. Only the value "application/json" is + * allowed over HTTP. + * @example application/json + * @enum {string|null} + */ + datacontenttype?: 'application/json' | null + /** + * Format: uri + * @description Identifies the schema that data adheres to. + */ + dataschema?: string | null + /** + * @description Describes the subject of the event in the context of the event producer + * (identified by source). + * @example customer-id + */ + subject: string + /** + * @description Timestamp of when the occurrence happened. Must adhere to RFC 3339. + * @example 2023-01-01T01:01:01.001Z + */ + time?: (string & components['schemas']['DateTime']) | null + /** @description The event payload. Optional, if present it must be a JSON object. */ + data?: { + [key: string]: unknown + } | null + } + /** + * Ingested Event + * @description An ingested metering event with ingestion metadata. + * @example { + * "event": { + * "id": "5c10fade-1c9e-4d6c-8275-c52c36731d3c", + * "source": "service-name", + * "specversion": "1.0", + * "type": "prompt", + * "subject": "customer_key", + * "time": "2023-01-01T01:01:01.001Z" + * }, + * "customer": { + * "id": "01G65Z755AFWAKHE12NY0CQ9FH" + * }, + * "ingested_at": "2023-01-01T01:01:01.001Z", + * "stored_at": "2023-01-01T01:01:02.001Z" + * } + */ + MeteringIngestedEvent: { + /** @description The original event ingested. */ + event: components['schemas']['MeteringEvent'] + /** @description The customer if the event is associated with a customer. */ + customer?: components['schemas']['CustomerReference'] + /** @description The date and time the event was ingested and its processing started. */ + ingested_at: components['schemas']['DateTime'] + /** @description The date and time the event was stored in the database. */ + stored_at: components['schemas']['DateTime'] + /** @description The validation errors of the ingested event. */ + validation_errors?: components['schemas']['MeteringIngestedEventValidationError'][] + } + /** @description Event validation errors. */ + MeteringIngestedEventValidationError: { + /** + * Code + * @description The machine readable code of the error. + */ + readonly code: string + /** + * Message + * @description The human readable description of the error. + */ + readonly message: string + /** + * Attributes + * @description Additional attributes. + */ + readonly attributes?: { + [key: string]: unknown + } + } + /** @description Numeric represents an arbitrary precision number. */ + Numeric: string + /** + * @description Organization-level default tax code references. + * + * Stores the default tax codes applied to specific billing contexts for this + * organization. Provisioned automatically when the organization is created. + */ + OrganizationDefaultTaxCodes: { + /** + * Invoicing tax code + * @description Default tax code for invoicing. + */ + invoicing_tax_code: components['schemas']['TaxCodeReference'] + /** + * Credit grant tax code + * @description Default tax code for credit grants. + */ + credit_grant_tax_code: components['schemas']['TaxCodeReference'] + /** @description Timestamp of creation. */ + readonly created_at: components['schemas']['DateTime'] + /** @description Timestamp of last update. */ + readonly updated_at: components['schemas']['DateTime'] + } + /** + * @description PlanAddon represents an association between a plan and an add-on, controlling + * which add-ons are available for purchase within a plan. + */ + PlanAddon: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * Add-on + * @description The add-on associated with the plan. + */ + addon: components['schemas']['AddonReferenceItem'] + /** + * From plan phase + * @description The key of the plan phase from which the add-on becomes available for purchase. + */ + from_plan_phase: components['schemas']['ResourceKey'] + /** + * Max quantity + * @description The maximum number of times the add-on can be purchased for the plan. For + * single-instance add-ons this field must be omitted. For multi-instance add-ons + * when omitted, unlimited quantity can be purchased. + */ + max_quantity?: number + /** + * Validation errors + * @description List of validation errors. + */ + readonly validation_errors?: components['schemas']['ProductCatalogValidationError'][] + } + /** @description Page paginated response. */ + PlanAddonPagePaginatedResponse: { + data: components['schemas']['PlanAddon'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Page paginated response. */ + PlanPagePaginatedResponse: { + data: components['schemas']['BillingPlan'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Page paginated response. */ + PricePagePaginatedResponse: { + data: components['schemas']['LLMCostPrice'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Validation errors providing detailed description of the issue. */ + ProductCatalogValidationError: { + /** + * Code + * @description Machine-readable error code. + */ + readonly code: string + /** + * Message + * @description Human-readable description of the error. + */ + readonly message: string + /** + * Attributes + * @description Additional structured context. + */ + readonly attributes?: { + [key: string]: unknown + } + /** + * Field + * @description The path to the field. + * @example addons/pro/ratecards/token/featureKey + */ + readonly field: string + } + /** + * Query String Filter + * @description A query filter for a string attribute. Operators are mutually exclusive, only + * one operator is allowed at a time. + */ + QueryFilterString: { + /** @description The attribute equals the provided value. */ + eq?: string + /** @description The attribute does not equal the provided value. */ + neq?: string + /** @description The attribute is one of the provided values. */ + in?: string[] + /** @description The attribute is not one of the provided values. */ + nin?: string[] + /** @description The attribute contains the provided value. */ + contains?: string + /** @description The attribute does not contain the provided value. */ + ncontains?: string + /** @description Combines the provided filters with a logical AND. */ + and?: components['schemas']['QueryFilterString'][] + /** @description Combines the provided filters with a logical OR. */ + or?: components['schemas']['QueryFilterString'][] + } + /** + * Query String Map Item Filter + * @description A query filter for an item in a string map attribute. Operators are mutually + * exclusive, only one operator is allowed at a time. + */ + QueryFilterStringMapItem: { + /** @description The attribute exists. */ + exists?: boolean + /** @description The attribute equals the provided value. */ + eq?: string + /** @description The attribute does not equal the provided value. */ + neq?: string + /** @description The attribute is one of the provided values. */ + in?: string[] + /** @description The attribute is not one of the provided values. */ + nin?: string[] + /** @description The attribute contains the provided value. */ + contains?: string + /** @description The attribute does not contain the provided value. */ + ncontains?: string + /** @description Combines the provided filters with a logical AND. */ + and?: components['schemas']['QueryFilterString'][] + /** @description Combines the provided filters with a logical OR. */ + or?: components['schemas']['QueryFilterString'][] + } + /** @description Recurring period with an anchor and an interval. */ + RecurringPeriod: { + /** + * Anchor time + * @description A date-time anchor to base the recurring period on. + * @example 2023-01-01T01:01:01.001Z + */ + anchor: components['schemas']['DateTime'] + /** + * Interval in ISO 8601 duration format + * @description The interval duration in ISO 8601 format. + * @example P1M + */ + interval: components['schemas']['ISO8601Duration'] + } + /** + * Resource Key + * @description A key is a unique string that is used to identify a resource. + * @example resource_key + */ + ResourceKey: string + /** + * Resource managed by + * @description Identifies which system manages a resource. + * + * Values: + * + * - `manual`: The resource is managed manually (overridden by our API users). + * - `system`: The resource is managed by the system. + * - `subscription`: The resource is managed by the subscription. + * @enum {string} + */ + ResourceManagedBy: 'manual' | 'system' | 'subscription' + /** + * @description Filters on the given string field value by either exact or fuzzy match. All + * properties are optional; provide exactly one to specify the comparison. + */ + StringFieldFilter: + | string + | { + /** @description Value strictly equals the given string value. */ + eq?: string + /** @description Value does not equal the given string value. */ + neq?: string + /** @description Value contains the given string value (fuzzy match). */ + contains?: string + /** + * Format: ArrayEncoding.commaDelimited + * @description Returns entities that fuzzy-match any of the comma-delimited phrases in the + * filter string. + */ + ocontains?: string + /** + * Format: ArrayEncoding.commaDelimited + * @description Returns entities that exact match any of the comma-delimited phrases in the + * filter string. + */ + oeq?: string + /** @description Value is greater than the given string value (lexicographic compare). */ + gt?: string + /** + * @description Value is greater than or equal to the given string value (lexicographic + * compare). + */ + gte?: string + /** @description Value is less than the given string value (lexicographic compare). */ + lt?: string + /** @description Value is less than or equal to the given string value (lexicographic compare). */ + lte?: string + /** + * @description When true, the field must be present (non-null); when false, the field must be + * absent (null). + */ + exists?: boolean + } + /** + * String Field Filter Exact + * @description Filters on the given string field value by exact match. All properties are + * optional; provide exactly one to specify the comparison. + */ + StringFieldFilterExact: + | string + | { + /** @description Value strictly equals the given string value. */ + eq?: string + /** + * Format: ArrayEncoding.commaDelimited + * @description Returns entities that exact match any of the comma-delimited phrases in the + * filter string. + */ + oeq?: string + /** @description Value does not equal the given string value. */ + neq?: string + } + /** @description Addon purchased with a subscription. */ + SubscriptionAddon: { + readonly id: components['schemas']['ULID'] + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** @description An ISO-8601 timestamp representation of entity creation date. */ + readonly created_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity last update date. */ + readonly updated_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of entity deletion date. */ + readonly deleted_at?: components['schemas']['DateTime'] + /** + * Add-on + * @description The add-on associated with the subscription. + */ + addon: components['schemas']['AddonReferenceItem'] + /** + * Quantity + * @description The quantity of the add-on. Always 1 for single instance add-ons. + */ + quantity: number + /** + * @description An ISO-8601 timestamp representation of which point in time the quantity was + * resolved to. + */ + readonly quantity_at: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of the cadence start of the resource. */ + readonly active_from: components['schemas']['DateTime'] + /** @description An ISO-8601 timestamp representation of the cadence end of the resource. */ + readonly active_to?: components['schemas']['DateTime'] + } + /** @description Page paginated response. */ + SubscriptionAddonPagePaginatedResponse: { + data: components['schemas']['SubscriptionAddon'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Page paginated response. */ + SubscriptionPagePaginatedResponse: { + data: components['schemas']['BillingSubscription'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description Page paginated response. */ + TaxCodePagePaginatedResponse: { + data: components['schemas']['BillingTaxCode'][] + meta: components['schemas']['PaginatedMeta'] + } + /** @description TaxCode reference. */ + TaxCodeReference: { + id: components['schemas']['ULID'] + } + /** @description TaxCode reference. */ + TaxCodeReferenceItem: { + id: components['schemas']['ULID'] + } + /** + * ULID + * @description ULID (Universally Unique Lexicographically Sortable Identifier). + * @example 01G65Z755AFWAKHE12NY0CQ9FH + */ + ULID: string + /** + * ULID Field Filter + * @description Filters on the given ULID field value by exact match. All properties are + * optional; provide exactly one to specify the comparison. + */ + ULIDFieldFilter: + | components['schemas']['ULID'] + | { + /** @description Value strictly equals the given ULID value. */ + eq?: components['schemas']['ULID'] + /** + * Format: ArrayEncoding.commaDelimited + * @description Returns entities that exact match any of the comma-delimited ULIDs in the filter + * string. + */ + oeq?: string + /** @description Value does not equal the given ULID value. */ + neq?: components['schemas']['ULID'] + } + /** + * @description Request body for updating the external payment settlement status of a credit + * grant. + */ + UpdateCreditGrantExternalSettlementRequest: { + /** @description The new payment settlement status. */ + status: components['schemas']['BillingCreditPurchasePaymentSettlementStatus'] + } + /** + * @description Request body for updating a feature. Currently only the unit_cost field can be + * updated. + */ + UpdateFeatureRequest: { + /** + * Unit cost + * @description Optional per-unit cost configuration. Use "manual" for a fixed per-unit cost, or + * "llm" to look up cost from the LLM cost database based on meter group-by + * properties. Set to `null` to clear the existing unit cost; omit to leave it + * unchanged. + */ + unit_cost?: components['schemas']['BillingFeatureUnitCost'] | null + } + /** @description Meter update request. */ + UpdateMeterRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name?: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * @description Named JSONPath expressions to extract the group by values from the event data. + * + * Keys must be unique and consist only alphanumeric and underscore characters. + * @example { + * "type": "$.type" + * } + */ + dimensions?: { + [key: string]: string + } + } + /** @description OrganizationDefaultTaxCodes update request. */ + UpdateOrganizationDefaultTaxCodesRequest: { + /** + * Invoicing tax code + * @description Default tax code for invoicing. + */ + invoicing_tax_code?: components['schemas']['TaxCodeReference'] + /** + * Credit grant tax code + * @description Default tax code for credit grants. + */ + credit_grant_tax_code?: components['schemas']['TaxCodeReference'] + } + /** @description Addon upsert request. */ + UpsertAddonRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * The InstanceType of the add-ons. Can be "single" or "multiple". + * @description The InstanceType of the add-ons. Can be "single" or "multiple". + */ + instance_type: components['schemas']['AddonInstanceType'] + /** + * Rate cards + * @description The rate cards of the add-on. + */ + rate_cards: components['schemas']['BillingRateCard'][] + } + /** @description AppCustomerData upsert request. */ + UpsertAppCustomerDataRequest: { + /** + * Stripe + * @description Used if the customer has a linked Stripe app. + */ + stripe?: components['schemas']['BillingAppCustomerDataStripe'] + /** + * External invoicing + * @description Used if the customer has a linked external invoicing app. + */ + external_invoicing?: components['schemas']['BillingAppCustomerDataExternalInvoicing'] + } + /** @description BillingProfile upsert request. */ + UpsertBillingProfileRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * @description The name and contact information for the supplier this billing profile + * represents + */ + supplier: components['schemas']['BillingParty'] + /** @description The billing workflow settings for this profile */ + workflow: components['schemas']['BillingWorkflow'] + /** @description Whether this is the default profile. */ + default: boolean + } + /** @description CustomerBillingData upsert request. */ + UpsertCustomerBillingDataRequest: { + /** + * Billing profile + * @description The billing profile for the customer. + * + * If not provided, the default billing profile will be used. + */ + billing_profile?: components['schemas']['BillingProfileReference'] + /** + * App customer data + * @description App customer data. + */ + app_data?: components['schemas']['BillingAppCustomerData'] + } + /** @description Customer upsert request. */ + UpsertCustomerRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * Usage Attribution + * @description Mapping to attribute metered usage to the customer by the event subject. + */ + usage_attribution?: components['schemas']['BillingCustomerUsageAttribution'] + /** + * Primary Email + * @description The primary email address of the customer. + */ + primary_email?: string + /** + * Currency + * @description Currency of the customer. Used for billing, tax and invoicing. + */ + currency?: components['schemas']['CurrencyCode'] + /** + * Billing Address + * @description The billing address of the customer. Used for tax and invoicing. + */ + billing_address?: components['schemas']['BillingAddress'] + } + /** @description PlanAddon upsert request. */ + UpsertPlanAddonRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * From plan phase + * @description The key of the plan phase from which the add-on becomes available for purchase. + */ + from_plan_phase: components['schemas']['ResourceKey'] + /** + * Max quantity + * @description The maximum number of times the add-on can be purchased for the plan. For + * single-instance add-ons this field must be omitted. For multi-instance add-ons + * when omitted, unlimited quantity can be purchased. + */ + max_quantity?: number + } + /** @description Plan upsert request. */ + UpsertPlanRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * Pro-rating enabled + * @description Whether pro-rating is enabled for this plan. + * @default true + */ + pro_rating_enabled?: boolean + /** + * Plan phases + * @description The plan phases define the pricing ramp for a subscription. A phase switch + * occurs only at the end of a billing period. At least one phase is required. + */ + phases: components['schemas']['BillingPlanPhase'][] + } + /** @description TaxCode upsert request. */ + UpsertTaxCodeRequest: { + /** + * @description Display name of the resource. + * + * Between 1 and 256 characters. + */ + name: string + /** + * @description Optional description of the resource. + * + * Maximum 1024 characters. + */ + description?: string + labels?: components['schemas']['Labels'] + /** + * App type to tax code mappings + * @description Mapping of app types to tax codes. + */ + app_mappings: components['schemas']['BillingTaxCodeAppMapping'][] + } + /** @description Subject key. */ + UsageAttributionSubjectKey: string + /** + * SortQuery + * @description The `asc` suffix is optional as the default sort order is ascending. + * The `desc` suffix is used to specify a descending order. + * Multiple sort attributes may be provided via a comma separated list. + * JSONPath notation may be used to specify a sub-attribute (eg: 'foo.bar desc'). + * @example created_at desc + */ + SortQuery: string + /** + * Labels + * @description Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. + * + * Keys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_". + * @example { + * "env": "test" + * } + */ + Labels: { + [key: string]: string + } + /** @description Contains pagination query parameters and the total number of objects returned. */ + PageMeta: { + /** @example 1 */ + number: number + /** @example 10 */ + size: number + /** @example 100 */ + total: number + } + /** + * PaginatedMeta + * @description returns the pagination information + */ + PaginatedMeta: { + page: components['schemas']['PageMeta'] + } + /** + * Error + * @description standard error + */ + BaseError: { + /** + * @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. + */ + readonly status: number + /** + * @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. + */ + readonly title: string + /** @description The error type. */ + readonly type?: string + /** + * @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. + */ + readonly instance: string + /** + * @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. + */ + readonly detail: string + } + /** + * @description invalid parameters rules + * @enum {string|null} + */ + InvalidRules: + | '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' + | null + InvalidParameterStandard: { + /** @example name */ + readonly field: string + rule?: components['schemas']['InvalidRules'] + /** @example body */ + source?: string + /** @example is a required field */ + readonly reason: string + } + InvalidParameterMinimumLength: { + /** @example name */ + readonly field: string + /** + * @description invalid parameters rules + * @enum {string} + */ + readonly rule: + | 'min_length' + | 'min_digits' + | 'min_lowercase' + | 'min_uppercase' + | 'min_symbols' + | 'min_items' + | 'min' + /** @example 8 */ + minimum: number + /** @example body */ + source?: string + /** @example must have at least 8 characters */ + readonly reason: string + } + InvalidParameterMaximumLength: { + /** @example name */ + readonly field: string + /** + * @description invalid parameters rules + * @enum {string} + */ + readonly rule: 'max_length' | 'max_items' | 'max' + /** @example 8 */ + maximum: number + /** @example body */ + source?: string + /** @example must not have more than 8 characters */ + readonly reason: string + } + InvalidParameterChoiceItem: { + /** @example name */ + readonly field: string + /** + * @description invalid parameters rules + * @enum {string} + */ + readonly rule: 'enum' + /** @example is a required field */ + readonly reason: string + readonly choices: unknown[] + /** @example body */ + source?: string + } + InvalidParameterDependentItem: { + /** @example name */ + readonly field: string + /** + * @description invalid parameters rules + * @enum {string|null} + */ + readonly rule: 'dependent_fields' | null + /** @example is a required field */ + readonly reason: string + readonly dependents: unknown[] | null + /** @example body */ + source?: string + } + /** @description invalid parameters */ + InvalidParameters: ( + | components['schemas']['InvalidParameterStandard'] + | components['schemas']['InvalidParameterMinimumLength'] + | components['schemas']['InvalidParameterMaximumLength'] + | components['schemas']['InvalidParameterChoiceItem'] + | components['schemas']['InvalidParameterDependentItem'] + )[] + BadRequestError: components['schemas']['BaseError'] & { + invalid_parameters: components['schemas']['InvalidParameters'] + } + UnauthorizedError: components['schemas']['BaseError'] & { + /** @example 401 */ + status?: unknown + /** @example Unauthorized */ + title?: unknown + /** @example https://httpstatuses.com/401 */ + type?: unknown + /** @example kong:trace:1234567890 */ + instance?: unknown + /** @example Invalid credentials */ + detail?: unknown + } + ForbiddenError: components['schemas']['BaseError'] & { + /** @example 403 */ + status?: unknown + /** @example Forbidden */ + title?: unknown + /** @example https://httpstatuses.com/403 */ + type?: unknown + /** @example kong:trace:1234567890 */ + instance?: unknown + /** @example Forbidden */ + detail?: unknown + } + NotFoundError: components['schemas']['BaseError'] & { + /** @example 404 */ + status?: unknown + /** @example Not Found */ + title?: unknown + /** @example https://httpstatuses.com/404 */ + type?: unknown + /** @example kong:trace:1234567890 */ + instance?: unknown + /** @example Not found */ + detail?: unknown + } + GoneError: components['schemas']['BaseError'] & { + /** @example 410 */ + status?: unknown + /** @example Gone */ + title?: unknown + /** @example https://httpstatuses.com/410 */ + type?: unknown + /** @example kong:trace:1234567890 */ + instance?: unknown + /** @example Gone */ + detail?: unknown + } + CursorMetaPage: { + /** + * Format: path + * @description URI to the first page + */ + first?: string + /** + * Format: path + * @description URI to the last page + */ + last?: string + /** + * Format: path + * @description URI to the next page + */ + next: string | null + /** + * Format: path + * @description URI to the previous page + */ + previous: string | null + /** + * @description Requested page size + * @example 10 + */ + size: number + } + /** @description Pagination metadata. */ + CursorMeta: { + page: components['schemas']['CursorMetaPage'] + } + ConflictError: components['schemas']['BaseError'] & { + /** @example 409 */ + status?: unknown + /** @example Conflict */ + title?: unknown + /** @example https://httpstatuses.com/409 */ + type?: unknown + /** @example kong:trace:1234567890 */ + instance?: unknown + /** @example Conflict */ + detail?: unknown + } + } + responses: { + /** @description Bad Request */ + BadRequest: { + headers: { + [name: string]: unknown + } + content: { + 'application/problem+json': components['schemas']['BadRequestError'] + } + } + /** @description Unauthorized */ + Unauthorized: { + headers: { + [name: string]: unknown + } + content: { + 'application/problem+json': components['schemas']['UnauthorizedError'] + } + } + /** @description Forbidden */ + Forbidden: { + headers: { + [name: string]: unknown + } + content: { + 'application/problem+json': components['schemas']['ForbiddenError'] + } + } + /** @description Not Found */ + NotFound: { + headers: { + [name: string]: unknown + } + content: { + 'application/problem+json': components['schemas']['NotFoundError'] + } + } + /** @description Gone */ + Gone: { + headers: { + [name: string]: unknown + } + content: { + 'application/problem+json': components['schemas']['GoneError'] + } + } + /** @description Conflict */ + Conflict: { + headers: { + [name: string]: unknown + } + content: { + 'application/problem+json': components['schemas']['ConflictError'] + } + } + } + parameters: { + CursorPaginationQuery: components['schemas']['CursorPaginationQueryPage'] + /** @description Determines which page of the collection to retrieve. */ + PagePaginationQuery: { + /** @description The number of items to include per page. */ + size?: number + /** @description The page number. */ + number?: number + } + } + requestBodies: never + headers: never + pathItems: never +} +export type Addon = components['schemas']['Addon'] +export type AddonInstanceType = components['schemas']['AddonInstanceType'] +export type AddonPagePaginatedResponse = + components['schemas']['AddonPagePaginatedResponse'] +export type AddonReference = components['schemas']['AddonReference'] +export type AddonReferenceItem = components['schemas']['AddonReferenceItem'] +export type AddonStatus = components['schemas']['AddonStatus'] +export type Address = components['schemas']['Address'] +export type AppPagePaginatedResponse = + components['schemas']['AppPagePaginatedResponse'] +export type BillingAddress = components['schemas']['BillingAddress'] +export type BillingApp = components['schemas']['BillingApp'] +export type BillingAppCatalogItem = + components['schemas']['BillingAppCatalogItem'] +export type BillingAppCustomerData = + components['schemas']['BillingAppCustomerData'] +export type BillingAppCustomerDataExternalInvoicing = + components['schemas']['BillingAppCustomerDataExternalInvoicing'] +export type BillingAppCustomerDataStripe = + components['schemas']['BillingAppCustomerDataStripe'] +export type BillingAppExternalInvoicing = + components['schemas']['BillingAppExternalInvoicing'] +export type BillingAppReference = components['schemas']['BillingAppReference'] +export type BillingAppSandbox = components['schemas']['BillingAppSandbox'] +export type BillingAppStatus = components['schemas']['BillingAppStatus'] +export type BillingAppStripe = components['schemas']['BillingAppStripe'] +export type BillingAppStripeCheckoutSessionCustomTextParams = + components['schemas']['BillingAppStripeCheckoutSessionCustomTextParams'] +export type BillingAppStripeCheckoutSessionMode = + components['schemas']['BillingAppStripeCheckoutSessionMode'] +export type BillingAppStripeCheckoutSessionUiMode = + components['schemas']['BillingAppStripeCheckoutSessionUIMode'] +export type BillingAppStripeCreateCheckoutSessionBillingAddressCollection = + components['schemas']['BillingAppStripeCreateCheckoutSessionBillingAddressCollection'] +export type BillingAppStripeCreateCheckoutSessionConsentCollection = + components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollection'] +export type BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreement = + components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreement'] +export type BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreementPosition = + components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionPaymentMethodReuseAgreementPosition'] +export type BillingAppStripeCreateCheckoutSessionConsentCollectionPromotions = + components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionPromotions'] +export type BillingAppStripeCreateCheckoutSessionConsentCollectionTermsOfService = + components['schemas']['BillingAppStripeCreateCheckoutSessionConsentCollectionTermsOfService'] +export type BillingAppStripeCreateCheckoutSessionCustomerUpdate = + components['schemas']['BillingAppStripeCreateCheckoutSessionCustomerUpdate'] +export type BillingAppStripeCreateCheckoutSessionCustomerUpdateBehavior = + components['schemas']['BillingAppStripeCreateCheckoutSessionCustomerUpdateBehavior'] +export type BillingAppStripeCreateCheckoutSessionRedirectOnCompletion = + components['schemas']['BillingAppStripeCreateCheckoutSessionRedirectOnCompletion'] +export type BillingAppStripeCreateCheckoutSessionRequestOptions = + components['schemas']['BillingAppStripeCreateCheckoutSessionRequestOptions'] +export type BillingAppStripeCreateCheckoutSessionResult = + components['schemas']['BillingAppStripeCreateCheckoutSessionResult'] +export type BillingAppStripeCreateCheckoutSessionTaxIdCollection = + components['schemas']['BillingAppStripeCreateCheckoutSessionTaxIdCollection'] +export type BillingAppStripeCreateCheckoutSessionTaxIdCollectionRequired = + components['schemas']['BillingAppStripeCreateCheckoutSessionTaxIdCollectionRequired'] +export type BillingAppStripeCreateCustomerPortalSessionOptions = + components['schemas']['BillingAppStripeCreateCustomerPortalSessionOptions'] +export type BillingAppStripeCreateCustomerPortalSessionResult = + components['schemas']['BillingAppStripeCreateCustomerPortalSessionResult'] +export type BillingAppType = components['schemas']['BillingAppType'] +export type BillingCharge = components['schemas']['BillingCharge'] +export type BillingChargeStatus = components['schemas']['BillingChargeStatus'] +export type BillingChargeTotals = components['schemas']['BillingChargeTotals'] +export type BillingChargesExpand = components['schemas']['BillingChargesExpand'] +export type BillingCostBasis = components['schemas']['BillingCostBasis'] +export type BillingCreditAdjustment = + components['schemas']['BillingCreditAdjustment'] +export type BillingCreditAvailabilityPolicy = + components['schemas']['BillingCreditAvailabilityPolicy'] +export type BillingCreditBalances = + components['schemas']['BillingCreditBalances'] +export type BillingCreditFundingMethod = + components['schemas']['BillingCreditFundingMethod'] +export type BillingCreditGrant = components['schemas']['BillingCreditGrant'] +export type BillingCreditGrantFilters = + components['schemas']['BillingCreditGrantFilters'] +export type BillingCreditGrantInvoiceReference = + components['schemas']['BillingCreditGrantInvoiceReference'] +export type BillingCreditGrantPurchase = + components['schemas']['BillingCreditGrantPurchase'] +export type BillingCreditGrantStatus = + components['schemas']['BillingCreditGrantStatus'] +export type BillingCreditGrantTaxConfig = + components['schemas']['BillingCreditGrantTaxConfig'] +export type BillingCreditPurchasePaymentSettlementStatus = + components['schemas']['BillingCreditPurchasePaymentSettlementStatus'] +export type BillingCreditTransaction = + components['schemas']['BillingCreditTransaction'] +export type BillingCreditTransactionType = + components['schemas']['BillingCreditTransactionType'] +export type BillingCurrency = components['schemas']['BillingCurrency'] +export type BillingCurrencyCode = components['schemas']['BillingCurrencyCode'] +export type BillingCurrencyCodeCustom = + components['schemas']['BillingCurrencyCodeCustom'] +export type BillingCurrencyCustom = + components['schemas']['BillingCurrencyCustom'] +export type BillingCurrencyFiat = components['schemas']['BillingCurrencyFiat'] +export type BillingCurrencyType = components['schemas']['BillingCurrencyType'] +export type BillingCustomer = components['schemas']['BillingCustomer'] +export type BillingCustomerData = components['schemas']['BillingCustomerData'] +export type BillingCustomerReference = + components['schemas']['BillingCustomerReference'] +export type BillingCustomerStripeCreateCheckoutSessionRequest = + components['schemas']['BillingCustomerStripeCreateCheckoutSessionRequest'] +export type BillingCustomerStripeCreateCustomerPortalSessionRequest = + components['schemas']['BillingCustomerStripeCreateCustomerPortalSessionRequest'] +export type BillingCustomerUsageAttribution = + components['schemas']['BillingCustomerUsageAttribution'] +export type BillingEntitlementAccessResult = + components['schemas']['BillingEntitlementAccessResult'] +export type BillingEntitlementType = + components['schemas']['BillingEntitlementType'] +export type BillingFeatureLlmTokenType = + components['schemas']['BillingFeatureLLMTokenType'] +export type BillingFeatureLlmUnitCost = + components['schemas']['BillingFeatureLLMUnitCost'] +export type BillingFeatureLlmUnitCostPricing = + components['schemas']['BillingFeatureLLMUnitCostPricing'] +export type BillingFeatureManualUnitCost = + components['schemas']['BillingFeatureManualUnitCost'] +export type BillingFeatureUnitCost = + components['schemas']['BillingFeatureUnitCost'] +export type BillingFlatFeeCharge = components['schemas']['BillingFlatFeeCharge'] +export type BillingFlatFeeDiscounts = + components['schemas']['BillingFlatFeeDiscounts'] +export type BillingParty = components['schemas']['BillingParty'] +export type BillingPartyAddresses = + components['schemas']['BillingPartyAddresses'] +export type BillingPartyTaxIdentity = + components['schemas']['BillingPartyTaxIdentity'] +export type BillingPlan = components['schemas']['BillingPlan'] +export type BillingPlanPhase = components['schemas']['BillingPlanPhase'] +export type BillingPlanStatus = components['schemas']['BillingPlanStatus'] +export type BillingPrice = components['schemas']['BillingPrice'] +export type BillingPriceFlat = components['schemas']['BillingPriceFlat'] +export type BillingPriceFree = components['schemas']['BillingPriceFree'] +export type BillingPriceGraduated = + components['schemas']['BillingPriceGraduated'] +export type BillingPricePaymentTerm = + components['schemas']['BillingPricePaymentTerm'] +export type BillingPriceTier = components['schemas']['BillingPriceTier'] +export type BillingPriceUnit = components['schemas']['BillingPriceUnit'] +export type BillingPriceVolume = components['schemas']['BillingPriceVolume'] +export type BillingProfile = components['schemas']['BillingProfile'] +export type BillingProfileAppReferences = + components['schemas']['BillingProfileAppReferences'] +export type BillingProfilePagePaginatedResponse = + components['schemas']['BillingProfilePagePaginatedResponse'] +export type BillingProfileReference = + components['schemas']['BillingProfileReference'] +export type BillingRateCard = components['schemas']['BillingRateCard'] +export type BillingRateCardDiscounts = + components['schemas']['BillingRateCardDiscounts'] +export type BillingRateCardProrationConfiguration = + components['schemas']['BillingRateCardProrationConfiguration'] +export type BillingRateCardProrationMode = + components['schemas']['BillingRateCardProrationMode'] +export type BillingRateCardTaxConfig = + components['schemas']['BillingRateCardTaxConfig'] +export type BillingSettlementMode = + components['schemas']['BillingSettlementMode'] +export type BillingSpendCommitments = + components['schemas']['BillingSpendCommitments'] +export type BillingSubscription = components['schemas']['BillingSubscription'] +export type BillingSubscriptionCancel = + components['schemas']['BillingSubscriptionCancel'] +export type BillingSubscriptionChange = + components['schemas']['BillingSubscriptionChange'] +export type BillingSubscriptionChangeResponse = + components['schemas']['BillingSubscriptionChangeResponse'] +export type BillingSubscriptionCreate = + components['schemas']['BillingSubscriptionCreate'] +export type BillingSubscriptionEditTiming = + components['schemas']['BillingSubscriptionEditTiming'] +export type BillingSubscriptionEditTimingEnum = + components['schemas']['BillingSubscriptionEditTimingEnum'] +export type BillingSubscriptionReference = + components['schemas']['BillingSubscriptionReference'] +export type BillingSubscriptionStatus = + components['schemas']['BillingSubscriptionStatus'] +export type BillingTaxBehavior = components['schemas']['BillingTaxBehavior'] +export type BillingTaxCode = components['schemas']['BillingTaxCode'] +export type BillingTaxCodeAppMapping = + components['schemas']['BillingTaxCodeAppMapping'] +export type BillingTaxConfig = components['schemas']['BillingTaxConfig'] +export type BillingTaxConfigExternalInvoicing = + components['schemas']['BillingTaxConfigExternalInvoicing'] +export type BillingTaxConfigStripe = + components['schemas']['BillingTaxConfigStripe'] +export type BillingTaxIdentificationCode = + components['schemas']['BillingTaxIdentificationCode'] +export type BillingTotals = components['schemas']['BillingTotals'] +export type BillingUsageBasedCharge = + components['schemas']['BillingUsageBasedCharge'] +export type BillingWorkflow = components['schemas']['BillingWorkflow'] +export type BillingWorkflowCollectionAlignment = + components['schemas']['BillingWorkflowCollectionAlignment'] +export type BillingWorkflowCollectionAlignmentAnchored = + components['schemas']['BillingWorkflowCollectionAlignmentAnchored'] +export type BillingWorkflowCollectionAlignmentSubscription = + components['schemas']['BillingWorkflowCollectionAlignmentSubscription'] +export type BillingWorkflowCollectionSettings = + components['schemas']['BillingWorkflowCollectionSettings'] +export type BillingWorkflowInvoicingSettings = + components['schemas']['BillingWorkflowInvoicingSettings'] +export type BillingWorkflowPaymentChargeAutomaticallySettings = + components['schemas']['BillingWorkflowPaymentChargeAutomaticallySettings'] +export type BillingWorkflowPaymentSendInvoiceSettings = + components['schemas']['BillingWorkflowPaymentSendInvoiceSettings'] +export type BillingWorkflowPaymentSettings = + components['schemas']['BillingWorkflowPaymentSettings'] +export type BillingWorkflowTaxSettings = + components['schemas']['BillingWorkflowTaxSettings'] +export type ChargePagePaginatedResponse = + components['schemas']['ChargePagePaginatedResponse'] +export type ClosedPeriod = components['schemas']['ClosedPeriod'] +export type CostBasisPagePaginatedResponse = + components['schemas']['CostBasisPagePaginatedResponse'] +export type CountryCode = components['schemas']['CountryCode'] +export type CreateAddonRequest = components['schemas']['CreateAddonRequest'] +export type CreateBillingProfileRequest = + components['schemas']['CreateBillingProfileRequest'] +export type CreateCostBasisRequest = + components['schemas']['CreateCostBasisRequest'] +export type CreateCreditAdjustmentRequest = + components['schemas']['CreateCreditAdjustmentRequest'] +export type CreateCreditGrantFilters = + components['schemas']['CreateCreditGrantFilters'] +export type CreateCreditGrantPurchase = + components['schemas']['CreateCreditGrantPurchase'] +export type CreateCreditGrantRequest = + components['schemas']['CreateCreditGrantRequest'] +export type CreateCreditGrantTaxConfig = + components['schemas']['CreateCreditGrantTaxConfig'] +export type CreateCurrencyCode = components['schemas']['CreateCurrencyCode'] +export type CreateCurrencyCustomRequest = + components['schemas']['CreateCurrencyCustomRequest'] +export type CreateCustomerRequest = + components['schemas']['CreateCustomerRequest'] +export type CreateFeatureRequest = components['schemas']['CreateFeatureRequest'] +export type CreateMeterRequest = components['schemas']['CreateMeterRequest'] +export type CreatePlanAddonRequest = + components['schemas']['CreatePlanAddonRequest'] +export type CreatePlanRequest = components['schemas']['CreatePlanRequest'] +export type CreateResourceReference = + components['schemas']['CreateResourceReference'] +export type CreateTaxCodeRequest = components['schemas']['CreateTaxCodeRequest'] +export type CreditBalance = components['schemas']['CreditBalance'] +export type CreditGrantPagePaginatedResponse = + components['schemas']['CreditGrantPagePaginatedResponse'] +export type CreditTransactionPaginatedResponse = + components['schemas']['CreditTransactionPaginatedResponse'] +export type CurrencyAmount = components['schemas']['CurrencyAmount'] +export type CurrencyCode = components['schemas']['CurrencyCode'] +export type CurrencyPagePaginatedResponse = + components['schemas']['CurrencyPagePaginatedResponse'] +export type CursorPaginationQueryPage = + components['schemas']['CursorPaginationQueryPage'] +export type CustomerPagePaginatedResponse = + components['schemas']['CustomerPagePaginatedResponse'] +export type CustomerReference = components['schemas']['CustomerReference'] +export type DateTime = components['schemas']['DateTime'] +export type DateTimeFieldFilter = components['schemas']['DateTimeFieldFilter'] +export type ExternalResourceKey = components['schemas']['ExternalResourceKey'] +export type Feature = components['schemas']['Feature'] +export type FeatureCostQueryResult = + components['schemas']['FeatureCostQueryResult'] +export type FeatureCostQueryRow = components['schemas']['FeatureCostQueryRow'] +export type FeatureMeterReference = + components['schemas']['FeatureMeterReference'] +export type FeaturePagePaginatedResponse = + components['schemas']['FeaturePagePaginatedResponse'] +export type FeatureReferenceItem = components['schemas']['FeatureReferenceItem'] +export type GetCreditBalanceParamsFilter = + components['schemas']['GetCreditBalanceParamsFilter'] +export type GovernanceFeatureAccess = + components['schemas']['GovernanceFeatureAccess'] +export type GovernanceFeatureAccessReason = + components['schemas']['GovernanceFeatureAccessReason'] +export type GovernanceFeatureAccessReasonCode = + components['schemas']['GovernanceFeatureAccessReasonCode'] +export type GovernanceQueryError = components['schemas']['GovernanceQueryError'] +export type GovernanceQueryErrorCode = + components['schemas']['GovernanceQueryErrorCode'] +export type GovernanceQueryRequest = + components['schemas']['GovernanceQueryRequest'] +export type GovernanceQueryRequestCustomers = + components['schemas']['GovernanceQueryRequestCustomers'] +export type GovernanceQueryRequestFeatures = + components['schemas']['GovernanceQueryRequestFeatures'] +export type GovernanceQueryResponse = + components['schemas']['GovernanceQueryResponse'] +export type GovernanceQueryResult = + components['schemas']['GovernanceQueryResult'] +export type Iso8601Duration = components['schemas']['ISO8601Duration'] +export type IngestedEventPaginatedResponse = + components['schemas']['IngestedEventPaginatedResponse'] +export type LlmCostModel = components['schemas']['LLMCostModel'] +export type LlmCostModelPricing = components['schemas']['LLMCostModelPricing'] +export type LlmCostOverrideCreate = + components['schemas']['LLMCostOverrideCreate'] +export type LlmCostPrice = components['schemas']['LLMCostPrice'] +export type LlmCostPriceSource = components['schemas']['LLMCostPriceSource'] +export type LlmCostProvider = components['schemas']['LLMCostProvider'] +export type ListAddonsParamsFilter = + components['schemas']['ListAddonsParamsFilter'] +export type ListChargesParamsFilter = + components['schemas']['ListChargesParamsFilter'] +export type ListCostBasesParamsFilter = + components['schemas']['ListCostBasesParamsFilter'] +export type ListCreditGrantsParamsFilter = + components['schemas']['ListCreditGrantsParamsFilter'] +export type ListCreditTransactionsParamsFilter = + components['schemas']['ListCreditTransactionsParamsFilter'] +export type ListCurrenciesParamsFilter = + components['schemas']['ListCurrenciesParamsFilter'] +export type ListCustomerEntitlementAccessResponseData = + components['schemas']['ListCustomerEntitlementAccessResponseData'] +export type ListCustomersParamsFilter = + components['schemas']['ListCustomersParamsFilter'] +export type ListEventsParamsFilter = + components['schemas']['ListEventsParamsFilter'] +export type ListFeatureParamsFilter = + components['schemas']['ListFeatureParamsFilter'] +export type ListLlmCostPricesParamsFilter = + components['schemas']['ListLLMCostPricesParamsFilter'] +export type ListMetersParamsFilter = + components['schemas']['ListMetersParamsFilter'] +export type ListPlansParamsFilter = + components['schemas']['ListPlansParamsFilter'] +export type ListSubscriptionsParamsFilter = + components['schemas']['ListSubscriptionsParamsFilter'] +export type Meter = components['schemas']['Meter'] +export type MeterAggregation = components['schemas']['MeterAggregation'] +export type MeterPagePaginatedResponse = + components['schemas']['MeterPagePaginatedResponse'] +export type MeterQueryFilters = components['schemas']['MeterQueryFilters'] +export type MeterQueryGranularity = + components['schemas']['MeterQueryGranularity'] +export type MeterQueryRequest = components['schemas']['MeterQueryRequest'] +export type MeterQueryResult = components['schemas']['MeterQueryResult'] +export type MeterQueryRow = components['schemas']['MeterQueryRow'] +export type MeteringEvent = components['schemas']['MeteringEvent'] +export type MeteringIngestedEvent = + components['schemas']['MeteringIngestedEvent'] +export type MeteringIngestedEventValidationError = + components['schemas']['MeteringIngestedEventValidationError'] +export type Numeric = components['schemas']['Numeric'] +export type OrganizationDefaultTaxCodes = + components['schemas']['OrganizationDefaultTaxCodes'] +export type PlanAddon = components['schemas']['PlanAddon'] +export type PlanAddonPagePaginatedResponse = + components['schemas']['PlanAddonPagePaginatedResponse'] +export type PlanPagePaginatedResponse = + components['schemas']['PlanPagePaginatedResponse'] +export type PricePagePaginatedResponse = + components['schemas']['PricePagePaginatedResponse'] +export type ProductCatalogValidationError = + components['schemas']['ProductCatalogValidationError'] +export type QueryFilterString = components['schemas']['QueryFilterString'] +export type QueryFilterStringMapItem = + components['schemas']['QueryFilterStringMapItem'] +export type RecurringPeriod = components['schemas']['RecurringPeriod'] +export type ResourceKey = components['schemas']['ResourceKey'] +export type ResourceManagedBy = components['schemas']['ResourceManagedBy'] +export type StringFieldFilter = components['schemas']['StringFieldFilter'] +export type StringFieldFilterExact = + components['schemas']['StringFieldFilterExact'] +export type SubscriptionAddon = components['schemas']['SubscriptionAddon'] +export type SubscriptionAddonPagePaginatedResponse = + components['schemas']['SubscriptionAddonPagePaginatedResponse'] +export type SubscriptionPagePaginatedResponse = + components['schemas']['SubscriptionPagePaginatedResponse'] +export type TaxCodePagePaginatedResponse = + components['schemas']['TaxCodePagePaginatedResponse'] +export type TaxCodeReference = components['schemas']['TaxCodeReference'] +export type TaxCodeReferenceItem = components['schemas']['TaxCodeReferenceItem'] +export type Ulid = components['schemas']['ULID'] +export type UlidFieldFilter = components['schemas']['ULIDFieldFilter'] +export type UpdateCreditGrantExternalSettlementRequest = + components['schemas']['UpdateCreditGrantExternalSettlementRequest'] +export type UpdateFeatureRequest = components['schemas']['UpdateFeatureRequest'] +export type UpdateMeterRequest = components['schemas']['UpdateMeterRequest'] +export type UpdateOrganizationDefaultTaxCodesRequest = + components['schemas']['UpdateOrganizationDefaultTaxCodesRequest'] +export type UpsertAddonRequest = components['schemas']['UpsertAddonRequest'] +export type UpsertAppCustomerDataRequest = + components['schemas']['UpsertAppCustomerDataRequest'] +export type UpsertBillingProfileRequest = + components['schemas']['UpsertBillingProfileRequest'] +export type UpsertCustomerBillingDataRequest = + components['schemas']['UpsertCustomerBillingDataRequest'] +export type UpsertCustomerRequest = + components['schemas']['UpsertCustomerRequest'] +export type UpsertPlanAddonRequest = + components['schemas']['UpsertPlanAddonRequest'] +export type UpsertPlanRequest = components['schemas']['UpsertPlanRequest'] +export type UpsertTaxCodeRequest = components['schemas']['UpsertTaxCodeRequest'] +export type UsageAttributionSubjectKey = + components['schemas']['UsageAttributionSubjectKey'] +export type SortQuery = components['schemas']['SortQuery'] +export type Labels = components['schemas']['Labels'] +export type PageMeta = components['schemas']['PageMeta'] +export type PaginatedMeta = components['schemas']['PaginatedMeta'] +export type BaseError = components['schemas']['BaseError'] +export type InvalidRules = components['schemas']['InvalidRules'] +export type InvalidParameterStandard = + components['schemas']['InvalidParameterStandard'] +export type InvalidParameterMinimumLength = + components['schemas']['InvalidParameterMinimumLength'] +export type InvalidParameterMaximumLength = + components['schemas']['InvalidParameterMaximumLength'] +export type InvalidParameterChoiceItem = + components['schemas']['InvalidParameterChoiceItem'] +export type InvalidParameterDependentItem = + components['schemas']['InvalidParameterDependentItem'] +export type InvalidParameters = components['schemas']['InvalidParameters'] +export type BadRequestError = components['schemas']['BadRequestError'] +export type UnauthorizedError = components['schemas']['UnauthorizedError'] +export type ForbiddenError = components['schemas']['ForbiddenError'] +export type NotFoundError = components['schemas']['NotFoundError'] +export type GoneError = components['schemas']['GoneError'] +export type CursorMetaPage = components['schemas']['CursorMetaPage'] +export type CursorMeta = components['schemas']['CursorMeta'] +export type ConflictError = components['schemas']['ConflictError'] +export type ResponseBadRequest = components['responses']['BadRequest'] +export type ResponseUnauthorized = components['responses']['Unauthorized'] +export type ResponseForbidden = components['responses']['Forbidden'] +export type ResponseNotFound = components['responses']['NotFound'] +export type ResponseGone = components['responses']['Gone'] +export type ResponseConflict = components['responses']['Conflict'] +export type ParameterCursorPaginationQuery = + components['parameters']['CursorPaginationQuery'] +export type ParameterPagePaginationQuery = + components['parameters']['PagePaginationQuery'] +export type $defs = Record +export interface operations { + 'list-addons': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort add-ons returned in the response. Supported sort attributes are: + * + * - `id` + * - `key` + * - `name` + * - `created_at` (default) + * - `updated_at` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** @description Filter add-ons returned in the response. */ + filter?: components['schemas']['ListAddonsParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['AddonPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-addon': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateAddonRequest'] + } + } + responses: { + /** @description Addon created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Addon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-addon': { + parameters: { + query?: never + header?: never + path: { + addonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Addon response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Addon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'update-addon': { + parameters: { + query?: never + header?: never + path: { + addonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertAddonRequest'] + } + } + responses: { + /** @description Addon upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Addon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'delete-addon': { + parameters: { + query?: never + header?: never + path: { + addonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'archive-addon': { + parameters: { + query?: never + header?: never + path: { + addonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Addon updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Addon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'publish-addon': { + parameters: { + query?: never + header?: never + path: { + addonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Addon updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Addon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-apps': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['AppPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-app': { + parameters: { + query?: never + header?: never + path: { + appId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description App response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingApp'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-currencies': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort currencies returned in the response. Supported sort attributes are: + * + * - `code` (default) + * - `name` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** + * @description Filter currencies returned in the response. + * + * To filter currencies by type add the following query param: filter[type]=custom + */ + filter?: components['schemas']['ListCurrenciesParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['CurrencyPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-custom-currency': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateCurrencyCustomRequest'] + } + } + responses: { + /** @description CurrencyCustom created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCurrencyCustom'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'list-cost-bases': { + parameters: { + query?: { + /** + * @description Filter cost bases returned in the response. + * + * To filter cost bases by fiat currency code add the following query param: + * filter[fiat_code]=USD + */ + filter?: components['schemas']['ListCostBasesParamsFilter'] + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + } + header?: never + path: { + currencyId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['CostBasisPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'create-cost-basis': { + parameters: { + query?: never + header?: never + path: { + currencyId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateCostBasisRequest'] + } + } + responses: { + /** @description CostBasis created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCostBasis'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'list-customers': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort customers returned in the response. Supported sort attributes are: + * + * - `id` + * - `name` (default) + * - `created_at` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** + * @description Filter customers returned in the response. + * + * To filter customers by key add the following query param: filter[key]=my-db-id + */ + filter?: components['schemas']['ListCustomersParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['CustomerPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-customer': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateCustomerRequest'] + } + } + responses: { + /** @description Customer created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCustomer'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-customer': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Customer response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCustomer'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'upsert-customer': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertCustomerRequest'] + } + } + responses: { + /** @description Customer upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCustomer'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'delete-customer': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'get-customer-billing': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description CustomerBillingData response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCustomerData'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-customer-billing': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertCustomerBillingDataRequest'] + } + } + responses: { + /** @description CustomerBillingData upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCustomerData'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'update-customer-billing-app-data': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertAppCustomerDataRequest'] + } + } + responses: { + /** @description AppCustomerData upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingAppCustomerData'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'create-customer-stripe-checkout-session': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BillingCustomerStripeCreateCheckoutSessionRequest'] + } + } + responses: { + /** @description CreateStripeCheckoutSessionResult created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingAppStripeCreateCheckoutSessionResult'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'create-customer-stripe-portal-session': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BillingCustomerStripeCreateCustomerPortalSessionRequest'] + } + } + responses: { + /** @description CreateStripeCustomerPortalSessionResult created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingAppStripeCreateCustomerPortalSessionResult'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'list-customer-charges': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort charges returned in the response. + * + * Supported sort attributes are: + * + * - `id` + * - `created_at` + * - `service_period.from` + * - `billing_period.from` + */ + sort?: components['schemas']['SortQuery'] + /** + * @description Filter charges. + * + * To filter charges by status add the following query param: + * `filter[status][oeq]=created,active` + */ + filter?: components['schemas']['ListChargesParamsFilter'] + /** + * @description Expand full objects for referenced entities. + * + * Supported values are: + * + * - `real_time_usage`: Expand the charge's real-time usage. + */ + expand?: components['schemas']['BillingChargesExpand'][] + } + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ChargePagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'create-credit-adjustment': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateCreditAdjustmentRequest'] + } + } + responses: { + /** @description CreditAdjustment created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCreditAdjustment'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'get-customer-credit-balance': { + parameters: { + query?: { + /** + * @description Return the credit balance as of this timestamp. + * + * Defaults to the current time. + */ + timestamp?: components['schemas']['DateTime'] + filter?: components['schemas']['GetCreditBalanceParamsFilter'] + } + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description CreditBalances response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCreditBalances'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-credit-grants': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** @description Filter credit grants returned in the response. */ + filter?: components['schemas']['ListCreditGrantsParamsFilter'] + } + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['CreditGrantPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'create-credit-grant': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateCreditGrantRequest'] + } + } + responses: { + /** @description CreditGrant created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCreditGrant'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'get-credit-grant': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + creditGrantId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description CreditGrant response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCreditGrant'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-credit-grant-external-settlement': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + creditGrantId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpdateCreditGrantExternalSettlementRequest'] + } + } + responses: { + /** @description CreditGrant updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingCreditGrant'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-credit-transactions': { + parameters: { + query?: { + page?: components['parameters']['CursorPaginationQuery'] + /** @description Filter credit transactions returned in the response. */ + filter?: components['schemas']['ListCreditTransactionsParamsFilter'] + } + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Cursor paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['CreditTransactionPaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-customer-entitlement-access': { + parameters: { + query?: never + header?: never + path: { + customerId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description List the customer's active features and their access. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ListCustomerEntitlementAccessResponseData'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'get-organization-default-tax-codes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description OrganizationDefaultTaxCodes response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['OrganizationDefaultTaxCodes'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-organization-default-tax-codes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpdateOrganizationDefaultTaxCodesRequest'] + } + } + responses: { + /** @description OrganizationDefaultTaxCodes upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['OrganizationDefaultTaxCodes'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-metering-events': { + parameters: { + query?: { + page?: components['parameters']['CursorPaginationQuery'] + /** + * @description Filter events returned in the response. + * + * To filter events by subject add the following query param: + * filter[subject][eq]=customer-1 + */ + filter?: components['schemas']['ListEventsParamsFilter'] + /** + * @description Sort events returned in the response. Supported sort attributes are: + * + * - `time` (default) + * - `ingested_at` + * - `stored_at` + * + * When omitted, events are sorted by `time desc` (most recent first). When a sort + * field is provided without a suffix, it sorts descending. Append the `asc` suffix + * to sort ascending, or the `desc` suffix to sort descending. + */ + sort?: components['schemas']['SortQuery'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Cursor paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IngestedEventPaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'ingest-metering-events': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/cloudevents+json': components['schemas']['MeteringEvent'] + 'application/cloudevents-batch+json': components['schemas']['MeteringEvent'][] + 'application/json': + | components['schemas']['MeteringEvent'] + | components['schemas']['MeteringEvent'][] + } + } + responses: { + /** @description The events have been ingested and are being processed asynchronously. */ + 202: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'list-features': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort features returned in the response. Supported sort attributes are: + * + * - `key` + * - `name` + * - `created_at` (default) + * - `updated_at` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** + * @description Filter features returned in the response. + * + * To filter features by meter_id add the following query param: + * filter[meter_id][oeq]= + */ + filter?: components['schemas']['ListFeatureParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['FeaturePagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-feature': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateFeatureRequest'] + } + } + responses: { + /** @description Feature created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Feature'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-feature': { + parameters: { + query?: never + header?: never + path: { + featureId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Feature response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Feature'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'delete-feature': { + parameters: { + query?: never + header?: never + path: { + featureId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-feature': { + parameters: { + query?: never + header?: never + path: { + featureId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpdateFeatureRequest'] + } + } + responses: { + /** @description Feature updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Feature'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'query-feature-cost': { + parameters: { + query?: never + header?: never + path: { + featureId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: { + content: { + 'application/json': components['schemas']['MeterQueryRequest'] + } + } + responses: { + /** @description The request has succeeded. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['FeatureCostQueryResult'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'query-governance-access': { + parameters: { + query?: { + page?: components['parameters']['CursorPaginationQuery'] + } + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['GovernanceQueryRequest'] + } + } + responses: { + /** @description The request has succeeded. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['GovernanceQueryResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'list-llm-cost-overrides': { + parameters: { + query?: { + filter?: components['schemas']['ListLLMCostPricesParamsFilter'] + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PricePagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-llm-cost-override': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['LLMCostOverrideCreate'] + } + } + responses: { + /** @description Price created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LLMCostPrice'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'delete-llm-cost-override': { + parameters: { + query?: never + header?: never + path: { + priceId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-llm-cost-prices': { + parameters: { + query?: { + /** @description Filter prices. */ + filter?: components['schemas']['ListLLMCostPricesParamsFilter'] + /** + * @description Sort prices returned in the response. Supported sort attributes are: + * + * - `id` + * - `provider.id` + * - `model.id` (default) + * - `effective_from` + * - `effective_to` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PricePagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-llm-cost-price': { + parameters: { + query?: never + header?: never + path: { + priceId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description The request has succeeded. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LLMCostPrice'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-meters': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort meters returned in the response. Supported sort attributes are: + * + * - `key` + * - `name` + * - `aggregation` + * - `createdAt` (default) + * - `updatedAt` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** + * @description Filter meters returned in the response. + * + * To filter meters by key add the following query param: filter[key]=my-meter-key + */ + filter?: components['schemas']['ListMetersParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MeterPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-meter': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateMeterRequest'] + } + } + responses: { + /** @description Meter created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Meter'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-meter': { + parameters: { + query?: never + header?: never + path: { + meterId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Meter response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Meter'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-meter': { + parameters: { + query?: never + header?: never + path: { + meterId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpdateMeterRequest'] + } + } + responses: { + /** @description Meter updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Meter'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'delete-meter': { + parameters: { + query?: never + header?: never + path: { + meterId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'query-meter': { + parameters: { + query?: never + header?: never + path: { + meterId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MeterQueryRequest'] + } + } + responses: { + /** @description The request has succeeded. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MeterQueryResult'] + 'text/csv': string + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-plans': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort plans returned in the response. Supported sort attributes are: + * + * - `id` + * - `key` + * - `version` + * - `created_at` (default) + * - `updated_at` + */ + sort?: components['schemas']['SortQuery'] + /** @description Filter plans returned in the response. */ + filter?: components['schemas']['ListPlansParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PlanPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-plan': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreatePlanRequest'] + } + } + responses: { + /** @description Plan created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingPlan'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-plan': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Plan response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingPlan'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'update-plan': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertPlanRequest'] + } + } + responses: { + /** @description Plan upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingPlan'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'delete-plan': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-plan-addons': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + } + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PlanAddonPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'create-plan-addon': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreatePlanAddonRequest'] + } + } + responses: { + /** @description PlanAddon created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PlanAddon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'get-plan-addon': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + planAddonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description PlanAddon response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PlanAddon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-plan-addon': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + planAddonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertPlanAddonRequest'] + } + } + responses: { + /** @description PlanAddon upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PlanAddon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'delete-plan-addon': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + planAddonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'archive-plan': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Plan updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingPlan'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'publish-plan': { + parameters: { + query?: never + header?: never + path: { + planId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Plan updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingPlan'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-billing-profiles': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingProfilePagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-billing-profile': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateBillingProfileRequest'] + } + } + responses: { + /** @description BillingProfile created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingProfile'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-billing-profile': { + parameters: { + query?: never + header?: never + path: { + id: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description BillingProfile response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingProfile'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'update-billing-profile': { + parameters: { + query?: never + header?: never + path: { + id: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertBillingProfileRequest'] + } + } + responses: { + /** @description BillingProfile updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingProfile'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'delete-billing-profile': { + parameters: { + query?: never + header?: never + path: { + id: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-subscriptions': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** + * @description Sort subscriptions returned in the response. Supported sort attributes are: + * + * - `id` + * - `active_from` (default) + * - `active_to` + * + * The `asc` suffix is optional as the default sort order is ascending. The `desc` + * suffix is used to specify a descending order. + */ + sort?: components['schemas']['SortQuery'] + /** @description Filter subscriptions. */ + filter?: components['schemas']['ListSubscriptionsParamsFilter'] + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['SubscriptionPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'create-subscription': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BillingSubscriptionCreate'] + } + } + responses: { + /** @description Subscription created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingSubscription'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 409: components['responses']['Conflict'] + } + } + 'get-subscription': { + parameters: { + query?: never + header?: never + path: { + subscriptionId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Subscription response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingSubscription'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'list-subscription-addons': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + sort?: components['schemas']['SortQuery'] + } + header?: never + path: { + subscriptionId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['SubscriptionAddonPagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'get-subscription-addon': { + parameters: { + query?: never + header?: never + path: { + subscriptionId: components['schemas']['ULID'] + subscriptionAddonId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description SubscriptionAddon response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['SubscriptionAddon'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'cancel-subscription': { + parameters: { + query?: never + header?: never + path: { + subscriptionId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BillingSubscriptionCancel'] + } + } + responses: { + /** @description Subscription updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingSubscription'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 409: components['responses']['Conflict'] + } + } + 'change-subscription': { + parameters: { + query?: never + header?: never + path: { + subscriptionId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BillingSubscriptionChange'] + } + } + responses: { + /** @description The request has succeeded. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingSubscriptionChangeResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 409: components['responses']['Conflict'] + } + } + 'unschedule-cancelation': { + parameters: { + query?: never + header?: never + path: { + subscriptionId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Subscription updated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingSubscription'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 409: components['responses']['Conflict'] + } + } + 'list-tax-codes': { + parameters: { + query?: { + /** @description Determines which page of the collection to retrieve. */ + page?: components['parameters']['PagePaginationQuery'] + /** @description Include deleted tax codes in the response. */ + include_deleted?: boolean + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Page paginated response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TaxCodePagePaginatedResponse'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'create-tax-code': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateTaxCodeRequest'] + } + } + responses: { + /** @description TaxCode created response. */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingTaxCode'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + } + } + 'get-tax-code': { + parameters: { + query?: never + header?: never + path: { + taxCodeId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description TaxCode response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingTaxCode'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } + 'upsert-tax-code': { + parameters: { + query?: never + header?: never + path: { + taxCodeId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['UpsertTaxCodeRequest'] + } + } + responses: { + /** @description TaxCode upsert response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BillingTaxCode'] + } + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + 410: components['responses']['Gone'] + } + } + 'delete-tax-code': { + parameters: { + query?: never + header?: never + path: { + taxCodeId: components['schemas']['ULID'] + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Deleted response. */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + 400: components['responses']['BadRequest'] + 401: components['responses']['Unauthorized'] + 403: components['responses']['Forbidden'] + 404: components['responses']['NotFound'] + } + } +} diff --git a/api/client/javascript/src/v3/subscriptions.ts b/api/client/javascript/src/v3/subscriptions.ts new file mode 100644 index 0000000000..c5ba7e6169 --- /dev/null +++ b/api/client/javascript/src/v3/subscriptions.ts @@ -0,0 +1,161 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + BillingSubscriptionCancel, + BillingSubscriptionChange, + BillingSubscriptionCreate, + operations, + paths, +} from './schemas.js' + +/** + * Subscriptions (v3) + * + * Thin wrapper over the v3 subscriptions endpoints. Bodies use the v3 wire + * shape verbatim (snake_case); no field renaming (Option A). + */ +export class Subscriptions { + constructor(private client: Client) {} + + /** + * Create a subscription + */ + public async create( + subscription: BillingSubscriptionCreate, + options?: RequestOptions, + ) { + const resp = await this.client.POST('/openmeter/subscriptions', { + body: subscription, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List subscriptions + */ + public async list( + params?: operations['list-subscriptions']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/subscriptions', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a subscription by ID + */ + public async get(subscriptionId: string, options?: RequestOptions) { + const resp = await this.client.GET( + '/openmeter/subscriptions/{subscriptionId}', + { + params: { path: { subscriptionId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Cancel a subscription + */ + public async cancel( + subscriptionId: string, + body: BillingSubscriptionCancel, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/subscriptions/{subscriptionId}/cancel', + { + body, + params: { path: { subscriptionId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Change a subscription (cancel + create in one step) + */ + public async change( + subscriptionId: string, + body: BillingSubscriptionChange, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/subscriptions/{subscriptionId}/change', + { + body, + params: { path: { subscriptionId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Unschedule a previously scheduled cancelation + */ + public async unscheduleCancelation( + subscriptionId: string, + options?: RequestOptions, + ) { + const resp = await this.client.POST( + '/openmeter/subscriptions/{subscriptionId}/unschedule-cancelation', + { + params: { path: { subscriptionId } }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * List the add-ons of a subscription + */ + public async listAddons( + subscriptionId: string, + params?: operations['list-subscription-addons']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/subscriptions/{subscriptionId}/addons', + { + params: { path: { subscriptionId }, query: params }, + ...options, + }, + ) + + return transformResponse(resp) + } + + /** + * Get an add-on association for a subscription + */ + public async getAddon( + subscriptionId: string, + subscriptionAddonId: string, + options?: RequestOptions, + ) { + const resp = await this.client.GET( + '/openmeter/subscriptions/{subscriptionId}/addons/{subscriptionAddonId}', + { + params: { path: { subscriptionAddonId, subscriptionId } }, + ...options, + }, + ) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/tax-codes.ts b/api/client/javascript/src/v3/tax-codes.ts new file mode 100644 index 0000000000..8b69dc621d --- /dev/null +++ b/api/client/javascript/src/v3/tax-codes.ts @@ -0,0 +1,87 @@ +import type { Client } from 'openapi-fetch' +import type { RequestOptions } from '../client/common.js' +import { transformResponse } from '../client/utils.js' +import type { + CreateTaxCodeRequest, + operations, + paths, + UpsertTaxCodeRequest, +} from './schemas.js' + +/** + * Tax codes (v3) + * + * Thin wrapper over the v3 tax code endpoints. Bodies use the v3 wire shape + * verbatim (snake_case); no field renaming (Option A). + */ +export class TaxCodes { + constructor(private client: Client) {} + + /** + * Create a tax code + */ + public async create(body: CreateTaxCodeRequest, options?: RequestOptions) { + const resp = await this.client.POST('/openmeter/tax-codes', { + body, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Get a tax code by ID + */ + public async get(taxCodeId: string, options?: RequestOptions) { + const resp = await this.client.GET('/openmeter/tax-codes/{taxCodeId}', { + params: { path: { taxCodeId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * List tax codes + */ + public async list( + params?: operations['list-tax-codes']['parameters']['query'], + options?: RequestOptions, + ) { + const resp = await this.client.GET('/openmeter/tax-codes', { + params: { query: params }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Upsert (replace) a tax code + */ + public async upsert( + taxCodeId: string, + body: UpsertTaxCodeRequest, + options?: RequestOptions, + ) { + const resp = await this.client.PUT('/openmeter/tax-codes/{taxCodeId}', { + body, + params: { path: { taxCodeId } }, + ...options, + }) + + return transformResponse(resp) + } + + /** + * Delete a tax code + */ + public async delete(taxCodeId: string, options?: RequestOptions) { + const resp = await this.client.DELETE('/openmeter/tax-codes/{taxCodeId}', { + params: { path: { taxCodeId } }, + ...options, + }) + + return transformResponse(resp) + } +} diff --git a/api/client/javascript/src/v3/v3.spec.ts b/api/client/javascript/src/v3/v3.spec.ts new file mode 100644 index 0000000000..ccd1e3281f --- /dev/null +++ b/api/client/javascript/src/v3/v3.spec.ts @@ -0,0 +1,448 @@ +import fetchMock from '@fetch-mock/vitest' +import { beforeEach, describe, expect, it } from 'vitest' +import { isHTTPError, OpenMeter } from '../client/index.js' + +// Smoke test for the v3 compatibility shim. Mirrors the runtime-validation +// intent of the generated v3 SDK's client-runtime-test.mjs: it exercises base +// URL composition, request shaping (method/path/query/body), snake_case body +// passthrough (Option A — no field renaming), and error throwing. The transport +// is stubbed via fetch-mock; no network is touched. + +interface Context { + baseUrl: string + client: OpenMeter +} + +describe('v3 shim', () => { + beforeEach((ctx) => { + fetchMock.mockReset() + const baseUrl = 'http://openmeter-mock.local' + ctx.baseUrl = baseUrl + ctx.client = new OpenMeter({ + apiKey: 'test-key', + baseUrl, + fetch: fetchMock.fetchHandler, + }) + }) + + it('create plan: POST /api/v3/openmeter/plans with snake_case body', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/plans` + const created = { id: '01J0000000000000000000PLAN', key: 'starter' } + fetchMock.route( + route, + { body: created, status: 201 }, + { method: 'POST', name: task.name }, + ) + + const resp = await client.v3.plans.create({ + billing_cadence: 'P1M', + currency: 'USD', + key: 'starter', + name: 'Starter', + phases: [], + }) + + // Response body deserialized and returned. + expect(resp).toMatchObject({ id: created.id, key: 'starter' }) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + + // The base URL is composed as /api/v3 and the snake_case body is + // sent verbatim (no camelCase renaming). + const call = fetchMock.callHistory.calls()[0] + expect(call?.url).toBe(route) + const sent = JSON.parse(String(call?.options?.body)) + expect(sent.billing_cadence).toBe('P1M') + expect(sent.key).toBe('starter') + }) + + it('create addon: POST /api/v3/openmeter/addons with snake_case body', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/addons` + const created = { id: '01J0000000000000000000ADDON', key: 'extra' } + fetchMock.route( + route, + { body: created, status: 201 }, + { method: 'POST', name: task.name }, + ) + + const resp = await client.v3.addons.create({ + currency: 'USD', + instance_type: 'single', + key: 'extra', + name: 'Extra', + rate_cards: [], + }) + + expect(resp).toMatchObject({ id: created.id, key: 'extra' }) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + + const call = fetchMock.callHistory.calls()[0] + expect(call?.url).toBe(route) + const sent = JSON.parse(String(call?.options?.body)) + // snake_case body field passed through verbatim (Option A). + expect(sent.instance_type).toBe('single') + expect(sent.key).toBe('extra') + }) + + it('list addons: GET /openmeter/addons with pagination query', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/addons` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + // `begin:` matcher so the deepObject query string doesn't break the match. + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.addons.list({ + page: { number: 1, size: 20 }, + }) + + expect(resp).toEqual(page) + const calledUrl = decodeURIComponent( + String(fetchMock.callHistory.calls()[0]?.url), + ) + expect(calledUrl).toContain('page[size]=20') + }) + + it('list meters: deepObject page[...] pagination query', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/meters` + const page = { data: [], meta: { page: 2, page_size: 50, total_count: 0 } } + // `begin:` matcher so the deepObject query string doesn't break the match. + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.meters.list({ + page: { number: 2, size: 50 }, + }) + + expect(resp).toEqual(page) + const calledUrl = decodeURIComponent( + String(fetchMock.callHistory.calls()[0]?.url), + ) + expect(calledUrl).toContain('page[size]=50') + expect(calledUrl).toContain('page[number]=2') + }) + + it('error: 4xx throws HTTPError', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/plans/missing` + fetchMock.route( + route, + { + body: { status: 404, title: 'Not Found', type: 'about:blank' }, + headers: { 'Content-Type': 'application/problem+json' }, + status: 404, + }, + { method: 'GET', name: task.name }, + ) + + await expect(client.v3.plans.get('missing')).rejects.toSatisfy( + (err: unknown) => isHTTPError(err) && err.status === 404, + ) + }) + + it('update plan: PUT /openmeter/plans/{planId} with snake_case body', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/plans/01PLAN` + fetchMock.route( + route, + { body: { id: '01PLAN', key: 'starter' }, status: 200 }, + { method: 'PUT', name: task.name }, + ) + + const resp = await client.v3.plans.update('01PLAN', { + name: 'Starter', + phases: [], + pro_rating_enabled: true, + }) + + expect(resp).toMatchObject({ id: '01PLAN' }) + const sent = JSON.parse( + String(fetchMock.callHistory.calls()[0]?.options?.body), + ) + // snake_case body field passed through verbatim (Option A). + expect(sent.pro_rating_enabled).toBe(true) + }) + + it('update feature: PATCH /openmeter/features/{featureId}', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/features/01FEAT` + fetchMock.route( + route, + { body: { id: '01FEAT' }, status: 200 }, + { method: 'PATCH', name: task.name }, + ) + + const resp = await client.v3.features.update('01FEAT', {}) + + expect(resp).toMatchObject({ id: '01FEAT' }) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('delete meter: DELETE /openmeter/meters/{meterId} (204)', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/meters/01METER` + fetchMock.route( + route, + { status: 204 }, + { method: 'DELETE', name: task.name }, + ) + + await client.v3.meters.delete('01METER') + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('list billing profiles: GET /openmeter/profiles', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/profiles` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.billingProfiles.list({ + page: { number: 1, size: 20 }, + }) + + expect(resp).toEqual(page) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('list currencies: GET /openmeter/currencies', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/currencies` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.currencies.list() + + expect(resp).toEqual(page) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('create tax code: POST /openmeter/tax-codes with snake_case body', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/tax-codes` + const created = { id: '01J00000000000000000000TAX', key: 'standard' } + fetchMock.route( + route, + { body: created, status: 201 }, + { method: 'POST', name: task.name }, + ) + + const resp = await client.v3.taxCodes.create({ + app_mappings: [], + key: 'standard', + name: 'Standard', + }) + + expect(resp).toMatchObject({ id: created.id, key: 'standard' }) + const sent = JSON.parse( + String(fetchMock.callHistory.calls()[0]?.options?.body), + ) + // snake_case body field passed through verbatim (Option A). + expect(sent.app_mappings).toEqual([]) + expect(sent.key).toBe('standard') + }) + + it('list llm cost prices: GET /openmeter/llm-cost/prices', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/llm-cost/prices` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.llmCost.listPrices() + + expect(resp).toEqual(page) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('list apps: GET /openmeter/apps', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/apps` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.apps.list() + + expect(resp).toEqual(page) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('query governance access: POST /openmeter/governance/query with snake_case body', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/governance/query` + const result = { data: [] } + fetchMock.route( + `begin:${route}`, + { body: result, status: 200 }, + { method: 'POST', name: task.name }, + ) + + const resp = await client.v3.governance.queryAccess({ + customer: { keys: ['cust-1'] }, + include_credits: true, + }) + + expect(resp).toEqual(result) + const sent = JSON.parse( + String(fetchMock.callHistory.calls()[0]?.options?.body), + ) + // snake_case body field passed through verbatim (Option A). + expect(sent.include_credits).toBe(true) + expect(sent.customer.keys).toEqual(['cust-1']) + }) + + it('get organization default tax codes: GET /openmeter/defaults/tax-codes', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/defaults/tax-codes` + const data = { vat: 'standard' } + fetchMock.route( + route, + { body: data, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.defaults.getOrganizationTaxCodes() + + expect(resp).toEqual(data) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('list plan addons: GET /openmeter/plans/{planId}/addons', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/plans/01PLAN/addons` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.plans.listAddons('01PLAN', { + page: { number: 1, size: 20 }, + }) + + expect(resp).toEqual(page) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) + + it('create credit grant: POST /openmeter/customers/{customerId}/credits/grants with snake_case body', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/customers/01CUST/credits/grants` + const created = { id: '01J0000000000000000000GRANT' } + fetchMock.route( + route, + { body: created, status: 201 }, + { method: 'POST', name: task.name }, + ) + + const resp = await client.v3.customers.createCreditGrant('01CUST', { + amount: '100', + currency: 'USD', + funding_method: 'none', + name: 'Welcome credits', + }) + + expect(resp).toMatchObject({ id: created.id }) + const sent = JSON.parse( + String(fetchMock.callHistory.calls()[0]?.options?.body), + ) + // snake_case body field passed through verbatim (Option A). + expect(sent.funding_method).toBe('none') + expect(sent.amount).toBe('100') + }) + + it('list subscription addons: GET /openmeter/subscriptions/{subscriptionId}/addons', async ({ + baseUrl, + client, + task, + }) => { + const route = `${baseUrl}/api/v3/openmeter/subscriptions/01SUB/addons` + const page = { data: [], meta: { page: 1, page_size: 20, total_count: 0 } } + fetchMock.route( + `begin:${route}`, + { body: page, status: 200 }, + { method: 'GET', name: task.name }, + ) + + const resp = await client.v3.subscriptions.listAddons('01SUB', { + page: { number: 1, size: 20 }, + }) + + expect(resp).toEqual(page) + expect(fetchMock.callHistory.done(task.name)).toBeTruthy() + }) +}) diff --git a/api/client/javascript/src/v3/zod/index.ts b/api/client/javascript/src/v3/zod/index.ts new file mode 100644 index 0000000000..f6d283c8c1 --- /dev/null +++ b/api/client/javascript/src/v3/zod/index.ts @@ -0,0 +1,9766 @@ +/** + * Generated by orval v8.7.0 🍺 + * Do not edit manually. + * OpenMeter and Konnect Metering & Billing API + * OpenMeter is a cloud native usage metering and billing service. The API allows +you to ingest events, query meter usage, and manage resources. + * OpenAPI spec version: 0.0.1 + */ +import * as zod from 'zod' + +/** + * List all add-ons. + * @summary List add-ons + */ +export const listAddonsQueryFilterIdOneRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listAddonsQueryFilterIdTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listAddonsQueryFilterIdTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListAddonsQueryParams = zod.object({ + filter: zod + .object({ + currency: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + id: zod + .union([ + zod.coerce + .string() + .regex(listAddonsQueryFilterIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listAddonsQueryFilterIdTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listAddonsQueryFilterIdTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + status: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + }) + .optional() + .describe('Filter add-ons returned in the response.'), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort add-ons returned in the response. Supported sort attributes are:\n\n- `id`\n- `key`\n- `name`\n- `created_at` (default)\n- `updated_at`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * Create a new add-on. + * @summary Create add-on + */ +export const createAddonBodyNameMax = 256 + +export const createAddonBodyDescriptionMax = 1024 + +export const createAddonBodyLabelsMaxOne = 63 + +export const createAddonBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createAddonBodyKeyOneMax = 64 + +export const createAddonBodyKeyOneRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createAddonBodyCurrencyOneOneMin = 3 +export const createAddonBodyCurrencyOneOneMax = 3 + +export const createAddonBodyCurrencyOneOneRegExp = /^[A-Z]{3}$/ +export const createAddonBodyRateCardsItemNameMax = 256 + +export const createAddonBodyRateCardsItemDescriptionMax = 1024 + +export const createAddonBodyRateCardsItemLabelsMaxOne = 63 + +export const createAddonBodyRateCardsItemLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createAddonBodyRateCardsItemKeyMax = 64 + +export const createAddonBodyRateCardsItemKeyRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createAddonBodyRateCardsItemFeatureOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createAddonBodyRateCardsItemBillingCadenceOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const createAddonBodyRateCardsItemPriceOneTwoAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemPriceOneThreeAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const createAddonBodyRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const createAddonBodyRateCardsItemPaymentTermDefault = 'in_arrears' +export const createAddonBodyRateCardsItemCommitmentsOneMinimumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemCommitmentsOneMaximumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemDiscountsOnePercentageMin = 0 +export const createAddonBodyRateCardsItemDiscountsOnePercentageMax = 100 + +export const createAddonBodyRateCardsItemDiscountsOneUsageOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createAddonBodyRateCardsItemTaxConfigOneCodeIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateAddonBody = zod + .object({ + currency: zod.coerce + .string() + .min(createAddonBodyCurrencyOneOneMin) + .max(createAddonBodyCurrencyOneOneMax) + .regex(createAddonBodyCurrencyOneOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('Fiat or custom currency code.') + .describe('The currency code of the add-on.'), + description: zod.coerce + .string() + .max(createAddonBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + instance_type: zod + .enum(['single', 'multiple']) + .describe( + 'The instanceType of the add-on.\n\n- `single`: Can be added to a subscription only once.\n- `multiple`: Can be added to a subscription more than once.', + ) + .describe( + 'The InstanceType of the add-ons. Can be "single" or "multiple".', + ), + key: zod.coerce + .string() + .min(1) + .max(createAddonBodyKeyOneMax) + .regex(createAddonBodyKeyOneRegExp) + .describe('A key is a unique string that is used to identify a resource.') + .describe( + 'A key is a semi-unique string that is used to identify the add-on. It is used to\nreference the latest `active` version of the add-on and is unique with the\nversion number.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createAddonBodyLabelsMaxOne) + .regex(createAddonBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createAddonBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + rate_cards: zod + .array( + zod + .object({ + billing_cadence: zod + .stringFormat( + 'ISO8601', + createAddonBodyRateCardsItemBillingCadenceOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The billing cadence of the rate card. When null, the charge is one-time\n(non-recurring). Only valid for flat prices.', + ), + commitments: zod + .object({ + maximum_amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemCommitmentsOneMaximumAmountOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe( + 'The customer is limited to spend at most the amount.', + ), + minimum_amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemCommitmentsOneMinimumAmountOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe( + 'The customer is committed to spend at least the amount.', + ), + }) + .describe( + 'Spend commitments for a rate card. The customer is committed to spend at least\nthe minimum amount and at most the maximum amount.', + ) + .optional() + .describe( + 'Spend commitments for this rate card. Only applicable to usage-based prices\n(unit, graduated, volume).', + ), + description: zod.coerce + .string() + .max(createAddonBodyRateCardsItemDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + discounts: zod + .object({ + percentage: zod.coerce + .number() + .min(createAddonBodyRateCardsItemDiscountsOnePercentageMin) + .max(createAddonBodyRateCardsItemDiscountsOnePercentageMax) + .optional() + .describe( + 'Percentage discount applied to the price (0–100).', + ), + usage: zod.coerce + .string() + .regex(createAddonBodyRateCardsItemDiscountsOneUsageOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe( + 'Number of usage units granted free before billing starts. Only applies to\nusage-based lines (not flat fees). Usage is treated as zero until this amount is\nexhausted.', + ), + }) + .describe('Discount configuration for a rate card.') + .optional() + .describe('The discounts of the rate card.'), + feature: zod + .object({ + id: zod.coerce + .string() + .regex(createAddonBodyRateCardsItemFeatureOneIdRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('Feature reference.') + .optional() + .describe('The feature associated with the rate card.'), + key: zod.coerce + .string() + .min(1) + .max(createAddonBodyRateCardsItemKeyMax) + .regex(createAddonBodyRateCardsItemKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createAddonBodyRateCardsItemLabelsMaxOne) + .regex(createAddonBodyRateCardsItemLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createAddonBodyRateCardsItemNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + payment_term: zod + .enum(['in_advance', 'in_arrears']) + .describe('The payment term of a flat price.') + .default(createAddonBodyRateCardsItemPaymentTermDefault) + .describe( + 'The payment term of the rate card. In advance payment term can only be used for\nflat prices.', + ), + price: zod + .union([ + zod + .object({ + type: zod.enum(['free']).describe('The type of the price.'), + }) + .describe('Free price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneTwoAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod.enum(['flat']).describe('The type of the price.'), + }) + .describe('Flat price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneThreeAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod.enum(['unit']).describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the graduated price. At least one tier is required.', + ), + type: zod + .enum(['graduated']) + .describe('The type of the price.'), + }) + .describe( + "Graduated tiered price.\n\nEach tier's rate applies only to the usage within that tier. Pricing can change\nas cumulative usage crosses tier boundaries.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.", + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the volume price. At least one tier is required.', + ), + type: zod + .enum(['volume']) + .describe('The type of the price.'), + }) + .describe( + 'Volume tiered price.\n\nThe maximum quantity within a period determines the per-unit price for all units\nin that period.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.', + ), + ]) + .describe('Price.') + .describe('The price of the rate card.'), + tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .optional() + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ), + code: zod + .object({ + id: zod.coerce + .string() + .regex( + createAddonBodyRateCardsItemTaxConfigOneCodeIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.'), + }) + .describe('The tax config of the rate card.') + .optional() + .describe('The tax config of the rate card.'), + }) + .describe( + 'A rate card defines the pricing and entitlement of a feature or service.', + ), + ) + .describe('The rate cards of the add-on.'), + }) + .describe('Addon create request.') + +/** + * Update an add-on by id. + * @summary Update add-on + */ +export const updateAddonPathAddonIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateAddonParams = zod.object({ + addonId: zod.coerce.string().regex(updateAddonPathAddonIdRegExp), +}) + +export const updateAddonBodyNameMax = 256 + +export const updateAddonBodyDescriptionMax = 1024 + +export const updateAddonBodyLabelsMaxOne = 63 + +export const updateAddonBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updateAddonBodyRateCardsItemNameMax = 256 + +export const updateAddonBodyRateCardsItemDescriptionMax = 1024 + +export const updateAddonBodyRateCardsItemLabelsMaxOne = 63 + +export const updateAddonBodyRateCardsItemLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updateAddonBodyRateCardsItemKeyMax = 64 + +export const updateAddonBodyRateCardsItemKeyRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const updateAddonBodyRateCardsItemFeatureOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updateAddonBodyRateCardsItemBillingCadenceOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const updateAddonBodyRateCardsItemPriceOneTwoAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemPriceOneThreeAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const updateAddonBodyRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const updateAddonBodyRateCardsItemPaymentTermDefault = 'in_arrears' +export const updateAddonBodyRateCardsItemCommitmentsOneMinimumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemCommitmentsOneMaximumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemDiscountsOnePercentageMin = 0 +export const updateAddonBodyRateCardsItemDiscountsOnePercentageMax = 100 + +export const updateAddonBodyRateCardsItemDiscountsOneUsageOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateAddonBodyRateCardsItemTaxConfigOneCodeIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateAddonBody = zod + .object({ + description: zod.coerce + .string() + .max(updateAddonBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + instance_type: zod + .enum(['single', 'multiple']) + .describe( + 'The instanceType of the add-on.\n\n- `single`: Can be added to a subscription only once.\n- `multiple`: Can be added to a subscription more than once.', + ) + .describe( + 'The InstanceType of the add-ons. Can be "single" or "multiple".', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updateAddonBodyLabelsMaxOne) + .regex(updateAddonBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updateAddonBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + rate_cards: zod + .array( + zod + .object({ + billing_cadence: zod + .stringFormat( + 'ISO8601', + updateAddonBodyRateCardsItemBillingCadenceOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The billing cadence of the rate card. When null, the charge is one-time\n(non-recurring). Only valid for flat prices.', + ), + commitments: zod + .object({ + maximum_amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemCommitmentsOneMaximumAmountOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe( + 'The customer is limited to spend at most the amount.', + ), + minimum_amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemCommitmentsOneMinimumAmountOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe( + 'The customer is committed to spend at least the amount.', + ), + }) + .describe( + 'Spend commitments for a rate card. The customer is committed to spend at least\nthe minimum amount and at most the maximum amount.', + ) + .optional() + .describe( + 'Spend commitments for this rate card. Only applicable to usage-based prices\n(unit, graduated, volume).', + ), + description: zod.coerce + .string() + .max(updateAddonBodyRateCardsItemDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + discounts: zod + .object({ + percentage: zod.coerce + .number() + .min(updateAddonBodyRateCardsItemDiscountsOnePercentageMin) + .max(updateAddonBodyRateCardsItemDiscountsOnePercentageMax) + .optional() + .describe( + 'Percentage discount applied to the price (0–100).', + ), + usage: zod.coerce + .string() + .regex(updateAddonBodyRateCardsItemDiscountsOneUsageOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe( + 'Number of usage units granted free before billing starts. Only applies to\nusage-based lines (not flat fees). Usage is treated as zero until this amount is\nexhausted.', + ), + }) + .describe('Discount configuration for a rate card.') + .optional() + .describe('The discounts of the rate card.'), + feature: zod + .object({ + id: zod.coerce + .string() + .regex(updateAddonBodyRateCardsItemFeatureOneIdRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('Feature reference.') + .optional() + .describe('The feature associated with the rate card.'), + key: zod.coerce + .string() + .min(1) + .max(updateAddonBodyRateCardsItemKeyMax) + .regex(updateAddonBodyRateCardsItemKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updateAddonBodyRateCardsItemLabelsMaxOne) + .regex(updateAddonBodyRateCardsItemLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updateAddonBodyRateCardsItemNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + payment_term: zod + .enum(['in_advance', 'in_arrears']) + .describe('The payment term of a flat price.') + .default(updateAddonBodyRateCardsItemPaymentTermDefault) + .describe( + 'The payment term of the rate card. In advance payment term can only be used for\nflat prices.', + ), + price: zod + .union([ + zod + .object({ + type: zod.enum(['free']).describe('The type of the price.'), + }) + .describe('Free price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneTwoAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod.enum(['flat']).describe('The type of the price.'), + }) + .describe('Flat price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneThreeAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod.enum(['unit']).describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the graduated price. At least one tier is required.', + ), + type: zod + .enum(['graduated']) + .describe('The type of the price.'), + }) + .describe( + "Graduated tiered price.\n\nEach tier's rate applies only to the usage within that tier. Pricing can change\nas cumulative usage crosses tier boundaries.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.", + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the volume price. At least one tier is required.', + ), + type: zod + .enum(['volume']) + .describe('The type of the price.'), + }) + .describe( + 'Volume tiered price.\n\nThe maximum quantity within a period determines the per-unit price for all units\nin that period.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.', + ), + ]) + .describe('Price.') + .describe('The price of the rate card.'), + tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .optional() + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ), + code: zod + .object({ + id: zod.coerce + .string() + .regex( + updateAddonBodyRateCardsItemTaxConfigOneCodeIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.'), + }) + .describe('The tax config of the rate card.') + .optional() + .describe('The tax config of the rate card.'), + }) + .describe( + 'A rate card defines the pricing and entitlement of a feature or service.', + ), + ) + .describe('The rate cards of the add-on.'), + }) + .describe('Addon upsert request.') + +/** + * Get add-on by id. + * @summary Get add-on + */ +export const getAddonPathAddonIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetAddonParams = zod.object({ + addonId: zod.coerce.string().regex(getAddonPathAddonIdRegExp), +}) + +/** + * Soft delete add-on by id. + * @summary Soft delete add-on + */ +export const deleteAddonPathAddonIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteAddonParams = zod.object({ + addonId: zod.coerce.string().regex(deleteAddonPathAddonIdRegExp), +}) + +/** + * Archive an add-on version. + * @summary Archive add-on version + */ +export const archiveAddonPathAddonIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ArchiveAddonParams = zod.object({ + addonId: zod.coerce.string().regex(archiveAddonPathAddonIdRegExp), +}) + +/** + * Publish an add-on version. + * @summary Publish add-on version + */ +export const publishAddonPathAddonIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const PublishAddonParams = zod.object({ + addonId: zod.coerce.string().regex(publishAddonPathAddonIdRegExp), +}) + +/** + * List installed apps. + * @summary List apps + */ +export const ListAppsQueryParams = zod.object({ + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * Get an installed app. + * @summary Get app + */ +export const getAppPathAppIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetAppParams = zod.object({ + appId: zod.coerce.string().regex(getAppPathAppIdRegExp), +}) + +/** + * List currencies supported by the billing system. + * @summary List currencies + */ +export const ListCurrenciesQueryParams = zod.object({ + filter: zod + .object({ + code: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + type: zod + .enum(['fiat', 'custom']) + .optional() + .describe( + 'Currency type for custom currencies. It should be a unique code but not\nconflicting with any existing standard currency codes.', + ), + }) + .optional() + .describe( + 'Filter currencies returned in the response.\n\nTo filter currencies by type add the following query param: filter[type]=custom', + ), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort currencies returned in the response. Supported sort attributes are:\n\n- `code` (default)\n- `name`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * Create a custom currency. This operation allows defining your own custom +currency for billing purposes. + * @summary Create custom currency + */ +export const createCustomCurrencyBodyNameMax = 256 + +export const createCustomCurrencyBodyDescriptionMax = 256 + +export const createCustomCurrencyBodyCodeMin = 3 +export const createCustomCurrencyBodyCodeMax = 24 + +export const CreateCustomCurrencyBody = zod + .object({ + code: zod.coerce + .string() + .min(createCustomCurrencyBodyCodeMin) + .max(createCustomCurrencyBodyCodeMax) + .describe( + 'Custom currency code. It should be a unique code but not conflicting with any\nexisting fiat currency codes.', + ), + description: zod.coerce + .string() + .min(1) + .max(createCustomCurrencyBodyDescriptionMax) + .optional() + .describe('Description of the currency.'), + name: zod.coerce + .string() + .min(1) + .max(createCustomCurrencyBodyNameMax) + .describe( + 'The name of the currency. It should be a human-readable string that represents\nthe name of the currency, such as "US Dollar" or "Euro".', + ), + symbol: zod.coerce + .string() + .min(1) + .optional() + .describe( + 'The symbol of the currency. It should be a string that represents the symbol of\nthe currency, such as "$" for US Dollar or "€" for Euro.', + ), + }) + .describe('CurrencyCustom create request.') + +/** + * List cost bases for a currency. For custom currencies, there can be multiple +cost bases with different `effective_from` dates. + * @summary List cost bases + */ +export const listCostBasesPathCurrencyIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListCostBasesParams = zod.object({ + currencyId: zod.coerce.string().regex(listCostBasesPathCurrencyIdRegExp), +}) + +export const listCostBasesQueryFilterFiatCodeOneMin = 3 +export const listCostBasesQueryFilterFiatCodeOneMax = 3 + +export const listCostBasesQueryFilterFiatCodeOneRegExp = /^[A-Z]{3}$/ + +export const ListCostBasesQueryParams = zod.object({ + filter: zod + .object({ + fiat_code: zod.coerce + .string() + .min(listCostBasesQueryFilterFiatCodeOneMin) + .max(listCostBasesQueryFilterFiatCodeOneMax) + .regex(listCostBasesQueryFilterFiatCodeOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .optional() + .describe('Filter cost bases by fiat currency code.'), + }) + .optional() + .describe( + 'Filter cost bases returned in the response.\n\nTo filter cost bases by fiat currency code add the following query param:\nfilter[fiat_code]=USD', + ), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * Create a cost basis for a currency. + * @summary Create cost basis + */ +export const createCostBasisPathCurrencyIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateCostBasisParams = zod.object({ + currencyId: zod.coerce.string().regex(createCostBasisPathCurrencyIdRegExp), +}) + +export const createCostBasisBodyFiatCodeOneMin = 3 +export const createCostBasisBodyFiatCodeOneMax = 3 + +export const createCostBasisBodyFiatCodeOneRegExp = /^[A-Z]{3}$/ +export const createCostBasisBodyRateOneRegExp = /^-?[0-9]+(\.[0-9]+)?$/ + +export const CreateCostBasisBody = zod + .object({ + effective_from: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'An ISO-8601 timestamp representation of the date from which the cost basis is\neffective. If not provided, it will be effective immediately and will be set to\n`now` by the system.', + ), + fiat_code: zod.coerce + .string() + .min(createCostBasisBodyFiatCodeOneMin) + .max(createCostBasisBodyFiatCodeOneMax) + .regex(createCostBasisBodyFiatCodeOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('The fiat currency code for the cost basis.'), + rate: zod.coerce + .string() + .regex(createCostBasisBodyRateOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('The cost rate for the currency.'), + }) + .describe('CostBasis create request.') + +/** + * @summary Create customer + */ +export const createCustomerBodyNameMax = 256 + +export const createCustomerBodyDescriptionMax = 1024 + +export const createCustomerBodyLabelsMaxOne = 63 + +export const createCustomerBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createCustomerBodyKeyMax = 256 + +export const createCustomerBodyUsageAttributionOneSubjectKeysMin = 0 + +export const createCustomerBodyCurrencyOneMin = 3 +export const createCustomerBodyCurrencyOneMax = 3 + +export const createCustomerBodyCurrencyOneRegExp = /^[A-Z]{3}$/ +export const createCustomerBodyBillingAddressOneCountryOneMin = 2 +export const createCustomerBodyBillingAddressOneCountryOneMax = 2 + +export const createCustomerBodyBillingAddressOneCountryOneRegExp = /^[A-Z]{2}$/ + +export const CreateCustomerBody = zod + .object({ + billing_address: zod + .object({ + city: zod.coerce.string().optional().describe('City.'), + country: zod.coerce + .string() + .min(createCustomerBodyBillingAddressOneCountryOneMin) + .max(createCustomerBodyBillingAddressOneCountryOneMax) + .regex(createCustomerBodyBillingAddressOneCountryOneRegExp) + .describe( + '[ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 country\ncode. Custom two-letter country codes are also supported for convenience.', + ) + .optional() + .describe( + 'Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html)\nalpha-2 format.', + ), + line1: zod.coerce + .string() + .optional() + .describe('First line of the address.'), + line2: zod.coerce + .string() + .optional() + .describe('Second line of the address.'), + phone_number: zod.coerce.string().optional().describe('Phone number.'), + postal_code: zod.coerce.string().optional().describe('Postal code.'), + state: zod.coerce.string().optional().describe('State or province.'), + }) + .describe('Address') + .optional() + .describe( + 'The billing address of the customer. Used for tax and invoicing.', + ), + currency: zod.coerce + .string() + .min(createCustomerBodyCurrencyOneMin) + .max(createCustomerBodyCurrencyOneMax) + .regex(createCustomerBodyCurrencyOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .optional() + .describe( + 'Currency of the customer. Used for billing, tax and invoicing.', + ), + description: zod.coerce + .string() + .max(createCustomerBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + key: zod.coerce + .string() + .min(1) + .max(createCustomerBodyKeyMax) + .describe( + 'ExternalResourceKey is a unique string that is used to identify a resource in an\nexternal system.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createCustomerBodyLabelsMaxOne) + .regex(createCustomerBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createCustomerBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + primary_email: zod.coerce + .string() + .optional() + .describe('The primary email address of the customer.'), + usage_attribution: zod + .object({ + subject_keys: zod + .array(zod.coerce.string().min(1).describe('Subject key.')) + .min(createCustomerBodyUsageAttributionOneSubjectKeysMin) + .describe( + 'The subjects that are attributed to the customer. Can be empty when no usage\nevent subjects are associated with the customer.', + ), + }) + .describe( + 'Mapping to attribute metered usage to the customer. One customer can have zero\nor more subjects, but one subject can only belong to one customer.', + ) + .optional() + .describe( + 'Mapping to attribute metered usage to the customer by the event subject.', + ), + }) + .describe('Customer create request.') + +/** + * @summary List customers + */ +export const listCustomersQueryFilterBillingProfileIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listCustomersQueryFilterBillingProfileIdTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listCustomersQueryFilterBillingProfileIdTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListCustomersQueryParams = zod.object({ + filter: zod + .object({ + billing_profile_id: zod + .union([ + zod.coerce + .string() + .regex(listCustomersQueryFilterBillingProfileIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listCustomersQueryFilterBillingProfileIdTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listCustomersQueryFilterBillingProfileIdTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + plan_key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + primary_email: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + usage_attribution_subject_key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + }) + .optional() + .describe( + 'Filter customers returned in the response.\n\nTo filter customers by key add the following query param: filter[key]=my-db-id', + ), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort customers returned in the response. Supported sort attributes are:\n\n- `id`\n- `name` (default)\n- `created_at`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * @summary Get customer + */ +export const getCustomerPathCustomerIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetCustomerParams = zod.object({ + customerId: zod.coerce.string().regex(getCustomerPathCustomerIdRegExp), +}) + +/** + * @summary Upsert customer + */ +export const upsertCustomerPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpsertCustomerParams = zod.object({ + customerId: zod.coerce.string().regex(upsertCustomerPathCustomerIdRegExp), +}) + +export const upsertCustomerBodyNameMax = 256 + +export const upsertCustomerBodyDescriptionMax = 1024 + +export const upsertCustomerBodyLabelsMaxOne = 63 + +export const upsertCustomerBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ + +export const upsertCustomerBodyUsageAttributionOneSubjectKeysMin = 0 + +export const upsertCustomerBodyCurrencyOneMin = 3 +export const upsertCustomerBodyCurrencyOneMax = 3 + +export const upsertCustomerBodyCurrencyOneRegExp = /^[A-Z]{3}$/ +export const upsertCustomerBodyBillingAddressOneCountryOneMin = 2 +export const upsertCustomerBodyBillingAddressOneCountryOneMax = 2 + +export const upsertCustomerBodyBillingAddressOneCountryOneRegExp = /^[A-Z]{2}$/ + +export const UpsertCustomerBody = zod + .object({ + billing_address: zod + .object({ + city: zod.coerce.string().optional().describe('City.'), + country: zod.coerce + .string() + .min(upsertCustomerBodyBillingAddressOneCountryOneMin) + .max(upsertCustomerBodyBillingAddressOneCountryOneMax) + .regex(upsertCustomerBodyBillingAddressOneCountryOneRegExp) + .describe( + '[ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 country\ncode. Custom two-letter country codes are also supported for convenience.', + ) + .optional() + .describe( + 'Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html)\nalpha-2 format.', + ), + line1: zod.coerce + .string() + .optional() + .describe('First line of the address.'), + line2: zod.coerce + .string() + .optional() + .describe('Second line of the address.'), + phone_number: zod.coerce.string().optional().describe('Phone number.'), + postal_code: zod.coerce.string().optional().describe('Postal code.'), + state: zod.coerce.string().optional().describe('State or province.'), + }) + .describe('Address') + .optional() + .describe( + 'The billing address of the customer. Used for tax and invoicing.', + ), + currency: zod.coerce + .string() + .min(upsertCustomerBodyCurrencyOneMin) + .max(upsertCustomerBodyCurrencyOneMax) + .regex(upsertCustomerBodyCurrencyOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .optional() + .describe( + 'Currency of the customer. Used for billing, tax and invoicing.', + ), + description: zod.coerce + .string() + .max(upsertCustomerBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(upsertCustomerBodyLabelsMaxOne) + .regex(upsertCustomerBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(upsertCustomerBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + primary_email: zod.coerce + .string() + .optional() + .describe('The primary email address of the customer.'), + usage_attribution: zod + .object({ + subject_keys: zod + .array(zod.coerce.string().min(1).describe('Subject key.')) + .min(upsertCustomerBodyUsageAttributionOneSubjectKeysMin) + .describe( + 'The subjects that are attributed to the customer. Can be empty when no usage\nevent subjects are associated with the customer.', + ), + }) + .describe( + 'Mapping to attribute metered usage to the customer. One customer can have zero\nor more subjects, but one subject can only belong to one customer.', + ) + .optional() + .describe( + 'Mapping to attribute metered usage to the customer by the event subject.', + ), + }) + .describe('Customer upsert request.') + +/** + * @summary Delete customer + */ +export const deleteCustomerPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteCustomerParams = zod.object({ + customerId: zod.coerce.string().regex(deleteCustomerPathCustomerIdRegExp), +}) + +/** + * @summary Get customer billing data + */ +export const getCustomerBillingPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetCustomerBillingParams = zod.object({ + customerId: zod.coerce.string().regex(getCustomerBillingPathCustomerIdRegExp), +}) + +/** + * @summary Update customer billing data + */ +export const updateCustomerBillingPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateCustomerBillingParams = zod.object({ + customerId: zod.coerce + .string() + .regex(updateCustomerBillingPathCustomerIdRegExp), +}) + +export const updateCustomerBillingBodyBillingProfileOneIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updateCustomerBillingBodyAppDataOneStripeOneLabelsOneMaxOne = 63 + +export const updateCustomerBillingBodyAppDataOneStripeOneLabelsOneRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updateCustomerBillingBodyAppDataOneExternalInvoicingOneLabelsOneMaxOne = 63 + +export const updateCustomerBillingBodyAppDataOneExternalInvoicingOneLabelsOneRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ + +export const UpdateCustomerBillingBody = zod + .object({ + app_data: zod + .object({ + external_invoicing: zod + .object({ + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max( + updateCustomerBillingBodyAppDataOneExternalInvoicingOneLabelsOneMaxOne, + ) + .regex( + updateCustomerBillingBodyAppDataOneExternalInvoicingOneLabelsOneRegExpOne, + ), + ) + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ) + .optional() + .describe( + 'Labels for this external invoicing integration on the customer.', + ), + }) + .describe('External invoicing customer data.') + .optional() + .describe( + 'Used if the customer has a linked external invoicing app.', + ), + stripe: zod + .object({ + customer_id: zod.coerce + .string() + .optional() + .describe('The Stripe customer ID used.'), + default_payment_method_id: zod.coerce + .string() + .optional() + .describe('The Stripe default payment method ID.'), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max( + updateCustomerBillingBodyAppDataOneStripeOneLabelsOneMaxOne, + ) + .regex( + updateCustomerBillingBodyAppDataOneStripeOneLabelsOneRegExpOne, + ), + ) + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ) + .optional() + .describe('Labels for this Stripe integration on the customer.'), + }) + .describe('Stripe customer data.') + .optional() + .describe('Used if the customer has a linked Stripe app.'), + }) + .describe('App customer data.') + .optional() + .describe('App customer data.'), + billing_profile: zod + .object({ + id: zod.coerce + .string() + .regex(updateCustomerBillingBodyBillingProfileOneIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .describe('The ID of the billing profile.'), + }) + .describe('Billing profile reference.') + .optional() + .describe( + 'The billing profile for the customer.\n\nIf not provided, the default billing profile will be used.', + ), + }) + .describe('CustomerBillingData upsert request.') + +/** + * @summary Update customer billing app data + */ +export const updateCustomerBillingAppDataPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateCustomerBillingAppDataParams = zod.object({ + customerId: zod.coerce + .string() + .regex(updateCustomerBillingAppDataPathCustomerIdRegExp), +}) + +export const updateCustomerBillingAppDataBodyStripeOneLabelsOneMaxOne = 63 + +export const updateCustomerBillingAppDataBodyStripeOneLabelsOneRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updateCustomerBillingAppDataBodyExternalInvoicingOneLabelsOneMaxOne = 63 + +export const updateCustomerBillingAppDataBodyExternalInvoicingOneLabelsOneRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ + +export const UpdateCustomerBillingAppDataBody = zod + .object({ + external_invoicing: zod + .object({ + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max( + updateCustomerBillingAppDataBodyExternalInvoicingOneLabelsOneMaxOne, + ) + .regex( + updateCustomerBillingAppDataBodyExternalInvoicingOneLabelsOneRegExpOne, + ), + ) + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ) + .optional() + .describe( + 'Labels for this external invoicing integration on the customer.', + ), + }) + .describe('External invoicing customer data.') + .optional() + .describe('Used if the customer has a linked external invoicing app.'), + stripe: zod + .object({ + customer_id: zod.coerce + .string() + .optional() + .describe('The Stripe customer ID used.'), + default_payment_method_id: zod.coerce + .string() + .optional() + .describe('The Stripe default payment method ID.'), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updateCustomerBillingAppDataBodyStripeOneLabelsOneMaxOne) + .regex( + updateCustomerBillingAppDataBodyStripeOneLabelsOneRegExpOne, + ), + ) + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ) + .optional() + .describe('Labels for this Stripe integration on the customer.'), + }) + .describe('Stripe customer data.') + .optional() + .describe('Used if the customer has a linked Stripe app.'), + }) + .describe('AppCustomerData upsert request.') + +/** + * Create a [Stripe Checkout Session](https://docs.stripe.com/payments/checkout) +for the customer. + +Creates a Checkout Session for collecting payment method information from +customers. The session operates in "setup" mode, which collects payment details +without charging the customer immediately. The collected payment method can be +used for future subscription billing. + +For hosted checkout sessions, redirect customers to the returned URL. For +embedded sessions, use the client_secret to initialize Stripe.js in your +application. + * @summary Create Stripe Checkout Session + */ +export const createCustomerStripeCheckoutSessionPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateCustomerStripeCheckoutSessionParams = zod.object({ + customerId: zod.coerce + .string() + .regex(createCustomerStripeCheckoutSessionPathCustomerIdRegExp), +}) + +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneBillingAddressCollectionDefault = + 'auto' +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomerUpdateOneAddressDefault = + 'never' +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomerUpdateOneNameDefault = + 'never' +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomerUpdateOneShippingDefault = + 'never' +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCurrencyOneMin = 3 +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCurrencyOneMax = 3 + +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCurrencyOneRegExp = + /^[A-Z]{3}$/ +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneAfterSubmitMessageMax = 1200 + +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneShippingAddressMessageMax = 1200 + +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneSubmitMessageMax = 1200 + +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneTermsOfServiceAcceptanceMessageMax = 1200 + +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneUiModeDefault = + 'hosted' +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneTaxIdCollectionOneEnabledDefault = false +export const createCustomerStripeCheckoutSessionBodyStripeOptionsOneTaxIdCollectionOneRequiredDefault = + 'never' + +export const CreateCustomerStripeCheckoutSessionBody = zod + .object({ + stripe_options: zod + .object({ + billing_address_collection: zod + .enum(['auto', 'required']) + .describe( + "Controls whether Checkout collects the customer's billing address.", + ) + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneBillingAddressCollectionDefault, + ) + .describe( + "Whether to collect the customer's billing address.\n\nDefaults to auto, which only collects the address when necessary for tax\ncalculation.", + ), + cancel_url: zod.coerce + .string() + .optional() + .describe( + 'URL to redirect customers who cancel the checkout session.\n\nNot allowed when ui_mode is "embedded".', + ), + client_reference_id: zod.coerce + .string() + .optional() + .describe( + 'Unique reference string for reconciling sessions with internal systems.\n\nCan be a customer ID, cart ID, or any other identifier.', + ), + consent_collection: zod + .object({ + payment_method_reuse_agreement: zod + .object({ + position: zod + .enum(['auto', 'hidden']) + .describe( + 'Position of payment method reuse agreement in the UI.', + ) + .optional() + .describe( + 'Position and visibility of the payment method reuse agreement.', + ), + }) + .describe('Payment method reuse agreement configuration.') + .optional() + .describe( + 'Controls the visibility of payment method reuse agreement.', + ), + promotions: zod + .enum(['auto', 'none']) + .describe('Promotional communication consent collection setting.') + .optional() + .describe( + 'Enables collection of promotional communication consent.\n\nOnly available to US merchants. When set to "auto", Checkout determines whether\nto show the option based on the customer\'s locale.', + ), + terms_of_service: zod + .enum(['none', 'required']) + .describe('Terms of service acceptance requirement.') + .optional() + .describe( + 'Requires customers to accept terms of service before payment.\n\nRequires a valid terms of service URL in your Stripe Dashboard settings.', + ), + }) + .describe('Checkout Session consent collection configuration.') + .optional() + .describe( + 'Configuration for collecting customer consent during checkout.', + ), + currency: zod.coerce + .string() + .min( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCurrencyOneMin, + ) + .max( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCurrencyOneMax, + ) + .regex( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCurrencyOneRegExp, + ) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .optional() + .describe( + 'Three-letter ISO 4217 currency code in uppercase.\n\nRequired for payment mode sessions. Optional for setup mode sessions.', + ), + custom_text: zod + .object({ + after_submit: zod + .object({ + message: zod.coerce + .string() + .max( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneAfterSubmitMessageMax, + ) + .optional() + .describe('The custom message text (max 1200 characters).'), + }) + .optional() + .describe( + 'Text displayed after the payment confirmation button.', + ), + shipping_address: zod + .object({ + message: zod.coerce + .string() + .max( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneShippingAddressMessageMax, + ) + .optional() + .describe('The custom message text (max 1200 characters).'), + }) + .optional() + .describe( + 'Text displayed alongside shipping address collection.', + ), + submit: zod + .object({ + message: zod.coerce + .string() + .max( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneSubmitMessageMax, + ) + .optional() + .describe('The custom message text (max 1200 characters).'), + }) + .optional() + .describe( + 'Text displayed alongside the payment confirmation button.', + ), + terms_of_service_acceptance: zod + .object({ + message: zod.coerce + .string() + .max( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomTextOneTermsOfServiceAcceptanceMessageMax, + ) + .optional() + .describe('The custom message text (max 1200 characters).'), + }) + .optional() + .describe( + 'Text replacing the default terms of service agreement text.', + ), + }) + .describe( + 'Custom text displayed at various stages of the checkout flow.', + ) + .optional() + .describe( + 'Custom text to display during checkout at various stages.', + ), + customer_update: zod + .object({ + address: zod + .enum(['auto', 'never']) + .describe( + 'Behavior for updating customer fields from checkout session.', + ) + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomerUpdateOneAddressDefault, + ) + .describe( + 'Whether to save the billing address to customer.address.\n\nDefaults to "never".', + ), + name: zod + .enum(['auto', 'never']) + .describe( + 'Behavior for updating customer fields from checkout session.', + ) + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomerUpdateOneNameDefault, + ) + .describe( + 'Whether to save the customer name to customer.name.\n\nDefaults to "never".', + ), + shipping: zod + .enum(['auto', 'never']) + .describe( + 'Behavior for updating customer fields from checkout session.', + ) + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneCustomerUpdateOneShippingDefault, + ) + .describe( + 'Whether to save shipping information to customer.shipping.\n\nDefaults to "never".', + ), + }) + .describe( + 'Controls which customer fields can be updated by the checkout session.', + ) + .optional() + .describe( + 'Controls which customer fields can be updated by the checkout session.', + ), + expires_at: zod.coerce + .number() + .optional() + .describe( + 'Unix timestamp when the checkout session expires.\n\nCan be 30 minutes to 24 hours from creation. Defaults to 24 hours.', + ), + locale: zod.coerce + .string() + .optional() + .describe( + 'IETF language tag for the checkout UI locale.\n\nIf blank or "auto", uses the browser\'s locale. Example: "en", "fr", "de".', + ), + metadata: zod + .record(zod.string(), zod.coerce.string()) + .optional() + .describe( + 'Set of key-value pairs to attach to the checkout session.\n\nUseful for storing additional structured information.', + ), + payment_method_types: zod + .array(zod.coerce.string()) + .optional() + .describe( + 'List of payment method types to enable (e.g., "card", "us_bank_account").\n\nIf not specified, Stripe enables all relevant payment methods.', + ), + redirect_on_completion: zod + .enum(['always', 'if_required', 'never']) + .describe('Redirect behavior for embedded checkout sessions.') + .optional() + .describe( + 'Redirect behavior for embedded checkout sessions.\n\nControls when to redirect users after completion. See:\nhttps://docs.stripe.com/payments/checkout/custom-success-page?payment-ui=embedded-form', + ), + return_url: zod.coerce + .string() + .optional() + .describe( + 'Return URL for embedded checkout sessions after payment authentication.\n\nRequired if ui_mode is "embedded" and redirect-based payment methods are\nenabled.', + ), + success_url: zod.coerce + .string() + .optional() + .describe( + 'Success URL to redirect customers after completing payment or setup.\n\nNot allowed when ui_mode is "embedded". See:\nhttps://docs.stripe.com/payments/checkout/custom-success-page', + ), + tax_id_collection: zod + .object({ + enabled: zod.coerce + .boolean() + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneTaxIdCollectionOneEnabledDefault, + ) + .describe( + 'Enable tax ID collection during checkout.\n\nDefaults to false.', + ), + required: zod + .enum(['if_supported', 'never']) + .describe('Tax ID collection requirement level.') + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneTaxIdCollectionOneRequiredDefault, + ) + .describe( + 'Whether tax ID collection is required.\n\nDefaults to "never".', + ), + }) + .describe('Tax ID collection configuration for checkout sessions.') + .optional() + .describe('Configuration for collecting tax IDs during checkout.'), + ui_mode: zod + .enum(['embedded', 'hosted']) + .describe('Checkout Session UI mode.') + .default( + createCustomerStripeCheckoutSessionBodyStripeOptionsOneUiModeDefault, + ) + .describe( + 'The UI mode for the checkout session.\n\n"hosted" displays a Stripe-hosted page. "embedded" integrates directly into your\napp. Defaults to "hosted".', + ), + }) + .describe( + "Configuration options for creating a Stripe Checkout Session.\n\nBased on Stripe's\n[Checkout Session API parameters](https://docs.stripe.com/api/checkout/sessions/create).", + ) + .describe( + "Options for configuring the Stripe Checkout Session.\n\nThese options are passed directly to Stripe's\n[checkout session creation API](https://docs.stripe.com/api/checkout/sessions/create).", + ), + }) + .describe( + 'Request to create a Stripe Checkout Session for the customer.\n\nCheckout Sessions are used to collect payment method information from customers\nin a secure, Stripe-hosted interface. This integration uses setup mode to\ncollect payment methods that can be charged later for subscription billing.', + ) + +/** + * Create Stripe Customer Portal Session. + +Useful to redirect the customer to the Stripe Customer Portal to manage their +payment methods, change their billing address and access their invoice history. +Only returns URL if the customer billing profile is linked to a stripe app and +customer. + * @summary Create Stripe customer portal session + */ +export const createCustomerStripePortalSessionPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateCustomerStripePortalSessionParams = zod.object({ + customerId: zod.coerce + .string() + .regex(createCustomerStripePortalSessionPathCustomerIdRegExp), +}) + +export const CreateCustomerStripePortalSessionBody = zod + .object({ + stripe_options: zod + .object({ + configuration_id: zod.coerce + .string() + .optional() + .describe( + 'The ID of an existing\n[Stripe configuration](https://docs.stripe.com/api/customer_portal/configurations)\nto use for this session, describing its functionality and features. If not\nspecified, the session uses the default configuration.', + ), + locale: zod.coerce + .string() + .optional() + .describe( + "The IETF\n[language tag](https://docs.stripe.com/api/customer_portal/sessions/create#create_portal_session-locale)\nof the locale customer portal is displayed in. If blank or `auto`, the\ncustomer's preferred_locales or browser's locale is used.", + ), + return_url: zod.coerce + .string() + .optional() + .describe( + 'The\n[URL to redirect](https://docs.stripe.com/api/customer_portal/sessions/create#create_portal_session-return_url)\nthe customer to after they have completed their requested actions.', + ), + }) + .describe('Request to create a Stripe Customer Portal Session.') + .describe('Options for configuring the Stripe Customer Portal Session.'), + }) + .describe( + 'Request to create a Stripe Customer Portal Session for the customer.\n\nUseful to redirect the customer to the Stripe Customer Portal to manage their\npayment methods, change their billing address and access their invoice history.\nOnly returns URL if the customer billing profile is linked to a stripe app and\ncustomer.', + ) + +/** + * List customer charges. + +Returns the customer's charges that are represented as either flat fee or +usage-based charges. + * @summary List customer charges + */ +export const listCustomerChargesPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListCustomerChargesParams = zod.object({ + customerId: zod.coerce + .string() + .regex(listCustomerChargesPathCustomerIdRegExp), +}) + +export const ListCustomerChargesQueryParams = zod.object({ + expand: zod + .array( + zod + .enum(['real_time_usage']) + .describe( + "Expands for customer charges.\n\nValues:\n\n- `real_time_usage`: The charge's real-time usage.", + ), + ) + .optional() + .describe( + "Expand full objects for referenced entities.\n\nSupported values are:\n\n- `real_time_usage`: Expand the charge's real-time usage.", + ), + filter: zod + .object({ + status: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ) + .optional() + .describe( + 'Filter charges by status.\n\nSupported statuses are:\n\n- `created`\n- `active`\n- `final`\n- `deleted`\n\nIf omitted, all statuses are returned except for `deleted`.', + ), + }) + .optional() + .describe( + 'Filter charges.\n\nTo filter charges by status add the following query param:\n`filter[status][oeq]=created,active`', + ), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort charges returned in the response.\n\nSupported sort attributes are:\n\n- `id`\n- `created_at`\n- `service_period.from`\n- `billing_period.from`', + ), +}) + +/** + * A credit adjustment can be used to make manual adjustments to a customer's +credit balance. + +Supported use-cases: + +- Usage correction + * @summary Create a credit adjustment + */ +export const createCreditAdjustmentPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateCreditAdjustmentParams = zod.object({ + customerId: zod.coerce + .string() + .regex(createCreditAdjustmentPathCustomerIdRegExp), +}) + +export const createCreditAdjustmentBodyNameMax = 256 + +export const createCreditAdjustmentBodyDescriptionMax = 1024 + +export const createCreditAdjustmentBodyLabelsMaxOne = 63 + +export const createCreditAdjustmentBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createCreditAdjustmentBodyCurrencyOneOneMin = 3 +export const createCreditAdjustmentBodyCurrencyOneOneMax = 3 + +export const createCreditAdjustmentBodyCurrencyOneOneRegExp = /^[A-Z]{3}$/ +export const createCreditAdjustmentBodyAmountOneRegExp = /^-?[0-9]+(\.[0-9]+)?$/ + +export const CreateCreditAdjustmentBody = zod + .object({ + amount: zod.coerce + .string() + .regex(createCreditAdjustmentBodyAmountOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('Granted credit amount.'), + currency: zod.coerce + .string() + .min(createCreditAdjustmentBodyCurrencyOneOneMin) + .max(createCreditAdjustmentBodyCurrencyOneOneMax) + .regex(createCreditAdjustmentBodyCurrencyOneOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('Fiat or custom currency code.') + .describe('The currency of the granted credits.'), + description: zod.coerce + .string() + .max(createCreditAdjustmentBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createCreditAdjustmentBodyLabelsMaxOne) + .regex(createCreditAdjustmentBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createCreditAdjustmentBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + }) + .describe('CreditAdjustment create request.') + +/** + * Get a credit balance. + * @summary Get a customer's credit balance + */ +export const getCustomerCreditBalancePathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetCustomerCreditBalanceParams = zod.object({ + customerId: zod.coerce + .string() + .regex(getCustomerCreditBalancePathCustomerIdRegExp), +}) + +export const GetCustomerCreditBalanceQueryParams = zod.object({ + filter: zod + .object({ + currency: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter credit balance by currency.'), + }) + .optional(), + timestamp: zod.coerce + .date() + .optional() + .describe( + 'Return the credit balance as of this timestamp.\n\nDefaults to the current time.', + ), +}) + +/** + * Create a new credit grant. A credit grant represents an allocation of prepaid +credits to a customer. + * @summary Create a new credit grant + */ +export const createCreditGrantPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateCreditGrantParams = zod.object({ + customerId: zod.coerce.string().regex(createCreditGrantPathCustomerIdRegExp), +}) + +export const createCreditGrantBodyNameMax = 256 + +export const createCreditGrantBodyDescriptionMax = 1024 + +export const createCreditGrantBodyLabelsMaxOne = 63 + +export const createCreditGrantBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createCreditGrantBodyCurrencyOneOneMin = 3 +export const createCreditGrantBodyCurrencyOneOneMax = 3 + +export const createCreditGrantBodyCurrencyOneOneRegExp = /^[A-Z]{3}$/ +export const createCreditGrantBodyAmountOneRegExp = /^-?[0-9]+(\.[0-9]+)?$/ +export const createCreditGrantBodyPurchaseOneCurrencyOneMin = 3 +export const createCreditGrantBodyPurchaseOneCurrencyOneMax = 3 + +export const createCreditGrantBodyPurchaseOneCurrencyOneRegExp = /^[A-Z]{3}$/ +export const createCreditGrantBodyPurchaseOnePerUnitCostBasisOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createCreditGrantBodyPurchaseOnePerUnitCostBasisDefault = '1.0' +export const createCreditGrantBodyPurchaseOneAvailabilityPolicyDefault = + 'on_creation' +export const createCreditGrantBodyTaxConfigOneTaxCodeOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createCreditGrantBodyFiltersFeaturesItemMax = 64 + +export const createCreditGrantBodyFiltersFeaturesItemRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createCreditGrantBodyPriorityDefault = 10 +export const createCreditGrantBodyPriorityMax = 1000 + +export const createCreditGrantBodyExpiresAfterOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ + +export const CreateCreditGrantBody = zod + .object({ + amount: zod.coerce + .string() + .regex(createCreditGrantBodyAmountOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('Granted credit amount.'), + currency: zod.coerce + .string() + .min(createCreditGrantBodyCurrencyOneOneMin) + .max(createCreditGrantBodyCurrencyOneOneMax) + .regex(createCreditGrantBodyCurrencyOneOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('Fiat or custom currency code.') + .describe('The currency of the granted credits.'), + description: zod.coerce + .string() + .max(createCreditGrantBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + expires_after: zod + .stringFormat('ISO8601', createCreditGrantBodyExpiresAfterOneRegExp) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The duration after which the credit grant expires.\n\nDefaults to never expiring.', + ), + filters: zod + .object({ + features: zod + .array( + zod.coerce + .string() + .min(1) + .max(createCreditGrantBodyFiltersFeaturesItemMax) + .regex(createCreditGrantBodyFiltersFeaturesItemRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + ) + .optional() + .describe( + 'Limit the credit grant to specific features. If no features are specified, the\ncredit grant can be used for any feature.', + ), + }) + .optional() + .describe('Filters for the credit grant.'), + funding_method: zod + .enum(['none', 'invoice', 'external']) + .describe( + 'The funding method describes how the grant is funded.\n\n- `none`: No funding workflow applies, for example promotional grants\n- `invoice`: The grant is funded by an in-system invoice flow\n- `external`: The grant is funded outside the system (e.g., wire transfer,\nexternal invoice, or manual reconciliation)', + ) + .describe('Funding method of the grant.'), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createCreditGrantBodyLabelsMaxOne) + .regex(createCreditGrantBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createCreditGrantBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + priority: zod.coerce + .number() + .min(1) + .max(createCreditGrantBodyPriorityMax) + .default(createCreditGrantBodyPriorityDefault) + .describe( + 'Draw-down priority of the grant. Lower values have higher priority.', + ), + purchase: zod + .object({ + availability_policy: zod + .enum(['on_creation']) + .describe( + 'When credits become available for consumption.\n\n- `on_creation`: Credits are available as soon as the grant is created.\n- `on_authorization`: Credits are available once the payment is authorized.\n- `on_settlement`: Credits are available once the payment is settled.', + ) + .default(createCreditGrantBodyPurchaseOneAvailabilityPolicyDefault) + .describe( + 'Controls when credits become available for consumption.\n\nDefaults to `on_creation`.', + ), + currency: zod.coerce + .string() + .min(createCreditGrantBodyPurchaseOneCurrencyOneMin) + .max(createCreditGrantBodyPurchaseOneCurrencyOneMax) + .regex(createCreditGrantBodyPurchaseOneCurrencyOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('Currency of the purchase amount.'), + per_unit_cost_basis: zod.coerce + .string() + .regex(createCreditGrantBodyPurchaseOnePerUnitCostBasisOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .default(createCreditGrantBodyPurchaseOnePerUnitCostBasisDefault) + .describe( + 'Cost basis per credit unit used to calculate the purchase amount.\n\nIf `per_unit_cost_basis` is 0.50 and credit amount is $100.00, the total charge\nis $50.00. The value must be greater than 0. If the cost basis is 0, use\n`funding_method=none` instead.\n\nDefaults to 1.0.', + ), + }) + .describe('Purchase and payment terms of the grant.') + .optional() + .describe( + 'Present when a funding workflow applies (funding_method is not `none`).', + ), + tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ) + .optional() + .describe('Tax behavior applied to the invoice line item.'), + tax_code: zod + .object({ + id: zod.coerce + .string() + .regex(createCreditGrantBodyTaxConfigOneTaxCodeOneIdRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.') + .optional() + .describe('Tax code applied to the invoice line item.'), + }) + .describe( + 'Tax configuration for a credit grant.\n\nTax configuration should be provided to ensure correct revenue recognition,\nincluding for externally funded grants.', + ) + .optional() + .describe( + "Tax configuration for the grant.\n\nFor `invoice` and `external` funding methods, tax configuration should be\nprovided to ensure correct revenue recognition. When not provided, the default\ncredit grant tax code is applied, if that's not set the global default taxcode\nis used.", + ), + }) + .describe('CreditGrant create request.') + +/** + * List credit grants. + * @summary List credit grants + */ +export const listCreditGrantsPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListCreditGrantsParams = zod.object({ + customerId: zod.coerce.string().regex(listCreditGrantsPathCustomerIdRegExp), +}) + +export const listCreditGrantsQueryFilterCurrencyOneMin = 3 +export const listCreditGrantsQueryFilterCurrencyOneMax = 3 + +export const listCreditGrantsQueryFilterCurrencyOneRegExp = /^[A-Z]{3}$/ + +export const ListCreditGrantsQueryParams = zod.object({ + filter: zod + .object({ + currency: zod.coerce + .string() + .min(listCreditGrantsQueryFilterCurrencyOneMin) + .max(listCreditGrantsQueryFilterCurrencyOneMax) + .regex(listCreditGrantsQueryFilterCurrencyOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .optional() + .describe('Filter credit grants by currency.'), + status: zod + .enum(['pending', 'active', 'expired', 'voided']) + .describe( + 'Credit grant lifecycle status.\n\n- `pending`: The credit block has been created but is not yet valid.\n(`effective_at` is in the future or availability_policy is not met)\n- `active`: The credit block is currently valid and eligible for consumption.\n(`effective_at` is in the past, `expires_at` is in the future and\navailability_policy is met)\n- `expired`: The credit block expired with remaining unused balance,\n`expires_at` time has passed.\n- `voided`: The credit block was voided. Remaining balance is forfeited.', + ) + .optional() + .describe('Filter credit grants by status.'), + }) + .optional() + .describe('Filter credit grants returned in the response.'), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * Get a credit grant. + * @summary Get a credit grant + */ +export const getCreditGrantPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const getCreditGrantPathCreditGrantIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetCreditGrantParams = zod.object({ + creditGrantId: zod.coerce + .string() + .regex(getCreditGrantPathCreditGrantIdRegExp), + customerId: zod.coerce.string().regex(getCreditGrantPathCustomerIdRegExp), +}) + +/** + * Update the payment settlement status of an externally funded credit grant. + +Use this endpoint to synchronize the payment state of an external payment with +the system so that revenue recognition and credit availability work as expected. + * @summary Update credit grant external settlement status + */ +export const updateCreditGrantExternalSettlementPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updateCreditGrantExternalSettlementPathCreditGrantIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateCreditGrantExternalSettlementParams = zod.object({ + creditGrantId: zod.coerce + .string() + .regex(updateCreditGrantExternalSettlementPathCreditGrantIdRegExp), + customerId: zod.coerce + .string() + .regex(updateCreditGrantExternalSettlementPathCustomerIdRegExp), +}) + +export const UpdateCreditGrantExternalSettlementBody = zod + .object({ + status: zod + .enum(['pending', 'authorized', 'settled']) + .describe( + 'Credit purchase payment settlement status.\n\n- `pending`: Payment has been initiated and is not yet authorized.\n- `authorized`: Payment has been authorized.\n- `settled`: Payment has been settled.', + ) + .describe('The new payment settlement status.'), + }) + .describe( + 'Request body for updating the external payment settlement status of a credit\ngrant.', + ) + +/** + * List credit transactions for a customer. + +Returns an immutable, chronological record of credit movements: funded credits +and consumed credits. Transactions are returned in reverse chronological order +by default. + * @summary List credit transactions + */ +export const listCreditTransactionsPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListCreditTransactionsParams = zod.object({ + customerId: zod.coerce + .string() + .regex(listCreditTransactionsPathCustomerIdRegExp), +}) + +export const listCreditTransactionsQueryFilterCurrencyOneOneMin = 3 +export const listCreditTransactionsQueryFilterCurrencyOneOneMax = 3 + +export const listCreditTransactionsQueryFilterCurrencyOneOneRegExp = + /^[A-Z]{3}$/ + +export const ListCreditTransactionsQueryParams = zod.object({ + filter: zod + .object({ + currency: zod.coerce + .string() + .min(listCreditTransactionsQueryFilterCurrencyOneOneMin) + .max(listCreditTransactionsQueryFilterCurrencyOneOneMax) + .regex(listCreditTransactionsQueryFilterCurrencyOneOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('Fiat or custom currency code.') + .optional() + .describe('Filter credit transactions by currency.'), + type: zod + .enum(['funded', 'consumed', 'expired']) + .describe( + 'The type of the credit transaction.\n\n- `funded`: Credit granted and available for consumption.\n- `consumed`: Credit consumed by usage or fees.\n- `expired`: Credit removed because it expired before being used.', + ) + .optional() + .describe('Filter credit transactions by type.'), + }) + .optional() + .describe('Filter credit transactions returned in the response.'), + page: zod + .object({ + after: zod.coerce + .string() + .optional() + .describe( + 'Request the next page of data, starting with the item after this parameter.', + ), + before: zod.coerce + .string() + .optional() + .describe( + 'Request the previous page of data, starting with the item before this parameter.', + ), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional(), +}) + +/** + * @summary List customer entitlement access + */ +export const listCustomerEntitlementAccessPathCustomerIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListCustomerEntitlementAccessParams = zod.object({ + customerId: zod.coerce + .string() + .regex(listCustomerEntitlementAccessPathCustomerIdRegExp), +}) + +/** + * @summary Update organization default tax codes + */ +export const updateOrganizationDefaultTaxCodesBodyInvoicingTaxCodeOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updateOrganizationDefaultTaxCodesBodyCreditGrantTaxCodeOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateOrganizationDefaultTaxCodesBody = zod + .object({ + credit_grant_tax_code: zod + .object({ + id: zod.coerce + .string() + .regex( + updateOrganizationDefaultTaxCodesBodyCreditGrantTaxCodeOneIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.') + .optional() + .describe('Default tax code for credit grants.'), + invoicing_tax_code: zod + .object({ + id: zod.coerce + .string() + .regex( + updateOrganizationDefaultTaxCodesBodyInvoicingTaxCodeOneIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.') + .optional() + .describe('Default tax code for invoicing.'), + }) + .describe('OrganizationDefaultTaxCodes update request.') + +/** + * List ingested events. + * @summary List metering events + */ +export const listMeteringEventsQueryFilterCustomerIdOneOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listMeteringEventsQueryFilterCustomerIdOneTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listMeteringEventsQueryFilterCustomerIdOneTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListMeteringEventsQueryParams = zod.object({ + filter: zod + .object({ + customer_id: zod + .union([ + zod.coerce + .string() + .regex(listMeteringEventsQueryFilterCustomerIdOneOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listMeteringEventsQueryFilterCustomerIdOneTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listMeteringEventsQueryFilterCustomerIdOneTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by the associated customer ID.'), + id: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by ID.'), + ingested_at: zod + .union([ + zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ), + zod.object({ + eq: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value strictly equals given RFC-3339 formatted timestamp in UTC.', + ), + gt: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is greater than the given RFC-3339 formatted timestamp in UTC.', + ), + gte: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is greater than or equal to the given RFC-3339 formatted timestamp in UTC.', + ), + lt: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is less than the given RFC-3339 formatted timestamp in UTC.', + ), + lte: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is less than or equal to the given RFC-3339 formatted timestamp in UTC.', + ), + }), + ]) + .describe( + 'Filters on the given datetime (RFC-3339) field value. All properties are\noptional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by the time the event was ingested.'), + source: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by source.'), + stored_at: zod + .union([ + zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ), + zod.object({ + eq: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value strictly equals given RFC-3339 formatted timestamp in UTC.', + ), + gt: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is greater than the given RFC-3339 formatted timestamp in UTC.', + ), + gte: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is greater than or equal to the given RFC-3339 formatted timestamp in UTC.', + ), + lt: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is less than the given RFC-3339 formatted timestamp in UTC.', + ), + lte: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is less than or equal to the given RFC-3339 formatted timestamp in UTC.', + ), + }), + ]) + .describe( + 'Filters on the given datetime (RFC-3339) field value. All properties are\noptional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by the time the event was stored.'), + subject: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by subject.'), + time: zod + .union([ + zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ), + zod.object({ + eq: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value strictly equals given RFC-3339 formatted timestamp in UTC.', + ), + gt: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is greater than the given RFC-3339 formatted timestamp in UTC.', + ), + gte: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is greater than or equal to the given RFC-3339 formatted timestamp in UTC.', + ), + lt: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is less than the given RFC-3339 formatted timestamp in UTC.', + ), + lte: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'Value is less than or equal to the given RFC-3339 formatted timestamp in UTC.', + ), + }), + ]) + .describe( + 'Filters on the given datetime (RFC-3339) field value. All properties are\noptional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by event time.'), + type: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter events by type.'), + }) + .optional() + .describe( + 'Filter events returned in the response.\n\nTo filter events by subject add the following query param:\nfilter[subject][eq]=customer-1', + ), + page: zod + .object({ + after: zod.coerce + .string() + .optional() + .describe( + 'Request the next page of data, starting with the item after this parameter.', + ), + before: zod.coerce + .string() + .optional() + .describe( + 'Request the previous page of data, starting with the item before this parameter.', + ), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional(), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort events returned in the response. Supported sort attributes are:\n\n- `time` (default)\n- `ingested_at`\n- `stored_at`\n\nWhen omitted, events are sorted by `time desc` (most recent first). When a sort\nfield is provided without a suffix, it sorts descending. Append the `asc` suffix\nto sort ascending, or the `desc` suffix to sort descending.', + ), +}) + +/** + * Ingests an event or batch of events following the CloudEvents specification. + * @summary Ingest metering events + */ + +export const ingestMeteringEventsBodyOneSpecversionDefault = '1.0' + +export const ingestMeteringEventsBodyTwoItemSpecversionDefault = '1.0' + +export const IngestMeteringEventsBody = zod.union([ + zod + .object({ + data: zod + .record(zod.string(), zod.unknown()) + .nullish() + .describe( + 'The event payload. Optional, if present it must be a JSON object.', + ), + datacontenttype: zod + .enum(['application/json']) + .nullish() + .describe( + 'Content type of the CloudEvents data value. Only the value "application/json" is\nallowed over HTTP.', + ), + dataschema: zod + .url() + .min(1) + .nullish() + .describe('Identifies the schema that data adheres to.'), + id: zod.coerce.string().min(1).describe('Identifies the event.'), + source: zod.coerce + .string() + .min(1) + .describe('Identifies the context in which an event happened.'), + specversion: zod.coerce + .string() + .min(1) + .default(ingestMeteringEventsBodyOneSpecversionDefault) + .describe( + 'The version of the CloudEvents specification which the event uses.', + ), + subject: zod.coerce + .string() + .min(1) + .describe( + 'Describes the subject of the event in the context of the event producer\n(identified by source).', + ), + time: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .nullish() + .describe( + 'Timestamp of when the occurrence happened. Must adhere to RFC 3339.', + ), + type: zod.coerce + .string() + .min(1) + .describe( + 'Contains a value describing the type of event related to the originating\noccurrence.', + ), + }) + .describe('Metering event following the CloudEvents specification.'), + zod.array( + zod + .object({ + data: zod + .record(zod.string(), zod.unknown()) + .nullish() + .describe( + 'The event payload. Optional, if present it must be a JSON object.', + ), + datacontenttype: zod + .enum(['application/json']) + .nullish() + .describe( + 'Content type of the CloudEvents data value. Only the value "application/json" is\nallowed over HTTP.', + ), + dataschema: zod + .url() + .min(1) + .nullish() + .describe('Identifies the schema that data adheres to.'), + id: zod.coerce.string().min(1).describe('Identifies the event.'), + source: zod.coerce + .string() + .min(1) + .describe('Identifies the context in which an event happened.'), + specversion: zod.coerce + .string() + .min(1) + .default(ingestMeteringEventsBodyTwoItemSpecversionDefault) + .describe( + 'The version of the CloudEvents specification which the event uses.', + ), + subject: zod.coerce + .string() + .min(1) + .describe( + 'Describes the subject of the event in the context of the event producer\n(identified by source).', + ), + time: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .nullish() + .describe( + 'Timestamp of when the occurrence happened. Must adhere to RFC 3339.', + ), + type: zod.coerce + .string() + .min(1) + .describe( + 'Contains a value describing the type of event related to the originating\noccurrence.', + ), + }) + .describe('Metering event following the CloudEvents specification.'), + ), +]) + +/** + * List all features. + * @summary List features + */ +export const listFeaturesQueryFilterMeterIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listFeaturesQueryFilterMeterIdTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listFeaturesQueryFilterMeterIdTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListFeaturesQueryParams = zod.object({ + filter: zod + .object({ + key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + meter_id: zod + .union([ + zod.coerce + .string() + .regex(listFeaturesQueryFilterMeterIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listFeaturesQueryFilterMeterIdTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listFeaturesQueryFilterMeterIdTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + }) + .optional() + .describe( + 'Filter features returned in the response.\n\nTo filter features by meter_id add the following query param:\nfilter[meter_id][oeq]=', + ), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort features returned in the response. Supported sort attributes are:\n\n- `key`\n- `name`\n- `created_at` (default)\n- `updated_at`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * Create a feature. + * @summary Create feature + */ +export const createFeatureBodyNameMax = 256 + +export const createFeatureBodyDescriptionMax = 1024 + +export const createFeatureBodyLabelsMaxOne = 63 + +export const createFeatureBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createFeatureBodyKeyMax = 64 + +export const createFeatureBodyKeyRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createFeatureBodyMeterOneIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createFeatureBodyMeterOneFiltersInMax = 100 + +export const createFeatureBodyMeterOneFiltersNinMax = 100 + +export const createFeatureBodyMeterOneFiltersAndItemInMax = 100 + +export const createFeatureBodyMeterOneFiltersAndItemNinMax = 100 + +export const createFeatureBodyMeterOneFiltersAndItemAndMax = 10 + +export const createFeatureBodyMeterOneFiltersAndItemOrMax = 10 + +export const createFeatureBodyMeterOneFiltersAndMax = 10 + +export const createFeatureBodyMeterOneFiltersOrItemInMax = 100 + +export const createFeatureBodyMeterOneFiltersOrItemNinMax = 100 + +export const createFeatureBodyMeterOneFiltersOrItemAndMax = 10 + +export const createFeatureBodyMeterOneFiltersOrItemOrMax = 10 + +export const createFeatureBodyMeterOneFiltersOrMax = 10 + +export const createFeatureBodyUnitCostOneOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createFeatureBodyUnitCostOneTwoPricingOneInputPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createFeatureBodyUnitCostOneTwoPricingOneOutputPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createFeatureBodyUnitCostOneTwoPricingOneCacheReadPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createFeatureBodyUnitCostOneTwoPricingOneReasoningPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createFeatureBodyUnitCostOneTwoPricingOneCacheWritePerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const CreateFeatureBody = zod + .object({ + description: zod.coerce + .string() + .max(createFeatureBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + key: zod.coerce + .string() + .min(1) + .max(createFeatureBodyKeyMax) + .regex(createFeatureBodyKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createFeatureBodyLabelsMaxOne) + .regex(createFeatureBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + meter: zod + .object({ + filters: zod + .record( + zod.string(), + zod + .object({ + and: zod + .array( + zod + .object({ + and: zod + .array(zod.unknown()) + .min(1) + .max(createFeatureBodyMeterOneFiltersAndItemAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe( + 'The attribute contains the provided value.', + ), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(createFeatureBodyMeterOneFiltersAndItemInMax) + .optional() + .describe( + 'The attribute is one of the provided values.', + ), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not equal the provided value.', + ), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(createFeatureBodyMeterOneFiltersAndItemNinMax) + .optional() + .describe( + 'The attribute is not one of the provided values.', + ), + or: zod + .array(zod.unknown()) + .min(1) + .max(createFeatureBodyMeterOneFiltersAndItemOrMax) + .optional() + .describe( + 'Combines the provided filters with a logical OR.', + ), + }) + .describe( + 'A query filter for a string attribute. Operators are mutually exclusive, only\none operator is allowed at a time.', + ), + ) + .min(1) + .max(createFeatureBodyMeterOneFiltersAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe('The attribute contains the provided value.'), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + exists: zod.coerce + .boolean() + .optional() + .describe('The attribute exists.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(createFeatureBodyMeterOneFiltersInMax) + .optional() + .describe('The attribute is one of the provided values.'), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe('The attribute does not equal the provided value.'), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(createFeatureBodyMeterOneFiltersNinMax) + .optional() + .describe('The attribute is not one of the provided values.'), + or: zod + .array( + zod + .object({ + and: zod + .array(zod.unknown()) + .min(1) + .max(createFeatureBodyMeterOneFiltersOrItemAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe( + 'The attribute contains the provided value.', + ), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(createFeatureBodyMeterOneFiltersOrItemInMax) + .optional() + .describe( + 'The attribute is one of the provided values.', + ), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not equal the provided value.', + ), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(createFeatureBodyMeterOneFiltersOrItemNinMax) + .optional() + .describe( + 'The attribute is not one of the provided values.', + ), + or: zod + .array(zod.unknown()) + .min(1) + .max(createFeatureBodyMeterOneFiltersOrItemOrMax) + .optional() + .describe( + 'Combines the provided filters with a logical OR.', + ), + }) + .describe( + 'A query filter for a string attribute. Operators are mutually exclusive, only\none operator is allowed at a time.', + ), + ) + .min(1) + .max(createFeatureBodyMeterOneFiltersOrMax) + .optional() + .describe('Combines the provided filters with a logical OR.'), + }) + .describe( + 'A query filter for an item in a string map attribute. Operators are mutually\nexclusive, only one operator is allowed at a time.', + ), + ) + .optional() + .describe('Filters to apply to the dimensions of the meter.'), + id: zod.coerce + .string() + .regex(createFeatureBodyMeterOneIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .describe('The ID of the meter to associate with this feature.'), + }) + .describe('Reference to a meter associated with a feature.') + .optional() + .describe( + 'The meter that the feature is associated with and based on which usage is\ncalculated. If not specified, the feature is static.', + ), + name: zod.coerce + .string() + .min(1) + .max(createFeatureBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + unit_cost: zod + .union([ + zod + .object({ + amount: zod.coerce + .string() + .regex(createFeatureBodyUnitCostOneOneAmountOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('Fixed per-unit cost amount in USD.'), + type: zod + .enum(['manual']) + .describe('The type discriminator for manual unit cost.'), + }) + .describe('A fixed per-unit cost amount.'), + zod + .object({ + model: zod.coerce + .string() + .optional() + .describe( + 'Static model ID value (e.g., "gpt-4", "claude-3-5-sonnet"). Use this when the\nfeature tracks a single model. Mutually exclusive with `model_property`.', + ), + model_property: zod.coerce + .string() + .optional() + .describe( + 'Meter group-by property that holds the model ID. Use this when the meter has a\ngroup-by dimension for model. Mutually exclusive with `model`.', + ), + pricing: zod + .object({ + cache_read_per_token: zod.coerce + .string() + .regex( + createFeatureBodyUnitCostOneTwoPricingOneCacheReadPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cost per cache read token in USD.'), + cache_write_per_token: zod.coerce + .string() + .regex( + createFeatureBodyUnitCostOneTwoPricingOneCacheWritePerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cost per cache write token in USD.'), + input_per_token: zod.coerce + .string() + .regex( + createFeatureBodyUnitCostOneTwoPricingOneInputPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .describe('Cost per input token in USD.'), + output_per_token: zod.coerce + .string() + .regex( + createFeatureBodyUnitCostOneTwoPricingOneOutputPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .describe('Cost per output token in USD.'), + reasoning_per_token: zod.coerce + .string() + .regex( + createFeatureBodyUnitCostOneTwoPricingOneReasoningPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cost per reasoning token in USD.'), + }) + .describe( + 'Resolved per-token pricing from the LLM cost database.', + ) + .optional() + .describe( + 'Resolved per-token pricing from the LLM cost database. Populated in responses\nwhen the provider and model can be determined, either from static values or from\nmeter group-by filters with exact matches.', + ), + provider: zod.coerce + .string() + .optional() + .describe( + 'Static LLM provider value (e.g., "openai", "anthropic"). Use this when the\nfeature tracks a single provider. Mutually exclusive with `provider_property`.', + ), + provider_property: zod.coerce + .string() + .optional() + .describe( + 'Meter group-by property that holds the LLM provider. Use this when the meter has\na group-by dimension for provider. Mutually exclusive with `provider`.', + ), + token_type: zod + .enum([ + 'input', + 'output', + 'cache_read', + 'cache_write', + 'reasoning', + 'request', + 'response', + ]) + .describe('Token type for LLM cost lookup.') + .optional() + .describe( + 'Static token type value. Use this when the feature tracks a single token type\n(e.g., only input tokens). `request` is an alias for `input`, `response` is an\nalias for `output`. Mutually exclusive with `token_type_property`.', + ), + token_type_property: zod.coerce + .string() + .optional() + .describe( + 'Meter group-by property that holds the token type. Use this when the meter has a\ngroup-by dimension for token type. Mutually exclusive with `token_type`.', + ), + type: zod + .enum(['llm']) + .describe('The type discriminator for LLM unit cost.'), + }) + .describe( + 'LLM cost lookup configuration. Each dimension (provider, model, token type) can\nbe specified as either a static value or a meter group-by property name\n(mutually exclusive).', + ), + ]) + .describe( + 'Per-unit cost configuration for a feature. Either a fixed manual amount or a\ndynamic LLM cost lookup.', + ) + .optional() + .describe( + 'Optional per-unit cost configuration. Use "manual" for a fixed per-unit cost, or\n"llm" to look up cost from the LLM cost database based on meter group-by\nproperties.', + ), + }) + .describe('Feature create request.') + +/** + * Get a feature by id. + * @summary Get feature + */ +export const getFeaturePathFeatureIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetFeatureParams = zod.object({ + featureId: zod.coerce.string().regex(getFeaturePathFeatureIdRegExp), +}) + +/** + * Update a feature by id. Currently only the unit_cost field can be updated. + * @summary Update feature + */ +export const updateFeaturePathFeatureIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateFeatureParams = zod.object({ + featureId: zod.coerce.string().regex(updateFeaturePathFeatureIdRegExp), +}) + +export const updateFeatureBodyUnitCostOneOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateFeatureBodyUnitCostOneTwoPricingOneInputPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateFeatureBodyUnitCostOneTwoPricingOneOutputPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateFeatureBodyUnitCostOneTwoPricingOneCacheReadPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateFeatureBodyUnitCostOneTwoPricingOneReasoningPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updateFeatureBodyUnitCostOneTwoPricingOneCacheWritePerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const UpdateFeatureBody = zod + .object({ + unit_cost: zod + .union([ + zod + .object({ + amount: zod.coerce + .string() + .regex(updateFeatureBodyUnitCostOneOneAmountOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('Fixed per-unit cost amount in USD.'), + type: zod + .enum(['manual']) + .describe('The type discriminator for manual unit cost.'), + }) + .describe('A fixed per-unit cost amount.'), + zod + .object({ + model: zod.coerce + .string() + .optional() + .describe( + 'Static model ID value (e.g., "gpt-4", "claude-3-5-sonnet"). Use this when the\nfeature tracks a single model. Mutually exclusive with `model_property`.', + ), + model_property: zod.coerce + .string() + .optional() + .describe( + 'Meter group-by property that holds the model ID. Use this when the meter has a\ngroup-by dimension for model. Mutually exclusive with `model`.', + ), + pricing: zod + .object({ + cache_read_per_token: zod.coerce + .string() + .regex( + updateFeatureBodyUnitCostOneTwoPricingOneCacheReadPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cost per cache read token in USD.'), + cache_write_per_token: zod.coerce + .string() + .regex( + updateFeatureBodyUnitCostOneTwoPricingOneCacheWritePerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cost per cache write token in USD.'), + input_per_token: zod.coerce + .string() + .regex( + updateFeatureBodyUnitCostOneTwoPricingOneInputPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .describe('Cost per input token in USD.'), + output_per_token: zod.coerce + .string() + .regex( + updateFeatureBodyUnitCostOneTwoPricingOneOutputPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .describe('Cost per output token in USD.'), + reasoning_per_token: zod.coerce + .string() + .regex( + updateFeatureBodyUnitCostOneTwoPricingOneReasoningPerTokenOneRegExp, + ) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cost per reasoning token in USD.'), + }) + .describe( + 'Resolved per-token pricing from the LLM cost database.', + ) + .optional() + .describe( + 'Resolved per-token pricing from the LLM cost database. Populated in responses\nwhen the provider and model can be determined, either from static values or from\nmeter group-by filters with exact matches.', + ), + provider: zod.coerce + .string() + .optional() + .describe( + 'Static LLM provider value (e.g., "openai", "anthropic"). Use this when the\nfeature tracks a single provider. Mutually exclusive with `provider_property`.', + ), + provider_property: zod.coerce + .string() + .optional() + .describe( + 'Meter group-by property that holds the LLM provider. Use this when the meter has\na group-by dimension for provider. Mutually exclusive with `provider`.', + ), + token_type: zod + .enum([ + 'input', + 'output', + 'cache_read', + 'cache_write', + 'reasoning', + 'request', + 'response', + ]) + .describe('Token type for LLM cost lookup.') + .optional() + .describe( + 'Static token type value. Use this when the feature tracks a single token type\n(e.g., only input tokens). `request` is an alias for `input`, `response` is an\nalias for `output`. Mutually exclusive with `token_type_property`.', + ), + token_type_property: zod.coerce + .string() + .optional() + .describe( + 'Meter group-by property that holds the token type. Use this when the meter has a\ngroup-by dimension for token type. Mutually exclusive with `token_type`.', + ), + type: zod + .enum(['llm']) + .describe('The type discriminator for LLM unit cost.'), + }) + .describe( + 'LLM cost lookup configuration. Each dimension (provider, model, token type) can\nbe specified as either a static value or a meter group-by property name\n(mutually exclusive).', + ), + ]) + .describe( + 'Per-unit cost configuration for a feature. Either a fixed manual amount or a\ndynamic LLM cost lookup.', + ) + .nullish() + .describe( + 'Optional per-unit cost configuration. Use "manual" for a fixed per-unit cost, or\n"llm" to look up cost from the LLM cost database based on meter group-by\nproperties. Set to `null` to clear the existing unit cost; omit to leave it\nunchanged.', + ), + }) + .describe( + 'Request body for updating a feature. Currently only the unit_cost field can be\nupdated.', + ) + +/** + * Delete a feature by id. + * @summary Delete feature + */ +export const deleteFeaturePathFeatureIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteFeatureParams = zod.object({ + featureId: zod.coerce.string().regex(deleteFeaturePathFeatureIdRegExp), +}) + +/** + * Query the cost of a feature. + * @summary Query feature cost + */ +export const queryFeatureCostPathFeatureIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const QueryFeatureCostParams = zod.object({ + featureId: zod.coerce.string().regex(queryFeatureCostPathFeatureIdRegExp), +}) + +export const queryFeatureCostBodyTimeZoneDefault = 'UTC' +export const queryFeatureCostBodyGroupByDimensionsMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsInMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsNinMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsAndItemInMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsAndItemNinMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsAndItemAndMax = 10 + +export const queryFeatureCostBodyFiltersOneDimensionsAndItemOrMax = 10 + +export const queryFeatureCostBodyFiltersOneDimensionsAndMax = 10 + +export const queryFeatureCostBodyFiltersOneDimensionsOrItemInMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsOrItemNinMax = 100 + +export const queryFeatureCostBodyFiltersOneDimensionsOrItemAndMax = 10 + +export const queryFeatureCostBodyFiltersOneDimensionsOrItemOrMax = 10 + +export const queryFeatureCostBodyFiltersOneDimensionsOrMax = 10 + +export const QueryFeatureCostBody = zod + .object({ + filters: zod + .object({ + dimensions: zod + .record( + zod.string(), + zod + .object({ + and: zod + .array( + zod + .object({ + and: zod + .array(zod.unknown()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsAndItemAndMax, + ) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe( + 'The attribute contains the provided value.', + ), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsAndItemInMax, + ) + .optional() + .describe( + 'The attribute is one of the provided values.', + ), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not equal the provided value.', + ), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsAndItemNinMax, + ) + .optional() + .describe( + 'The attribute is not one of the provided values.', + ), + or: zod + .array(zod.unknown()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsAndItemOrMax, + ) + .optional() + .describe( + 'Combines the provided filters with a logical OR.', + ), + }) + .describe( + 'A query filter for a string attribute. Operators are mutually exclusive, only\none operator is allowed at a time.', + ), + ) + .min(1) + .max(queryFeatureCostBodyFiltersOneDimensionsAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe('The attribute contains the provided value.'), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + exists: zod.coerce + .boolean() + .optional() + .describe('The attribute exists.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(queryFeatureCostBodyFiltersOneDimensionsInMax) + .optional() + .describe('The attribute is one of the provided values.'), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe('The attribute does not equal the provided value.'), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(queryFeatureCostBodyFiltersOneDimensionsNinMax) + .optional() + .describe('The attribute is not one of the provided values.'), + or: zod + .array( + zod + .object({ + and: zod + .array(zod.unknown()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsOrItemAndMax, + ) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe( + 'The attribute contains the provided value.', + ), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsOrItemInMax, + ) + .optional() + .describe( + 'The attribute is one of the provided values.', + ), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not equal the provided value.', + ), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsOrItemNinMax, + ) + .optional() + .describe( + 'The attribute is not one of the provided values.', + ), + or: zod + .array(zod.unknown()) + .min(1) + .max( + queryFeatureCostBodyFiltersOneDimensionsOrItemOrMax, + ) + .optional() + .describe( + 'Combines the provided filters with a logical OR.', + ), + }) + .describe( + 'A query filter for a string attribute. Operators are mutually exclusive, only\none operator is allowed at a time.', + ), + ) + .min(1) + .max(queryFeatureCostBodyFiltersOneDimensionsOrMax) + .optional() + .describe('Combines the provided filters with a logical OR.'), + }) + .describe( + 'A query filter for an item in a string map attribute. Operators are mutually\nexclusive, only one operator is allowed at a time.', + ), + ) + .optional() + .describe( + 'Filters to apply to the dimensions of the query. For `subject` and `customer_id`\nonly equals ("eq", "in") comparisons are supported.', + ), + }) + .describe('Filters to apply to a meter query.') + .optional() + .describe('Filters to apply to the query.'), + from: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe('The start of the period the usage is queried from.'), + granularity: zod + .enum(['PT1M', 'PT1H', 'P1D', 'P1M']) + .describe( + 'The granularity of the time grouping. Time durations are specified in ISO 8601\nformat.', + ) + .optional() + .describe( + 'The size of the time buckets to group the usage into. If not specified, the\nusage is aggregated over the entire period.', + ), + group_by_dimensions: zod + .array(zod.coerce.string()) + .max(queryFeatureCostBodyGroupByDimensionsMax) + .optional() + .describe('The dimensions to group the results by.'), + time_zone: zod.coerce + .string() + .default(queryFeatureCostBodyTimeZoneDefault) + .describe( + 'The value is the name of the time zone as defined in the IANA Time Zone Database\n(http://www.iana.org/time-zones). The time zone is used to determine the start\nand end of the time buckets. If not specified, the UTC timezone will be used.', + ), + to: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe('The end of the period the usage is queried to.'), + }) + .describe('A meter query request.') + +/** + * Query feature access for a list of customers. + +The endpoint resolves each provided identifier to a customer and returns the +access status for the requested features, plus optional credit balance +availability. + +_Designed to be called on a fixed refresh interval and the query response is +intended to be cached._ + * @summary Query governance access + */ +export const QueryGovernanceAccessQueryParams = zod.object({ + page: zod + .object({ + after: zod.coerce + .string() + .optional() + .describe( + 'Request the next page of data, starting with the item after this parameter.', + ), + before: zod.coerce + .string() + .optional() + .describe( + 'Request the previous page of data, starting with the item before this parameter.', + ), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional(), +}) + +export const queryGovernanceAccessBodyIncludeCreditsDefault = false +export const queryGovernanceAccessBodyCustomerOneKeysMax = 100 + +export const queryGovernanceAccessBodyFeatureOneKeysMax = 100 + +export const QueryGovernanceAccessBody = zod + .object({ + customer: zod + .object({ + keys: zod + .array(zod.coerce.string()) + .min(1) + .max(queryGovernanceAccessBodyCustomerOneKeysMax) + .describe( + 'Each entry can be a customer `key` or a usage-attribution subject `key`.\nIdentifiers that cannot be resolved to a customer are reported in the response\n`errors` array.', + ), + }) + .describe('List of customer identifiers to evaluate access for.'), + feature: zod + .object({ + keys: zod + .array(zod.coerce.string()) + .min(1) + .max(queryGovernanceAccessBodyFeatureOneKeysMax) + .describe('List of feature keys to evaluate access for.'), + }) + .describe( + 'Optional list of feature keys to evaluate access for. If omitted, all features\navailable in the organization are returned. Providing this list is recommended\nto reduce the response size and the load on the backend services.', + ) + .optional(), + include_credits: zod.coerce + .boolean() + .default(queryGovernanceAccessBodyIncludeCreditsDefault) + .describe( + 'Whether to include credit balance availability for each resolved customer. When\ntrue, each feature evaluation includes credit balance checks.\n\nDefaults to `false`.', + ), + }) + .describe('Query to evaluate feature access for a list of customers.') + +/** + * List per-namespace price overrides. + * @summary List LLM cost overrides + */ +export const ListLlmCostOverridesQueryParams = zod.object({ + filter: zod + .object({ + currency: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by currency code. e.g. ?filter[currency][eq]=USD'), + model_id: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by model ID. e.g. ?filter[model_id][eq]=gpt-4'), + model_name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe( + 'Filter by model name. e.g. ?filter[model_name][contains]=gpt', + ), + provider: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by provider. e.g. ?filter[provider][eq]=openai'), + source: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by source. e.g. ?filter[source][eq]=system'), + }) + .optional(), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * Create a per-namespace price override. + * @summary Create LLM cost override + */ +export const createLlmCostOverrideBodyPricingOneInputPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createLlmCostOverrideBodyPricingOneOutputPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createLlmCostOverrideBodyPricingOneCacheReadPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createLlmCostOverrideBodyPricingOneCacheWritePerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createLlmCostOverrideBodyPricingOneReasoningPerTokenOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createLlmCostOverrideBodyCurrencyOneMin = 3 +export const createLlmCostOverrideBodyCurrencyOneMax = 3 + +export const createLlmCostOverrideBodyCurrencyOneRegExp = /^[A-Z]{3}$/ + +export const CreateLlmCostOverrideBody = zod + .object({ + currency: zod.coerce + .string() + .min(createLlmCostOverrideBodyCurrencyOneMin) + .max(createLlmCostOverrideBodyCurrencyOneMax) + .regex(createLlmCostOverrideBodyCurrencyOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('Currency code.'), + effective_from: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .describe('When this override becomes effective.'), + effective_to: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe('When this override expires.'), + model_id: zod.coerce.string().describe('Canonical model identifier.'), + model_name: zod.coerce + .string() + .optional() + .describe('Human-readable model name.'), + pricing: zod + .object({ + cache_read_per_token: zod.coerce + .string() + .regex(createLlmCostOverrideBodyPricingOneCacheReadPerTokenOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cache read price per token (USD).'), + cache_write_per_token: zod.coerce + .string() + .regex(createLlmCostOverrideBodyPricingOneCacheWritePerTokenOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Cache write price per token (USD).'), + input_per_token: zod.coerce + .string() + .regex(createLlmCostOverrideBodyPricingOneInputPerTokenOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('Input price per token (USD).'), + output_per_token: zod.coerce + .string() + .regex(createLlmCostOverrideBodyPricingOneOutputPerTokenOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .describe('Output price per token (USD).'), + reasoning_per_token: zod.coerce + .string() + .regex(createLlmCostOverrideBodyPricingOneReasoningPerTokenOneRegExp) + .describe('Numeric represents an arbitrary precision number.') + .optional() + .describe('Reasoning output price per token (USD).'), + }) + .describe('Token pricing for an LLM model, denominated per token.') + .describe('Token pricing data.'), + provider: zod.coerce.string().describe('Provider/vendor of the model.'), + }) + .describe( + 'Input for creating a per-namespace price override. Unique per provider, model\nand currency. If an override already exists for the given provider, model and\ncurrency, it will be updated. If an override does not exist, it will be created.', + ) + +/** + * Delete a per-namespace price override. + * @summary Delete LLM cost override + */ +export const deleteLlmCostOverridePathPriceIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteLlmCostOverrideParams = zod.object({ + priceId: zod.coerce.string().regex(deleteLlmCostOverridePathPriceIdRegExp), +}) + +/** + * List global LLM cost prices. Returns prices with overrides applied if any. + * @summary List LLM cost prices + */ +export const ListLlmCostPricesQueryParams = zod.object({ + filter: zod + .object({ + currency: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by currency code. e.g. ?filter[currency][eq]=USD'), + model_id: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by model ID. e.g. ?filter[model_id][eq]=gpt-4'), + model_name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe( + 'Filter by model name. e.g. ?filter[model_name][contains]=gpt', + ), + provider: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by provider. e.g. ?filter[provider][eq]=openai'), + source: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter by source. e.g. ?filter[source][eq]=system'), + }) + .optional() + .describe('Filter prices.'), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort prices returned in the response. Supported sort attributes are:\n\n- `id`\n- `provider.id`\n- `model.id` (default)\n- `effective_from`\n- `effective_to`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * Get a specific LLM cost price by ID. Returns the price with overrides applied if +any. + * @summary Get LLM cost price + */ +export const getLlmCostPricePathPriceIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetLlmCostPriceParams = zod.object({ + priceId: zod.coerce.string().regex(getLlmCostPricePathPriceIdRegExp), +}) + +/** + * Create a meter. + * @summary Create meter + */ +export const createMeterBodyNameMax = 256 + +export const createMeterBodyDescriptionMax = 1024 + +export const createMeterBodyLabelsMaxOne = 63 + +export const createMeterBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createMeterBodyKeyMax = 64 + +export const createMeterBodyKeyRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ + +export const CreateMeterBody = zod + .object({ + aggregation: zod + .enum(['sum', 'count', 'unique_count', 'avg', 'min', 'max', 'latest']) + .describe('The aggregation type to use for the meter.') + .describe('The aggregation type to use for the meter.'), + description: zod.coerce + .string() + .max(createMeterBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + dimensions: zod + .record(zod.string(), zod.coerce.string()) + .optional() + .describe( + 'Named JSONPath expressions to extract the group by values from the event data.\n\nKeys must be unique and consist only alphanumeric and underscore characters.', + ), + event_type: zod.coerce + .string() + .min(1) + .describe('The event type to include in the aggregation.'), + events_from: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + 'The date since the meter should include events. Useful to skip old events. If\nnot specified, all historical events are included.', + ), + key: zod.coerce + .string() + .min(1) + .max(createMeterBodyKeyMax) + .regex(createMeterBodyKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createMeterBodyLabelsMaxOne) + .regex(createMeterBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createMeterBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + value_property: zod.coerce + .string() + .min(1) + .optional() + .describe( + "JSONPath expression to extract the value from the ingested event's data\nproperty.\n\nThe ingested value for sum, avg, min, and max aggregations is a number or a\nstring that can be parsed to a number.\n\nFor unique_count aggregation, the ingested value must be a string. For count\naggregation the value_property is ignored.", + ), + }) + .describe('Meter create request.') + +/** + * List meters. + * @summary List meters + */ +export const ListMetersQueryParams = zod.object({ + filter: zod + .object({ + key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter meters by key.'), + name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ) + .optional() + .describe('Filter meters by name.'), + }) + .optional() + .describe( + 'Filter meters returned in the response.\n\nTo filter meters by key add the following query param: filter[key]=my-meter-key', + ), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort meters returned in the response. Supported sort attributes are:\n\n- `key`\n- `name`\n- `aggregation`\n- `createdAt` (default)\n- `updatedAt`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * Get a meter by ID. + * @summary Get meter + */ +export const getMeterPathMeterIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetMeterParams = zod.object({ + meterId: zod.coerce.string().regex(getMeterPathMeterIdRegExp), +}) + +/** + * Update a meter. + * @summary Update meter + */ +export const updateMeterPathMeterIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateMeterParams = zod.object({ + meterId: zod.coerce.string().regex(updateMeterPathMeterIdRegExp), +}) + +export const updateMeterBodyNameMax = 256 + +export const updateMeterBodyDescriptionMax = 1024 + +export const updateMeterBodyLabelsMaxOne = 63 + +export const updateMeterBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ + +export const UpdateMeterBody = zod + .object({ + description: zod.coerce + .string() + .max(updateMeterBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + dimensions: zod + .record(zod.string(), zod.coerce.string()) + .optional() + .describe( + 'Named JSONPath expressions to extract the group by values from the event data.\n\nKeys must be unique and consist only alphanumeric and underscore characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updateMeterBodyLabelsMaxOne) + .regex(updateMeterBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updateMeterBodyNameMax) + .optional() + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + }) + .describe('Meter update request.') + +/** + * Delete a meter. + * @summary Delete meter + */ +export const deleteMeterPathMeterIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteMeterParams = zod.object({ + meterId: zod.coerce.string().regex(deleteMeterPathMeterIdRegExp), +}) + +/** + * Query a meter for usage. + +Set `Accept: application/json` (the default) to get a structured JSON response. +Set `Accept: text/csv` to download the same data as a CSV file suitable for +spreadsheets. The CSV columns, in order, are: + +`from, to, [subject,] [customer_id, customer_key, customer_name,] , value` + +The `subject` column is emitted only when `subject` is in the query's +`group_by_dimensions`. The three `customer_*` columns are emitted together only +when `customer_id` is in the query's `group_by_dimensions`. + * @summary Query meter + */ +export const queryMeterPathMeterIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const QueryMeterParams = zod.object({ + meterId: zod.coerce.string().regex(queryMeterPathMeterIdRegExp), +}) + +export const queryMeterBodyTimeZoneDefault = 'UTC' +export const queryMeterBodyGroupByDimensionsMax = 100 + +export const queryMeterBodyFiltersOneDimensionsInMax = 100 + +export const queryMeterBodyFiltersOneDimensionsNinMax = 100 + +export const queryMeterBodyFiltersOneDimensionsAndItemInMax = 100 + +export const queryMeterBodyFiltersOneDimensionsAndItemNinMax = 100 + +export const queryMeterBodyFiltersOneDimensionsAndItemAndMax = 10 + +export const queryMeterBodyFiltersOneDimensionsAndItemOrMax = 10 + +export const queryMeterBodyFiltersOneDimensionsAndMax = 10 + +export const queryMeterBodyFiltersOneDimensionsOrItemInMax = 100 + +export const queryMeterBodyFiltersOneDimensionsOrItemNinMax = 100 + +export const queryMeterBodyFiltersOneDimensionsOrItemAndMax = 10 + +export const queryMeterBodyFiltersOneDimensionsOrItemOrMax = 10 + +export const queryMeterBodyFiltersOneDimensionsOrMax = 10 + +export const QueryMeterBody = zod + .object({ + filters: zod + .object({ + dimensions: zod + .record( + zod.string(), + zod + .object({ + and: zod + .array( + zod + .object({ + and: zod + .array(zod.unknown()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsAndItemAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe( + 'The attribute contains the provided value.', + ), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsAndItemInMax) + .optional() + .describe( + 'The attribute is one of the provided values.', + ), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not equal the provided value.', + ), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsAndItemNinMax) + .optional() + .describe( + 'The attribute is not one of the provided values.', + ), + or: zod + .array(zod.unknown()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsAndItemOrMax) + .optional() + .describe( + 'Combines the provided filters with a logical OR.', + ), + }) + .describe( + 'A query filter for a string attribute. Operators are mutually exclusive, only\none operator is allowed at a time.', + ), + ) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe('The attribute contains the provided value.'), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + exists: zod.coerce + .boolean() + .optional() + .describe('The attribute exists.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsInMax) + .optional() + .describe('The attribute is one of the provided values.'), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe('The attribute does not equal the provided value.'), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsNinMax) + .optional() + .describe('The attribute is not one of the provided values.'), + or: zod + .array( + zod + .object({ + and: zod + .array(zod.unknown()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsOrItemAndMax) + .optional() + .describe( + 'Combines the provided filters with a logical AND.', + ), + contains: zod.coerce + .string() + .optional() + .describe( + 'The attribute contains the provided value.', + ), + eq: zod.coerce + .string() + .optional() + .describe('The attribute equals the provided value.'), + in: zod + .array(zod.coerce.string()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsOrItemInMax) + .optional() + .describe( + 'The attribute is one of the provided values.', + ), + ncontains: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not contain the provided value.', + ), + neq: zod.coerce + .string() + .optional() + .describe( + 'The attribute does not equal the provided value.', + ), + nin: zod + .array(zod.coerce.string()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsOrItemNinMax) + .optional() + .describe( + 'The attribute is not one of the provided values.', + ), + or: zod + .array(zod.unknown()) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsOrItemOrMax) + .optional() + .describe( + 'Combines the provided filters with a logical OR.', + ), + }) + .describe( + 'A query filter for a string attribute. Operators are mutually exclusive, only\none operator is allowed at a time.', + ), + ) + .min(1) + .max(queryMeterBodyFiltersOneDimensionsOrMax) + .optional() + .describe('Combines the provided filters with a logical OR.'), + }) + .describe( + 'A query filter for an item in a string map attribute. Operators are mutually\nexclusive, only one operator is allowed at a time.', + ), + ) + .optional() + .describe( + 'Filters to apply to the dimensions of the query. For `subject` and `customer_id`\nonly equals ("eq", "in") comparisons are supported.', + ), + }) + .describe('Filters to apply to a meter query.') + .optional() + .describe('Filters to apply to the query.'), + from: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe('The start of the period the usage is queried from.'), + granularity: zod + .enum(['PT1M', 'PT1H', 'P1D', 'P1M']) + .describe( + 'The granularity of the time grouping. Time durations are specified in ISO 8601\nformat.', + ) + .optional() + .describe( + 'The size of the time buckets to group the usage into. If not specified, the\nusage is aggregated over the entire period.', + ), + group_by_dimensions: zod + .array(zod.coerce.string()) + .max(queryMeterBodyGroupByDimensionsMax) + .optional() + .describe('The dimensions to group the results by.'), + time_zone: zod.coerce + .string() + .default(queryMeterBodyTimeZoneDefault) + .describe( + 'The value is the name of the time zone as defined in the IANA Time Zone Database\n(http://www.iana.org/time-zones). The time zone is used to determine the start\nand end of the time buckets. If not specified, the UTC timezone will be used.', + ), + to: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe('The end of the period the usage is queried to.'), + }) + .describe('A meter query request.') + +/** + * List all plans. + * @summary List plans + */ +export const ListPlansQueryParams = zod.object({ + filter: zod + .object({ + currency: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + key: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + name: zod + .union([ + zod.coerce.string(), + zod.object({ + contains: zod.coerce + .string() + .optional() + .describe('Value contains the given string value (fuzzy match).'), + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + exists: zod.coerce + .boolean() + .optional() + .describe( + 'When true, the field must be present (non-null); when false, the field must be\nabsent (null).', + ), + gt: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than the given string value (lexicographic compare).', + ), + gte: zod.coerce + .string() + .optional() + .describe( + 'Value is greater than or equal to the given string value (lexicographic\ncompare).', + ), + lt: zod.coerce + .string() + .optional() + .describe( + 'Value is less than the given string value (lexicographic compare).', + ), + lte: zod.coerce + .string() + .optional() + .describe( + 'Value is less than or equal to the given string value (lexicographic compare).', + ), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + ocontains: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that fuzzy-match any of the comma-delimited phrases in the\nfilter string.', + ), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by either exact or fuzzy match. All\nproperties are optional; provide exactly one to specify the comparison.', + ), + status: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + }) + .optional() + .describe('Filter plans returned in the response.'), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort plans returned in the response. Supported sort attributes are:\n\n- `id`\n- `key`\n- `version`\n- `created_at` (default)\n- `updated_at`', + ), +}) + +/** + * Create a new plan. + * @summary Create plan + */ +export const createPlanBodyNameMax = 256 + +export const createPlanBodyDescriptionMax = 1024 + +export const createPlanBodyLabelsMaxOne = 63 + +export const createPlanBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createPlanBodyKeyOneMax = 64 + +export const createPlanBodyKeyOneRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createPlanBodyCurrencyOneMin = 3 +export const createPlanBodyCurrencyOneMax = 3 + +export const createPlanBodyCurrencyOneRegExp = /^[A-Z]{3}$/ +export const createPlanBodyBillingCadenceOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const createPlanBodyProRatingEnabledDefault = true +export const createPlanBodyPhasesItemNameMax = 256 + +export const createPlanBodyPhasesItemDescriptionMax = 1024 + +export const createPlanBodyPhasesItemLabelsMaxOne = 63 + +export const createPlanBodyPhasesItemLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createPlanBodyPhasesItemKeyMax = 64 + +export const createPlanBodyPhasesItemKeyRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createPlanBodyPhasesItemDurationOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const createPlanBodyPhasesItemRateCardsItemNameMax = 256 + +export const createPlanBodyPhasesItemRateCardsItemDescriptionMax = 1024 + +export const createPlanBodyPhasesItemRateCardsItemLabelsMaxOne = 63 + +export const createPlanBodyPhasesItemRateCardsItemLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemKeyMax = 64 + +export const createPlanBodyPhasesItemRateCardsItemKeyRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const createPlanBodyPhasesItemRateCardsItemFeatureOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createPlanBodyPhasesItemRateCardsItemBillingCadenceOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneTwoAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneThreeAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const createPlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const createPlanBodyPhasesItemRateCardsItemPaymentTermDefault = + 'in_arrears' +export const createPlanBodyPhasesItemRateCardsItemCommitmentsOneMinimumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemCommitmentsOneMaximumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMin = 0 +export const createPlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMax = 100 + +export const createPlanBodyPhasesItemRateCardsItemDiscountsOneUsageOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const createPlanBodyPhasesItemRateCardsItemTaxConfigOneCodeIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreatePlanBody = zod + .object({ + billing_cadence: zod + .stringFormat('ISO8601', createPlanBodyBillingCadenceOneRegExp) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .describe('The billing cadence for subscriptions using this plan.'), + currency: zod.coerce + .string() + .min(createPlanBodyCurrencyOneMin) + .max(createPlanBodyCurrencyOneMax) + .regex(createPlanBodyCurrencyOneRegExp) + .describe( + 'Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html)\ncurrency code. Custom three-letter currency codes are also supported for\nconvenience.', + ) + .describe('The currency code of the plan.'), + description: zod.coerce + .string() + .max(createPlanBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + key: zod.coerce + .string() + .min(1) + .max(createPlanBodyKeyOneMax) + .regex(createPlanBodyKeyOneRegExp) + .describe('A key is a unique string that is used to identify a resource.') + .describe( + 'A key is a semi-unique string that is used to identify the plan. It is used to\nreference the latest `active` version of the plan and is unique with the version\nnumber.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createPlanBodyLabelsMaxOne) + .regex(createPlanBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createPlanBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + phases: zod + .array( + zod + .object({ + description: zod.coerce + .string() + .max(createPlanBodyPhasesItemDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + duration: zod + .stringFormat( + 'ISO8601', + createPlanBodyPhasesItemDurationOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The duration of the phase. When not specified, the phase runs indefinitely. Only\nthe last phase may omit the duration.', + ), + key: zod.coerce + .string() + .min(1) + .max(createPlanBodyPhasesItemKeyMax) + .regex(createPlanBodyPhasesItemKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createPlanBodyPhasesItemLabelsMaxOne) + .regex(createPlanBodyPhasesItemLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createPlanBodyPhasesItemNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + rate_cards: zod + .array( + zod + .object({ + billing_cadence: zod + .stringFormat( + 'ISO8601', + createPlanBodyPhasesItemRateCardsItemBillingCadenceOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The billing cadence of the rate card. When null, the charge is one-time\n(non-recurring). Only valid for flat prices.', + ), + commitments: zod + .object({ + maximum_amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemCommitmentsOneMaximumAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'The customer is limited to spend at most the amount.', + ), + minimum_amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemCommitmentsOneMinimumAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'The customer is committed to spend at least the amount.', + ), + }) + .describe( + 'Spend commitments for a rate card. The customer is committed to spend at least\nthe minimum amount and at most the maximum amount.', + ) + .optional() + .describe( + 'Spend commitments for this rate card. Only applicable to usage-based prices\n(unit, graduated, volume).', + ), + description: zod.coerce + .string() + .max(createPlanBodyPhasesItemRateCardsItemDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + discounts: zod + .object({ + percentage: zod.coerce + .number() + .min( + createPlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMin, + ) + .max( + createPlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMax, + ) + .optional() + .describe( + 'Percentage discount applied to the price (0–100).', + ), + usage: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemDiscountsOneUsageOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Number of usage units granted free before billing starts. Only applies to\nusage-based lines (not flat fees). Usage is treated as zero until this amount is\nexhausted.', + ), + }) + .describe('Discount configuration for a rate card.') + .optional() + .describe('The discounts of the rate card.'), + feature: zod + .object({ + id: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemFeatureOneIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('Feature reference.') + .optional() + .describe('The feature associated with the rate card.'), + key: zod.coerce + .string() + .min(1) + .max(createPlanBodyPhasesItemRateCardsItemKeyMax) + .regex(createPlanBodyPhasesItemRateCardsItemKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max( + createPlanBodyPhasesItemRateCardsItemLabelsMaxOne, + ) + .regex( + createPlanBodyPhasesItemRateCardsItemLabelsRegExpOne, + ), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createPlanBodyPhasesItemRateCardsItemNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + payment_term: zod + .enum(['in_advance', 'in_arrears']) + .describe('The payment term of a flat price.') + .default( + createPlanBodyPhasesItemRateCardsItemPaymentTermDefault, + ) + .describe( + 'The payment term of the rate card. In advance payment term can only be used for\nflat prices.', + ), + price: zod + .union([ + zod + .object({ + type: zod + .enum(['free']) + .describe('The type of the price.'), + }) + .describe('Free price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneTwoAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneThreeAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the flat price.', + ), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the unit price.', + ), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the graduated price. At least one tier is required.', + ), + type: zod + .enum(['graduated']) + .describe('The type of the price.'), + }) + .describe( + "Graduated tiered price.\n\nEach tier's rate applies only to the usage within that tier. Pricing can change\nas cumulative usage crosses tier boundaries.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.", + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the flat price.', + ), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the unit price.', + ), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the volume price. At least one tier is required.', + ), + type: zod + .enum(['volume']) + .describe('The type of the price.'), + }) + .describe( + 'Volume tiered price.\n\nThe maximum quantity within a period determines the per-unit price for all units\nin that period.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.', + ), + ]) + .describe('Price.') + .describe('The price of the rate card.'), + tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .optional() + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ), + code: zod + .object({ + id: zod.coerce + .string() + .regex( + createPlanBodyPhasesItemRateCardsItemTaxConfigOneCodeIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.'), + }) + .describe('The tax config of the rate card.') + .optional() + .describe('The tax config of the rate card.'), + }) + .describe( + 'A rate card defines the pricing and entitlement of a feature or service.', + ), + ) + .describe('The rate cards of the plan.'), + }) + .describe( + "The plan phase or pricing ramp allows changing a plan's rate cards over time as\na subscription progresses.", + ), + ) + .min(1) + .describe( + 'The plan phases define the pricing ramp for a subscription. A phase switch\noccurs only at the end of a billing period. At least one phase is required.', + ), + pro_rating_enabled: zod.coerce + .boolean() + .default(createPlanBodyProRatingEnabledDefault) + .describe('Whether pro-rating is enabled for this plan.'), + }) + .describe('Plan create request.') + +/** + * Update a plan by id. + * @summary Update plan + */ +export const updatePlanPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdatePlanParams = zod.object({ + planId: zod.coerce.string().regex(updatePlanPathPlanIdRegExp), +}) + +export const updatePlanBodyNameMax = 256 + +export const updatePlanBodyDescriptionMax = 1024 + +export const updatePlanBodyLabelsMaxOne = 63 + +export const updatePlanBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updatePlanBodyProRatingEnabledDefault = true +export const updatePlanBodyPhasesItemNameMax = 256 + +export const updatePlanBodyPhasesItemDescriptionMax = 1024 + +export const updatePlanBodyPhasesItemLabelsMaxOne = 63 + +export const updatePlanBodyPhasesItemLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updatePlanBodyPhasesItemKeyMax = 64 + +export const updatePlanBodyPhasesItemKeyRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const updatePlanBodyPhasesItemDurationOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const updatePlanBodyPhasesItemRateCardsItemNameMax = 256 + +export const updatePlanBodyPhasesItemRateCardsItemDescriptionMax = 1024 + +export const updatePlanBodyPhasesItemRateCardsItemLabelsMaxOne = 63 + +export const updatePlanBodyPhasesItemRateCardsItemLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemKeyMax = 64 + +export const updatePlanBodyPhasesItemRateCardsItemKeyRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ +export const updatePlanBodyPhasesItemRateCardsItemFeatureOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updatePlanBodyPhasesItemRateCardsItemBillingCadenceOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneTwoAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneThreeAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const updatePlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ + +export const updatePlanBodyPhasesItemRateCardsItemPaymentTermDefault = + 'in_arrears' +export const updatePlanBodyPhasesItemRateCardsItemCommitmentsOneMinimumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemCommitmentsOneMaximumAmountOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMin = 0 +export const updatePlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMax = 100 + +export const updatePlanBodyPhasesItemRateCardsItemDiscountsOneUsageOneRegExp = + /^-?[0-9]+(\.[0-9]+)?$/ +export const updatePlanBodyPhasesItemRateCardsItemTaxConfigOneCodeIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdatePlanBody = zod + .object({ + description: zod.coerce + .string() + .max(updatePlanBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updatePlanBodyLabelsMaxOne) + .regex(updatePlanBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updatePlanBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + phases: zod + .array( + zod + .object({ + description: zod.coerce + .string() + .max(updatePlanBodyPhasesItemDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + duration: zod + .stringFormat( + 'ISO8601', + updatePlanBodyPhasesItemDurationOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The duration of the phase. When not specified, the phase runs indefinitely. Only\nthe last phase may omit the duration.', + ), + key: zod.coerce + .string() + .min(1) + .max(updatePlanBodyPhasesItemKeyMax) + .regex(updatePlanBodyPhasesItemKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updatePlanBodyPhasesItemLabelsMaxOne) + .regex(updatePlanBodyPhasesItemLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updatePlanBodyPhasesItemNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + rate_cards: zod + .array( + zod + .object({ + billing_cadence: zod + .stringFormat( + 'ISO8601', + updatePlanBodyPhasesItemRateCardsItemBillingCadenceOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .optional() + .describe( + 'The billing cadence of the rate card. When null, the charge is one-time\n(non-recurring). Only valid for flat prices.', + ), + commitments: zod + .object({ + maximum_amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemCommitmentsOneMaximumAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'The customer is limited to spend at most the amount.', + ), + minimum_amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemCommitmentsOneMinimumAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'The customer is committed to spend at least the amount.', + ), + }) + .describe( + 'Spend commitments for a rate card. The customer is committed to spend at least\nthe minimum amount and at most the maximum amount.', + ) + .optional() + .describe( + 'Spend commitments for this rate card. Only applicable to usage-based prices\n(unit, graduated, volume).', + ), + description: zod.coerce + .string() + .max(updatePlanBodyPhasesItemRateCardsItemDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + discounts: zod + .object({ + percentage: zod.coerce + .number() + .min( + updatePlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMin, + ) + .max( + updatePlanBodyPhasesItemRateCardsItemDiscountsOnePercentageMax, + ) + .optional() + .describe( + 'Percentage discount applied to the price (0–100).', + ), + usage: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemDiscountsOneUsageOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Number of usage units granted free before billing starts. Only applies to\nusage-based lines (not flat fees). Usage is treated as zero until this amount is\nexhausted.', + ), + }) + .describe('Discount configuration for a rate card.') + .optional() + .describe('The discounts of the rate card.'), + feature: zod + .object({ + id: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemFeatureOneIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('Feature reference.') + .optional() + .describe('The feature associated with the rate card.'), + key: zod.coerce + .string() + .min(1) + .max(updatePlanBodyPhasesItemRateCardsItemKeyMax) + .regex(updatePlanBodyPhasesItemRateCardsItemKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max( + updatePlanBodyPhasesItemRateCardsItemLabelsMaxOne, + ) + .regex( + updatePlanBodyPhasesItemRateCardsItemLabelsRegExpOne, + ), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updatePlanBodyPhasesItemRateCardsItemNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + payment_term: zod + .enum(['in_advance', 'in_arrears']) + .describe('The payment term of a flat price.') + .default( + updatePlanBodyPhasesItemRateCardsItemPaymentTermDefault, + ) + .describe( + 'The payment term of the rate card. In advance payment term can only be used for\nflat prices.', + ), + price: zod + .union([ + zod + .object({ + type: zod + .enum(['free']) + .describe('The type of the price.'), + }) + .describe('Free price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneTwoAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the flat price.'), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.'), + zod + .object({ + amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneThreeAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe('The amount of the unit price.'), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the flat price.', + ), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the unit price.', + ), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneFourTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the graduated price. At least one tier is required.', + ), + type: zod + .enum(['graduated']) + .describe('The type of the price.'), + }) + .describe( + "Graduated tiered price.\n\nEach tier's rate applies only to the usage within that tier. Pricing can change\nas cumulative usage crosses tier boundaries.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.", + ), + zod + .object({ + tiers: zod + .array( + zod + .object({ + flat_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemFlatPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the flat price.', + ), + type: zod + .enum(['flat']) + .describe('The type of the price.'), + }) + .describe('Flat price.') + .optional() + .describe( + 'The flat price component of the tier. Charged once when the tier is entered.', + ), + unit_price: zod + .object({ + amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUnitPriceOneAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .describe( + 'The amount of the unit price.', + ), + type: zod + .enum(['unit']) + .describe('The type of the price.'), + }) + .describe( + 'Unit price.\n\nCharges a fixed rate per billing unit. When UnitConfig is present on the rate\ncard, billing units are the converted quantities (e.g. GB instead of bytes).', + ) + .optional() + .describe( + 'The unit price component of the tier. Charged per billing unit within the tier.', + ), + up_to_amount: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemPriceOneFiveTiersItemUpToAmountOneRegExp, + ) + .describe( + 'Numeric represents an arbitrary precision number.', + ) + .optional() + .describe( + 'Up to and including this quantity will be contained in the tier. If undefined,\nthe tier is open-ended (the last tier).', + ), + }) + .describe( + 'A price tier used in graduated and volume pricing.\n\nAt least one price component (flat_price or unit_price) must be set. When\nUnitConfig is present on the rate card, up_to_amount is expressed in converted\nbilling units.', + ), + ) + .min(1) + .describe( + 'The tiers of the volume price. At least one tier is required.', + ), + type: zod + .enum(['volume']) + .describe('The type of the price.'), + }) + .describe( + 'Volume tiered price.\n\nThe maximum quantity within a period determines the per-unit price for all units\nin that period.\n\nWhen UnitConfig is present on the rate card, tier boundaries (up_to_amount) are\nexpressed in converted billing units.', + ), + ]) + .describe('Price.') + .describe('The price of the rate card.'), + tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .optional() + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ), + code: zod + .object({ + id: zod.coerce + .string() + .regex( + updatePlanBodyPhasesItemRateCardsItemTaxConfigOneCodeIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.'), + }) + .describe('The tax config of the rate card.') + .optional() + .describe('The tax config of the rate card.'), + }) + .describe( + 'A rate card defines the pricing and entitlement of a feature or service.', + ), + ) + .describe('The rate cards of the plan.'), + }) + .describe( + "The plan phase or pricing ramp allows changing a plan's rate cards over time as\na subscription progresses.", + ), + ) + .min(1) + .describe( + 'The plan phases define the pricing ramp for a subscription. A phase switch\noccurs only at the end of a billing period. At least one phase is required.', + ), + pro_rating_enabled: zod.coerce + .boolean() + .default(updatePlanBodyProRatingEnabledDefault) + .describe('Whether pro-rating is enabled for this plan.'), + }) + .describe('Plan upsert request.') + +/** + * Get a plan by id. + * @summary Get plan + */ +export const getPlanPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetPlanParams = zod.object({ + planId: zod.coerce.string().regex(getPlanPathPlanIdRegExp), +}) + +/** + * Delete a plan by id. + * @summary Delete plan + */ +export const deletePlanPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeletePlanParams = zod.object({ + planId: zod.coerce.string().regex(deletePlanPathPlanIdRegExp), +}) + +/** + * List add-ons associated with a plan. + * @summary List add-ons for plan + */ +export const listPlanAddonsPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListPlanAddonsParams = zod.object({ + planId: zod.coerce.string().regex(listPlanAddonsPathPlanIdRegExp), +}) + +export const ListPlanAddonsQueryParams = zod.object({ + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * Add an add-on to a plan. + * @summary Add add-on to plan + */ +export const createPlanAddonPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreatePlanAddonParams = zod.object({ + planId: zod.coerce.string().regex(createPlanAddonPathPlanIdRegExp), +}) + +export const createPlanAddonBodyNameMax = 256 + +export const createPlanAddonBodyDescriptionMax = 1024 + +export const createPlanAddonBodyLabelsMaxOne = 63 + +export const createPlanAddonBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createPlanAddonBodyAddonOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createPlanAddonBodyFromPlanPhaseOneMax = 64 + +export const createPlanAddonBodyFromPlanPhaseOneRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ + +export const CreatePlanAddonBody = zod + .object({ + addon: zod + .object({ + id: zod.coerce + .string() + .regex(createPlanAddonBodyAddonOneIdRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('Addon reference.') + .describe('The add-on associated with the plan.'), + description: zod.coerce + .string() + .max(createPlanAddonBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + from_plan_phase: zod.coerce + .string() + .min(1) + .max(createPlanAddonBodyFromPlanPhaseOneMax) + .regex(createPlanAddonBodyFromPlanPhaseOneRegExp) + .describe('A key is a unique string that is used to identify a resource.') + .describe( + 'The key of the plan phase from which the add-on becomes available for purchase.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createPlanAddonBodyLabelsMaxOne) + .regex(createPlanAddonBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + max_quantity: zod.coerce + .number() + .min(1) + .optional() + .describe( + 'The maximum number of times the add-on can be purchased for the plan. For\nsingle-instance add-ons this field must be omitted. For multi-instance add-ons\nwhen omitted, unlimited quantity can be purchased.', + ), + name: zod.coerce + .string() + .min(1) + .max(createPlanAddonBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + }) + .describe('PlanAddon create request.') + +/** + * Get an add-on association for a plan. + * @summary Get add-on association for plan + */ +export const getPlanAddonPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const getPlanAddonPathPlanAddonIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetPlanAddonParams = zod.object({ + planAddonId: zod.coerce.string().regex(getPlanAddonPathPlanAddonIdRegExp), + planId: zod.coerce.string().regex(getPlanAddonPathPlanIdRegExp), +}) + +/** + * Update an add-on association for a plan. + * @summary Update add-on association for plan + */ +export const updatePlanAddonPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updatePlanAddonPathPlanAddonIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdatePlanAddonParams = zod.object({ + planAddonId: zod.coerce.string().regex(updatePlanAddonPathPlanAddonIdRegExp), + planId: zod.coerce.string().regex(updatePlanAddonPathPlanIdRegExp), +}) + +export const updatePlanAddonBodyNameMax = 256 + +export const updatePlanAddonBodyDescriptionMax = 1024 + +export const updatePlanAddonBodyLabelsMaxOne = 63 + +export const updatePlanAddonBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updatePlanAddonBodyFromPlanPhaseOneMax = 64 + +export const updatePlanAddonBodyFromPlanPhaseOneRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ + +export const UpdatePlanAddonBody = zod + .object({ + description: zod.coerce + .string() + .max(updatePlanAddonBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + from_plan_phase: zod.coerce + .string() + .min(1) + .max(updatePlanAddonBodyFromPlanPhaseOneMax) + .regex(updatePlanAddonBodyFromPlanPhaseOneRegExp) + .describe('A key is a unique string that is used to identify a resource.') + .describe( + 'The key of the plan phase from which the add-on becomes available for purchase.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updatePlanAddonBodyLabelsMaxOne) + .regex(updatePlanAddonBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + max_quantity: zod.coerce + .number() + .min(1) + .optional() + .describe( + 'The maximum number of times the add-on can be purchased for the plan. For\nsingle-instance add-ons this field must be omitted. For multi-instance add-ons\nwhen omitted, unlimited quantity can be purchased.', + ), + name: zod.coerce + .string() + .min(1) + .max(updatePlanAddonBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + }) + .describe('PlanAddon upsert request.') + +/** + * Remove an add-on from a plan. + * @summary Remove add-on from plan + */ +export const deletePlanAddonPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const deletePlanAddonPathPlanAddonIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeletePlanAddonParams = zod.object({ + planAddonId: zod.coerce.string().regex(deletePlanAddonPathPlanAddonIdRegExp), + planId: zod.coerce.string().regex(deletePlanAddonPathPlanIdRegExp), +}) + +/** + * Archive a plan version. + * @summary Archive plan version + */ +export const archivePlanPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ArchivePlanParams = zod.object({ + planId: zod.coerce.string().regex(archivePlanPathPlanIdRegExp), +}) + +/** + * Publish a plan version. + * @summary Publish plan version + */ +export const publishPlanPathPlanIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const PublishPlanParams = zod.object({ + planId: zod.coerce.string().regex(publishPlanPathPlanIdRegExp), +}) + +/** + * List billing profiles. + * @summary List billing profiles + */ +export const ListBillingProfilesQueryParams = zod.object({ + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * Create a new billing profile. + +Billing profiles contain the settings for billing and controls invoice +generation. An organization can have multiple billing profiles defined. A +billing profile is linked to a specific app. This association is established +during the billing profile's creation and remains immutable. + * @summary Create a new billing profile + */ +export const createBillingProfileBodyNameMax = 256 + +export const createBillingProfileBodyDescriptionMax = 1024 + +export const createBillingProfileBodyLabelsMaxOne = 63 + +export const createBillingProfileBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createBillingProfileBodySupplierOneKeyOneMax = 256 + +export const createBillingProfileBodySupplierOneTaxIdOneCodeOneMax = 32 + +export const createBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMin = 2 +export const createBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMax = 2 + +export const createBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneRegExp = + /^[A-Z]{2}$/ +export const createBillingProfileBodyWorkflowOneCollectionOneAlignmentOneTwoRecurringPeriodOneIntervalOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const createBillingProfileBodyWorkflowOneCollectionOneAlignmentDefault = + { type: 'subscription' } as const +export const createBillingProfileBodyWorkflowOneCollectionOneIntervalDefault = + 'PT1H' +export const createBillingProfileBodyWorkflowOneInvoicingOneAutoAdvanceDefault = true +export const createBillingProfileBodyWorkflowOneInvoicingOneDraftPeriodDefault = + 'P0D' +export const createBillingProfileBodyWorkflowOneInvoicingOneProgressiveBillingDefault = true +export const createBillingProfileBodyWorkflowOnePaymentOneTwoDueAfterDefault = + 'P30D' +export const createBillingProfileBodyWorkflowOneTaxOneEnabledDefault = true +export const createBillingProfileBodyWorkflowOneTaxOneEnforcedDefault = false +export const createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneStripeOneCodeRegExp = + /^txcd_\d{8}$/ +export const createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneExternalInvoicingOneCodeMax = 64 + +export const createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createBillingProfileBodyAppsOneTaxOneIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createBillingProfileBodyAppsOneInvoicingOneIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createBillingProfileBodyAppsOnePaymentOneIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CreateBillingProfileBody = zod + .object({ + apps: zod + .object({ + invoicing: zod + .object({ + id: zod.coerce + .string() + .regex(createBillingProfileBodyAppsOneInvoicingOneIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .describe('The ID of the app.'), + }) + .describe('App reference.') + .describe('The invoicing app used for this workflow.'), + payment: zod + .object({ + id: zod.coerce + .string() + .regex(createBillingProfileBodyAppsOnePaymentOneIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .describe('The ID of the app.'), + }) + .describe('App reference.') + .describe('The payment app used for this workflow.'), + tax: zod + .object({ + id: zod.coerce + .string() + .regex(createBillingProfileBodyAppsOneTaxOneIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .describe('The ID of the app.'), + }) + .describe('App reference.') + .describe('The tax app used for this workflow.'), + }) + .describe('References to the applications used by a billing profile.') + .describe('The applications used by this billing profile.'), + default: zod.coerce + .boolean() + .describe('Whether this is the default profile.'), + description: zod.coerce + .string() + .max(createBillingProfileBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createBillingProfileBodyLabelsMaxOne) + .regex(createBillingProfileBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createBillingProfileBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + supplier: zod + .object({ + addresses: zod + .object({ + billing_address: zod + .object({ + city: zod.coerce.string().optional().describe('City.'), + country: zod.coerce + .string() + .min( + createBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMin, + ) + .max( + createBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMax, + ) + .regex( + createBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneRegExp, + ) + .describe( + '[ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 country\ncode. Custom two-letter country codes are also supported for convenience.', + ) + .optional() + .describe( + 'Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html)\nalpha-2 format.', + ), + line1: zod.coerce + .string() + .optional() + .describe('First line of the address.'), + line2: zod.coerce + .string() + .optional() + .describe('Second line of the address.'), + phone_number: zod.coerce + .string() + .optional() + .describe('Phone number.'), + postal_code: zod.coerce + .string() + .optional() + .describe('Postal code.'), + state: zod.coerce + .string() + .optional() + .describe('State or province.'), + }) + .describe('Address') + .describe('Billing address.'), + }) + .describe('A collection of addresses for the party.') + .optional() + .describe('Address for where information should be sent if needed.'), + id: zod.coerce + .string() + .optional() + .describe('Unique identifier for the party.'), + key: zod.coerce + .string() + .min(1) + .max(createBillingProfileBodySupplierOneKeyOneMax) + .describe( + 'ExternalResourceKey is a unique string that is used to identify a resource in an\nexternal system.', + ) + .optional() + .describe('An optional unique key of the party.'), + name: zod.coerce + .string() + .optional() + .describe('Legal name or representation of the party.'), + tax_id: zod + .object({ + code: zod.coerce + .string() + .min(1) + .max(createBillingProfileBodySupplierOneTaxIdOneCodeOneMax) + .describe( + 'Tax identifier code is a normalized tax code shown on the original identity\ndocument.', + ) + .optional() + .describe( + 'Normalized tax identification code shown on the original identity document.', + ), + }) + .describe( + 'Identity stores the details required to identify an entity for tax purposes in a\nspecific country.', + ) + .optional() + .describe( + "The entity's legal identification used for tax purposes. They may have other\nnumbers, but we're only interested in those valid for tax purposes.", + ), + }) + .describe('Party represents a person or business entity.') + .describe( + 'The name and contact information for the supplier this billing profile\nrepresents', + ), + workflow: zod + .object({ + collection: zod + .object({ + alignment: zod + .union([ + zod + .object({ + type: zod + .enum(['subscription']) + .describe('The type of alignment.'), + }) + .describe( + 'BillingWorkflowCollectionAlignmentSubscription specifies the alignment for\ncollecting the pending line items into an invoice.', + ), + zod + .object({ + recurring_period: zod + .object({ + anchor: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .describe( + 'A date-time anchor to base the recurring period on.', + ), + interval: zod + .stringFormat( + 'ISO8601', + createBillingProfileBodyWorkflowOneCollectionOneAlignmentOneTwoRecurringPeriodOneIntervalOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .describe( + 'The interval duration in ISO 8601 format.', + ), + }) + .describe( + 'Recurring period with an anchor and an interval.', + ) + .describe('The recurring period for the alignment.'), + type: zod + .enum(['anchored']) + .describe('The type of alignment.'), + }) + .describe( + 'BillingWorkflowCollectionAlignmentAnchored specifies the alignment for\ncollecting the pending line items into an invoice.', + ), + ]) + .describe( + 'The alignment for collecting the pending line items into an invoice.\n\nDefaults to subscription, which means that we are to create a new invoice every\ntime the a subscription period starts (for in advance items) or ends (for in\narrears items).', + ) + .default( + createBillingProfileBodyWorkflowOneCollectionOneAlignmentDefault, + ) + .describe( + 'The alignment for collecting the pending line items into an invoice.', + ), + interval: zod.coerce + .string() + .default( + createBillingProfileBodyWorkflowOneCollectionOneIntervalDefault, + ) + .describe( + 'This grace period can be used to delay the collection of the pending line items\nspecified in alignment.\n\nThis is useful, in case of multiple subscriptions having slightly different\nbilling periods.', + ), + }) + .describe( + 'Workflow collection specifies how to collect the pending line items for an\ninvoice.', + ) + .optional() + .describe('The collection settings for this workflow'), + invoicing: zod + .object({ + auto_advance: zod.coerce + .boolean() + .default( + createBillingProfileBodyWorkflowOneInvoicingOneAutoAdvanceDefault, + ) + .describe( + 'Whether to automatically issue the invoice after the draftPeriod has passed.', + ), + draft_period: zod.coerce + .string() + .default( + createBillingProfileBodyWorkflowOneInvoicingOneDraftPeriodDefault, + ) + .describe( + 'The period for the invoice to be kept in draft status for manual reviews.', + ), + progressive_billing: zod.coerce + .boolean() + .default( + createBillingProfileBodyWorkflowOneInvoicingOneProgressiveBillingDefault, + ) + .describe( + 'Should progressive billing be allowed for this workflow?', + ), + }) + .describe('Invoice settings for a billing workflow.') + .optional() + .describe('The invoicing settings for this workflow'), + payment: zod + .union([ + zod + .object({ + collection_method: zod + .enum(['charge_automatically']) + .describe('The collection method for the invoice.'), + }) + .describe( + 'Payment settings for a billing workflow when the collection method is charge\nautomatically.', + ), + zod + .object({ + collection_method: zod + .enum(['send_invoice']) + .describe('The collection method for the invoice.'), + due_after: zod.coerce + .string() + .default( + createBillingProfileBodyWorkflowOnePaymentOneTwoDueAfterDefault, + ) + .describe( + "The period after which the invoice is due. With some payment solutions it's only\napplicable for manual collection method.", + ), + }) + .describe( + 'Payment settings for a billing workflow when the collection method is send\ninvoice.', + ), + ]) + .describe('Payment settings for a billing workflow.') + .optional() + .describe('The payment settings for this workflow'), + tax: zod + .object({ + default_tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ) + .optional() + .describe( + "Tax behavior.\n\nIf not specified the billing profile is used to determine the tax behavior. If\nnot specified in the billing profile, the provider's default behavior is used.", + ), + external_invoicing: zod + .object({ + code: zod.coerce + .string() + .max( + createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneExternalInvoicingOneCodeMax, + ) + .describe( + 'The tax code should be interpreted by the external invoicing provider.', + ), + }) + .describe('External invoicing tax config.') + .optional() + .describe('External invoicing tax config.'), + stripe: zod + .object({ + code: zod.coerce + .string() + .regex( + createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneStripeOneCodeRegExp, + ) + .describe( + 'Product [tax code](https://docs.stripe.com/tax/tax-codes).', + ), + }) + .describe('The tax config for Stripe.') + .optional() + .describe('Stripe tax config.'), + tax_code: zod + .object({ + id: zod.coerce + .string() + .regex( + createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeOneIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.') + .optional() + .describe( + 'Tax code reference.\n\nWhen both `tax_code` and `tax_code_id` are provided, `tax_code` takes\nprecedence. When `stripe.code` is also provided, `tax_code` still wins and\n`stripe.code` is ignored.', + ), + tax_code_id: zod.coerce + .string() + .regex( + createBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeIdOneRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Tax code ID.'), + }) + .describe('Set of provider specific tax configs.') + .optional() + .describe( + 'Default tax configuration to apply to the invoices for line items.', + ), + enabled: zod.coerce + .boolean() + .default(createBillingProfileBodyWorkflowOneTaxOneEnabledDefault) + .describe( + 'Enable automatic tax calculation when tax is supported by the app. For example,\nwith Stripe Invoicing when enabled, tax is calculated via Stripe Tax.', + ), + enforced: zod.coerce + .boolean() + .default(createBillingProfileBodyWorkflowOneTaxOneEnforcedDefault) + .describe( + 'Enforce tax calculation when tax is supported by the app. When enabled, the\nbilling system will not allow to create an invoice without tax calculation.\nEnforcement is different per apps, for example, Stripe app requires customer to\nhave a tax location when starting a paid subscription.', + ), + }) + .describe('Tax settings for a billing workflow.') + .optional() + .describe('The tax settings for this workflow'), + }) + .describe('Billing workflow settings.') + .describe('The billing workflow settings for this profile'), + }) + .describe('BillingProfile create request.') + +/** + * Get a billing profile. + * @summary Get a billing profile + */ +export const getBillingProfilePathIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetBillingProfileParams = zod.object({ + id: zod.coerce.string().regex(getBillingProfilePathIdRegExp), +}) + +/** + * Update a billing profile. + * @summary Update a billing profile + */ +export const updateBillingProfilePathIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateBillingProfileParams = zod.object({ + id: zod.coerce.string().regex(updateBillingProfilePathIdRegExp), +}) + +export const updateBillingProfileBodyNameMax = 256 + +export const updateBillingProfileBodyDescriptionMax = 1024 + +export const updateBillingProfileBodyLabelsMaxOne = 63 + +export const updateBillingProfileBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const updateBillingProfileBodySupplierOneKeyOneMax = 256 + +export const updateBillingProfileBodySupplierOneTaxIdOneCodeOneMax = 32 + +export const updateBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMin = 2 +export const updateBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMax = 2 + +export const updateBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneRegExp = + /^[A-Z]{2}$/ +export const updateBillingProfileBodyWorkflowOneCollectionOneAlignmentOneTwoRecurringPeriodOneIntervalOneRegExp = + /^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$/ +export const updateBillingProfileBodyWorkflowOneCollectionOneAlignmentDefault = + { type: 'subscription' } as const +export const updateBillingProfileBodyWorkflowOneCollectionOneIntervalDefault = + 'PT1H' +export const updateBillingProfileBodyWorkflowOneInvoicingOneAutoAdvanceDefault = true +export const updateBillingProfileBodyWorkflowOneInvoicingOneDraftPeriodDefault = + 'P0D' +export const updateBillingProfileBodyWorkflowOneInvoicingOneProgressiveBillingDefault = true +export const updateBillingProfileBodyWorkflowOnePaymentOneTwoDueAfterDefault = + 'P30D' +export const updateBillingProfileBodyWorkflowOneTaxOneEnabledDefault = true +export const updateBillingProfileBodyWorkflowOneTaxOneEnforcedDefault = false +export const updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneStripeOneCodeRegExp = + /^txcd_\d{8}$/ +export const updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneExternalInvoicingOneCodeMax = 64 + +export const updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeOneIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpdateBillingProfileBody = zod + .object({ + default: zod.coerce + .boolean() + .describe('Whether this is the default profile.'), + description: zod.coerce + .string() + .max(updateBillingProfileBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(updateBillingProfileBodyLabelsMaxOne) + .regex(updateBillingProfileBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(updateBillingProfileBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + supplier: zod + .object({ + addresses: zod + .object({ + billing_address: zod + .object({ + city: zod.coerce.string().optional().describe('City.'), + country: zod.coerce + .string() + .min( + updateBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMin, + ) + .max( + updateBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneMax, + ) + .regex( + updateBillingProfileBodySupplierOneAddressesOneBillingAddressOneCountryOneRegExp, + ) + .describe( + '[ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 country\ncode. Custom two-letter country codes are also supported for convenience.', + ) + .optional() + .describe( + 'Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html)\nalpha-2 format.', + ), + line1: zod.coerce + .string() + .optional() + .describe('First line of the address.'), + line2: zod.coerce + .string() + .optional() + .describe('Second line of the address.'), + phone_number: zod.coerce + .string() + .optional() + .describe('Phone number.'), + postal_code: zod.coerce + .string() + .optional() + .describe('Postal code.'), + state: zod.coerce + .string() + .optional() + .describe('State or province.'), + }) + .describe('Address') + .describe('Billing address.'), + }) + .describe('A collection of addresses for the party.') + .optional() + .describe('Address for where information should be sent if needed.'), + id: zod.coerce + .string() + .optional() + .describe('Unique identifier for the party.'), + key: zod.coerce + .string() + .min(1) + .max(updateBillingProfileBodySupplierOneKeyOneMax) + .describe( + 'ExternalResourceKey is a unique string that is used to identify a resource in an\nexternal system.', + ) + .optional() + .describe('An optional unique key of the party.'), + name: zod.coerce + .string() + .optional() + .describe('Legal name or representation of the party.'), + tax_id: zod + .object({ + code: zod.coerce + .string() + .min(1) + .max(updateBillingProfileBodySupplierOneTaxIdOneCodeOneMax) + .describe( + 'Tax identifier code is a normalized tax code shown on the original identity\ndocument.', + ) + .optional() + .describe( + 'Normalized tax identification code shown on the original identity document.', + ), + }) + .describe( + 'Identity stores the details required to identify an entity for tax purposes in a\nspecific country.', + ) + .optional() + .describe( + "The entity's legal identification used for tax purposes. They may have other\nnumbers, but we're only interested in those valid for tax purposes.", + ), + }) + .describe('Party represents a person or business entity.') + .describe( + 'The name and contact information for the supplier this billing profile\nrepresents', + ), + workflow: zod + .object({ + collection: zod + .object({ + alignment: zod + .union([ + zod + .object({ + type: zod + .enum(['subscription']) + .describe('The type of alignment.'), + }) + .describe( + 'BillingWorkflowCollectionAlignmentSubscription specifies the alignment for\ncollecting the pending line items into an invoice.', + ), + zod + .object({ + recurring_period: zod + .object({ + anchor: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .describe( + 'A date-time anchor to base the recurring period on.', + ), + interval: zod + .stringFormat( + 'ISO8601', + updateBillingProfileBodyWorkflowOneCollectionOneAlignmentOneTwoRecurringPeriodOneIntervalOneRegExp, + ) + .describe( + '[ISO 8601 Duration](https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm)\nstring.', + ) + .describe( + 'The interval duration in ISO 8601 format.', + ), + }) + .describe( + 'Recurring period with an anchor and an interval.', + ) + .describe('The recurring period for the alignment.'), + type: zod + .enum(['anchored']) + .describe('The type of alignment.'), + }) + .describe( + 'BillingWorkflowCollectionAlignmentAnchored specifies the alignment for\ncollecting the pending line items into an invoice.', + ), + ]) + .describe( + 'The alignment for collecting the pending line items into an invoice.\n\nDefaults to subscription, which means that we are to create a new invoice every\ntime the a subscription period starts (for in advance items) or ends (for in\narrears items).', + ) + .default( + updateBillingProfileBodyWorkflowOneCollectionOneAlignmentDefault, + ) + .describe( + 'The alignment for collecting the pending line items into an invoice.', + ), + interval: zod.coerce + .string() + .default( + updateBillingProfileBodyWorkflowOneCollectionOneIntervalDefault, + ) + .describe( + 'This grace period can be used to delay the collection of the pending line items\nspecified in alignment.\n\nThis is useful, in case of multiple subscriptions having slightly different\nbilling periods.', + ), + }) + .describe( + 'Workflow collection specifies how to collect the pending line items for an\ninvoice.', + ) + .optional() + .describe('The collection settings for this workflow'), + invoicing: zod + .object({ + auto_advance: zod.coerce + .boolean() + .default( + updateBillingProfileBodyWorkflowOneInvoicingOneAutoAdvanceDefault, + ) + .describe( + 'Whether to automatically issue the invoice after the draftPeriod has passed.', + ), + draft_period: zod.coerce + .string() + .default( + updateBillingProfileBodyWorkflowOneInvoicingOneDraftPeriodDefault, + ) + .describe( + 'The period for the invoice to be kept in draft status for manual reviews.', + ), + progressive_billing: zod.coerce + .boolean() + .default( + updateBillingProfileBodyWorkflowOneInvoicingOneProgressiveBillingDefault, + ) + .describe( + 'Should progressive billing be allowed for this workflow?', + ), + }) + .describe('Invoice settings for a billing workflow.') + .optional() + .describe('The invoicing settings for this workflow'), + payment: zod + .union([ + zod + .object({ + collection_method: zod + .enum(['charge_automatically']) + .describe('The collection method for the invoice.'), + }) + .describe( + 'Payment settings for a billing workflow when the collection method is charge\nautomatically.', + ), + zod + .object({ + collection_method: zod + .enum(['send_invoice']) + .describe('The collection method for the invoice.'), + due_after: zod.coerce + .string() + .default( + updateBillingProfileBodyWorkflowOnePaymentOneTwoDueAfterDefault, + ) + .describe( + "The period after which the invoice is due. With some payment solutions it's only\napplicable for manual collection method.", + ), + }) + .describe( + 'Payment settings for a billing workflow when the collection method is send\ninvoice.', + ), + ]) + .describe('Payment settings for a billing workflow.') + .optional() + .describe('The payment settings for this workflow'), + tax: zod + .object({ + default_tax_config: zod + .object({ + behavior: zod + .enum(['inclusive', 'exclusive']) + .describe( + 'Tax behavior.\n\nThis enum is used to specify whether tax is included in the price or excluded\nfrom the price.', + ) + .optional() + .describe( + "Tax behavior.\n\nIf not specified the billing profile is used to determine the tax behavior. If\nnot specified in the billing profile, the provider's default behavior is used.", + ), + external_invoicing: zod + .object({ + code: zod.coerce + .string() + .max( + updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneExternalInvoicingOneCodeMax, + ) + .describe( + 'The tax code should be interpreted by the external invoicing provider.', + ), + }) + .describe('External invoicing tax config.') + .optional() + .describe('External invoicing tax config.'), + stripe: zod + .object({ + code: zod.coerce + .string() + .regex( + updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneStripeOneCodeRegExp, + ) + .describe( + 'Product [tax code](https://docs.stripe.com/tax/tax-codes).', + ), + }) + .describe('The tax config for Stripe.') + .optional() + .describe('Stripe tax config.'), + tax_code: zod + .object({ + id: zod.coerce + .string() + .regex( + updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeOneIdRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + }) + .describe('TaxCode reference.') + .optional() + .describe( + 'Tax code reference.\n\nWhen both `tax_code` and `tax_code_id` are provided, `tax_code` takes\nprecedence. When `stripe.code` is also provided, `tax_code` still wins and\n`stripe.code` is ignored.', + ), + tax_code_id: zod.coerce + .string() + .regex( + updateBillingProfileBodyWorkflowOneTaxOneDefaultTaxConfigOneTaxCodeIdOneRegExp, + ) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Tax code ID.'), + }) + .describe('Set of provider specific tax configs.') + .optional() + .describe( + 'Default tax configuration to apply to the invoices for line items.', + ), + enabled: zod.coerce + .boolean() + .default(updateBillingProfileBodyWorkflowOneTaxOneEnabledDefault) + .describe( + 'Enable automatic tax calculation when tax is supported by the app. For example,\nwith Stripe Invoicing when enabled, tax is calculated via Stripe Tax.', + ), + enforced: zod.coerce + .boolean() + .default(updateBillingProfileBodyWorkflowOneTaxOneEnforcedDefault) + .describe( + 'Enforce tax calculation when tax is supported by the app. When enabled, the\nbilling system will not allow to create an invoice without tax calculation.\nEnforcement is different per apps, for example, Stripe app requires customer to\nhave a tax location when starting a paid subscription.', + ), + }) + .describe('Tax settings for a billing workflow.') + .optional() + .describe('The tax settings for this workflow'), + }) + .describe('Billing workflow settings.') + .describe('The billing workflow settings for this profile'), + }) + .describe('BillingProfile upsert request.') + +/** + * Delete a billing profile. + +Only such billing profiles can be deleted that are: + +- not the default profile +- not pinned to any customer using customer overrides +- only have finalized invoices + * @summary Delete a billing profile + */ +export const deleteBillingProfilePathIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteBillingProfileParams = zod.object({ + id: zod.coerce.string().regex(deleteBillingProfilePathIdRegExp), +}) + +/** + * @summary Create subscription + */ +export const createSubscriptionBodyLabelsMaxOne = 63 + +export const createSubscriptionBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createSubscriptionBodyCustomerIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createSubscriptionBodyCustomerKeyOneMax = 256 + +export const createSubscriptionBodyPlanIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const createSubscriptionBodyPlanKeyOneMax = 64 + +export const createSubscriptionBodyPlanKeyOneRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ + +export const CreateSubscriptionBody = zod + .object({ + billing_anchor: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + "A billing anchor is the fixed point in time that determines the subscription's\nrecurring billing cycle. It affects when charges occur and how prorations are\ncalculated. Common anchors:\n\n- Calendar month (1st of each month): `2025-01-01T00:00:00Z`\n- Subscription anniversary (day customer signed up)\n- Custom date (customer-specified day)\n\nIf not provided, the subscription will be created with the subscription's\ncreation time as the billing anchor.", + ), + customer: zod + .object({ + id: zod.coerce + .string() + .regex(createSubscriptionBodyCustomerIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe( + 'The ID of the customer to create the subscription for.\n\nEither customer ID or customer key must be provided. If both are provided, the\nID will be used.', + ), + key: zod.coerce + .string() + .min(1) + .max(createSubscriptionBodyCustomerKeyOneMax) + .describe( + 'ExternalResourceKey is a unique string that is used to identify a resource in an\nexternal system.', + ) + .optional() + .describe( + 'The key of the customer to create the subscription for.\n\nEither customer ID or customer key must be provided. If both are provided, the\nID will be used.', + ), + }) + .describe('The customer to create the subscription for.'), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createSubscriptionBodyLabelsMaxOne) + .regex(createSubscriptionBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + plan: zod + .object({ + id: zod.coerce + .string() + .regex(createSubscriptionBodyPlanIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe( + 'The plan ID of the subscription. Set if subscription is created from a plan.\n\nID or Key of the plan is required if creating a subscription from a plan. If\nboth are provided, the ID will be used.', + ), + key: zod.coerce + .string() + .min(1) + .max(createSubscriptionBodyPlanKeyOneMax) + .regex(createSubscriptionBodyPlanKeyOneRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ) + .optional() + .describe( + 'The plan Key of the subscription, if any. Set if subscription is created from a\nplan.\n\nID or Key of the plan is required if creating a subscription from a plan. If\nboth are provided, the ID will be used.', + ), + version: zod.coerce + .number() + .optional() + .describe( + 'The plan version of the subscription, if any. If not provided, the latest\nversion of the plan will be used.', + ), + }) + .describe('The plan reference of the subscription.'), + }) + .describe('Subscription create request.') + +/** + * @summary List subscriptions + */ +export const listSubscriptionsQueryFilterIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterIdTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterIdTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterCustomerIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterCustomerIdTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterCustomerIdTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterPlanIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterPlanIdTwoEqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const listSubscriptionsQueryFilterPlanIdTwoNeqOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListSubscriptionsQueryParams = zod.object({ + filter: zod + .object({ + customer_id: zod + .union([ + zod.coerce + .string() + .regex(listSubscriptionsQueryFilterCustomerIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listSubscriptionsQueryFilterCustomerIdTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listSubscriptionsQueryFilterCustomerIdTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + id: zod + .union([ + zod.coerce + .string() + .regex(listSubscriptionsQueryFilterIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listSubscriptionsQueryFilterIdTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listSubscriptionsQueryFilterIdTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + plan_id: zod + .union([ + zod.coerce + .string() + .regex(listSubscriptionsQueryFilterPlanIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ), + zod.object({ + eq: zod.coerce + .string() + .regex(listSubscriptionsQueryFilterPlanIdTwoEqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value strictly equals the given ULID value.'), + neq: zod.coerce + .string() + .regex(listSubscriptionsQueryFilterPlanIdTwoNeqOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe('Value does not equal the given ULID value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited ULIDs in the filter\nstring.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given ULID field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + plan_key: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + status: zod + .union([ + zod.coerce.string(), + zod.object({ + eq: zod.coerce + .string() + .optional() + .describe('Value strictly equals the given string value.'), + neq: zod.coerce + .string() + .optional() + .describe('Value does not equal the given string value.'), + oeq: zod.coerce + .string() + .optional() + .describe( + 'Returns entities that exact match any of the comma-delimited phrases in the\nfilter string.', + ), + }), + ]) + .optional() + .describe( + 'Filters on the given string field value by exact match. All properties are\noptional; provide exactly one to specify the comparison.', + ), + }) + .optional() + .describe('Filter subscriptions.'), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce + .string() + .optional() + .describe( + 'Sort subscriptions returned in the response. Supported sort attributes are:\n\n- `id`\n- `active_from` (default)\n- `active_to`\n\nThe `asc` suffix is optional as the default sort order is ascending. The `desc`\nsuffix is used to specify a descending order.', + ), +}) + +/** + * @summary Get subscription + */ +export const getSubscriptionPathSubscriptionIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetSubscriptionParams = zod.object({ + subscriptionId: zod.coerce + .string() + .regex(getSubscriptionPathSubscriptionIdRegExp), +}) + +/** + * List the addons of a subscription. + * @summary List subscription addons + */ +export const listSubscriptionAddonsPathSubscriptionIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ListSubscriptionAddonsParams = zod.object({ + subscriptionId: zod.coerce + .string() + .regex(listSubscriptionAddonsPathSubscriptionIdRegExp), +}) + +export const ListSubscriptionAddonsQueryParams = zod.object({ + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), + sort: zod.coerce.string().optional(), +}) + +/** + * Get an add-on association for a subscription. + * @summary Get add-on association for subscription + */ +export const getSubscriptionAddonPathSubscriptionIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const getSubscriptionAddonPathSubscriptionAddonIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetSubscriptionAddonParams = zod.object({ + subscriptionAddonId: zod.coerce + .string() + .regex(getSubscriptionAddonPathSubscriptionAddonIdRegExp), + subscriptionId: zod.coerce + .string() + .regex(getSubscriptionAddonPathSubscriptionIdRegExp), +}) + +/** + * Cancels the subscription. Will result in a scheduling conflict if there are +other subscriptions scheduled to start after the cancelation time. + * @summary Cancel subscription + */ +export const cancelSubscriptionPathSubscriptionIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const CancelSubscriptionParams = zod.object({ + subscriptionId: zod.coerce + .string() + .regex(cancelSubscriptionPathSubscriptionIdRegExp), +}) + +export const cancelSubscriptionBodyTimingDefault = 'immediate' + +export const CancelSubscriptionBody = zod + .object({ + timing: zod + .union([ + zod + .enum(['immediate', 'next_billing_cycle']) + .describe( + 'Subscription edit timing. When immediate, the requested changes take effect\nimmediately. When next_billing_cycle, the requested changes take effect at the\nnext billing cycle.', + ), + zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ), + ]) + .describe( + 'Subscription edit timing defined when the changes should take effect. If the\nprovided configuration is not supported by the subscription, an error will be\nreturned.', + ) + .default(cancelSubscriptionBodyTimingDefault) + .describe('If not provided the subscription is canceled immediately.'), + }) + .describe('Request for canceling a subscription.') + +/** + * Closes a running subscription and starts a new one according to the +specification. Can be used for upgrades, downgrades, and plan changes. + * @summary Change subscription + */ +export const changeSubscriptionPathSubscriptionIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const ChangeSubscriptionParams = zod.object({ + subscriptionId: zod.coerce + .string() + .regex(changeSubscriptionPathSubscriptionIdRegExp), +}) + +export const changeSubscriptionBodyLabelsMaxOne = 63 + +export const changeSubscriptionBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const changeSubscriptionBodyCustomerIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const changeSubscriptionBodyCustomerKeyOneMax = 256 + +export const changeSubscriptionBodyPlanIdOneRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ +export const changeSubscriptionBodyPlanKeyOneMax = 64 + +export const changeSubscriptionBodyPlanKeyOneRegExp = + /^[a-z0-9]+(?:_[a-z0-9]+)*$/ + +export const ChangeSubscriptionBody = zod + .object({ + billing_anchor: zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ) + .optional() + .describe( + "A billing anchor is the fixed point in time that determines the subscription's\nrecurring billing cycle. It affects when charges occur and how prorations are\ncalculated. Common anchors:\n\n- Calendar month (1st of each month): `2025-01-01T00:00:00Z`\n- Subscription anniversary (day customer signed up)\n- Custom date (customer-specified day)\n\nIf not provided, the subscription will be created with the subscription's\ncreation time as the billing anchor.", + ), + customer: zod + .object({ + id: zod.coerce + .string() + .regex(changeSubscriptionBodyCustomerIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe( + 'The ID of the customer to create the subscription for.\n\nEither customer ID or customer key must be provided. If both are provided, the\nID will be used.', + ), + key: zod.coerce + .string() + .min(1) + .max(changeSubscriptionBodyCustomerKeyOneMax) + .describe( + 'ExternalResourceKey is a unique string that is used to identify a resource in an\nexternal system.', + ) + .optional() + .describe( + 'The key of the customer to create the subscription for.\n\nEither customer ID or customer key must be provided. If both are provided, the\nID will be used.', + ), + }) + .describe('The customer to create the subscription for.'), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(changeSubscriptionBodyLabelsMaxOne) + .regex(changeSubscriptionBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + plan: zod + .object({ + id: zod.coerce + .string() + .regex(changeSubscriptionBodyPlanIdOneRegExp) + .describe( + 'ULID (Universally Unique Lexicographically Sortable Identifier).', + ) + .optional() + .describe( + 'The plan ID of the subscription. Set if subscription is created from a plan.\n\nID or Key of the plan is required if creating a subscription from a plan. If\nboth are provided, the ID will be used.', + ), + key: zod.coerce + .string() + .min(1) + .max(changeSubscriptionBodyPlanKeyOneMax) + .regex(changeSubscriptionBodyPlanKeyOneRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ) + .optional() + .describe( + 'The plan Key of the subscription, if any. Set if subscription is created from a\nplan.\n\nID or Key of the plan is required if creating a subscription from a plan. If\nboth are provided, the ID will be used.', + ), + version: zod.coerce + .number() + .optional() + .describe( + 'The plan version of the subscription, if any. If not provided, the latest\nversion of the plan will be used.', + ), + }) + .describe('The plan reference of the subscription.'), + timing: zod + .union([ + zod + .enum(['immediate', 'next_billing_cycle']) + .describe( + 'Subscription edit timing. When immediate, the requested changes take effect\nimmediately. When next_billing_cycle, the requested changes take effect at the\nnext billing cycle.', + ), + zod.coerce + .date() + .describe( + '[RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in\nUTC.', + ), + ]) + .describe( + 'Subscription edit timing defined when the changes should take effect. If the\nprovided configuration is not supported by the subscription, an error will be\nreturned.', + ) + .describe( + 'Timing configuration for the change, when the change should take effect. For\nchanging a subscription, the accepted values depend on the subscription\nconfiguration.', + ), + }) + .describe('Request for changing a subscription.') + +/** + * Unschedules the subscription cancelation. + * @summary Unschedule subscription cancelation + */ +export const unscheduleCancelationPathSubscriptionIdRegExp = + /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UnscheduleCancelationParams = zod.object({ + subscriptionId: zod.coerce + .string() + .regex(unscheduleCancelationPathSubscriptionIdRegExp), +}) + +/** + * @summary Create tax code + */ +export const createTaxCodeBodyNameMax = 256 + +export const createTaxCodeBodyDescriptionMax = 1024 + +export const createTaxCodeBodyLabelsMaxOne = 63 + +export const createTaxCodeBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ +export const createTaxCodeBodyKeyMax = 64 + +export const createTaxCodeBodyKeyRegExp = /^[a-z0-9]+(?:_[a-z0-9]+)*$/ + +export const CreateTaxCodeBody = zod + .object({ + app_mappings: zod + .array( + zod + .object({ + app_type: zod + .enum(['sandbox', 'stripe', 'external_invoicing']) + .describe('The type of the app.') + .describe('The app type that the tax code is associated with.'), + tax_code: zod.coerce.string().describe('Tax code.'), + }) + .describe('Mapping of app types to tax codes.'), + ) + .describe('Mapping of app types to tax codes.'), + description: zod.coerce + .string() + .max(createTaxCodeBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + key: zod.coerce + .string() + .min(1) + .max(createTaxCodeBodyKeyMax) + .regex(createTaxCodeBodyKeyRegExp) + .describe( + 'A key is a unique string that is used to identify a resource.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(createTaxCodeBodyLabelsMaxOne) + .regex(createTaxCodeBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(createTaxCodeBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + }) + .describe('TaxCode create request.') + +/** + * @summary List tax codes + */ +export const ListTaxCodesQueryParams = zod.object({ + include_deleted: zod.coerce + .boolean() + .optional() + .describe('Include deleted tax codes in the response.'), + page: zod + .object({ + number: zod.coerce.number().optional().describe('The page number.'), + size: zod.coerce + .number() + .optional() + .describe('The number of items to include per page.'), + }) + .optional() + .describe('Determines which page of the collection to retrieve.'), +}) + +/** + * @summary Get tax code + */ +export const getTaxCodePathTaxCodeIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const GetTaxCodeParams = zod.object({ + taxCodeId: zod.coerce.string().regex(getTaxCodePathTaxCodeIdRegExp), +}) + +/** + * @summary Upsert tax code + */ +export const upsertTaxCodePathTaxCodeIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const UpsertTaxCodeParams = zod.object({ + taxCodeId: zod.coerce.string().regex(upsertTaxCodePathTaxCodeIdRegExp), +}) + +export const upsertTaxCodeBodyNameMax = 256 + +export const upsertTaxCodeBodyDescriptionMax = 1024 + +export const upsertTaxCodeBodyLabelsMaxOne = 63 + +export const upsertTaxCodeBodyLabelsRegExpOne = + /^[a-z0-9A-Z]{1}([a-z0-9A-Z-._]*[a-z0-9A-Z]+)?$/ + +export const UpsertTaxCodeBody = zod + .object({ + app_mappings: zod + .array( + zod + .object({ + app_type: zod + .enum(['sandbox', 'stripe', 'external_invoicing']) + .describe('The type of the app.') + .describe('The app type that the tax code is associated with.'), + tax_code: zod.coerce.string().describe('Tax code.'), + }) + .describe('Mapping of app types to tax codes.'), + ) + .describe('Mapping of app types to tax codes.'), + description: zod.coerce + .string() + .max(upsertTaxCodeBodyDescriptionMax) + .optional() + .describe( + 'Optional description of the resource.\n\nMaximum 1024 characters.', + ), + labels: zod + .record( + zod.string(), + zod.coerce + .string() + .min(1) + .max(upsertTaxCodeBodyLabelsMaxOne) + .regex(upsertTaxCodeBodyLabelsRegExpOne), + ) + .optional() + .describe( + 'Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. \n\nKeys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_".\n', + ), + name: zod.coerce + .string() + .min(1) + .max(upsertTaxCodeBodyNameMax) + .describe( + 'Display name of the resource.\n\nBetween 1 and 256 characters.', + ), + }) + .describe('TaxCode upsert request.') + +/** + * @summary Delete tax code + */ +export const deleteTaxCodePathTaxCodeIdRegExp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/ + +export const DeleteTaxCodeParams = zod.object({ + taxCodeId: zod.coerce.string().regex(deleteTaxCodePathTaxCodeIdRegExp), +}) From 096b9626e0fa401f34f1c0a5903233ad734ead7e Mon Sep 17 00:00:00 2001 From: rolosp <6114043+rolosp@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:17:56 +0200 Subject: [PATCH 2/2] test: added an e2e test comparision for both v1 and v3 clients --- e2e/playwright/.gitignore | 5 + e2e/playwright/README.md | 46 +++ e2e/playwright/package.json | 23 ++ e2e/playwright/playwright.config.ts | 19 + e2e/playwright/pnpm-lock.yaml | 111 ++++++ .../tests/productcatalog.smoke.v1.spec.ts | 375 ++++++++++++++++++ .../tests/productcatalog.smoke.v3.spec.ts | 341 ++++++++++++++++ e2e/playwright/tsconfig.json | 14 + 8 files changed, 934 insertions(+) create mode 100644 e2e/playwright/.gitignore create mode 100644 e2e/playwright/README.md create mode 100644 e2e/playwright/package.json create mode 100644 e2e/playwright/playwright.config.ts create mode 100644 e2e/playwright/pnpm-lock.yaml create mode 100644 e2e/playwright/tests/productcatalog.smoke.v1.spec.ts create mode 100644 e2e/playwright/tests/productcatalog.smoke.v3.spec.ts create mode 100644 e2e/playwright/tsconfig.json diff --git a/e2e/playwright/.gitignore b/e2e/playwright/.gitignore new file mode 100644 index 0000000000..80a36b7e84 --- /dev/null +++ b/e2e/playwright/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +test-results/ +playwright-report/ +blob-report/ +.pnpm-store/ diff --git a/e2e/playwright/README.md b/e2e/playwright/README.md new file mode 100644 index 0000000000..cf9b58161c --- /dev/null +++ b/e2e/playwright/README.md @@ -0,0 +1,46 @@ +# Playwright e2e — v3 shim smoke + +Live-server smoke test for the `@openmeter/sdk` **v3 compatibility shim** +(`om.v3.*`, under `api/client/javascript/src/v3/`). It is the TypeScript parity +of `e2e/productcatalog_smoke_v3_test.go`: the same plan + addon authoring flow, +but driven through the shim instead of raw Go HTTP. + +This uses [Playwright's API-testing mode](https://playwright.dev/docs/api-testing) +— Playwright is only the runner (`test`/`expect`, no browser, no `webServer`). +The client under test is the shim itself, over Node's `fetch`. Dependencies are +deliberately minimal: Playwright plus the local `@openmeter/sdk`. + +## Run it + +1. Start a local OpenMeter (the same server the Go e2e suite uses): + + ```bash + make -C .. env-local-up # from e2e/: brings up docker-compose, server on :38888 + ``` + +2. Build the SDK (the shim is consumed from its built `dist/`) and install: + + ```bash + pnpm install # links @openmeter/sdk via file: + pnpm run build:sdk # builds api/client/javascript -> dist/ + ``` + +3. Run the smoke: + + ```bash + pnpm test # OPENMETER_ADDRESS defaults to http://localhost:38888 + ``` + + `pnpm run test:full` does build:sdk + install + test in one shot. + +Point at a different server with `OPENMETER_ADDRESS=https://host pnpm test`. +There is no auth locally; set an API key by constructing the client with +`{ baseUrl, apiKey }` if you target an authenticated environment. + +## Notes + +- The shim surfaces the v3 wire shape **verbatim** (snake_case, "Option A"), so + responses read with snake_case fields (`validation_errors`, `effective_from`, + `from_plan_phase`, …) — assertions match the Go test's wire assertions. +- Not wired into CI yet. To run in CI, build the SDK and run this against the + same docker-compose server the `e2e` job already stands up. diff --git a/e2e/playwright/package.json b/e2e/playwright/package.json new file mode 100644 index 0000000000..feffb9048c --- /dev/null +++ b/e2e/playwright/package.json @@ -0,0 +1,23 @@ +{ + "name": "@openmeter/e2e-playwright", + "version": "0.0.0", + "private": true, + "description": "Playwright API-testing smoke tests for the @openmeter/sdk v3 compatibility shim against a live OpenMeter server", + "type": "module", + "scripts": { + "build:sdk": "pnpm -C ../../api/client/javascript install --frozen-lockfile && pnpm -C ../../api/client/javascript build", + "typecheck": "tsc --noEmit", + "test": "playwright test" + }, + "dependencies": { + "@openmeter/sdk": "file:../../api/client/javascript" + }, + "devDependencies": { + "@playwright/test": "^1.49.0", + "@types/node": "^22.0.0", + "typescript": "^5.6.0" + }, + "engines": { + "node": ">=22.0.0" + } +} diff --git a/e2e/playwright/playwright.config.ts b/e2e/playwright/playwright.config.ts new file mode 100644 index 0000000000..8ef2341161 --- /dev/null +++ b/e2e/playwright/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from '@playwright/test' + +// API-testing config for the @openmeter/sdk v3 shim smoke test. There is no +// browser project and no webServer: the tests drive the shim (`om.v3.*`) over +// Node's fetch against an already-running OpenMeter server (the same one the Go +// e2e suite targets — `make -C e2e env-local-up`, OPENMETER_ADDRESS). +export default defineConfig({ + testDir: './tests', + // The smoke flow is inherently ordered (describe.serial) and shares state, so + // a single worker keeps runs deterministic and avoids key collisions. + workers: 1, + fullyParallel: false, + // No retries — a flaky smoke should fail loudly, not be papered over. + retries: 0, + reporter: 'list', + // Bound a hung server the way the Go suite's v3RequestTimeout does. + timeout: 60_000, + expect: { timeout: 30_000 }, +}) diff --git a/e2e/playwright/pnpm-lock.yaml b/e2e/playwright/pnpm-lock.yaml new file mode 100644 index 0000000000..4e0a17dc49 --- /dev/null +++ b/e2e/playwright/pnpm-lock.yaml @@ -0,0 +1,111 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@openmeter/sdk': + specifier: file:../../api/client/javascript + version: file:../../api/client/javascript(react@19.2.7) + devDependencies: + '@playwright/test': + specifier: ^1.49.0 + version: 1.60.0 + '@types/node': + specifier: ^22.0.0 + version: 22.19.19 + typescript: + specifier: ^5.6.0 + version: 5.9.3 + +packages: + + '@openmeter/sdk@file:../../api/client/javascript': + resolution: {directory: ../../api/client/javascript, type: directory} + engines: {node: '>=22.0.0'} + peerDependencies: + react: '>=18.0.0' + + '@playwright/test@1.60.0': + resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} + engines: {node: '>=18'} + hasBin: true + + '@types/node@22.19.19': + resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + openapi-fetch@0.17.0: + resolution: {integrity: sha512-PsbZR1wAPcG91eEthKhN+Zn92FMHxv+/faECIwjXdxfTODGSGegYv0sc1Olz+HYPvKOuoXfp+0pA2XVt2cI0Ig==} + + openapi-typescript-helpers@0.1.0: + resolution: {integrity: sha512-OKTGPthhivLw/fHz6c3OPtg72vi86qaMlqbJuVJ23qOvQ+53uw1n7HdmkJFibloF7QEjDrDkzJiOJuockM/ljw==} + + playwright-core@1.60.0: + resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.60.0: + resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} + engines: {node: '>=18'} + hasBin: true + + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} + engines: {node: '>=0.10.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + +snapshots: + + '@openmeter/sdk@file:../../api/client/javascript(react@19.2.7)': + dependencies: + openapi-fetch: 0.17.0 + openapi-typescript-helpers: 0.1.0 + react: 19.2.7 + + '@playwright/test@1.60.0': + dependencies: + playwright: 1.60.0 + + '@types/node@22.19.19': + dependencies: + undici-types: 6.21.0 + + fsevents@2.3.2: + optional: true + + openapi-fetch@0.17.0: + dependencies: + openapi-typescript-helpers: 0.1.0 + + openapi-typescript-helpers@0.1.0: {} + + playwright-core@1.60.0: {} + + playwright@1.60.0: + dependencies: + playwright-core: 1.60.0 + optionalDependencies: + fsevents: 2.3.2 + + react@19.2.7: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} diff --git a/e2e/playwright/tests/productcatalog.smoke.v1.spec.ts b/e2e/playwright/tests/productcatalog.smoke.v1.spec.ts new file mode 100644 index 0000000000..a61ad52459 --- /dev/null +++ b/e2e/playwright/tests/productcatalog.smoke.v1.spec.ts @@ -0,0 +1,375 @@ +import { expect, test } from '@playwright/test' +import { + type AddonCreate, + type Feature, + type FeatureCreateInputs, + isHTTPError, + type Meter, + type MeterCreate, + OpenMeter, + type Plan, + type PlanAddon, + type PlanAddonCreate, + type PlanCreate, + type PlanReplaceUpdate, + type RateCard, +} from '@openmeter/sdk' + +// Live-server smoke for the legacy v1 OpenMeter client (`om.*`). +// +// This is the v1 counterpart of productcatalog.smoke.v3.spec.ts — the SAME +// flow, written against the v1 client so the two can be read side by side. The +// instructive difference is *how the types are obtained and used*: +// +// v1 (this file): the request/response types are re-exported from the package +// root (`export * from './schemas.js'`), so we import them by +// name — `PlanCreate`, `RateCard`, `Plan`, `PlanAddon`, … — and +// both bodies and responses are fully typed with no casts. +// +// v3 (.v3 file): the v3 schema types are NOT re-exported from the root, so the +// test has to *derive* request types off the method signatures +// (`Parameters[0]`) and cast +// responses with `as { ... }`. +// +// The wire shapes differ too, which is the other half of the comparison: +// - v1 is camelCase (`billingCadence`, `rateCards`, `validationErrors`); v3 is +// snake_case verbatim. +// - v1 references features by `featureKey` and meters by `meterSlug`/`slug`; +// v3 references by `feature.id` / `meter.id`. +// - v1 rate cards are `flat_fee` / `usage_based` wrappers with the payment term +// nested in the flat price; v3 has a flat price union with `payment_term` on +// the rate card. +// - v1 tiered prices use `type: 'tiered'` + `mode: 'graduated'`; v3 uses +// `type: 'graduated'` directly. +// - v1 list responses paginate under `items`; v3 under `data`. +// - v1 `PlanAddon` has no own id — the association is keyed by `addon` + +// `fromPlanPhase`; v3 has a distinct plan-addon `id`. +// +// Requires a running OpenMeter (no auth locally). Point it at the server with +// OPENMETER_ADDRESS (defaults to the docker-compose port used by `make -C e2e`). + +const address = process.env.OPENMETER_ADDRESS ?? 'http://localhost:38888' + +// The v1 client targets the bare host (it owns the `/api/v1` path prefix) and +// resolves the Bearer header only when apiKey is set, so the local server (no +// auth) needs only baseUrl. +const om = new OpenMeter({ baseUrl: address }) + +// uniqueKey mirrors the Go helper: a fixture key that survives re-runs against a +// shared database without collision. +function uniqueKey(prefix: string): string { + return `${prefix}_${Date.now()}_${Math.floor(Math.random() * 10_000)}` +} + +// defined unwraps the `T | undefined` that the client methods return on success +// (transformResponse returns the parsed body or undefined). Asserting + casting +// here keeps each call site typed as the concrete response model. +function defined(value: T): NonNullable { + expect(value, 'expected a response body').toBeDefined() + return value as NonNullable +} + +// --- Fixture builders (parity with e2e/v3helpers_test.go, v1 types) --- + +function validFlatRateCard(keyPrefix: string): RateCard { + return { + type: 'flat_fee', + key: uniqueKey(keyPrefix), + name: `Test Rate Card ${keyPrefix}`, + billingCadence: 'P1M', + // v1 puts the payment term inside the price, not on the rate card. + price: { type: 'flat', amount: '10', paymentTerm: 'in_advance' }, + } +} + +function validUnitRateCard(feature: Feature): RateCard { + return { + type: 'usage_based', + // v1 references the feature by key (string), not by id. + key: feature.key, + name: `Test Unit Rate Card ${feature.key}`, + featureKey: feature.key, + billingCadence: 'P1M', + price: { type: 'unit', amount: '0.10' }, + } +} + +function validGraduatedRateCard(feature: Feature): RateCard { + return { + type: 'usage_based', + key: feature.key, + name: `Test Graduated Rate Card ${feature.key}`, + featureKey: feature.key, + billingCadence: 'P1M', + price: { + // v1 tiered price: type 'tiered' + mode 'graduated' (v3 uses 'graduated'). + type: 'tiered', + mode: 'graduated', + tiers: [ + { + upToAmount: '100', + flatPrice: null, + unitPrice: { type: 'unit', amount: '0.10' }, + }, + { flatPrice: null, unitPrice: { type: 'unit', amount: '0.05' } }, + ], + }, + } +} + +// validationCodes pulls the product-catalog validation codes out of a thrown +// HTTPError's problem extensions — identical helper to the v3 test (both v1 and +// v3 product-catalog validation surface through the same commonhttp envelope: +// extensions.validationErrors). +function validationCodes(err: unknown): string[] { + if (!isHTTPError(err)) return [] + const extensions = err.getField('extensions') as + | { validationErrors?: Array<{ code?: string }> } + | undefined + return (extensions?.validationErrors ?? []) + .map((e) => e.code) + .filter((c): c is string => typeof c === 'string') +} + +test.describe.serial('v1 client product catalog smoke', () => { + const meters: Meter[] = [] + const features: Feature[] = [] + + let planId = '' + let addonId = '' + let phaseKey = '' + // Track the three valid rate cards across the invalid-loop steps so the + // "remove defective" PUT can rebuild the phase from the same baseline. + let validRateCards: RateCard[] = [] + + test.beforeAll(async () => { + // given: + // - two meters and two features bound to them (by slug), the raw materials + // the plan's usage-based rate cards reference (by featureKey). + for (let i = 0; i < 2; i++) { + const slug = uniqueKey('sanity_meter') + const meterBody: MeterCreate = { + slug, + name: `Test Meter ${slug}`, + aggregation: 'SUM', // v1 aggregation is upper-case (v3 is lower-case). + eventType: uniqueKey('sanity_event'), + valueProperty: '$.value', + } + const meter = defined(await om.meters.create(meterBody)) + expect(meter.id).toBeTruthy() + meters.push(meter) + + const featureKey = uniqueKey('sanity_feature') + const featureBody: FeatureCreateInputs = { + key: featureKey, + name: `Test Feature ${featureKey}`, + meterSlug: slug, + } + const feature = defined(await om.features.create(featureBody)) + expect(feature.id).toBeTruthy() + features.push(feature) + } + }) + + test('creates a draft plan with a single flat rate card', async () => { + // when: + // - a plan is created with the baseline single-flat-rate-card phase. + phaseKey = uniqueKey('phase_1') + const body: PlanCreate = { + key: uniqueKey('sanity_plan'), + name: 'Sanity Plan', + currency: 'USD', + billingCadence: 'P1M', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + duration: null, // last (only) phase runs indefinitely. + rateCards: [validFlatRateCard('fee')], + }, + ], + } + const plan: Plan = defined(await om.plans.create(body)) + + // then: + // - it lands as a draft with the single rate card. + expect(plan.id).toBeTruthy() + expect(plan.status).toBe('draft') + expect(plan.phases).toHaveLength(1) + expect(plan.phases[0].rateCards).toHaveLength(1) + planId = plan.id + }) + + test('updates the plan to carry flat + usage + graduated rate cards', async () => { + // given: + // - three different rate card shapes on one phase. The flat fee is + // in_advance; both usage-based ones default to in_arrears. Only the unit + // one carries a feature reference here. + const flat = validFlatRateCard('sanity_flat') + const usage = validUnitRateCard(features[0]) + const graduated = validGraduatedRateCard(features[1]) + + // when: + // - v1 update (PlanReplaceUpdate) requires billingCadence; v3's + // UpsertPlanRequest only needs name + phases. + const body: PlanReplaceUpdate = { + name: 'Sanity Plan', + billingCadence: 'P1M', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + duration: null, + rateCards: [flat, usage, graduated], + }, + ], + } + const plan: Plan = defined(await om.plans.update(planId, body)) + + // then: + // - all three rate cards round-trip and the usage card keeps its feature. + expect(plan.phases).toHaveLength(1) + expect(plan.phases[0].rateCards).toHaveLength(3) + + const usageRC = plan.phases[0].rateCards.find((rc) => rc.key === usage.key) + expect(usageRC, 'usage rate card missing after update').toBeTruthy() + expect( + usageRC?.featureKey, + 'usage rate card lost its feature binding after update', + ).toBe(features[0].key) + }) + + test('adds a defective rate card and surfaces validationErrors', async () => { + // given: + // - the current valid rate cards read back from the plan, so we don't drift + // from server-normalized values (e.g. "0.10" -> "0.1"). + const current: Plan = defined(await om.plans.get(planId)) + expect(current.phases[0].rateCards).toHaveLength(3) + validRateCards = current.phases[0].rateCards + + // - a defective flat rate card whose billing cadence (P2W) doesn't align + // with the plan's P1M cadence — surfaces a single actionable error. + const defective: RateCard = { + ...validFlatRateCard('defective_cadence'), + billingCadence: 'P2W', + } + + // when: + // - updating the draft with the defective card is accepted (drafts may carry + // validation errors). + await om.plans.update(planId, { + name: 'Sanity Plan', + billingCadence: 'P1M', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + duration: null, + rateCards: [...validRateCards, defective], + }, + ], + }) + + // then: + // - GET surfaces the cadence-unaligned validation error on the draft. + const got: Plan = defined(await om.plans.get(planId)) + expect(got.validationErrors, 'expected validationErrors on the draft').toBeTruthy() + const codes = (got.validationErrors ?? []).map((e) => e.code) + expect(codes).toContain('rate_card_billing_cadence_unaligned') + + // - publish is rejected with the same code (400). + let publishErr: unknown + try { + await om.plans.publish(planId) + } catch (e) { + publishErr = e + } + expect(isHTTPError(publishErr), 'publish should reject the defective draft').toBe(true) + expect((publishErr as { status: number }).status).toBe(400) + expect(validationCodes(publishErr)).toContain('rate_card_billing_cadence_unaligned') + }) + + test('removes the defective rate card and clears validationErrors', async () => { + // when: + // - the phase is rebuilt from the known-good baseline. + const plan: Plan = defined( + await om.plans.update(planId, { + name: 'Sanity Plan', + billingCadence: 'P1M', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + duration: null, + rateCards: validRateCards, + }, + ], + }), + ) + + // then: + // - the three valid cards remain and validationErrors clears. + expect(plan.phases[0].rateCards).toHaveLength(3) + + const got: Plan = defined(await om.plans.get(planId)) + if (got.validationErrors != null) { + expect( + got.validationErrors, + 'expected validationErrors to clear after removing the defective rate card', + ).toHaveLength(0) + } + }) + + test('creates a draft addon', async () => { + // when: + const body: AddonCreate = { + key: uniqueKey('sanity_addon'), + name: 'Test Addon sanity_addon', + currency: 'USD', + instanceType: 'single', + rateCards: [validFlatRateCard('addon_fee')], + } + const addon = defined(await om.addons.create(body)) + + // then: + expect(addon.id).toBeTruthy() + expect(addon.status).toBe('draft') + addonId = addon.id + }) + + test('publishes the addon', async () => { + const addon = defined(await om.addons.publish(addonId)) + expect(addon.status).toBe('active') + }) + + test('attaches the published addon to the plan', async () => { + // when: + const body: PlanAddonCreate = { + // v1 attaches by addonId (string); v3 nests addon: { id }. + addonId, + fromPlanPhase: phaseKey, + } + const planAddon: PlanAddon = defined(await om.plans.addons.create(planId, body)) + + // then: + // - v1 PlanAddon has no own id; it carries the full addon + phase key. + expect(planAddon.addon.id).toBe(addonId) + expect(planAddon.fromPlanPhase).toBe(phaseKey) + }) + + test('publishes the plan and keeps the attached addon', async () => { + // when: + const plan: Plan = defined(await om.plans.publish(planId)) + + // then: + // - the plan goes active with an effectiveFrom window... + expect(plan.status).toBe('active') + expect(plan.effectiveFrom).toBeTruthy() + + // - ...and the attached addon survives the transition. v1 paginates under + // `items` and the association is keyed by the addon id (no plan-addon id). + const page = defined(await om.plans.addons.list(planId)) + const found = page.items.some((pa) => pa.addon.id === addonId) + expect(found, 'attached plan-addon missing after plan publish').toBe(true) + }) +}) diff --git a/e2e/playwright/tests/productcatalog.smoke.v3.spec.ts b/e2e/playwright/tests/productcatalog.smoke.v3.spec.ts new file mode 100644 index 0000000000..c731ef5044 --- /dev/null +++ b/e2e/playwright/tests/productcatalog.smoke.v3.spec.ts @@ -0,0 +1,341 @@ +import { expect, test } from '@playwright/test' +import { isHTTPError, OpenMeter } from '@openmeter/sdk' + +// Live-server smoke for the @openmeter/sdk v3 compatibility shim (`om.v3.*`). +// +// This is the TypeScript parity of e2e/productcatalog_smoke_v3_test.go: it +// exercises the same cross-cutting plan + addon authoring flow end to end, but +// through the shim instead of raw Go HTTP. Where the Go test asserts the v3 +// wire shape directly, this one asserts the same shape coming back through the +// shim — which surfaces the wire verbatim (snake_case, "Option A"), so the +// fields read identically (status, phases[].rate_cards, validation_errors, …). +// +// Flow (identical to the Go smoke): +// - Create two meters + two features bound to them. +// - Create a draft plan with a single flat rate card. +// - Update the plan to carry flat + usage (with feature) + graduated rate cards. +// - Add a defective rate card (cadence-misaligned) and confirm the +// draft-with-errors loop: GET surfaces validation_errors, publish is +// rejected with the same code. +// - Remove the defective rate card and confirm validation_errors clears. +// - Create a draft addon and publish it. +// - Attach the published addon to the still-draft plan. +// - Publish the plan and confirm the attached addon survives the transition. +// +// Requires a running OpenMeter (no auth locally). Point it at the server with +// OPENMETER_ADDRESS (defaults to the docker-compose port used by `make -C e2e`). + +const address = process.env.OPENMETER_ADDRESS ?? 'http://localhost:38888' + +// The shim appends `/api/v3` and resolves the Bearer header only when apiKey is +// set, so the bare local server (no auth) needs only baseUrl. +const om = new OpenMeter({ baseUrl: address }) + +// uniqueKey mirrors the Go helper: a fixture key that survives re-runs against a +// shared database without collision. +function uniqueKey(prefix: string): string { + return `${prefix}_${Date.now()}_${Math.floor(Math.random() * 10_000)}` +} + +// Derive the exact request types from the shim's method signatures — the v3 +// schema types aren't re-exported from the package root, so we pull them off the +// methods instead. RateCard is the element type shared by plan rate-card arrays; +// the explicit return type narrows the discriminated `price`/`payment_term` +// literals without `as const`. +type CreatePlanBody = Parameters[0] +type RateCard = CreatePlanBody['phases'][number]['rate_cards'][number] + +// --- Fixture builders (parity with e2e/v3helpers_test.go) --- + +function validFlatRateCard(keyPrefix: string): RateCard { + return { + key: uniqueKey(keyPrefix), + name: `Test Rate Card ${keyPrefix}`, + price: { type: 'flat', amount: '10' }, + billing_cadence: 'P1M', + payment_term: 'in_advance', + } +} + +function validUnitRateCard(feature: { id: string; key: string }): RateCard { + return { + key: feature.key, + name: `Test Unit Rate Card ${feature.key}`, + price: { type: 'unit', amount: '0.10' }, + billing_cadence: 'P1M', + payment_term: 'in_arrears', + feature: { id: feature.id }, + } +} + +function validGraduatedRateCard(feature: { id: string; key: string }): RateCard { + return { + key: feature.key, + name: `Test Graduated Rate Card ${feature.key}`, + price: { + type: 'graduated', + tiers: [ + { up_to_amount: '100', unit_price: { type: 'unit', amount: '0.10' } }, + { unit_price: { type: 'unit', amount: '0.05' } }, + ], + }, + billing_cadence: 'P1M', + payment_term: 'in_arrears', + feature: { id: feature.id }, + } +} + +// validationCodes pulls the product-catalog validation codes out of a thrown +// HTTPError's problem extensions — the shim analogue of the Go +// v3Problem.ValidationErrors() helper. +function validationCodes(err: unknown): string[] { + if (!isHTTPError(err)) return [] + const extensions = err.getField('extensions') as + | { validationErrors?: Array<{ code?: string }> } + | undefined + return (extensions?.validationErrors ?? []) + .map((e) => e.code) + .filter((c): c is string => typeof c === 'string') +} + +test.describe.serial('v3 shim product catalog smoke', () => { + const meters: Array<{ id: string }> = [] + const features: Array<{ id: string; key: string }> = [] + + let planId = '' + let addonId = '' + let planAddonId = '' + let phaseKey = '' + // Track the three valid rate cards across the invalid-loop steps so the + // "remove defective" PUT can rebuild the phase from the same baseline. + let validRateCards: RateCard[] = [] + + test.beforeAll(async () => { + // given: + // - two meters and two features bound to them, the raw materials the plan's + // usage-based rate cards reference. + for (let i = 0; i < 2; i++) { + const meterKey = uniqueKey('sanity_meter') + const meter = (await om.v3.meters.create({ + key: meterKey, + name: `Test Meter ${meterKey}`, + aggregation: 'sum', + event_type: uniqueKey('sanity_event'), + value_property: '$.value', + })) as { id: string } + expect(meter.id).toBeTruthy() + meters.push(meter) + + const featureKey = uniqueKey('sanity_feature') + const feature = (await om.v3.features.create({ + key: featureKey, + name: `Test Feature ${featureKey}`, + meter: { id: meter.id }, + })) as { id: string; key: string } + expect(feature.id).toBeTruthy() + features.push(feature) + } + }) + + test('creates a draft plan with a single flat rate card', async () => { + // when: + // - a plan is created with the baseline single-flat-rate-card phase. + phaseKey = uniqueKey('phase_1') + const plan = (await om.v3.plans.create({ + key: uniqueKey('sanity_plan'), + name: 'Sanity Plan', + currency: 'USD', + billing_cadence: 'P1M', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + rate_cards: [validFlatRateCard('fee')], + }, + ], + })) as { id: string; status: string; phases: Array<{ rate_cards: unknown[] }> } + + // then: + // - it lands as a draft with the single rate card. + expect(plan.id).toBeTruthy() + expect(plan.status).toBe('draft') + expect(plan.phases).toHaveLength(1) + expect(plan.phases[0].rate_cards).toHaveLength(1) + planId = plan.id + }) + + test('updates the plan to carry flat + usage + graduated rate cards', async () => { + // given: + // - three different rate card shapes on one phase. The flat fee is + // in_advance; both usage-based ones are in_arrears (unit/graduated prices + // cannot be in_advance). Only the unit one carries a feature reference. + const flat = validFlatRateCard('sanity_flat') + const usage = validUnitRateCard(features[0]) + const graduated = validGraduatedRateCard(features[1]) + + // when: + const plan = (await om.v3.plans.update(planId, { + name: 'Sanity Plan', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + rate_cards: [flat, usage, graduated], + }, + ], + })) as { + phases: Array<{ + rate_cards: Array<{ key: string; feature?: { id: string } }> + }> + } + + // then: + // - all three rate cards round-trip and the usage card keeps its feature. + expect(plan.phases).toHaveLength(1) + expect(plan.phases[0].rate_cards).toHaveLength(3) + + const usageRC = plan.phases[0].rate_cards.find((rc) => rc.key === usage.key) + expect(usageRC, 'usage rate card missing after update').toBeTruthy() + expect( + usageRC?.feature?.id, + 'usage rate card lost its feature binding after update', + ).toBe(usage.feature?.id) + }) + + test('adds a defective rate card and surfaces validation_errors', async () => { + // given: + // - the current valid rate cards read back from the plan, so we don't drift + // from server-normalized values (e.g. "0.10" -> "0.1"). + const current = (await om.v3.plans.get(planId)) as { + phases: Array<{ rate_cards: RateCard[] }> + } + expect(current.phases[0].rate_cards).toHaveLength(3) + validRateCards = current.phases[0].rate_cards + + // - a defective flat rate card whose billing cadence (P2W) doesn't align + // with the plan's P1M cadence — picked because it surfaces a single + // actionable validation error with a useful field path. + const defective: RateCard = { + ...validFlatRateCard('defective_cadence'), + billing_cadence: 'P2W', + } + + // when: + // - updating the draft with the defective card is accepted (drafts may carry + // validation errors). + await om.v3.plans.update(planId, { + name: 'Sanity Plan', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + rate_cards: [...validRateCards, defective], + }, + ], + }) + + // then: + // - GET surfaces the cadence-unaligned validation error on the draft. + const got = (await om.v3.plans.get(planId)) as { + validation_errors?: Array<{ code: string }> + } + expect(got.validation_errors, 'expected validation_errors on the draft').toBeTruthy() + const codes = (got.validation_errors ?? []).map((e) => e.code) + expect(codes).toContain('rate_card_billing_cadence_unaligned') + + // - publish is rejected with the same code (400). + let publishErr: unknown + try { + await om.v3.plans.publish(planId) + } catch (e) { + publishErr = e + } + expect(isHTTPError(publishErr), 'publish should reject the defective draft').toBe(true) + expect((publishErr as { status: number }).status).toBe(400) + expect(validationCodes(publishErr)).toContain('rate_card_billing_cadence_unaligned') + }) + + test('removes the defective rate card and clears validation_errors', async () => { + // when: + // - the phase is rebuilt from the known-good baseline. + const plan = (await om.v3.plans.update(planId, { + name: 'Sanity Plan', + phases: [ + { + key: phaseKey, + name: 'Sanity Phase', + rate_cards: validRateCards, + }, + ], + })) as { phases: Array<{ rate_cards: unknown[] }> } + + // then: + // - the three valid cards remain and validation_errors clears. + expect(plan.phases[0].rate_cards).toHaveLength(3) + + const got = (await om.v3.plans.get(planId)) as { + validation_errors?: unknown[] + } + if (got.validation_errors != null) { + expect( + got.validation_errors, + 'expected validation_errors to clear after removing the defective rate card', + ).toHaveLength(0) + } + }) + + test('creates a draft addon', async () => { + // when: + const addon = (await om.v3.addons.create({ + key: uniqueKey('sanity_addon'), + name: 'Test Addon sanity_addon', + currency: 'USD', + instance_type: 'single', + rate_cards: [validFlatRateCard('addon_fee')], + })) as { id: string; status: string } + + // then: + expect(addon.id).toBeTruthy() + expect(addon.status).toBe('draft') + addonId = addon.id + }) + + test('publishes the addon', async () => { + const addon = (await om.v3.addons.publish(addonId)) as { status: string } + expect(addon.status).toBe('active') + }) + + test('attaches the published addon to the plan', async () => { + // when: + const planAddon = (await om.v3.plans.createAddon(planId, { + name: 'Test Plan Addon', + addon: { id: addonId }, + from_plan_phase: phaseKey, + })) as { id: string; addon: { id: string }; from_plan_phase: string } + + // then: + expect(planAddon.addon.id).toBe(addonId) + expect(planAddon.from_plan_phase).toBe(phaseKey) + planAddonId = planAddon.id + }) + + test('publishes the plan and keeps the attached addon', async () => { + // when: + const plan = (await om.v3.plans.publish(planId)) as { + status: string + effective_from?: unknown + } + + // then: + // - the plan goes active with an effective_from window... + expect(plan.status).toBe('active') + expect(plan.effective_from).toBeTruthy() + + // - ...and the attached addon survives the transition. + const page = (await om.v3.plans.listAddons(planId)) as { + data: Array<{ id: string }> + } + const found = page.data.some((pa) => pa.id === planAddonId) + expect(found, 'attached plan-addon missing after plan publish').toBe(true) + }) +}) diff --git a/e2e/playwright/tsconfig.json b/e2e/playwright/tsconfig.json new file mode 100644 index 0000000000..b52f952d98 --- /dev/null +++ b/e2e/playwright/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "nodenext", + "lib": ["ESNext"], + "types": ["node"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmit": true + }, + "include": ["tests/**/*.ts", "playwright.config.ts"] +}