Zumik
v2 · Native state

Billing

Read the billing account, set a monthly budget, opt into overage, start Stripe Checkout, open the customer portal, and the Stripe webhook contract.

Stripe is the source of truth for money; Zumik keeps the projection it needs to enforce caps inline with inference. The console reads the account, sets budgets, opts into overage, and starts Checkout; Stripe webhooks credit prepaid balances and refresh subscription state. Money is tracked in integer micro-USD (1e-6 USD). See the billing and budgets guide.

All endpoints except the webhook require a bearer API key. See authentication.

Read the account

GET /v2/billing/account

curl https://api.zumik.ai/v2/billing/account \
  -H "Authorization: Bearer $ZUMIK_API_KEY"
{
  "id": "prj_01jy7n0a4c8m2t6v9q3wrxk7bd",
  "object": "billing_account",
  "project_id": "prj_01jy7n0a4c8m2t6v9q3wrxk7bd",
  "plan": "base",
  "subscription_status": "active",
  "credit_balance_micros": 4250000,
  "cycle_spend_micros": 750000,
  "monthly_budget_micros": 20000000,
  "overage_mode": "pause",
  "created_at": "2026-06-01T00:00:00Z",
  "updated_at": "2026-06-15T16:40:11Z"
}
objectstring

Always billing_account.

project_idstring

The owning project.

planstring

The plan tier: free, base, or pilot.

stripe_customer_idstring

The Stripe customer id, omitted until a payment method is linked. Never a card number.

subscription_statusstring

none, active, past_due, or canceled. Inference is allowed only when active.

credit_balance_microsinteger

Remaining prepaid plus allowance credits this cycle, in micro-USD.

cycle_spend_microsinteger

Spend accumulated this cycle, in micro-USD.

monthly_budget_microsinteger

The hard monthly cap, omitted when none is set.

overage_modestring

pause (default) or allow.

created_atstring
RFC 3339 timestamp.
updated_atstring
RFC 3339 timestamp.

Set a monthly budget

POST /v2/billing/budget

Sets the hard monthly cap and re-arms the 50/80/100% alert ladder for the cycle.

monthly_budget_usdnumber

The cap in whole USD. Must be non-negative. null removes the cap.

curl https://api.zumik.ai/v2/billing/budget \
  -H "Authorization: Bearer $ZUMIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "monthly_budget_usd": 20 }'

Returns the updated billing account.

Opt into overage

POST /v2/billing/overage

When overage is off (the default), inference pauses at the cap with quota_exceeded. Enabling it bills past the cap at pay-as-you-go rates and requires explicit confirmation.

allow_overagebooleanrequired

true to bill past the cap, false to pause at it.

confirmboolean

Must be true when allow_overage is true.

curl https://api.zumik.ai/v2/billing/overage \
  -H "Authorization: Bearer $ZUMIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "allow_overage": true, "confirm": true }'

Returns the updated billing account with overage_mode set.

Add credits (PaymentIntent)

POST /v2/billing/payment-intent

