Merion API

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-After header 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 /health and 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.

Get started

Ready to integrate with Merion?

API access is available to approved partners and integrators. Contact us to start the conversation — no commitment required.