Appearance
Billing
Monthly plans and credit top-ups for a workspace, charged in US dollars.
API keys can't buy credits or change plans. They can read GET /v1/billing; everything else needs a signed-in session in the Cinara app and returns 403.
Only a workspace owner or admin can buy. Any member can read the billing state.
How money becomes credits:
- Your app asks Cinara for a top-up order or a plan, and gets back what checkout needs.
- The person pays in the payment provider's checkout.
- Cinara is told by the payment provider that the money arrived, and grants the credits.
Credits are granted when the payment clears, not when checkout closes. POST /v1/billing/confirm only lets the page say "thank you" sooner.
- Top-up credits stay in the workspace while it's open.
- Plan credits reset at each renewal: the unused part of the previous month is removed before the new month's credits are granted. The same happens when a plan ends.
Endpoints:
GET /v1/billingPOST /v1/billing/topupsPOST /v1/billing/subscriptionsPOST /v1/billing/subscriptions/cancelPOST /v1/billing/confirm
Plans and packs
| Plan | Price a month | Credits a month |
|---|---|---|
| Starter | $6 | 36,000 |
| Creator | $22 | 140,000 |
| Pro | $99 | 700,000 |
| Scale | $299 | 2,100,000 |
| Pack | Price | Credits |
|---|---|---|
small | $3 | 10,000 |
medium | $15 | 50,000 |
large | $60 | 200,000 |
Prices are in US dollars, and every amount in the API is in cents (amountCents, cents).
Get the billing state
GET /v1/billing
The workspace's plan, balance, what's for sale, and its recent purchases. An API key can read this.
Response
200 OK
json
{
"plan": "free",
"credits": 8420,
"currency": "USD",
"available": false,
"canManage": true,
"subscription": null,
"plans": [
{ "id": "starter", "label": "Starter", "credits": 36000, "cents": 600, "currency": "USD" },
{ "id": "creator", "label": "Creator", "credits": 140000, "cents": 2200, "currency": "USD" },
{ "id": "pro", "label": "Pro", "credits": 700000, "cents": 9900, "currency": "USD" },
{ "id": "scale", "label": "Scale", "credits": 2100000, "cents": 29900, "currency": "USD" }
],
"topups": [
{ "id": "small", "credits": 10000, "cents": 300, "currency": "USD" },
{ "id": "medium", "credits": 50000, "cents": 1500, "currency": "USD" },
{ "id": "large", "credits": 200000, "cents": 6000, "currency": "USD" }
],
"purchases": [
{
"id": "6f2a9c41-8e3b-4d7a-b5c6-1f0d9e2a7b34",
"kind": "topup",
"plan": null,
"credits": 10000,
"amountCents": 300,
"currency": "USD",
"status": "paid",
"createdAt": "2026-09-15T12:04:11.220418+00:00",
"paidAt": "2026-09-15T12:04:39.771640+00:00"
}
]
}| Field | Description |
|---|---|
plan | The workspace's plan: free, or a paid plan's id once its first payment clears. |
credits | The workspace's credit balance. |
currency | Always USD. |
available | true when checkout is switched on. Buying returns 502 while it isn't. |
canManage | true for a workspace owner or admin: only they can buy. |
subscription | The workspace's current plan, or null. |
plans | The monthly plans for sale. |
topups | The credit packs for sale. |
purchases | The last 20 orders, newest first. status is created, paid, failed or refunded; kind is topup or plan. |
The subscription object:
| Field | Description |
|---|---|
id | Cinara's id for the plan. |
plan / planLabel | For example creator and Creator. |
status | Where the plan is: created and authenticated before the first payment clears, then active. |
credits / amountCents | What the plan grants each month, and its monthly price. |
currentStart / currentEnd | The month that's paid for, or null before the first payment. |
cancelAtPeriodEnd | true after a cancellation: the plan runs to currentEnd, then stops. |
Errors
| Status | error | Message |
|---|---|---|
| 401 | unauthorized | No key, or the key isn't valid. |
Credits
Free.
Example
bash
curl https://api.cinara.ai/v1/billing \
-H "Authorization: Bearer $CINARA_API_KEY"Buy a credit top-up
POST /v1/billing/topups
Starts a one-off purchase of credits. It creates the order; the credits arrive when the payment clears.
Needs a signed-in owner or admin, and a verified phone. API keys get 403.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
pack | string | yes | small, medium or large. |
Response
201 Created
json
{
"order": {
"id": "6f2a9c41-8e3b-4d7a-b5c6-1f0d9e2a7b34",
"kind": "topup",
"plan": null,
"credits": 10000,
"amountCents": 300,
"currency": "USD",
"status": "created",
"createdAt": "2026-09-15T12:04:11.220418+00:00",
"paidAt": null
},
"providerOrderId": "order_PkQ2r7X1aB3cD4",
"keyId": "<the checkout key>",
"amountCents": 300,
"currency": "USD",
"credits": 10000
}providerOrderId and keyId are what the payment provider's checkout needs to take the payment in the browser. Nothing is charged, and no credits are granted, until that payment clears.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Choose a credit pack |
| 403 | forbidden | API keys can't buy credits or change plans. Sign in to Cinara to do this. |
| 403 | forbidden | Only an owner or admin can buy credits. |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 502 | payment_unavailable | Payments aren't switched on yet. |
| 502 | payment_unavailable | Payment couldn't be started. Try again. |
Credits
The purchase itself is free to start. The pack's credits are granted when the payment clears.
Start a plan
POST /v1/billing/subscriptions
Starts a monthly plan. A workspace has one plan at a time.
Needs a signed-in owner or admin, and a verified phone. API keys get 403.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
plan | string | yes | starter, creator, pro or scale. |
Response
201 Created
json
{
"subscription": {
"id": "b3d7f1a9-2c4e-4b8a-9d6f-5e0c3a7b1d92",
"plan": "creator",
"planLabel": "Creator",
"status": "created",
"credits": 140000,
"amountCents": 2200,
"currency": "USD",
"currentStart": null,
"currentEnd": null,
"cancelAtPeriodEnd": false
},
"providerSubscriptionId": "sub_PkQ5t8Y2cD6eF7",
"keyId": "<the checkout key>"
}providerSubscriptionId and keyId are what checkout needs. The first month's credits are granted when the first payment clears, and the workspace's plan changes then.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Choose a plan |
| 403 | forbidden | API keys can't buy credits or change plans. Sign in to Cinara to do this. |
| 403 | forbidden | Only an owner or admin can change the plan. |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 409 | already_subscribed | This workspace is already on Creator. Cancel it first to change plan. |
| 409 | already_subscribed | This workspace already has a plan starting. |
| 502 | payment_unavailable | Payments aren't switched on yet. |
| 502 | payment_unavailable | The plan couldn't be started. Try again. |
To change plan, cancel the current one and start the new one.
Cancel a plan
POST /v1/billing/subscriptions/cancel
Stops the plan renewing. It stays active until the end of the month that's been paid for.
Needs a signed-in owner or admin, and a verified phone. API keys get 403.
Response
200 OK
json
{
"subscription": {
"id": "b3d7f1a9-2c4e-4b8a-9d6f-5e0c3a7b1d92",
"plan": "creator",
"planLabel": "Creator",
"status": "active",
"credits": 140000,
"amountCents": 2200,
"currency": "USD",
"currentStart": "2026-09-15T12:10:02.000Z",
"currentEnd": "2026-10-15T12:10:02.000Z",
"cancelAtPeriodEnd": true
},
"message": "Your plan stays active until the end of the month you've paid for."
}When the plan ends, the workspace goes back to free and the unused part of its plan credits is removed. Credits bought as top-ups stay.
Errors
| Status | error | Message |
|---|---|---|
| 403 | forbidden | API keys can't buy credits or change plans. Sign in to Cinara to do this. |
| 403 | forbidden | Only an owner or admin can change the plan. |
| 404 | not_found | There's no plan to cancel. |
| 502 | payment_unavailable | The plan couldn't be cancelled. Try again. |
Confirm a payment
POST /v1/billing/confirm
Hands Cinara what checkout reported, so the page can say "thank you" and show the new balance sooner. Credits are granted when the payment clears whether or not this is called, and calling it twice never grants twice.
Needs a signed-in session and a verified phone. API keys get 403.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
paymentId | string | yes | The payment id checkout returned. |
signature | string | yes | The signature checkout returned. |
orderId | string | one of | The providerOrderId of a top-up. |
subscriptionId | string | one of | The providerSubscriptionId of a plan. |
Response
200 OK
For a top-up:
json
{ "ok": true, "granted": true, "credits": 18420 }granted is true when this call is what added the credits, and false when they had already arrived.
For a plan:
json
{ "ok": true, "message": "Your plan is starting. Credits arrive as soon as the payment clears.", "credits": 8420 }Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | That payment couldn't be checked |
| 403 | forbidden | API keys can't buy credits or change plans. Sign in to Cinara to do this. |
| 403 | phone_unverified | Verify your phone number to start creating. |
| 404 | not_found | That payment isn't ours. |
| 404 | not_found | That plan isn't ours. |
Related
- Billing: the Billing page people use in the app.
- History and account: the balance and what each generation cost.
- Credits: how credits are reserved, settled and refunded.