Errors

Errors come back as JSON with an error field.

{ "error": "unauthorized" }

Codes

CodeMeaning
200It worked. Reads answer 200. So does the ingest webhook on a new article, on a re-send and on a delete.
400The request is wrong. A cursor that does not decode. A since that is not a date. A body that is not JSON. A payload that produced no title. An image that could not be copied.
401The credential is missing or unknown or revoked or malformed. They are not told apart.
402Over a plan limit. Or the account is suspended.
403The credential is real but may not do this. A key used on the wrong surface. An inactive site. An inactive source. An article routed to a site the source may not reach.
404No article with that slug is published on the site the key reads. Or, on a delete through the ingest webhook, no article with that id was sent by the source, or it is already in the trash.
413The ingest webhook body is over the size limit.

There is no 429. Rate limiting sits in front of the API.

402

A quota refusal carries the numbers with it.

{
  "error": "plan limit reached: monthly_reads allows 10,000 reads and 31,402 are in use. Upgrade at https://coppercms.com/pricing",
  "limit": "monthly_reads",
  "used": 31402,
  "allowed": 10000
}

Reads are not cut off at the limit. Going over adds a header. The articles keep being served. Only a large overrun is refused.

See Plans and limits.

403 on ingest

A routing refusal names the site. A partner cannot fix routing they cannot see.

{ "error": "…", "sites": ["9b1e…"] }

Retrying

Retry a 5xx.

Do not retry a 400 or a 401 or a 403 or a 413. The request will not be different next time. The exception is an image that could not be copied: send again once the image is reachable. See Images.

A 402 clears when the month rolls over or when the plan changes.