Operational guide
Handle errors and rate limits
Use stable error codes for application logic, request IDs for support, and idempotency keys whenever you retry a create request.
Error response format
Every 4xx and 5xx response contains an error object. The human-readable message can change; the error code remains stable within the API version.
{
"error": {
"code": "rate_limit_exceeded",
"message": "The project exceeded its request allowance.",
"request_id": "req_01J6Y44C9N7Q2H5K8M3P"
}
}| Field | Use |
|---|---|
error.code | Branch on this stable, machine-readable value. |
error.message | Log or display a concise explanation for a developer. |
error.request_id | Include this value when contacting support about the request. |
Respond to common errors
| Status | Code | What to do |
|---|---|---|
| 400 | invalid_request | Correct the field named in the response before retrying. |
| 401 | authentication_failed | Check the bearer header, key status, and test or live environment. |
| 404 | delivery_not_found | Confirm the delivery ID and use the key from the project that created it. |
| 409 | idempotency_conflict | Reuse an idempotency key only with the original request data. |
| 429 | rate_limit_exceeded | Wait for the number of seconds in Retry-After. |
| 500–599 | internal_error | Retry with backoff and the same idempotency key. |
Rate limits
Each project can make 600 requests per minute. Successful responses report the limit, remaining requests, and seconds until the current window resets. A 429 response also includes Retry-After.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
RateLimit-Limit: 600
RateLimit-Remaining: 0
RateLimit-Reset: 42
Retry-After: 42
Relayline-Request-Id: req_01J6Y44C9N7Q2H5K8M3PWhen RateLimit-Remaining approaches zero, reduce concurrency. After a 429, wait for Retry-After before sending another request.
Retry safely
Retry 429 responses, 5xx responses, and network failures. Do not retry other 4xx responses without changing the request. This example handles HTTP retries; add equivalent handling for network errors in your application.
const delay = (milliseconds) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
async function createDelivery(payload, apiKey, idempotencyKey) {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(
'https://api.relayline.example/v1/deliveries',
{
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ...payload, idempotency_key: idempotencyKey }),
},
);
if (response.ok) return response.json();
const canRetry = response.status === 429 || response.status >= 500;
if (!canRetry || attempt === 3) {
const problem = await response.json();
throw new Error(`${problem.error.code}: ${problem.error.message}`);
}
const retryAfterHeader = response.headers.get('Retry-After');
const retryAfter = retryAfterHeader === null
? Number.NaN
: Number(retryAfterHeader);
const waitSeconds = Number.isFinite(retryAfter) && retryAfter >= 0
? retryAfter
: 2 ** attempt;
await delay(waitSeconds * 1000);
}
}