Batch requests

Send APIVerve batch requests at scale: dedupe and chunk inputs, read per-item results, re-queue only rate-limited items, and reconcile what was billed.

  • 40 min
  • Advanced

The Fundamentals course introduced batching as a loop: slice the list into 200s, post each slice, pause if anything was rate-limited. That loop is correct and it is enough for a few hundred rows. At production volume it has three gaps. It pays for duplicate inputs. It treats a chunk as all-or-nothing when the API reports success item by item. And after a pause it moves on to the next chunk, so the items that were turned away are simply lost.

This lesson builds the version you would run against a real list: plan the batches, send them, classify every item, and re-queue exactly the ones that are worth sending again.

The contract, precisely

A batch is per endpoint: POST https://api.apiverve.com/v1/<api>/batch with a JSON body. Every element of requests is the parameter object you would send to that endpoint on its own. GET and POST endpoints are written the same way, as keys on the object.

{ "requests": [ { "number": 42 }, { "number": 7 }, { "number": "abc" } ] }

The response:

{
  "status": "ok",
  "count": 3,
  "billed": 2,
  "rateLimited": 0,
  "results": [
    { "status": "ok", "error": null, "data": { "number": 42, "words": "forty-two" } },
    { "status": "ok", "error": null, "data": { "number": 7, "words": "seven" } },
    { "status": "error", "error": "...", "data": null }
  ]
}

(data is trimmed here; each item carries the endpoint's full response.)

What each part guarantees:

PartMeaning
HTTP statusWhether the batch ran. 200 even if every item failed. A 4xx means the batch itself was refused: no requests array, more than 200 items, or a key problem that would stop a single call
countItems you sent
billedItems that cost credits. Multiply by the endpoint's per-call cost for credits spent
rateLimitedItems turned away by this minute's rate window
results[i]The answer to requests[i]. Order is guaranteed, so the index is the correlation

Each results entry is an ordinary envelope (status, error, data, and premium when fields were gated). Two kinds of item failure come from the batch machinery itself, and those carry a numeric code:

  • code: 429: the item did not fit in this minute's rate window. It also carries retryAfter, in seconds.
  • code: 402 with error: "insufficient credits": the account's balance ran out before this item.

Any other failed item has no code. It is the endpoint's own answer for that input (a validation error, nothing found), exactly what the same parameters would return as a single call. So branch on status first, and on code only to recognise the two batch-level refusals.

Two limits shape everything else: at most 200 items per call (201 is a 400 telling you to chunk), and one endpoint per batch. An empty requests array is legal and returns count: 0 immediately.

Try it liveNumber to Words1 credit
GEThttps://api.apiverve.com/v1/numbertowords
curl "https://api.apiverve.com/v1/numbertowords?number=200" \
  -H "x-api-key: YOUR_API_KEY"
Sign in or create a free account to run this with your own key.

One item's worth of work at 1 credit. A batch of 200 of these is still 200 credits; batching saves round trips, not credits.

How a batch spends credits and rate limit

Batching is easy to misread as a discount. It is not. Before running anything, the batch looks at two budgets and fills items in the order you sent them:

  1. Credits. It works out how many items your remaining balance can pay for at this endpoint's cost. Items past that point are answered with 402 and never run.
  2. Rate window. Of the affordable items, it takes as many as fit in your key's per-minute window and commits exactly that many slots. A batch of 150 uses 150 slots, not one. Items past the window come back as 429 with retryAfter.

Then the runnable items execute, the bill is settled once for the whole batch, and the response carries x-api-remaining-credits with the balance after settlement, plus x-rate-limit-limit, x-rate-limit-remaining and, when something was turned away, retry-after. Those rate headers are readable from server code; browsers cannot see them across origins.

Consequences you design around:

  • Chunk size is bounded by your rate limit, not just by 200. If your key's window holds 60 requests a minute, a 200-item batch runs 60 and returns 140 429s. Read x-rate-limit-limit from any response and size chunks to the room you actually have.
  • Credit-refused items do not burn rate slots. A 402 item never reaches the window.
  • Order is priority. Credits and rate room are both handed out from the front of the array. If the list might exceed what you can afford, put the rows that matter most first.
  • Only successful items bill. Validation failures, 402s and 429s cost nothing. billed, not count, is the number to reconcile.
  • Duplicates bill every time. Two identical items are two lookups and two charges. The API does not deduplicate for you.

That last point is the cheapest win in this lesson.

Check yourself

Your key's window allows 60 requests per minute and it is currently empty. You send one batch of 200 Email Validator items (20 credits each); 5 of the first 60 items are malformed emails, and the balance covers everything. What comes back?

Run every example on your own key. Free plan, no card.

Scaling up?

Volume pricing, custom SLAs, and dedicated support for high-traffic teams.

Contact sales