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, YouTube channel, Pinterest Business account or LinkedIn profile/Page 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 six accounts can use six. Each destination reserves one unit when accepted for its scheduled period. Before its first publishing request, Castrook atomically claims a unit in the current period. A successful publication consumes that unit in the claimed period, even if processing finishes after reset; failure or cancellation releases it. Uncertain deliveries stay reserved until reconciled. Idempotent replays are free. |
| API requests | New API operations, comment reads/replies, fresh publishing-option lookups and Pinterest board/section discovery. Cached resource/status reads, GET /usage, cancellations, disconnects, disabling webhooks and exact post replays are free. Authentication, scope, rate and 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 | Verified direct uploads and bytes ingested from source URLs. Uploaded assets are counted once and are not billed again when reused for delivery. URL ingests count once per destination at their largest transfer, so retries never add more. Reservations protect simultaneous uploads; one bounded file can cross the remaining allowance. |
| 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 can run at the same time for your workspace. Large files also share a bounded buffer budget, so fewer run together. |
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 uses no monthly API allowance.
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 request rejected at an allowance does not create new work. An earlier accepted request keeps its identity: read its status or replay the exact post with its original idempotency key. A limit error on a post destination describes that destination’s delivery, not whether the post was accepted. Limits never create charges.
| 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()) {
// New work was rejected. Preserve the key and inspect earlier work if needed.
console.warn(error.details.metric, 'resets at', error.details.reset_at);
} else {
throw error;
}
}What keeps working at a limit
- Accepted work keeps its identity and reservation. Delivery checks the applicable period and plan before the first publishing request; already submitted provider work remains recoverable.
- When the publication, media or new-connection allowance is used up, other requests keep working, including status reads, cancellations and disconnects.
- At the API request allowance, cached status/usage reads, cancellations, disconnects, disabling webhooks and exact post replays keep working. New operations, comment requests and fresh publishing-option lookups wait for reset or an upgrade.
- 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.