Skip to main content
Limits depend on your SuperX plan, with separate buckets for reads (GET), writes (POST, PATCH, DELETE), live contact enrichment (adding contact-list members) and Engage feed fetches: Limits aggregate per account: all your API keys, the CLI and MCP draw from the same budget. MCP tool calls are read-classed; MCP write tools (scheduling, articles, signal agents, media) also count against the write limit. Adding a contact-list member counts against both the write limit and the tighter enrichment limit, and so does GET /v1/contacts/{id}?refresh=true. Anything that resolves an X handle or list live costs one enrichment unit too: creating or updating an Engage feed with x_list_id / x_list_url, adding a profile_watch, follower_watch or list_watch signal, and creating a signal agent whose signals include any of those three (one unit for the whole create, however many such entries it carries). Keyword feeds, contact-list feeds and keyword_watch signals cost no enrichment. The enrichment unit pays for the lookup itself, so it is spent even when the request is then rejected: an X-list feed create that fails on the 8-feed cap (409 feed_limit_reached) has already resolved the list and does not get the unit back. The live X lookups spend enrichment too, and more than one unit each where they make more than one upstream call: GET /v1/x/posts/{id} costs 1 (2 with include_quotes), GET /v1/x/posts/{id}/replies costs a flat 3 (it walks up to 3 pages), GET /v1/x/users/{handle} costs 1, and GET /v1/x/users/{handle}/posts costs 1 for a handle SuperX already knows and 2 for one it does not. A multi-unit call is all-or-nothing: it is rejected without charging anything rather than half-charged. Bulk adding members (POST /v1/contact-lists/{id}/members/bulk) costs one write and no enrichment: it resolves ids SuperX already knows and never calls out to X. The bulk queue endpoints (POST /v1/scheduled-posts/bulk/retime, /bulk/auto-retweet, /bulk/delete) cost one write each no matter how many posts they touch, so changing 100 posts at once is one unit rather than 100. A feed fetch (GET /v1/engage/feeds/{id}/posts) counts against the feed bucket, and a list feed that rotates its members counts as 3 fetches. GET /v1/engage/mentions counts as a flat 3 fetches too: one call reads several pages of X plus the posts each mention replies to. Collecting a dataset (POST /v1/datasets) has a cap of its own: 10 collections per account per day, shared with the collections Ask SuperX runs in the app, resetting at midnight UTC (429 collection_quota_exceeded). Refining one (POST /v1/datasets/{id}/refine) creates a dataset too, so it counts against the same 10; research (POST /v1/datasets with source: "research") does not, and is bounded by the research_profiles day cap below instead. A collection that reads X also spends enrichment: 1 unit for the size estimate, plus the pages the walk is expected to need, all charged before the walk starts, so X-RateLimit-Remaining already reflects work that finishes after a 202. my_posts and my_replies read your own synced posts and spend no enrichment at all, and a collection that matches nobody gives its daily slot back. The dataset reads (GET /v1/datasets/{id}/rows and GET /v1/datasets/{id}/export) each parse one whole dataset, up to about 5MB, per call, so page at limit=100 rather than looping at a small limit: ten calls at 100 rows are far cheaper on both sides than a hundred calls at 10. POST /v1/datasets/{id}/contacts costs one write and no enrichment however many people it copies, because the profiles come from the dataset itself. POST /v1/datasets/{id}/outreach-drafts and POST /v1/datasets/{id}/refine cost no enrichment either: both work on rows that are already stored. Media uploads have one more cap of their own: 100 per API key per day, counted per key rather than per account. Windows are fixed (aligned to the clock minute and UTC day), not sliding.

Response headers

Every authenticated /v1 response, not just rate-limited ones, includes:

When you hit a limit

Over-limit requests return 429 with a Retry-After header (seconds) and this body:
Honor Retry-After before retrying. For sustained workloads, spread requests out rather than bursting at the top of each minute, and page with limit=100 to reduce request counts.

Credits

Endpoints that run an AI model spend AI credits on top of the request limits above. One credit is one cent of model spend. Some calls have a flat per-unit price (post drafting), and others charge what the work actually cost when it finishes (cover generation), so read the price per call below rather than assuming one rule. Your plan includes a pool: paid plans get a monthly pool that resets on your billing date, trials get a daily one. GET /v1/me returns the current pool:
Typical costs today: Drafts that fail to generate are refunded, and a call where every draft failed returns 502 generation_failed with nothing charged. A lead search that never reaches X is not charged either. A cover generation that fails outright is refunded in full. A cover that TIMES OUT (504) keeps its 25 credits: the render may well have completed and landed in the article’s cover history, so read the article before retrying. The reply draft and the four composer tools refund in full when the model call fails before it produces anything. The free calls above charge nothing at all, so they send no X-Credits-Charged header. They still send X-Credits-Remaining and X-Credits-Reset, and they still have ceilings of their own: see the two sections below. Research is settled when the run finishes, which for a background run (more than 5 profiles) is after the 202: the response body cannot report a final figure, so read the pool with GET /v1/me afterwards. The same is true of a background refinement.

Credit headers

Responses from a credit-charging endpoint carry:

When the pool is empty

An exhausted pool returns 429 ai_credits_exhausted with three fields in the envelope, plus a Retry-After header when the reset time is known:
reset_at is a unix timestamp in seconds. Buy a top-up or wait for the pool to refill; retrying sooner returns the same error.

Per-day action limits

