Errors
The API uses conventional HTTP status codes and returns a consistent JSON error envelope for every non-2xx response.
Error envelope
{
"error": "Not Found",
"message": "Link not found",
"statusCode": 404,
"details": null,
"timestamp": "2026-07-10T12:00:00.000Z",
"path": "/api/v1/links/nope",
"requestId": "req-abc123"
}
| Field | Type | Always present | Meaning |
|---|---|---|---|
error | string | yes | Short error label (e.g. Validation Error, Not Found, Unauthorized) |
message | string | yes | Human-readable explanation |
statusCode | number | yes | The HTTP status code |
details | array/object | no | Extra context — present on validation errors (see below) |
timestamp | string | yes | ISO-8601 time the error was generated |
path | string | yes | The request path |
requestId | string | usually | Correlation id — include it in support requests |
SDK mapping
The planned TypeScript SDK (not published yet) will throw an APIError whose code maps to the API's
error label, message to message, and details to details. It also exposes
status, rateLimit, and retryAfter.
Validation errors
400 validation failures include a details array, one entry per invalid field:
{
"error": "Validation Error",
"message": "Request validation failed",
"statusCode": 400,
"details": [
{
"field": "longUrl",
"message": "Invalid URL format (only http/https allowed)",
"code": "custom"
}
]
}
Status codes
| Status | error label | When |
|---|---|---|
400 | Validation Error / Bad Request | Invalid input, malformed body, bad reference |
401 | Unauthorized | Missing or invalid API key / JWT |
403 | Forbidden | Authenticated but lacking scope, or tier limit reached |
404 | Not Found | Resource (or route) does not exist |
409 | Conflict | Uniqueness violation (e.g. a short code already exists) |
429 | Too Many Requests | Rate limit exceeded — see Retry-After |
500 | Internal Server Error | Unexpected server error |
Rate-limit errors
429 responses include a Retry-After header (seconds) alongside the standard
X-RateLimit-* headers. The planned SDK will retry idempotent requests automatically and
honor Retry-After; see Authentication → Rate limiting.
Handling errors well
- Read
error+message, not just the status code — the message explains the specific cause. - Log
requestIdso support can trace a failed call. - Treat
403from tier limits as an upgrade prompt, not a bug — the message will say which limit was hit. - Make retries idempotent. The planned SDK will never replay POST/PATCH; if you retry
writes yourself, use an idempotency strategy (e.g.
externalIdfor conversions).