Batch / Bulk Endpoint
One API call that handles many records at once, instead of firing a separate request per row until the rate limit cuts you off.
See it
What it is
A batch endpoint takes an array where the normal endpoint takes an object: POST /contacts/batch with 500 contacts instead of 500 calls to POST /contacts. You win back the per-request overhead: 500 round trips collapse into one, along with 499 sets of headers, auth checks, and handler dispatches, plus most of your rate limit budget, and the server gets to do one bulk database write instead of five hundred single-row ones. Connection setup is usually not part of the win, since HTTP clients keep connections alive and reuse them; count it only when every call would have opened a fresh one.
Reach for it on imports, migrations, backfills, and nightly syncs. Four decisions to make out loud: the maximum items per call (100 to 1000 is the usual range), whether the batch is all-or-nothing inside a transaction or allows partial success, whether it answers synchronously or hands back a job id to poll, and how the caller pages through work that exceeds the limit. Anything longer than a few seconds of processing should go async.
Gotcha: partial success is where batch APIs get painful. If item 237 fails validation, a bare 400 tells the caller nothing, so return a per-item result array carrying the input index, a stable error code, and the id on success. Let callers attach their own reference id to each item so results can be matched back to source rows, and make the whole call idempotent: a client that times out and retries should not create 500 duplicates.
Ask AI for it
Add a bulk endpoint POST /contacts/batch that accepts { items: [...] } with a maximum of 500 items and an Idempotency-Key header. Validate all items first, then persist them in a single bulk database operation. Use partial-success semantics: respond 207 with { results: [{ index, ref, status: 'created' | 'failed', id, error: { code, message } }], summary: { created, failed } } so the caller can retry only the failures. Reject oversized payloads with 413 and a message stating the limit. If the work would take more than 10 seconds, return 202 with a jobId instead and add a GET /jobs/:id endpoint reporting progress and per-item results.