{"openapi":"3.1.0","info":{"title":"VellumCharter API","version":"1.0.0","description":"Customer-facing API for VellumCharter — the monetization + entitlements layer. All routes are authenticated with a per-tenant secret API key sent in the `x-api-key` header; these clients are server-side only (never ship the key to a browser). The hot path is `GET .../entitlements`, a single key lookup returning a customer's pre-flattened entitlement blob. A `404` from that route means \"no access\", not an error."},"servers":[{"url":"https://api.vellumcharter.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"tags":[{"name":"Entitlements"},{"name":"Checkout & subscriptions"},{"name":"Billing"},{"name":"Provisioning"},{"name":"Credits"}],"paths":{"/tenants/{tenantId}/customers/{customerId}/entitlements":{"get":{"tags":["Entitlements"],"summary":"Read a customer's resolved entitlements","description":"The hot path. Returns the customer's pre-flattened entitlement blob. A `404` is the normal \"no access / no record\" outcome — SDKs map it to an empty, no-access set.","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/customerId"}],"responses":{"200":{"description":"The resolved entitlements.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entitlements"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No entitlement record for this customer (treat as no access).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementsNotFound"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/checkout":{"post":{"tags":["Checkout & subscriptions"],"summary":"Create a hosted Checkout session for a customer","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"The hosted checkout URL to redirect the customer to.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutUrlResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscribe":{"post":{"tags":["Checkout & subscriptions"],"summary":"Create a subscription for a customer server-side (no hosted page)","description":"Creates a (optionally trialing) subscription directly. Use this when the account already has a payment method on file; otherwise use checkout or setup-checkout first.","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"}}}},"responses":{"201":{"description":"The created subscription id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tenants/{tenantId}/accounts/{accountId}/billing/setup-checkout":{"post":{"tags":["Billing"],"summary":"Create a setup-mode Checkout session to capture a payment method","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupCheckoutRequest"}}}},"responses":{"200":{"description":"The hosted setup URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutUrlResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tenants/{tenantId}/accounts/{accountId}/payment-methods":{"get":{"tags":["Billing"],"summary":"List the account's saved card payment methods","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"}],"responses":{"200":{"description":"The account's cards.","content":{"application/json":{"schema":{"type":"object","required":["methods"],"properties":{"methods":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMethod"}}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NoBillingCustomer"}}}},"/tenants/{tenantId}/accounts/{accountId}/payment-methods/{methodId}":{"patch":{"tags":["Billing"],"summary":"Set the account's default payment method","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/methodId"}],"responses":{"200":{"description":"The new default method id.","content":{"application/json":{"schema":{"type":"object","required":["default"],"properties":{"default":{"type":"string"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NoBillingCustomer"}}},"delete":{"tags":["Billing"],"summary":"Detach a payment method from the account","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/methodId"}],"responses":{"200":{"description":"The detached method id.","content":{"application/json":{"schema":{"type":"object","required":["removed"],"properties":{"removed":{"type":"string"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/payment-method":{"patch":{"tags":["Billing"],"summary":"Override the default payment method on a customer's subscription","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["methodId"],"properties":{"methodId":{"type":"string"}}}}}},"responses":{"200":{"description":"The updated subscription + default method.","content":{"application/json":{"schema":{"type":"object","required":["subscription","default"],"properties":{"subscription":{"type":"string"},"default":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The customer has no subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/invoices":{"get":{"tags":["Billing"],"summary":"List invoices for an account (optionally one customer)","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"name":"customerId","in":"query","required":false,"description":"Filter to the named customer's subscription invoices.","schema":{"type":"string"}}],"responses":{"200":{"description":"The invoices (most recent first).","content":{"application/json":{"schema":{"type":"object","required":["invoices"],"properties":{"invoices":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NoBillingCustomer"}}}},"/tenants/{tenantId}/accounts/{accountId}/invoices/{invoiceId}/pdf":{"get":{"tags":["Billing"],"summary":"Redirect to an invoice's hosted PDF","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"name":"invoiceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to the hosted invoice PDF.","headers":{"Location":{"description":"The hosted PDF URL.","schema":{"type":"string","format":"uri"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The invoice has no PDF.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscription":{"get":{"tags":["Checkout & subscriptions"],"summary":"Get a customer's current subscription","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"responses":{"200":{"description":"The customer's live subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The customer has no subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Checkout & subscriptions"],"summary":"Set a customer's full subscription state (declarative)","description":"Reconciles the live subscription to the desired shape in one Stripe update (proration applies immediately). Omitting addOnModuleIds means no add-ons; omitting seats keeps the current count.","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDesiredState"}}}},"responses":{"200":{"description":"The updated subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The customer has no subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Checkout & subscriptions"],"summary":"Cancel a customer's subscription","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"},{"name":"atPeriodEnd","in":"query","required":false,"description":"Cancel at period end instead of immediately.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"The cancellation result.","content":{"application/json":{"schema":{"type":"object","required":["canceled","atPeriodEnd"],"properties":{"canceled":{"type":"string","description":"The customer id."},"atPeriodEnd":{"type":"boolean"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The customer has no subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscription/seats":{"patch":{"tags":["Checkout & subscriptions"],"summary":"Change the subscription's seat count","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["seats"],"properties":{"seats":{"type":"integer","minimum":1}}}}}},"responses":{"200":{"description":"Updated subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscription/add-ons":{"patch":{"tags":["Checkout & subscriptions"],"summary":"Add or remove priced add-on modules","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddOnsPatch"}}}},"responses":{"200":{"description":"Updated subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscription/plan":{"patch":{"tags":["Checkout & subscriptions"],"summary":"Change the subscription's tier (plan version)","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["planId","planVersion"],"properties":{"planId":{"type":"string"},"planVersion":{"type":"integer"}}}}}},"responses":{"200":{"description":"Updated subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscription/preview":{"post":{"tags":["Checkout & subscriptions"],"summary":"Preview the cost of a subscription change (stateless)","description":"Returns the immediate proration charge/credit and next invoice total for a proposed change. Any subset of the desired state may be sent for a what-if; omitted fields keep their current value. Send the same body to PUT to apply.","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDesiredState"}}}},"responses":{"200":{"description":"The cost preview.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionPreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}/subscription/reactivate":{"post":{"tags":["Checkout & subscriptions"],"summary":"Clear a pending period-end cancellation","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"responses":{"200":{"description":"The reactivated subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tenants/{tenantId}/accounts":{"post":{"tags":["Provisioning"],"summary":"Create an account (the billing entity that holds a subscription)","parameters":[{"$ref":"#/components/parameters/tenantId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountRequest"}}}},"responses":{"201":{"description":"The created account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/tenants/{tenantId}/accounts/{accountId}":{"patch":{"tags":["Provisioning"],"summary":"Update an account's operational status","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusUpdateRequest"}}}},"responses":{"200":{"description":"The updated account.","content":{"application/json":{"schema":{"type":"object","required":["accountId","status"],"properties":{"accountId":{"type":"string"},"status":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/tenants/{tenantId}/accounts/{accountId}/customers":{"post":{"tags":["Provisioning"],"summary":"Create a customer (member) under an account","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerRequest"}}}},"responses":{"201":{"description":"The created customer.","content":{"application/json":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/tenants/{tenantId}/accounts/{accountId}/customers/{customerId}":{"patch":{"tags":["Provisioning"],"summary":"Update a customer's operational status","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"},{"$ref":"#/components/parameters/customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusUpdateRequest"}}}},"responses":{"200":{"description":"The updated customer.","content":{"application/json":{"schema":{"type":"object","required":["customerId","status"],"properties":{"customerId":{"type":"string"},"status":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/tenants/{tenantId}/accounts/{accountId}/credit-checkout":{"post":{"tags":["Credits"],"summary":"Create a one-time Checkout session to buy a credit pack","description":"A one-time (non-recurring) hosted Checkout for a prepaid credit pack. Billing flows through the account's billing customer; the credits land in the named customer's wallet once payment completes. Buy several packs at once with `quantity`.","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/accountId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditCheckoutRequest"}}}},"responses":{"200":{"description":"The hosted checkout URL to redirect the customer to.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutUrlResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tenants/{tenantId}/customers/{customerId}/credits":{"get":{"tags":["Credits"],"summary":"List a customer's prepaid credit balances","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/customerId"}],"responses":{"200":{"description":"The customer's wallets, one per credit type they hold.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditBalances"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/tenants/{tenantId}/customers/{customerId}/credits/{creditTypeId}":{"get":{"tags":["Credits"],"summary":"Read one prepaid credit balance","description":"A never-purchased wallet reads as `balance: 0` (not a 404).","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/creditTypeId"}],"responses":{"200":{"description":"The balance for this credit type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditBalance"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/tenants/{tenantId}/customers/{customerId}/credits/{creditTypeId}/consume":{"post":{"tags":["Credits"],"summary":"Consume credits from a customer's wallet","description":"Atomically deducts `amount` credits, all-or-nothing. Supply a stable `idempotencyKey` (e.g. the game id): a retried call with the same key is a safe no-op that returns the already-applied balance with `duplicate: true`. A `409` means the wallet has fewer than `amount` credits (nothing deducted).","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/creditTypeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsumeRequest"}}}},"responses":{"200":{"description":"Credits consumed (or a duplicate no-op); the resulting balance.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsumeResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/InsufficientCredits"}}}},"/tenants/{tenantId}/credit-types":{"get":{"tags":["Credits"],"summary":"List the tenant's credit types","description":"The catalog of credit types a consuming app can offer. Read-only and tenant-scoped (not per customer) — use it to render a \"buy credits\" UI.","parameters":[{"$ref":"#/components/parameters/tenantId"}],"responses":{"200":{"description":"The tenant's credit types.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditTypes"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/tenants/{tenantId}/credit-types/{creditTypeId}/packs":{"get":{"tags":["Credits"],"summary":"List the packs for sale within a credit type","description":"The purchasable packs (denominations) for one credit type, with their grant size and price. Pass a pack's `packId` to credit-checkout to buy it. Billing-provider ids are intentionally not exposed.","parameters":[{"$ref":"#/components/parameters/tenantId"},{"$ref":"#/components/parameters/creditTypeId"}],"responses":{"200":{"description":"The packs for this credit type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditPacks"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}}},"webhooks":{"entitlementChange":{"post":{"summary":"Entitlement-change push (VellumCharter → your endpoint)","description":"When a customer's entitlements change, VellumCharter POSTs this event to a tenant's configured push URL. Best-effort: up to 3 attempts; any 2xx acknowledges. Pull-first (the entitlements endpoint) remains the default — push exists for tenants whose side effects must fire immediately.","security":[],"parameters":[{"name":"vellumcharter-signature","in":"header","required":true,"description":"`t=<unix>,v1=<hex>` where `hex = HMAC-SHA256(pushSecret, \"<t>.<rawBody>\")`. Verify against the raw request body and reject timestamps outside a 300s tolerance. The SDKs ship `verify_push_signature` / equivalent.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushEvent"}}}},"responses":{"200":{"description":"Acknowledged. Any 2xx acks; a non-2xx triggers a retry."}}}}},"components":{"securitySchemes":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key"}},"parameters":{"tenantId":{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}},"accountId":{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}},"customerId":{"name":"customerId","in":"path","required":true,"schema":{"type":"string"}},"methodId":{"name":"methodId","in":"path","required":true,"schema":{"type":"string"}},"creditTypeId":{"name":"creditTypeId","in":"path","required":true,"schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"Invalid request (missing/invalid parameters or body).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The API key's tenant does not match the path tenant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"The target resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NoBillingCustomer":{"description":"The account has no billing customer set up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InsufficientCredits":{"description":"The wallet has fewer than the requested credits; nothing was deducted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCredits"}}}}},"schemas":{"AddOnsPatch":{"type":"object","description":"Add and/or remove priced add-on module ids the tier offers.","properties":{"add":{"type":"array","items":{"type":"string"}},"remove":{"type":"array","items":{"type":"string"}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"Entitlements":{"type":"object","required":["modules","config"],"properties":{"accountId":{"type":"string"},"planId":{"type":"string"},"planVersion":{"type":"integer"},"status":{"type":"string","description":"Subscription status, e.g. active, trialing, past_due, canceled."},"currentPeriodEnd":{"type":"string","format":"date-time"},"modules":{"type":"array","items":{"type":"string"},"description":"The module ids the customer may use right now."},"config":{"type":"object","additionalProperties":true,"description":"Flattened config values (e.g. max_users)."},"billingSubscriptionId":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"EntitlementsNotFound":{"type":"object","required":["tenantId","customerId","error"],"properties":{"tenantId":{"type":"string"},"customerId":{"type":"string"},"error":{"type":"string","example":"no entitlements"}}},"CheckoutRequest":{"type":"object","required":["customerId","planId","planVersion","successUrl","cancelUrl"],"properties":{"customerId":{"type":"string"},"planId":{"type":"string"},"planVersion":{"type":"integer"},"seats":{"type":"integer","minimum":1,"default":1},"addOnModuleIds":{"type":"array","items":{"type":"string"},"description":"Priced add-on module ids the tier offers; added as extra line items."},"successUrl":{"type":"string","format":"uri"},"cancelUrl":{"type":"string","format":"uri"}}},"CheckoutUrlResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}},"CreditCheckoutRequest":{"type":"object","description":"Buy credits in one Checkout. Either pass a single `creditTypeId` + `packId` (+ optional `quantity`), or pass `items` to buy several packs at once (denominations and credit types may be mixed); all credits land in the one named customer's wallets.","required":["customerId","successUrl","cancelUrl"],"properties":{"customerId":{"type":"string","description":"The customer whose wallet the purchased credits land in."},"creditTypeId":{"type":"string","description":"Single-pack form; ignored when `items` is given."},"packId":{"type":"string","description":"Single-pack form — the pack SKU to buy; ignored when `items` is given."},"quantity":{"type":"integer","minimum":1,"default":1,"description":"Single-pack form — how many of `packId` to buy; grants grantQty × quantity."},"items":{"type":"array","description":"Multi-denomination form — one line per pack. Takes precedence over `packId`.","items":{"$ref":"#/components/schemas/CreditCheckoutItem"}},"successUrl":{"type":"string","format":"uri"},"cancelUrl":{"type":"string","format":"uri"}}},"CreditCheckoutItem":{"type":"object","required":["creditTypeId","packId"],"properties":{"creditTypeId":{"type":"string"},"packId":{"type":"string","description":"The pack SKU to buy (sets the grant size + price)."},"quantity":{"type":"integer","minimum":1,"default":1,"description":"How many of this pack to buy; grants grantQty × quantity."}}},"ConsumeRequest":{"type":"object","required":["amount","idempotencyKey"],"properties":{"amount":{"type":"integer","minimum":1,"description":"How many credits to deduct, all-or-nothing."},"idempotencyKey":{"type":"string","description":"Stable per logical operation (e.g. `game:<id>:start`). A retry with the same key is a safe no-op. Scoped to this (customer, creditType)."}}},"ConsumeResponse":{"type":"object","required":["creditTypeId","consumed","balance","duplicate"],"properties":{"creditTypeId":{"type":"string"},"consumed":{"type":"integer","description":"The amount requested (and deducted, unless duplicate)."},"balance":{"type":"integer","description":"The wallet balance after this operation."},"duplicate":{"type":"boolean","description":"True when the idempotencyKey had already been applied (no new deduction)."}}},"CreditBalance":{"type":"object","required":["creditTypeId","balance"],"properties":{"creditTypeId":{"type":"string"},"balance":{"type":"integer"}}},"CreditBalances":{"type":"object","required":["credits"],"properties":{"credits":{"type":"array","items":{"$ref":"#/components/schemas/CreditBalance"}}}},"CreditType":{"type":"object","required":["creditTypeId","name"],"properties":{"creditTypeId":{"type":"string"},"name":{"type":"string"}}},"CreditTypes":{"type":"object","required":["creditTypes"],"properties":{"creditTypes":{"type":"array","items":{"$ref":"#/components/schemas/CreditType"}}}},"CreditPack":{"type":"object","required":["creditTypeId","packId","name","grantQty"],"properties":{"creditTypeId":{"type":"string"},"packId":{"type":"string"},"name":{"type":"string"},"grantQty":{"type":"integer","description":"Credits granted per unit purchased."},"amount":{"type":"integer","description":"Price in the currency's minor units (e.g. cents)."},"currency":{"type":"string","description":"ISO currency code","e.g. `usd`.":null}}},"CreditPacks":{"type":"object","required":["packs"],"properties":{"packs":{"type":"array","items":{"$ref":"#/components/schemas/CreditPack"}}}},"InsufficientCredits":{"type":"object","required":["error","balance"],"properties":{"error":{"type":"string","example":"insufficient credits"},"balance":{"type":"integer","description":"The current (unchanged) wallet balance."}}},"SubscribeRequest":{"type":"object","required":["planId","planVersion"],"properties":{"planId":{"type":"string"},"planVersion":{"type":"integer"},"seats":{"type":"integer","minimum":1,"default":1},"addOnModuleIds":{"type":"array","items":{"type":"string"}}}},"SubscribeResponse":{"type":"object","required":["subscriptionId"],"properties":{"subscriptionId":{"type":"string"}}},"SetupCheckoutRequest":{"type":"object","required":["successUrl","cancelUrl"],"properties":{"successUrl":{"type":"string","format":"uri"},"cancelUrl":{"type":"string","format":"uri"}}},"PaymentMethod":{"type":"object","required":["id","isDefault"],"properties":{"id":{"type":"string"},"brand":{"type":"string"},"last4":{"type":"string"},"expMonth":{"type":"integer"},"expYear":{"type":"integer"},"name":{"type":"string","description":"Cardholder name from the billing details."},"isDefault":{"type":"boolean"}}},"Invoice":{"type":"object","required":["id","status","amountDue","amountPaid","subtotal","total","paid","currency","created"],"properties":{"id":{"type":"string"},"number":{"type":["string","null"]},"status":{"type":["string","null"]},"amountDue":{"type":"integer","description":"Smallest currency unit (e.g. cents)."},"amountPaid":{"type":"integer"},"subtotal":{"type":"integer","description":"Total before tax","smallest currency unit.":null},"total":{"type":"integer","description":"Total after tax","smallest currency unit.":null},"tax":{"type":["integer","null"],"description":"Tax amount","smallest currency unit.":null},"paid":{"type":"boolean"},"currency":{"type":"string"},"created":{"type":"string","format":"date-time"},"hostedInvoiceUrl":{"type":["string","null"],"format":"uri"},"invoicePdf":{"type":["string","null"],"format":"uri"}}},"SubscriptionView":{"type":"object","required":["id","status","cancelAtPeriodEnd"],"properties":{"id":{"type":"string"},"status":{"type":"string"},"cancelAtPeriodEnd":{"type":"boolean"},"seats":{"type":"integer"},"amount":{"type":"integer","description":"Recurring price per seat","smallest currency unit.":null},"currency":{"type":"string"},"interval":{"type":"string","description":"Billing interval of the recurring price","e.g. month or year.":null},"currentPeriodStart":{"type":"string","format":"date-time"},"currentPeriodEnd":{"type":"string","format":"date-time"},"trialEnd":{"type":"string","format":"date-time","description":"When the trial ends","if trialing.":null},"canceledAt":{"type":"string","format":"date-time","description":"When the subscription was canceled","if it has been.":null},"defaultPaymentMethod":{"type":"string","description":"The subscription's default payment-method id","when set.":null}}},"SubscriptionDesiredState":{"type":"object","required":["planId","planVersion"],"properties":{"planId":{"type":"string"},"planVersion":{"type":"integer"},"seats":{"type":"integer","minimum":1,"description":"Defaults to the current seat count when omitted."},"addOnModuleIds":{"type":"array","items":{"type":"string"},"description":"Priced add-on module ids the tier offers. Omitted = no add-ons."}}},"SubscriptionPreview":{"type":"object","required":["immediateCharge","credit","nextInvoiceTotal","currency","lines"],"properties":{"immediateCharge":{"type":"integer","description":"Sum of positive proration lines","smallest currency unit.":null},"credit":{"type":"integer","description":"Sum of negative proration lines (<= 0)."},"nextInvoiceTotal":{"type":"integer"},"currency":{"type":"string"},"lines":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string"},"amount":{"type":"integer"}}}}}},"CreateAccountRequest":{"type":"object","required":["accountId"],"properties":{"accountId":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"billingCustomerId":{"type":"string","description":"Adopt an existing billing customer id instead of creating one."},"createBillingCustomer":{"type":"boolean","description":"Create a new billing customer (ignored when billingCustomerId is given)."}}},"CreateAccountResponse":{"type":"object","required":["accountId"],"properties":{"accountId":{"type":"string"},"billingCustomerId":{"type":"string"}}},"CreateCustomerRequest":{"type":"object","required":["customerId"],"properties":{"customerId":{"type":"string"},"email":{"type":"string","format":"email"}}},"StatusUpdateRequest":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}}},"PushEvent":{"type":"object","required":["type","tenantId","accountId","customerId","status","planId","planVersion","modules"],"properties":{"type":{"type":"string","description":"The VellumCharter-native event; consumers switch on this.","enum":["subscription.created","subscription.updated","subscription.canceled","subscription.paused","subscription.resumed","subscription.trial_will_end","payment.succeeded","payment.failed","payment.action_required"]},"tenantId":{"type":"string"},"accountId":{"type":"string"},"customerId":{"type":"string"},"status":{"type":"string"},"planId":{"type":"string"},"planVersion":{"type":"integer"},"modules":{"type":"array","items":{"type":"string"}},"currentPeriodEnd":{"type":"string","format":"date-time"},"seats":{"type":"integer","description":"Seat count on the subscription","when known.":null},"invoice":{"type":"object","description":"Present only on payment.* events; the invoice that triggered the push.","required":["id","amountDue","amountPaid","currency"],"properties":{"id":{"type":"string"},"number":{"type":["string","null"]},"status":{"type":["string","null"]},"amountDue":{"type":"integer","description":"Smallest currency unit (e.g. cents)."},"amountPaid":{"type":"integer"},"currency":{"type":"string"},"hostedInvoiceUrl":{"type":["string","null"],"format":"uri"},"invoicePdf":{"type":["string","null"],"format":"uri"}}}}}}}}