Skip to main content
5 min read

Rate limits & errors

Things fail. Networks blink. Providers go quiet. This page is about what abm.dev does when they do, and what you should do back.

The short version: abm.dev never guesses. A value is cited or it is not returned. So most of your error handling is not about bad data — it is about missing data, slow data, and the occasional bad request.

How requests work

Two endpoints. That is the whole surface for enrichment.

HTTP
POST https://api.abm.dev/api/v2/enrichments
GET  https://api.abm.dev/api/v2/enrichments/{id}

Authenticate with a header. Send JSON.

HTTP
x-api-key: YOUR_API_KEY
Content-Type: application/json
JSON
{ "targets": [ { "type": "person", "email": "[email protected]" } ] }

Each target also takes a LinkedIn URL or a company domain. You POST once to start an enrichment, then GET the same {id} to read it. The {id} is your handle for everything after.

Note

Send your key as either the x-api-key header (used here) or Authorization: Bearer on POST /api/v2/enrichments. The full, live contract is at the API reference.

What a “clean” response still won’t promise

There is no failure here, but you should plan for it anyway.

A response is a set of canonical fields — eighty-nine of them, forty-three person and forty-six company — plus up to forty signals. Resolved from ten data sources: LinkedIn, Companies House, Perplexity, Tavily, Hunter, and others, returned as one answer.

Every value carries three things: its source (which provider stood behind it), a confidence between 0 and 1, and a selection_reason explaining why that value was chosen. Higher confidence means more sources agreed. Lower confidence means fewer. Read it; do not assume it.

The rule that governs all of this: a value is cited or it is not returned.No fabricated facts. No silent fallbacks. So a “missing” field is not an error. It is honesty. If a contact has no verified title, you get no title — not a guess.

Treat absence as a first-class case. Branch on whether a field is present, not on whether the request succeeded.

When a request is rejected

A request can be rejected before any enrichment runs. The usual reasons:

  • The key is wrong, missing, or revoked. Check the x-api-key header. Generate or rotate keys from the dashboard and the getting-started guide.
  • The body is malformed. It must be valid JSON with Content-Type: application/json. Match the shape above: a type and an input.
  • The input cannot be resolved. An address that points nowhere, a domain that does not exist. There is nothing to cite, so nothing comes back.

Lead with the simple checks. Most rejected requests are a bad header or a bad body, not a bad service.

The exact HTTP status codes and error-response shape are documented with the live endpoints — see the enrichment reference. We will not reprint numbers here that we cannot verify.

When a request is slow

Enrichment talks to ten sources. Sometimes one of them is slow, and the answer takes a moment to assemble.

For agent loops, abm.dev streams progress in real time over SSE, so a long-running enrichment is not a black box — you watch it fill in. For batch jobs, a webhook fires when the job finishes; you do not poll a queue by hand. (Streaming and webhook specifics are evolving — see the jobs reference and for-agents for the current contract.)

If you are not streaming, the pattern is plain: POST to start, then GET /api/v2/enrichments/{id} to read the result when it is ready.

How to retry without making it worse

The {id} is the safety rail. Reading an enrichment is just a GET — do it as many times as you like.

  1. POST once to start. Keep the {id} it returns.
  2. Re-read, don’t re-submit. If a read is slow or your connection drops, GET /api/v2/enrichments/{id} again. You are reading the same job, not buying a new one.
  3. Space out retries. Wait a little, wait longer the next time. A failed read is rarely fixed by an instant second try.
  4. Stop and look at persistent failures. If a GET keeps failing, the problem is the request or the key, not luck. Re-check the header and the {id}.

This matters for cost. Pricing is per enrichment — about €0.29 each, no subscription, credits that never expire, all ten sources included. Re-reading an {id} with GET does not start a new enrichment. Re-POSTing the same input does. When in doubt, read; do not re-submit. See pricing.

What we are not telling you (on purpose)

No invented rate-limit numbers. No plan-tier names. No retry schedule we cannot stand behind. No webhook signature scheme. The live API reference is the source of truth for limits, status codes, and the webhook contract; this page points you there rather than guessing.

If you hit a wall the docs don’t cover, open a ticket.

Where to go next

abm.dev is operated by Foxley Farm Operations Ltd (UK Company No. 16392009), Oakham, United Kingdom. GDPR-compliant.