Skip to main content
Errors are RFC 9457 problem documents, served as application/problem+json:
Branch on code, never on title or detail — those are prose and may be reworded. code is stable. Every response, success or failure, also carries a Request-Id header; quote it when you contact support.
type links directly to that code’s entry on this page, so the URL in an error always takes you to its explanation.

Authentication (401)

missing_api_key

No Authorization header on the request. Fix: Send Authorization: Bearer ck_live_... (or ck_sandbox_...).

invalid_api_key

The header is malformed, or the key isn’t one we recognize. Also returned when the scheme isn’t Bearer, or the key doesn’t start with ck_live_ / ck_sandbox_. Fix: Check the key was copied whole — they’re shown once at issuance.

revoked_api_key

The key was revoked. Fix: Use a current key, or ask us to issue a replacement.

expired_api_key

The key passed its expiry date. Fix: Ask us for a fresh key.

partner_disabled

The account itself is disabled — no key will work. Fix: Contact api@trycactus.com.

Access (403)

The key authenticated, but can’t reach this product. The code tells you who can unblock it. See Product access for which endpoints belong to which product.

product_not_enabled

Your account isn’t enabled for that product. Fix: Contact api@trycactus.com — only Cactus can add a product to an account.

missing_scope

Your account has the product, but the key you used was issued without it. Fix: Use a key that carries the scope. Ask us if you’re not sure which of your keys does.

Request (400)

invalid_request

Malformed body or parameters. The errors[] array lists each offending field with a field, code, and message. Fix: Correct the fields named in errors[].

Not found (404)

not_found

No such resource — or it belongs to another account. The two are deliberately indistinguishable, so one account can’t probe another’s ids. Fix: Check the id, and that it was created with the same account.

Method not allowed (405)

method_not_allowed

The path exists but not for that HTTP method. Fix: Check the method against the API reference.

Conflict (409)

The resource exists but isn’t in a state that allows this call. All of these become retryable once the underlying condition changes.

document_not_uploaded

The document was registered, but the file bytes never arrived. Fix: PUT the file to the upload URL from POST /v1/documents before referencing it.

document_in_use

The document is attached to an extraction or underwriting still in flight. Fix: Wait for that job to reach a terminal status, then retry.

extraction_not_completed

You asked for the result before the job finished. Fix: Poll the extraction (or use ?wait=) until status is completed. Better still, register a webhook endpoint.

underwriting_inputs_not_completed

You asked for the result before the job finished. Fix: Poll until status is completed, or use a webhook.

Rejected at acceptance (422)

Validation failures. None of these are billed — a document is only charged once it passes acceptance.

document_not_found

A referenced document id doesn’t exist. Fix: Check the id from the POST /v1/documents response.

document_deleted

A referenced document has been deleted. Fix: Re-upload it.

duplicate_document

The same document id appears more than once in one request. Fix: De-duplicate document_ids.

document_over_size_cap

Over 500 pages or 100 MB. Rejected outright and not charged. Fix: Split the file and submit the parts separately.

document_type_unresolvable

We couldn’t determine the document’s type. Fix: Set declared_type explicitly. See Preparing documents.

unsupported_asset_class

There’s no underwriting model for that asset class yet. The message lists the supported ones. Fix: Use a supported asset class, or ask us about the one you need.

end_user_ref_required

Your account requires end_user_ref on every run, so each of your users’ analyses lands in its own isolated workspace. Fix: Pass end_user_ref — your own opaque identifier for that user.

rate_unavailable

No rate-card line exists for that document type on your account. Fix: Contact api@trycactus.com — this is a configuration gap on our side.

Rate limit (429)

rate_limited

Too many requests. Fix: Wait the number of seconds in the Retry-After header, then retry.

Server (500)

internal_error

Something failed on our side. Fix: Retry. If it persists, send us the request_id from the response.
Jobs that fail after being billed are refunded in full, automatically. A failed extraction or underwriting never costs you anything.