Skip to main content

Account, usage & keys

Everything about the account behind a key: what it can spend, what it has spent, and which keys can act as it.


GET /v1/account

The current balance, plan, and subscription state. The endpoint to call before spending, and the cheapest way to verify a key works.

Returns

FieldTypeDescription
remainingCreditsnumbermax(0, monthlyBudgetCredits + purchasedCredits − spentCreditsThisPeriod). What you can actually spend.
user.email · user.name · user.imageIdentity of the account.
user.tierenumnone (Free) · standard · pro · max.
user.currentPeriodEndstring | nullISO date the billing period ends and the monthly grant resets.
user.cancelAtPeriodEndbooleanSubscription is set to lapse at period end.
user.pastDuebooleanA renewal charge failed and is being retried. The tier is still active — a grace period, not a lockout.
user.spentCreditsThisPeriodnumberCredits consumed since the period started.
user.purchasedCreditsnumberTop-up balance. Never expires and isn't reset by the monthly cycle.
plan.tier · plan.monthlyPriceUsd · plan.monthlyBudgetCreditsThe account's current plan.
Request
curl -s https://api.corte.so/v1/account \
-H "Authorization: Bearer corte_sk_…"
Response
{
"user": {
"email": "you@example.com",
"name": "You",
"image": null,
"tier": "pro",
"currentPeriodEnd": "2026-08-14T00:00:00.000Z",
"cancelAtPeriodEnd": false,
"pastDue": false,
"spentCreditsThisPeriod": 1288,
"purchasedCredits": 500
},
"plan": {
"tier": "pro",
"monthlyPriceUsd": 30,
"monthlyBudgetCredits": 3500
},
"remainingCredits": 2712
}

:::tip Preflight expensive work Compare remainingCredits against the estimatedCredits a creation call would return. It won't prevent a 402 from a concurrent spend, but it stops a batch job from discovering the problem halfway through. :::


GET /v1/plans

The purchasable plan ladder, cheapest first. No authentication required — this is public catalog data for pricing pages.

none (Free) is excluded; this endpoint lists what you can buy.

Returns { "plans": [...] }.

FieldTypeDescription
tierenumstandard · pro · max.
monthlyPriceUsdnumberList price.
monthlyBudgetCreditsnumberCredits granted each period.
discountedMonthlyPriceUsdnumberPresent only when a promotional price is active.
Request
curl -s https://api.corte.so/v1/plans
Response
{
"plans": [
{ "tier": "standard", "monthlyPriceUsd": 10, "monthlyBudgetCredits": 1000 },
{ "tier": "pro", "monthlyPriceUsd": 30, "monthlyBudgetCredits": 3500 },
{ "tier": "max", "monthlyPriceUsd": 80, "monthlyBudgetCredits": 10000 }
]
}

Any purchase — a top-up or a plan — unlocks the full model catalog; firstTopupBonusCredits is the bonus a first top-up would add, or null once the account has bought anything. Credits and storage are what scale up the ladder — see Plans & pricing.


GET /v1/usage

The account's credit ledger, newest first. Every grant and every charge.

Query parameters

NameTypeDefaultDescription
limitnumber100Max 500.
offsetnumber0

Returns

FieldTypeDescription
entriesobject[]The page.
remainingCreditsnumberCurrent balance, same as GET /v1/account.
totalnumberTotal ledger rows for the account — page with this.

The ledger entry

FieldTypeDescription
idstringEntry id.
kindenummonthly_grant · topup · generation · transcription · agent_usage · storage · plugin_purchase · plugin_payout · adjustment.
deltaCreditsnumberNegative is spend, positive is a grant.
refstring | nullThe id of what caused it — a generation job id, a Stripe reference.
notestring | nullHuman context, usually the model id.
createdAtstringISO 8601.
projectIdstring | nullSet when the spend was project-billed.
actorUserId · actorEmailstring | nullWho triggered it, when that differs from the payer.
previewUrl · previewKindThumbnail of what a generation charge bought. Signed and expiring.
Request
curl -s "https://api.corte.so/v1/usage?limit=3" \
-H "Authorization: Bearer corte_sk_…"
Response
{
"entries": [
{
"id": "aa41e0c7-…",
"kind": "generation",
"deltaCredits": -85,
"ref": "5f2b9c14-8a3d-4b21-9e77-0c4a1d6f8e02",
"note": "kling-3",
"createdAt": "2026-07-28T14:04:47.019Z",
"projectId": null,
"actorUserId": null,
"actorEmail": null,
"previewUrl": "https://media.corte.so/…?X-Amz-Signature=…",
"previewKind": "video"
},
{
"id": "3b8f01d5-…",
"kind": "topup",
"deltaCredits": 500,
"ref": "cs_live_a1B2c3…",
"note": "$5.00 top-up",
"createdAt": "2026-07-24T08:12:33.905Z",
"projectId": null,
"actorUserId": null,
"actorEmail": null,
"previewUrl": null,
"previewKind": null
},
{
"id": "df70a2e9-…",
"kind": "monthly_grant",
"deltaCredits": 3500,
"ref": null,
"note": "Pro monthly grant",
"createdAt": "2026-07-14T00:00:04.331Z",
"projectId": null,
"actorUserId": null,
"actorEmail": null,
"previewUrl": null,
"previewKind": null
}
],
"remainingCredits": 2712,
"total": 418
}

