Skip to content
OmniLeadDocs
Sign in

Handle errors

The error object every API error uses, what each error code means, and how to fix it.

Available on Agency3 min readLast updated

The API uses standard HTTP status codes and returns the same error object for every failure. Each error has a stable code you can branch on, a message written for humans, and a doc_url that links to its explanation on this page.

The error object

Error response
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_request",
    "message": "limit must be between 1 and 100.",
    "param": "limit",
    "doc_url": "https://omni.cloudgens.net/docs/api/errors#invalid_request"
  }
}
FieldDescription
typeThe broad class of error, such as invalid_request_error or rate_limit_error.
codeA stable, machine-readable code from the table below. Branch on this.
messageWhat happened and how to fix it. Show it in logs; don't parse it, because wording can improve.
paramThe request field that caused the error, when there is one.
doc_urlA link to this page, anchored to the code.

Every response, including errors, carries a Request-Id header. Include it when you contact support.

Status codes

StatusMeaning
200, 201, 202Success. 201 means something was created; 202 means a background job was queued.
400The request was invalid.
401No valid API key.
402Not enough credits.
403The plan doesn't include this.
404Not found in this workspace.
409Conflict with current state.
429Rate limited.
500Something failed on our side.

Error codes

invalid_request

400. A parameter is missing, has the wrong type or fails validation. param names the field, and message says what's expected, for example "limit must be between 1 and 100" or "Send exactly one of email or domain".

Fix: correct the field and send the request again. Don't retry unchanged; it will fail the same way.

authentication_failed

401. The Authorization header is missing, isn't in the form Bearer <key>, or the key has been revoked.

Fix: send Authorization: Bearer ol_live_… with an active key from Settings → API. See Authenticate with API keys.

insufficient_credits

402. The workspace doesn't have enough credits for a search page or a reveal. Nothing was charged.

Fix: buy a credit pack, move to a plan with more credits, or wait for your plan credits to renew. Check the balance first with GET /credits if you're about to run a large batch.

permission_denied

403. The workspace's plan doesn't include what you asked for. Usually the workspace isn't on Agency, which is the plan that includes the API. It also happens when you search a lens the plan doesn't include.

Fix: upgrade the workspace in Settings → Billing, or use a lens your plan includes.

not_found

404. No object with that ID exists in this workspace. IDs are scoped to a workspace, so a key from one workspace can't see another's objects, and deleted objects return 404.

Fix: check the ID, and check you're using the key for the right workspace.

conflict

409. The request conflicts with current state. Common causes:

  • Creating a lead with an email that already exists in the workspace. The message includes the existing lead's ID.
  • Reusing an Idempotency-Key with a different request body.
  • Adding a tag or suppression that's being changed by another request at the same moment.

Fix: fetch the current object and decide what to do, or use a new Idempotency-Key for a genuinely new request.

rate_limited

429. More than 120 requests in one minute with this key. The response includes Retry-After.

Fix: wait the number of seconds in Retry-After, then retry with backoff. See Rate limits.

internal_error

500. Something failed on our side. It's safe to retry: send the same Idempotency-Key on POST requests so nothing is done twice.

Fix: retry with exponential backoff. If it keeps happening, contact support with the Request-Id header.

Errors that aren't errors

Some outcomes are normal results rather than errors, so they return 2xx:

  • A reveal where no verifiable contact was found returns 200 with status: "no_contact_found" and credits_charged: 0.
  • Revealing an entity the workspace already revealed returns 200 with already_revealed: true and credits_charged: 0.
  • Enrolling leads returns 201 even if some were skipped. Check the skipped array for each lead's reason: already_enrolled, suppressed, no_email, email_invalid, country_blocked or not_found.

Handle errors in code

const res = await fetch("https://omni.cloudgens.net/api/v1/reveals", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.OMNILEAD_API_KEY}`,
    "OmniLead-Version": "2026-09-28",
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ entity_id: "ent_inv_3Jd8Kq" }),
});

if (!res.ok) {
  const { error } = await res.json();
  switch (error.code) {
    case "insufficient_credits":
      // Pause the batch and alert someone to top up.
      break;
    case "rate_limited":
      // Wait for Retry-After, then retry with the same Idempotency-Key.
      break;
    default:
      throw new Error(`${error.code}: ${error.message} (${res.headers.get("request-id")})`);
  }
}

What's next