Errors
Every failure has one shape. Switch on error.type,
show error.message, log meta.request_id.
The error envelope
type— a stable machine-readable string from the table below. New types may be added; treat an unknown one by its HTTP status.message— a sentence for a human. It may change; do not parse it.details— optional array of objects with more context, usually{field, issue}for validation errors.meta.request_id— also sent as theX-Request-Idheader. Quote it when you contact support.
Request
curl -X POST https://api.digitalagency.tools/v1/contacts \
-H "Authorization: Bearer $DA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"not-an-email"}'
Response · 422
{
"error": {
"type": "invalid_request",
"message": "Some fields are missing or invalid.",
"details": [
{ "field": "name", "issue": "required" },
{ "field": "email", "issue": "must be an email address" }
]
},
"meta": { "request_id": "req_4c316f1c2a9e0b7d" }
}
Error types
| Type | Status | Meaning | What to do |
|---|---|---|---|
unauthorized | 401 | No key, a malformed key, or a key that is unknown or revoked. | Check the Authorization header; create a new key if this one was revoked. |
forbidden | 403 | The key is valid but lacks the scope this endpoint needs. | Use a key with a higher scope. |
feature_not_enabled | 403 | The business's plan does not include API access, or the feature this resource needs. | Upgrade the plan; see Feature availability. |
not_found | 404 | No such endpoint, or a resource that does not exist or belongs to another business. | Check the id. Do not retry. |
method_not_allowed | 405 | The path exists but not with this HTTP method. | Use the method named in the message. |
conflict | 409 | An Idempotency-Key was reused with a different request body. | Use a fresh key for a different request. |
invalid_request | 422 | The body or query failed validation. details[] says which field and why. | Fix the input. Do not retry unchanged. |
rate_limited | 429 | Too many requests from this key in the current minute. | Wait for Retry-After seconds, then retry. |
ai_unavailable | 503 | An AI-assisted endpoint was called but no AI provider is configured. | Retry later, or use the non-AI endpoint. |
server_error | 500 | Something failed on our side. The detail is logged against the request id. | Retry with backoff; quote the request_id if it persists. |
404, not 403
A resource that belongs to another business answers exactly as one that does not exist. That is deliberate: a 403 would confirm the id is real.
Retrying
Retry rate_limited after Retry-After, and
server_error with exponential backoff. Do not retry a 4xx unchanged —
it will fail the same way. Make retried POSTs safe with an
Idempotency-Key.