Plans and limits
v1Monthly allowances for each plan, how usage is counted, and how to read usage and handle limit errors without retry loops.
Limits never create charges. When an allowance is used up, new work is rejected with a clear error until the period resets or you upgrade.
Plans
Every plan includes every feature; plans differ only in allowances. Prices are per month in US dollars, plus applicable tax. Compare plans.
| Live allowance | Free | Starter | Growth | Scale |
|---|---|---|---|---|
| Price per month | $0 | $9 | $19 | $39 |
| Connected live accounts | 2 | 10 | 40 | 100 |
| Successful publications / month | 20 | 300 | 1,500 | 5,000 |
| New media ingested / month | 1 GB | 30 GB | 150 GB | 500 GB |
| API requests / month | 2,000 | 25,000 | 100,000 | 250,000 |
| Comment reads and replies / month (within API requests) | 200 | 3,000 | 15,000 | 50,000 |
| API requests / minute | 30 | 60 | 120 | 300 |
| Concurrent media ingests | 1 | 2 | 5 | 10 |
| New account connections / month | 4 | 20 | 80 | 200 |
Test mode
Test keys have their own allowance on every plan: 10 test accounts, 1,000 simulated publications and 10,000 requests a month. Test usage never counts against live allowances, and test accounts never use a live account slot.
How usage is counted
| Allowance | What counts |
|---|---|
| Connected accounts | Live accounts connected right now. Each TikTok account, Instagram professional account, Facebook Page or YouTube channel uses one slot. Reauthorizing a connected account is free, and disconnecting frees its slot. |
| New connections | Each live account that goes from disconnected to connected. This stops accounts being rotated through one plan: Free 4, Starter 20, Growth 80, Scale 200 a month. |
| Publications | One per successful destination, so a post to four accounts can use four. Each destination reserves one unit when the post is accepted, in the period it is scheduled for. The unit is consumed when that destination publishes, in the period it completes, and released if it fails or is canceled. Uncertain deliveries stay reserved until they are reconciled. Idempotent replays are free. |
| API requests | Every request made with an API key, including reads and GET /usage. Failed authentication, missing scopes, rate or allowance rejections and server errors (5xx) never count. Dashboard activity never counts. |
| Comment requests | Live comment reads and replies. They also count as API requests. |
| Media | Bytes Castrook fetches from your media URL to deliver a destination (TikTok and YouTube today). The allowance is checked before any byte moves, and each destination is charged once, for its largest transfer, so retries never add more. The last transfer in a period can go over by at most one file (128 MiB). |
| Rate | API-key requests per minute, shared by the keys of a workspace and mode: Free 30, Starter 60, Growth 120, Scale 300. Dashboard sessions have a separate limit of 120 a minute. |
| Concurrent ingests | Media ingests Castrook runs at the same time for your workspace. |
Usage periods
Paid plans reset every month from the moment the subscription started (UTC). Free, beta, complimentary and test-mode allowances reset at the start of each calendar month (UTC). Unused allowance doesn’t roll over. Every meter reports its reset_at.
Read your usage
Any active key can call GET /usage; no scope is needed. It reports the key’s own mode, test or live, and counts as one API request.
curl https://castrook.com/api/v1/usage \
-H "Authorization: Bearer $CASTROOK_API_KEY"{
"data": {
"mode": "live",
"plan": "starter",
"plan_source": "subscription",
"catalog_version": "2026-09",
"period": {
"start": "2026-10-03T14:20:00.000Z",
"end": "2026-11-03T14:20:00.000Z"
},
"reset_at": "2026-11-03T14:20:00.000Z",
"grace_ends_at": null,
"accounts": { "used": 6, "limit": 10, "remaining": 4 },
"publications": {
"used": 128,
"reserved": 12,
"limit": 300,
"remaining": 160,
"reset_at": "2026-11-03T14:20:00.000Z"
},
"api_requests": {
"used": 4210,
"reserved": 0,
"limit": 25000,
"remaining": 20790,
"reset_at": "2026-11-03T14:20:00.000Z"
},
"media_bytes": {
"used": 5400000000,
"reserved": 0,
"limit": 30000000000,
"remaining": 24600000000,
"reset_at": "2026-11-03T14:20:00.000Z"
},
"comment_requests": {
"used": 310,
"reserved": 0,
"limit": 3000,
"remaining": 2690,
"reset_at": "2026-11-03T14:20:00.000Z"
},
"new_connections": {
"used": 2,
"reserved": 0,
"limit": 20,
"remaining": 18,
"reset_at": "2026-11-03T14:20:00.000Z"
},
"rate_limit": { "per_minute": 60 },
"concurrent_ingests": 2
}
}| Field | Meaning |
|---|---|
mode | test or live: the key’s environment |
plan | free, starter, growth or scale |
plan_source | Why these limits apply: subscription, comp (complimentary), beta or free |
catalog_version | The plan catalog version, currently 2026-09 |
period | Start and end of the current usage period |
reset_at | When the allowances reset: the end of the period |
grace_ends_at | When the current source stops applying: beta access, a complimentary plan or a failed-payment grace period. Otherwise null. |
accounts | used, limit and remaining connected accounts |
publications | Publication meter |
api_requests | API request meter |
media_bytes | Media meter in bytes; null in test mode |
comment_requests | Comment request meter; null in test mode |
new_connections | New connection meter; null in test mode |
rate_limit.per_minute | API-key requests allowed per minute |
concurrent_ingests | Media ingests that can run at the same time |
Each meter has used (consumed this period), reserved (held for accepted work that hasn’t finished), limit, remaining (the limit minus used and reserved, never below zero) and reset_at.
Rate limits
Every API response includes the rate-limit headers for the key’s workspace and mode, or for your dashboard session.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests left in the current minute |
X-RateLimit-Reset | When the current minute ends, in Unix seconds |
Retry-After | On 429 responses, the seconds to wait. For usage_limit_exceeded it is the time until the allowance resets. |
Limit errors
A limit error means nothing was accepted and nothing was charged. Handle it once; never retry it in a loop.
| Code | HTTP | Returned when | Details |
|---|---|---|---|
usage_limit_exceeded | 429 | A monthly allowance would be exceeded: API requests, publications, new connections, or media before a transfer. Also reported as a destination error at delivery. | metric, mode, plan, limit, used, reserved, remaining, reset_at, upgrade_url, retry_after_seconds |
rate_limit_exceeded | 429 | The per-minute rate was reached | retry_after_seconds, limit |
account_limit_reached | 409 | Connecting one more account would exceed the plan, or more than 10 test accounts | mode, plan, limit, connected, upgrade_url |
account_capacity_exceeded | 409 | A live post while more accounts are connected than the plan allows, for example after a downgrade or when beta access ends. Also reported as a destination error at delivery. | mode, plan, limit, connected, upgrade_url |
{
"error": {
"code": "usage_limit_exceeded",
"message": "This workspace has used its 300 live publications for this period. It resets at 2026-11-03T14:20:00.000Z. Upgrade the plan for a larger allowance.",
"details": {
"metric": "publications",
"mode": "live",
"plan": "starter",
"limit": 300,
"used": 296,
"reserved": 4,
"remaining": 0,
"reset_at": "2026-11-03T14:20:00.000Z",
"upgrade_url": "https://castrook.com/dashboard/billing",
"retry_after_seconds": 432000
}
},
"request_id": "req_example"
}Don’t retry usage_limit_exceeded before reset_at. For a larger allowance, upgrade from Billing in the dashboard; upgrade_url links there. The TypeScript SDK never retries these errors.
try {
await castrook.posts.create(payload, { idempotencyKey: 'campaign-42-post-7' });
} catch (error) {
if (error instanceof CastrookError && error.isUsageLimit()) {
// Nothing was accepted or charged. Try again after the reset.
console.warn(error.details.metric, 'resets at', error.details.reset_at);
} else {
throw error;
}
}What keeps working at a limit
- Work that was already accepted keeps its reservation and is delivered.
- When the publication, media or new-connection allowance is used up, other requests keep working, including status reads, cancellations and disconnects.
- When the API request allowance is used up, API keys are rejected until the reset. The dashboard keeps working, because dashboard activity never counts.
- Billing is always available, so you can upgrade at once.
Plan changes and capacity
Upgrades apply immediately. Downgrades take effect at the next renewal. If a downgrade, a cancellation or the end of beta access leaves more connected accounts than the plan allows, nothing is disconnected or deleted: new live posts fail with account_capacity_exceeded until you disconnect accounts or upgrade. Scheduled posts are checked again before delivery, and a destination that is over capacity or out of allowance fails with the matching error and releases its reservation.