Errors and rate limits
The error format, every error code, and the request rate limit.
Error format
Errors use a non-2xx status and the same JSON shape:
{
"error": {
"message": "Your Pro plan includes 100 dynamic codes. Upgrade or archive a code to add another.",
"code": "PLAN_LIMIT"
}
}
message is written for people and safe to show to your users. Branch on code, not on the message text.
Invalid input returns INVALID_REQUEST with an issues list that says which field failed and why:
{
"error": {
"message": "Invalid request",
"code": "INVALID_REQUEST",
"issues": [
{
"code": "invalid_format",
"format": "url",
"path": ["url"],
"message": "Invalid URL"
}
]
}
}
Error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | A field is missing or invalid, or the body isn't JSON. See issues |
| 401 | UNAUTHORIZED | Missing, wrong or revoked key. See Authentication |
| 402 | PLAN_FEATURE | The workspace's plan doesn't include this. The message names the plan that does |
| 402 | PLAN_LIMIT | A plan quota is full, for example dynamic codes or bio pages. The message gives the limit |
| 403 | EMAIL_UNVERIFIED | The person who created the key must verify their email address before creating dynamic codes |
| 404 | NOT_FOUND | The id doesn't exist in this workspace |
| 409 | EDIT_LOCKED | The code is over the plan's limit after a downgrade. It can't be edited until you upgrade or archive another code, and it stops redirecting 14 days after the workspace went over |
| 409 | INVALID_STATE | The change doesn't fit the code's current state, for example changing the URL of a code that isn't a URL code |
| 409 | INVALID_KEY_OWNER | The person who created the key no longer exists. Create a new key |
| 422 | DESTINATION_BLOCKED | The destination failed a safety check (for example a known phishing or malware site), or too many destination changes were made in a short time. The message says which |
| 429 | RATE_LIMITED | Too many requests. Wait for the number of seconds in Retry-After |
| 500 | INTERNAL | Something went wrong on our side. Retry later |
Plan errors look like this:
{
"error": {
"message": "This needs the Pro plan or higher (redirect rules; this workspace is on Starter). Upgrade at dynaqr.app/pricing.",
"code": "PLAN_FEATURE"
}
}
Rate limits
Each API key can make 120 requests per minute. Over the limit, the API returns 429 with a Retry-After header giving the seconds to wait:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
{"error": {"message": "Rate limit exceeded", "code": "RATE_LIMITED"}}
Each key has its own limit. Retry 429 and 5xx responses with a backoff. Don't retry other 4xx errors without changing the request.