Error codes
Every failure on every route is the same body: { code, message, docs_url, details? }. The code is from this list and nothing else, and docs_url points at the anchor on this page. A malformed body, an unknown listing and an unhandled fault are errors too, and they are in here for the same reason.
32 codes. Match on code, never on message — the message is allowed to become more specific over time and the code is not. The routes list shows which of these each route can return.
Payment
| Code | Status | Meaning | What to do |
|---|---|---|---|
| insufficient_ | 402 | The payer does not hold enough USDC to cover this price. | Fund the payer address with USDC on the network named in the 402 and retry. |
| expired_ | 402 | The payment authorization has expired. Request a fresh quote. | Request the resource again to get a fresh 402, then sign that one. |
| replay | 409 | This payment authorization has already been used. | The authorization was already settled. Re-fetch the resource; the existing purchase is returned. |
| settlement_ | 402 | Payment verified but not yet settled. Access is granted only after settlement. | Verification succeeded but settlement has not confirmed. Retry with the same authorization. |
| settlement_ | 504 | Settlement did not confirm in time. Retry with the same authorization. | Retry with the same authorization. It has not been consumed. |
| authorization_ | 400 | The payment authorization does not match this listing, version or amount. | The signed amount, listing or version does not match the quote. Take a fresh 402. |
| price_ | 409 | The price changed since this quote was issued. A fresh 402 is attached. | A fresh 402 is attached to the response. Sign that one. |
| sanctioned_ | 403 | This address appears on a sanctions list. No payment can be processed. | No retry will succeed. Contact the abuse address if you believe this is wrong. |
Listing
| Code | Status | Meaning | What to do |
|---|---|---|---|
| listing_ | 409 | This listing cannot go live yet. | The blocking array names what is missing. Fix each, then publish again. |
| licence_ | 409 | No resale-compatible licence was found for this repository. | No longer returned. A missing or unrecognised licence does not block publishing or selling. |
| scan_ | 409 | The security scan failed for this release. | The scan found one of the five things that block a release — a secret, a HIGH or CRITICAL dependency CVE, a dependency known to be malicious, hidden-Unicode instruction smuggling in a text or tool-description file, or a size-limit breach. scan_report on GET /api/listings/{id} names the finding, its rule and its path and line. Fix it in the repository and cut a new version: the verdict is terminal, so the same version cannot be re-scanned. |
| version_ | 409 | That version already exists for this listing. | Tags are immutable here. Cut a new release rather than moving the tag. |
| description_ | 409 | A description and a trigger hint are required before publishing. | PATCH the listing with a description and a trigger hint, then publish. |
| retired | 410 | This listing is no longer sold. | This listing is no longer sold. Holders can still fetch every version they own. |
| not_ | 403 | This wallet does not own that version. | This wallet has not bought that version. Fetch the resource to be quoted a price. |
| derivative_ | 409 | This artifact substantially overlaps an existing listing. | The artifact overlaps an existing listing by 90% or more. It cannot be published. |
| public_ | 422 | Only private repositories can be listed. Make the repository private and try again. | Only private repositories can be listed. Make the repository private on GitHub, then create the listing again. |
Identity
| Code | Status | Meaning | What to do |
|---|---|---|---|
| invalid_ | 401 | The API key is missing, malformed or revoked. | Check the Authorization: Bearer x4c_live_… header, or rotate the agent key with a wallet signature. A website session key returns this once it expires or you sign out — sign in again. |
| insufficient_ | 403 | The API key does not carry the scope this route requires. | Rotate the key to get one carrying the scope this route needs. |
| step_ | 403 | This action requires a fresh signature from the bound payout address. | Sign a fresh challenge from the bound payout address and send it as step_up. |
| terms_ | 409 | The accepted terms version is not the current one. | Fetch GET /api/terms and accept the version it returns. |
| payout_ | 400 | The payout address was not proved by a valid signed challenge. | GET /api/auth/challenge?address=…&purpose=address_proof, sign the message, and resend it as address_proof. |
| invite_ | 403 | A valid invite code is required to register through the API. | API registration needs an invite code in this version. |
| invalid_ | 401 | The wallet signature is missing, malformed, expired or already used. | The nonce is unknown, expired, already used, or the signature does not recover to that address. Take a new challenge. |
Limits
| Code | Status | Meaning | What to do |
|---|---|---|---|
| rate_ | 429 | Too many requests. Retry after the interval given. | Wait retry_after_seconds and retry. The window is fixed, not sliding. |
| repo_ | 413 | The repository exceeds the 200 MB / 20,000 file cap. | The cap is 200 MB and 20,000 files. Trim the repository or split the listing. |
| too_ | 409 | You already have the maximum number of unpublished listings. | Publish or retire an existing draft first. |
General
| Code | Status | Meaning | What to do |
|---|---|---|---|
| blocked_ | 451 | This service is unavailable in your jurisdiction. | This service is not available where the request originated. |
| paused | 503 | This is temporarily unavailable. Try again shortly. | |
| invalid_ | 400 | The request body or parameters did not validate. | The details.issues array names the field and the reason for each failure. |
| not_ | 404 | No such listing, version or resource. | Check the owner, slug and version. Draft listings are not readable by their URL. |
| internal | 500 | Something went wrong on our side. | Retry. If it persists, the error is ours and the request id in the response headers identifies it. |