Creates a Stripe PaymentIntent for a amount_usd credit top-up and returns its client secret plus the publishable key. The console mounts the Stripe Payment Element with these, so the card is entered inline on Zumik — the customer never leaves the app, and card data goes from the browser straight to Stripe (it never touches Zumik's servers). The card is saved for off-session auto-recharge. The webhook credits the balance on payment_intent.succeeded.

amount_usdnumberrequired

Credits to add, in whole USD. Must be between $5 and $10,000.

curl -X POST https://api.zumik.ai/v2/billing/payment-intent \
  -H "Authorization: Bearer $ZUMIK_API_KEY" \
  -H "content-type: application/json" \
  -d '{"amount_usd": 25}'
{
  "client_secret": "pi_..._secret_...",
  "publishable_key": "pk_live_...",
  "amount_usd": 25
}
client_secretstring

The PaymentIntent client secret. Pass it to Stripe.js to confirm the payment client-side.

publishable_keystring

The Stripe publishable key for mounting the Payment Element.

Auto-recharge

POST /v2/billing/auto-recharge

Configure balance-triggered auto top-up. When on and the credit balance falls to or below threshold_usd, Zumik charges the saved card for amount_usd off-session. Enabling requires a saved card (made by a prior top-up). Returns the updated billing account.

enabledbooleanrequired

Turn auto-recharge on or off.

threshold_usdnumber

Recharge when the balance falls to or below this (USD). Default $5.

amount_usdnumber

How much to add per recharge (USD), $5-$10,000. Default $25.

curl -X POST https://api.zumik.ai/v2/billing/auto-recharge \
  -H "Authorization: Bearer $ZUMIK_API_KEY" \
  -H "content-type: application/json" \
  -d '{"enabled": true, "threshold_usd": 5, "amount_usd": 25}'

Open the customer portal

POST /v2/billing/portal

Opens the Stripe customer portal so the user can update their card or view invoices. Requires an existing Stripe customer (i.e. they have made a top-up).

curl -X POST https://api.zumik.ai/v2/billing/portal \
  -H "Authorization: Bearer $ZUMIK_API_KEY"
{ "url": "https://billing.stripe.com/p/session/..." }
urlstring

The hosted Stripe billing-portal URL.

Stripe webhook

POST /v2/billing/stripe-webhook

The endpoint Stripe posts events to. It is unauthenticated at the bearer-token layer and authenticates by verifying the Stripe-Signature header against the configured webhook secret before any state change. It is not called by your application.

It acts on checkout.session.completed, invoice.payment_succeeded, invoice.payment_failed, and customer.subscription.deleted for subscriptions, and invoice.payment_succeeded/invoice.paid, invoice.voided, and invoice.finalized for enterprise contracts (routed by the invoice's contract_id metadata). Unknown event types are acknowledged and ignored.

{ "received": true }
receivedboolean

Always true once a verified event is accepted.

Enterprise contracts

Negotiated annual deals are billed with Stripe Invoicing, not the self-serve credit top-up. These endpoints require an API key with the admin scope.

A contract moves open (invoice issued) → paid (the contract invoice is paid, which sets the account to the enterprise plan, marks it active, and grants the contract's credit allowance for the term) or void. The term is term_months from the paid date. Renewal issues a fresh invoice on the same terms.

Create a contract

POST /v2/billing/enterprise/contracts

Creates (or reuses) the project's Stripe customer, adds an invoice item for the annual value, then finalizes and sends a collection invoice carrying the project and contract metadata.

annual_price_usdnumberrequired

The negotiated annual contract value billed on the invoice.

credit_allowance_usdnumberrequired

Inference credit granted to the account when the invoice is paid.

term_monthsintegerdefault: 12

Contract term, 1–60 months.

customer_emailstring

Billing email. Required when the project has no Stripe customer yet.

descriptionstring

Line-item description shown on the invoice.

{
  "id": "ent_01jy...",
  "object": "enterprise_contract",
  "project_id": "prj_01jy...",
  "status": "open",
  "annual_price_micros": 120000000000,
  "credit_allowance_micros": 50000000000,
  "term_months": 12,
  "stripe_customer_id": "cus_...",
  "stripe_invoice_id": "in_...",
  "hosted_invoice_url": "https://invoice.stripe.com/i/...",
  "created_at": "2026-06-15T16:00:00Z",
  "updated_at": "2026-06-15T16:00:00Z"
}

List / retrieve

GET /v2/billing/enterprise/contracts returns { "object": "list", "data": [...] }, newest first. GET /v2/billing/enterprise/contracts/{id} returns one contract.

Void

POST /v2/billing/enterprise/contracts/{id}/void voids the contract's open Stripe invoice and marks the contract void. A paid contract can't be voided (issue a credit note in Stripe instead).

Renew

POST /v2/billing/enterprise/contracts/{id}/renew issues the next term's invoice on the same price, allowance, and term, returning the new contract. The account is re-credited when that invoice is paid.

Errors

StatusCodeWhen
400invalid_request_errorNegative budget, overage without confirm: true, billing not configured, a non-positive annual_price_usd, voiding a paid contract, or Stripe rejected the request.
401invalid_api_keyMissing or invalid API key, or an invalid Stripe signature on the webhook.
403insufficient_scopeAn enterprise endpoint called without an admin-scoped key.
404invalid_request_errorThe contract does not exist in this project.

See the full table on errors.

On this page