Appearance
Billing
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.
How credits behave:
- Plan credits arrive every month. Unused ones roll over for up to two more months, then expire, and plan credits are capped at three months of the plan. A yearly plan is charged once a year and still grants credits monthly.
- Free credits: a workspace on the free plan is topped back up to 10,000 credits each month. They don't roll over.
- Bought credits (top-ups) don't end with a plan.
- Credits are used in that order: plan credits (oldest first), then free credits, then bought ones.
- Speech through an API key costs 0.6 credits a character instead of 1.
Endpoints:
GET /v1/billingPOST /v1/billing/topupsPOST /v1/billing/subscriptionsPOST /v1/billing/subscriptions/changePOST /v1/billing/subscriptions/cancelPOST /v1/billing/confirm
Plans and packs
| Plan | id | A month | A year | Credits a month |
|---|---|---|---|---|
| Starter | starter | $6 | $60 | 43,000 |
| Creator | creator | $22 ($11 the first month for new subscribers) | $220 | 175,000 |
| Pro | pro | $99 | $990 | 860,000 |
| Scale | scale | $299 | $2,990 | 2,600,000 |
| Business | business | $990 | $9,900 | 8,600,000 |
| Pack | Price | Credits |
|---|---|---|
small | $10 | 35,000 |
medium | $20 | 75,000 |
large | $50 | 200,000 |
bulk | $100 | 425,000 |
Prices are in US dollars, and every amount in the API is in cents (amountCents, cents, yearlyCents, introCents).
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": 12580,
"currency": "USD",
"available": true,
"keyId": "<the checkout key>",
"canManage": true,
"subscription": null,
"plans": [
{
"id": "starter",
"label": "Starter",
"credits": 43000,
"cents": 600,
"yearlyCents": 6000,
"introCents": null,
"currency": "USD"
},
{
"id": "creator",
"label": "Creator",
"credits": 175000,
"cents": 2200,
"yearlyCents": 22000,
"introCents": 1100,
"currency": "USD"
},
{
"id": "pro",
"label": "Pro",
"credits": 860000,
"cents": 9900,
"yearlyCents": 99000,
"introCents": null,
"currency": "USD"
},
{
"id": "scale",
"label": "Scale",
"credits": 2600000,
"cents": 29900,
"yearlyCents": 299000,
"introCents": null,
"currency": "USD"
},
{
"id": "business",
"label": "Business",
"credits": 8600000,
"cents": 99000,
"yearlyCents": 990000,
"introCents": null,
"currency": "USD"
}
],
"introEligible": true,
"balance": {
"planCredits": 0,
"otherCredits": 12580,
"expiring": []
},
"free": {
"monthlyCredits": 10000,
"nextRefillAt": "2026-10-14T17:50:36.000Z"
},
"apiRates": {
"speechPerCharacter": 0.6,
"transcribePerMinute": 100
},
"rollover": {
"months": 2,
"capMonths": 3
},
"topups": [
{
"id": "small",
"credits": 35000,
"cents": 1000,
"currency": "USD"
},
{
"id": "medium",
"credits": 75000,
"cents": 2000,
"currency": "USD"
},
{
"id": "large",
"credits": 200000,
"cents": 5000,
"currency": "USD"
},
{
"id": "bulk",
"credits": 425000,
"cents": 10000,
"currency": "USD"
}
],
"rates": [
{
"id": "speech",
"name": "Speech",
"group": "Voice",
"credits": 1,
"unit": "character",
"note": "Narration and voiceover in 37 languages. HD voices are 2 credits a character."
},
{
"id": "dialogue",
"name": "Dialogue",
"group": "Voice",
"credits": 1,
"unit": "character",
"note": "A scene with a voice for every character, at the same rate as Speech."
}
],
"purchases": []
}rates lists every tool (two are shown above). purchases holds the last 20 orders.
| 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. |
keyId | The public checkout key, for reopening checkout on a plan waiting for payment. |
canManage | true for a workspace owner or admin: only they can buy. |
subscription | The workspace's current plan, or null. |
plans | The plans for sale. yearlyCents is the yearly price; introCents is Creator's first-month price, set only when introEligible. |
introEligible | true for a workspace that has never paid for a plan. |
balance.planCredits | How much of credits is plan credits, which can expire. |
balance.otherCredits | Bought and free credits. |
balance.expiring | Plan credits still held, oldest first, each with the date it expires. |
free | On the free plan: monthlyCredits and nextRefillAt. Otherwise null. |
apiRates | What an API key pays: speechPerCharacter and transcribePerMinute. |
rollover | months a plan grant rolls over, and the cap in capMonths. |
topups | The credit packs for sale. |
rates | Every tool's credit rate: credits per unit, with paidOnly on tools only paid plans can use. |
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 | created and authenticated before the first payment clears, then active. |
interval | month or year. |
credits / amountCents / yearlyCents | What the plan grants each month, and its monthly and yearly price. |
introOffer | true while on Creator's first-month price. |
currentStart / currentEnd | The period that's paid for, or null before the first payment. |
nextGrantAt | On a yearly plan, when next month's credits arrive. |
pendingPlan / pendingPlanLabel | A cheaper plan waiting to start at renewal, or null. |
cancelAtPeriodEnd | true after a cancellation: the plan runs to currentEnd, then stops. |
canChangePlan | false once a plan is set to end. |
checkoutId | Set while a plan waits for its first payment: pass it to checkout to finish paying. |
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, large or bulk. |
Response
201 Created
json
{
"order": {
"id": "6f2a9c41-8e3b-4d7a-b5c6-1f0d9e2a7b34",
"kind": "topup",
"plan": null,
"credits": 35000,
"amountCents": 1000,
"currency": "USD",
"status": "created",
"createdAt": "2026-09-15T12:04:11.220418+00:00",
"paidAt": null
},
"providerOrderId": "order_PkQ2r7X1aB3cD4",
"keyId": "<the checkout key>",
"amountCents": 1000,
"currency": "USD",
"credits": 35000
}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 or yearly 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, scale or business. |
interval | string | no | month (default) or year. Creator's first-month price applies to monthly plans for workspaces that have never paid for one. |
Response
201 Created
json
{
"subscription": {
"id": "b3d7f1a9-2c4e-4b8a-9d6f-5e0c3a7b1d92",
"plan": "creator",
"planLabel": "Creator",
"status": "created",
"credits": 175000,
"amountCents": 2200,
"yearlyCents": 22000,
"currency": "USD",
"currentStart": null,
"currentEnd": null,
"cancelAtPeriodEnd": false,
"interval": "month",
"introOffer": true,
"nextGrantAt": null,
"pendingPlan": null,
"pendingPlanLabel": null,
"canChangePlan": true,
"checkoutId": "sub_PkQ5t8Y2cD6eF7"
},
"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. Choose the plan you want instead and Cinara will move you over. |
| 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 move to another plan, use Change plan.
Change plan
POST /v1/billing/subscriptions/change
Moves the workspace to another plan without cancelling first.
- A plan nobody has paid for yet is replaced: the response has
needsPayment: trueand what checkout needs for the new plan. - An upgrade takes effect straight away. The difference in price is charged to the card already on file, with no checkout, and the extra credits are granted when that payment clears. Unused credits stay.
- A move to a cheaper plan waits for renewal and shows as
pendingPlan. Unused plan credits don't carry over when it happens. - Moving between monthly and yearly on a paying plan isn't done in place: cancel, and start the other one when the plan ends.
Needs a signed-in owner or admin, and a verified phone. API keys get 403.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
plan | string | yes | The plan to move to. |
interval | string | no | month or year. Defaults to the current plan's. |
Response
200 OK
json
{
"subscription": { "plan": "scale", "planLabel": "Scale", "status": "active", "interval": "month", "pendingPlan": null },
"needsPayment": false,
"message": "Moving you to Scale. The difference is charged to your card now, and the extra credits arrive as soon as it's paid."
}When needsPayment is true, the response also has providerSubscriptionId and keyId, as when starting a plan.
Errors
| Status | error | Message |
|---|---|---|
| 400 | invalid_request | Choose a plan |
| 400 | invalid_request | This workspace is already on Pro. |
| 400 | invalid_request | Switching to yearly billing happens at renewal. Cancel this plan, and choose the yearly one when it ends. |
| 403 | forbidden | Only an owner or admin can change the plan. |
| 404 | not_found | There's no plan to change. Choose one to start. |
| 502 | payment_unavailable | The plan couldn't be changed just now, and nothing was charged. Try again in a minute. |
Cancel a plan
POST /v1/billing/subscriptions/cancel
Stops the plan renewing. A plan that's paying stays active until the end of the period that's been paid for; one that was never paid for stops straight away.
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": 175000,
"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, its unused plan credits end, and its monthly free credits start again a month later. Bought credits 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": 47580 }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.