For per-project spend broken down by actor, use GET /v1/projects/:id/usage.


GET /v1/health

Liveness plus which upstream integrations this deployment has credentials for. No authentication required.

Request
curl -s https://api.corte.so/v1/health
Response
{
"ok": true,
"providers": { "anthropic": true, "fal": true, "stripe": true, "s3": true }
}

A false provider explains an otherwise puzzling forbidden or provider_unavailable: fal: false means generation isn't wired up on this deployment.


API keys

Keys are how anything outside the browser authenticates. Corte stores only a SHA-256 hash, so a secret is returned exactly once, at creation. Limit: 20 keys per account.

An existing key can mint new keys. That's convenient and worth thinking about — a leaked key can create more keys, so revoking the leaked one alone may not be enough. Audit the list after any incident.

The key object

FieldTypeDescription
idstringKey id — what you pass to DELETE.
namestringYour label.
createdAtstringISO 8601.
lastUsedAtstring | nullUpdated on every authenticated request. null means never used.
scopesstring[] | nullAreas the key may reach. null is full access.

The secret is never in this object. It exists only in the POST response.

Scopes

scopes entries are <area>:<access>, where area is one of content, media, integrations, generation, workflows, cuts, projects, plugins, community, build, agents, account, and access is read (GET requests) or rw (everything). rw implies read. See API keys → Scopes for what each area covers.

The same vocabulary bounds what an agent may reach, with one difference: an agent can never hold the account area, and a scoped key cannot create an agent more powerful than itself.

There is no public or delivery scope — that is a delivery token, a different credential.

A request outside a key's scopes returns 403 forbidden, naming the scope it needed:

{ "error": { "code": "forbidden", "message": "This API key is not scoped for POST /v1/content/types — it needs \"content:rw\"" } }

The same scopes govern the MCP server: a scoped key is offered only the tools it can call.

POST /v1/api-keys

Create a key.

Body{ "name": "…", "scopes": [...] }. Both are required; name is non-empty and trimmed to 100 characters, scopes must name at least one area.

Returns { apiKey, secret }. secret is shown once. Store it before you read anything else.

Request
curl -s -X POST https://api.corte.so/v1/api-keys \
-H "Authorization: Bearer corte_sk_…" \
-H "Content-Type: application/json" \
-d '{ "name": "ci-render-bot", "scopes": ["media:rw", "workflows:rw"] }'
Response
{
"apiKey": {
"id": "c0f81a37-4d92-4b16-8e05-71a3c9d0b284",
"name": "ci-render-bot",
"createdAt": "2026-07-28T20:15:41.008Z",
"lastUsedAt": null,
"scopes": ["media:rw", "workflows:rw"]
},
"secret": "corte_sk_9f3a1c7e5b204d86af10c92e7d3b6f41a58c07e29d4b3c6"
}

invalid_params when name is empty, the account already has 20 keys, or scopes is missing, empty, or contains an unknown entry. There is no endpoint to change a key's scopes — revoke it and create a new one.

GET /v1/api-keys

List your keys, newest first. Secrets are never included.

Returns { "apiKeys": [...] }.

Response
{
"apiKeys": [
{ "id": "c0f81a37-…", "name": "ci-render-bot", "createdAt": "2026-07-28T20:15:41.008Z", "lastUsedAt": "2026-07-28T20:41:19.772Z", "scopes": ["media:rw", "workflows:rw"] },
{ "id": "5a94e0b2-…", "name": "claude-code", "createdAt": "2026-07-11T09:03:12.441Z", "lastUsedAt": "2026-07-27T18:22:05.130Z", "scopes": null }
]
}

lastUsedAt is the cheapest way to find keys worth revoking: anything null or months stale is an integration nobody is running.

DELETE /v1/api-keys/:id

Revoke a key. Effective immediately — in-flight requests with that key start failing unauthenticated.

Returns { "ok": true }. not_found if the id isn't one of yours.

Request
curl -s -X DELETE https://api.corte.so/v1/api-keys/c0f81a37-… \
-H "Authorization: Bearer corte_sk_…"