Some AI actions also carry a per-day count cap per plan, so an unusually cheap run cannot be repeated all day. Over the cap returns 429 ai_action_limited with scope: "account", retry_after, reset_at and a Retry-After header; the counter resets at midnight UTC. The uncapped actions read no live data, so credits are what bound them (plus, for refine, the 10-collections-a-day allowance, and for cover generation, the account’s own daily and monthly cover caps). The free actions are not in that table because they cost no credits, but each has its own ai_action_limited ceiling with scope: "account": POST /v1/signals/keywords/suggest and POST /v1/signals/icp/expand have no ceiling of their own: they run inside SuperX’s own process, so the short-term limiter the SuperX app applies to them does not reach the API and your plan’s request rate limit is their only bound. Each is still a model call, so keep them occasional rather than looping. POST /v1/signals/icp/expand-from-url is the exception: it goes through the app, so the app’s limiter binds it too, and more than 10 calls in 10 minutes returns 429 rate_limited (honour Retry-After; it clears in about a minute) rather than ai_action_limited. All five free endpoints are POSTs, so all five need a key with the write scope, as every non-GET route on this API does, whether or not they create anything. Credit and action limits fail closed: when SuperX cannot verify your balance or your day count, the call is refused rather than run for free.

Fair-use ceiling on live-data actions

The actions that read X live for you (a lead search, a research run, and the style-guide fallback below) also draw on a platform-wide daily ceiling shared by every SuperX account. It exists so that no single integration can exhaust what everyone else relies on; it is generous enough that normal use never meets it, and it is not a per-account quota you can raise by upgrading. Reaching it returns the same 429 ai_action_limited, with scope: "platform" instead of "account":
Always read scope before telling a user anything: on platform their own allowance is untouched, so wait for reset_at and retry rather than reporting them as out of quota. Like the other ceilings, it fails closed. One free endpoint reaches this ceiling too. POST /v1/context/style-guide/regenerate normally reads the account’s posts out of SuperX and touches nothing live, but an account with fewer than 5 recent posts stored has them read live instead, and that read is counted here (up to 4 requests). So a scope: "platform" refusal on the style guide means “a brand new account could not be read right now”, never “you are out of credits”. That live read is also limited to 3 attempts per account per day, because the hourly cooldown only starts after a run that SUCCEEDS: an account whose live read keeps coming back too thin would otherwise be free to retry all day against a ceiling everyone shares. Over the 3, the same 429 comes back with scope: "account" and a midnight reset_at.

Live X lookups

The /v1/x/* endpoints read X live rather than SuperX’s stored data, so they carry a second limit on top of the enrichment bucket above: an allowance of 300 live lookups per account per UTC day, SHARED with Ask SuperX inside the SuperX app. Heavy API use eats into what Ask can look up that day, and the other way around. Over the allowance returns 429 lookup_quota_exceeded: POST /v1/engage/reply-draft with a post_id reads the post live, so it spends one lookup from the same 300 a day. Pass post with the wording instead and it spends none. Profile research (POST /v1/datasets with source: "research") reads X live too, so it draws on the SAME 300 a day: one or two lookups per profile it researches. It does not answer 429 when the allowance runs out mid-run, though. The profiles it could not read come back in meta.skipped with a reason, only the profiles it did research are charged, and a run where nothing could be read answers 200 with data: null and every credit returned.
reset_at is a unix timestamp in seconds at the next midnight UTC. Like the credit limits, this one fails closed: when SuperX cannot verify your day count, the lookup is refused rather than run unmetered, and it answers with the same code. Results are cached server-side for about 15 minutes. A repeat lookup inside that window still costs its enrichment units (the enrichment bucket counts the call), but it does NOT touch the 300/day allowance, because nothing was fetched from X. GET /v1/inspiration/media is not a live X read and costs no enrichment. It has its own two caps per account instead: a burst of 20 refilling one every 3 seconds, and 500 FRESH searches per UTC day. Repeats of a recent identical search come from a short cache and do not count against the daily 500. Both return 429 rate_limited with Retry-After. There is no pagination on that endpoint: one query returns at most 120 items, so ask for limit=120 and filter your side rather than calling it repeatedly. lookup_quota_exceeded covers three cases and the body says which: your own allowance is used up (limit is present), the SuperX-wide allowance is used up (no limit, because it is not your account’s budget), or the counter could not be verified and the call was refused rather than run unmetered (no limit, and a short retry_after rather than one pointing at midnight). Read error.retry_after rather than assuming midnight.

DM limits

Direct messages are not AI credits and are not metered like them. Each plan carries its own DM allowances, and GET /v1/dm/limits returns all of them for an account:
  • a monthly message allowance (monthly.max), with monthly.committed counting the messages already queued and not yet sent, which are held against the allowance until they go out or are cancelled,
  • a daily bulk allowance (daily_bulk.max), how many may go out in a rolling 24 hours,
  • per_post_max, how many people one post’s auto_dm may message,
  • posts_with_auto_dm, how many scheduled posts a month may carry an auto_dm at all.
POST /v1/dm/campaigns counts against the writes bucket like any other write, and costs no AI credits. When an allowance is used up it answers 429 dm_limit_reached with a Retry-After header and a scope:
On scope: "day" the campaign does not have to wait: send it again with spread: true and the messages today’s allowance cannot hold are placed over the coming days instead of being skipped. One caveat: when GET /v1/dm/limits reports scheduling_enabled: false, placing messages on later days is switched off account-wide, so spread: true is ignored and the overflow is counted in skipped instead. Neither the campaign endpoint nor auto_dm sends anything at the time you call it. Both ENQUEUE, and the SuperX app’s scheduler sends within these limits, which is why a campaign answers with counts rather than deliveries. Unsent messages can be cancelled with DELETE /v1/dm/campaigns/{id}, and cancelling gives the monthly allowance back.

Failed authentication attempts

Requests with unknown or revoked keys are limited separately, per IP address, at 20 per minute. This limiter never affects correctly authenticated traffic.