Error Handling & Rate Limits
HTTP status codes, the error envelope format, retry strategies, rate limit guidance, and idempotency considerations for the Merion API.
HTTP status codes
200 OK- Request succeeded. The response body contains the result.
400 Bad Request- The request payload is invalid — malformed JSON, missing required fields, or an unknown form key. The response body contains a JSON error envelope with field-level detail.
401 Unauthorized- A Bearer token was required but was not provided, has expired, or is invalid. Obtain or refresh a token and retry.
403 Forbidden- The token is valid but the client does not have permission for the requested resource or action.
404 Not Found- The endpoint or resource does not exist. Check the URL and the API Reference.
409 Conflict- The request would create a duplicate or conflict with existing state. Do not retry without resolving the conflict.
422 Unprocessable Entity- The request was syntactically valid JSON but semantically invalid — for example, a required field was present but empty, or a value failed a business rule. The response body contains field-level detail.
429 Too Many Requests- Rate limit exceeded. See the
Retry-Afterheader for how long to wait before retrying. 500 Internal Server Error- An unexpected error occurred on the server. Retry after a delay. If the error persists, contact [email protected].
503 Service Unavailable- The API is temporarily unavailable. Check
/healthand status.merion.com.au before retrying.
Error envelope format
All error responses use a consistent JSON envelope. The fields key is only
present for validation errors (400 and 422):
{"error": "validation_error",
"message": "Human-readable description of the error",
"fields": {
"field_name": "Field-specific error message"
}
}
Always read the message value — it is intended to be surfaced to an administrator
or logged for debugging. The error value is a machine-readable code.
The fields map is keyed by form field name when available.
Handling specific status codes
400 and 422 — validation errors
Log the full error envelope. Surface the fields messages to the user or
administrator where appropriate. Do not retry without fixing the payload —
the same request will produce the same error.
401 — unauthorised
Check whether the token has expired (use expires_in from the token response
to track expiry proactively). If the token is valid but still rejected, the token may
have been revoked — re-authenticate. See Authentication.
429 — rate limited
Back off and retry after the number of seconds in the Retry-After response header.
If Retry-After is not present, use exponential backoff (see recipe below).
Do not retry in a tight loop — this will not succeed and may result in a longer block.
500 and 503 — server errors
Retry with exponential backoff. After 3–5 failed retries, fail gracefully and notify the
operator. Check /health before retrying — if it returns
non-200, the API is unavailable and retrying immediately is pointless.
Retry recipe
async function apiRequestWithRetry(fn, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fn();
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After") ?? "5");
const delay = retryAfter * 1000 * Math.pow(2, attempt);
await new Promise(r => setTimeout(r, delay));
continue;
}
if (res.status >= 500 && attempt < maxRetries) {
const delay = 1000 * Math.pow(2, attempt);
await new Promise(r => setTimeout(r, delay));
continue;
}
return res;
}
throw new Error("Max retries exceeded");
} This recipe doubles the wait time on each retry (exponential backoff). For production use, add jitter — a small random offset — to prevent multiple clients from retrying in synchrony after an incident.
Rate limits
Merion applies rate limits to all API endpoints. The specific limits are not published — they are set to protect the service, not to restrict legitimate integrators. If you routinely hit 429 responses, contact [email protected] to discuss your use case.
The health endpoint is subject to rate limiting like any other endpoint — poll it at most once per minute.
Idempotency
The POST /public/forms/{key} endpoint is not idempotent —
submitting the same form twice will create two records. Implement de-duplication at your
integration layer if necessary. For example, track submitted form session IDs in your
own database, and check before submitting to avoid sending duplicate referrals.
Do not automatically retry on 400 or 422 responses — the payload is invalid and the same error will occur again. Fix the payload first.
Ready to integrate with Merion?
API access is available to approved partners and integrators. Contact us to start the conversation — no commitment required.