Skip to content
ReinoAds

OperationsIntegration Preview

Error Handling

Error response structure, error codes and safe retry strategies.

Preview

Error codes and response structure are illustrative. No rate limit values are committed in this documentation; limits for your account are shared in your integration documentation.

ReinoAds uses standard HTTP status codes and returns a machine-readable code field with every error. A decision that ends in blocked_by_policy or no_fill is not an error; those are returned as an outcome inside a 200 response.

{
  "error": {
    "code": "invalid_placement",
    "message": "Placement 'rewarded_v2' was not found in this environment.",
    "param": "placement",
    "request_id": "req_01HZXD8W2K"
  }
}
codeHTTPMeaning
invalid_request400The request body is invalid or a required field is missing.
missing_consent400The consent object was not provided.
authentication_failed401The API key is missing, invalid or revoked.
permission_denied403The key is not authorized for this operation, e.g. a publishable key calling a management endpoint.
environment_mismatch403A sandbox key tried to access a live resource, or vice versa.
invalid_placement404The placement was not found in this environment.
conflict409A resource with the same name already exists, or concurrent updates collided.
rate_limited429Too many requests were sent in a short period.
internal_error500An unexpected error occurred on the ReinoAds side.
service_unavailable503The service is temporarily unavailable.

Retries

  • Don't retry 4xx errors (except 429); fix the request instead.
  • Retry 429, 500 and 503 with exponential backoff and jitter; honor the Retry-After header when present.
  • Send an Idempotency-Key header on POST requests to management endpoints to avoid creating duplicates.
  • If a decision request times out or fails, leave the slot empty; never make your user experience depend on an ad response.
async function requestWithRetry(body: unknown, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    const res = await fetch("https://api.reinoads.com/v1/decisions", {
      method: "POST",
      headers: {
        Authorization: "Bearer " + process.env.REINOADS_SECRET_KEY,
        "Content-Type": "application/json"
      },
      body: JSON.stringify(body)
    });

    if (res.ok) return res.json();
    if (![429, 500, 503].includes(res.status)) throw await res.json();

    const retryAfter = Number(res.headers.get("Retry-After"));
    const delay = retryAfter > 0
      ? retryAfter * 1000
      : 2 ** i * 250 + Math.random() * 100;
    await new Promise((r) => setTimeout(r, delay));
  }
  return { outcome: "no_fill" };
}

Contacting support

When contacting support, include the request_id from the error response and the decision ID (dec_...) if available. These values contain no personal data.