DocumentationPlans and limits

Plans and limits

v1

Monthly 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 allowanceFreeStarterGrowthScale
Price per month$0$9$19$39
Connected live accounts21040100
Successful publications / month203001,5005,000
New media ingested / month1 GB30 GB150 GB500 GB
API requests / month2,00025,000100,000250,000
Comment reads and replies / month (within API requests)2003,00015,00050,000
API requests / minute3060120300
Concurrent media ingests12510
New account connections / month42080200

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

AllowanceWhat counts
Connected accountsLive 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 connectionsEach 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.
PublicationsOne 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 requestsNew 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 requestsLive comment reads and replies. They also count as API requests.
MediaVerified 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.
RateAPI-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 ingestsMedia 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"
A live Starter workspace
{
  "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
  }
}
FieldMeaning
modetest or live: the key’s environment
planfree, starter, growth or scale
plan_sourceWhy these limits apply: subscription, comp (complimentary), beta or free
catalog_versionThe plan catalog version, currently 2026-09
periodStart and end of the current usage period
reset_atWhen the allowances reset: the end of the period
grace_ends_atWhen the current source stops applying: beta access, a complimentary plan or a failed-payment grace period. Otherwise null.
accountsused, limit and remaining connected accounts
publicationsPublication meter
api_requestsAPI request meter
media_bytesMedia meter in bytes; null in test mode
comment_requestsComment request meter; null in test mode
new_connectionsNew connection meter; null in test mode
rate_limit.per_minuteAPI-key requests allowed per minute
concurrent_ingestsMedia 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.

HeaderMeaning
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests left in the current minute
X-RateLimit-ResetWhen the current minute ends, in Unix seconds
Retry-AfterOn 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.

CodeHTTPReturned whenDetails
usage_limit_exceeded429A 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_exceeded429The per-minute rate was reachedretry_after_seconds, limit
account_limit_reached409Connecting one more account would exceed the plan, or more than 10 test accountsmode, plan, limit, connected, upgrade_url
account_capacity_exceeded409A 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
HTTP 429 · Retry-After: 432000
{
  "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.

TypeScript
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.