# How do I retry failed data API calls in a batch job without being billed twice?

> Safe retries for a nightly Douyin or TikTok comment job: which errors to retry, how one Idempotency-Key per request prevents double billing, and a retry function.

Canonical page: https://okdata.online/answers/retry-api-calls-without-double-billing/

**Short answer: **Give every request its own retry key, derived from the endpoint and parameters, and resend with that same key when a call times out or the connection drops. On okdata a repeat within 24 hours returns the stored result at no charge, so a 1,500-page Douyin comment job costs $3.00 however many retries it takes. Retry only errors marked as retryable, and never retry a not-found.

A nightly job pulls three pages of comments for each of 500 Douyin videos. Somewhere in those 1,500 calls a few will time out or lose the connection. The dangerous case is the one where you never saw a response: the call may have completed and been billed, or not. Retrying blindly can pay twice; not retrying leaves a hole in the data. Idempotency keys remove the dilemma.

## How the key works

- Send an `Idempotency-Key` header with each request.
- The same key with the same request within 24 hours returns the stored result: `meta.replayed: true`, a charge of `"0"`, and an `Idempotent-Replayed: true` header.
- If the first attempt failed, nothing was stored, so the retry simply runs again. Failed calls were never charged.
- If the first attempt is still running, you get `rate_limited` with `retry_after_seconds: 1`. Wait and resend.
- The same key with a different request is rejected as `invalid_params`, so derive one key per request, not one per job.

How long a key lasts is a common question with every API that uses them, as in [this one about payment keys](https://developer.squareup.com/forums/t/how-long-are-idempotency-keys-retained-for-the-createpayment-endpoint/28303). Here the answer is 24 hours.

## Which outcomes to retry

| Code | Retry? |
|---|---|
| `rate_limited` | yes, after `retry_after_seconds` |
| `upstream_busy`, `upstream_failed`, `internal_error` | yes, with backoff |
| `timeout`, or no response at all | yes, with the same key |
| `not_found`, `invalid_params`, `unauthorized`, `insufficient_balance` | no, fix or skip |

## A retry function to paste

```python
import hashlib, json, os, time, requests

KEY = os.environ["OKDATA_API_KEY"]

def call(path, **params):
    idem = hashlib.sha256(json.dumps([path, params], sort_keys=True).encode()).hexdigest()
    h = {"Authorization": f"Bearer {KEY}", "Idempotency-Key": idem}
    for attempt in range(6):
        try:
            body = requests.get(f"https://api.okdata.online{path}", headers=h, params=params, timeout=90).json()
        except requests.RequestException:
            time.sleep(2 ** attempt)              # no response: resend with the same key
            continue
        if body["code"] == "ok":
            return body
        if body.get("retry") not in ("yes", "same_key"):
            raise RuntimeError(f"{body['code']}: {body['message']}")
        time.sleep(body.get("retry_after_seconds") or 2 ** attempt)
    raise RuntimeError(f"gave up after retries: {path} {params}")

page = call("/v1/douyin/videos/comments/list", id="7301234567890123456", sort="hot")
```

The same function works for [TikTok video comments](/apis/tiktok/videos/comments/list/) and every other endpoint; [Douyin video comments](/apis/douyin/videos/comments/list/) is $0.002 a page, and a replay is free.

## Two more habits

- Keep each response's `request_id`. `GET https://api.okdata.online/v1/calls/{request_id}` tells you how any single call settled.
- Cap the attempts. A call that still fails after six tries usually means an outage; check the status and rerun the job later with the same keys.

The full list of codes, with which are charged and which are worth retrying, is on the [errors page](/docs/errors/).

## Endpoints used

- [Douyin video comments](https://okdata.online/apis/douyin/videos/comments/list/) `douyin.videos.comments.list`: $0.002 per call · about 20 comments per page
- [TikTok video comments](https://okdata.online/apis/tiktok/videos/comments/list/) `tiktok.videos.comments.list`: $0.002 per call · about 50 comments per page

Updated 2026-11-12
