Skip to main content
details is an allow-listed subset per code, for example field and reason for invalid_input, resourceType for not_found, retryAfterSeconds for rate_limited, or platform, target, and a short hint for unsupported_object. Messages are safe to show to users; they never echo source diagnostics. Page cursors report expired_cursor, malformed_cursor, invalid_signature, unsupported_version, or no_next_page in details.reason under invalid_input. A search cursor that continues another platform’s search reports platform_mismatch. The lists that have no cursor — the newest TikTok videos and an advertiser’s ads, and advertiser search — reject a cursor parameter with invalid_input.

details.reason on a list

The list surface names its object with a selector and reads only the parameters the selected platform supports, so invalid_input carries the reason the value was refused, the platform that judged it, and one plain hint. A parameter the platform does not read is always refused, never quietly ignored:
Instagram and TikTok list an account by handle, so an id is served from the handle last observed for it. When nothing has named that id, the answer asks for the handle rather than guessing:
not_found stays reserved for its own meaning: the platform says the account is gone.

Codes

The TypeScript SDK exposes the same information as RefmatterError with status, code, requestId, retryable, and retryAfterSeconds.

Waiting after a 429

A rate_limited response carries details.retryAfterSeconds and a Retry-After header with the same whole number of seconds. The value reflects the real state of the source, not a fixed backoff: usually a few seconds, sometimes minutes or hours while a platform is limiting us. Wait that long before trying again.

Free errors

Item lookup charges for an item, never for a failure. Every error it returns — invalid input, an account link, a removed item, a rate limit, a timeout, a disabled route, even an access refusal — costs nothing and carries Refmatter-Credits-Charged: 0. So does a fetch whose result could not be written. A transcript is never charged on its own, so asking for one that turns out to be empty adds nothing to the price of the item. There is never a partial charge and never a job to poll instead of an answer. A 402 insufficient_credits is free in the same way: the workspace balance ran out, so the platform is never contacted and nothing is charged. Every charged endpoint reports the balance in Refmatter-Credits-Remaining, on the 402 as well, so you can see it reach zero before a request is refused. Work that costs nothing keeps answering at a zero balance: a repeat within your maxAge, an empty page, Resolve a URL and imports. An unsupported_object from lookup or import says what you sent and what to pass instead:
target is item, account, or absent. The hint is a fixed sentence of at most 160 characters; it never echoes the URL you sent. Resolve a URL returns the same judgement as a 200 with a machine-readable reason, before you spend anything.