---
title: "POST /api/v1/batches"
method: POST
path: "/api/v1/batches"
---

# POST /api/v1/batches

`POST /api/v1/batches`

## Request

- Base URL: `https://12backlinks.com`
- URL: `https://12backlinks.com/api/v1/batches`
- Auth: HTTP bearer

Measure how many referring domains the pages ranking on Google page 1 have, for each keyword in a market: median and q25 to q75 range of the top 10, compared with positions 11 to 30, with a significance test. PAID: 1 credit per unique keyword, charged at launch, including cached results; a failed analysis is not refunded. Check get_account first and tell the user the cost. Call it sequentially (one launch at a time per account; a concurrent launch gets 429 launch_in_progress, retry after a few seconds); get_batch can run in parallel. Returns the batch: HTTP 201 (MCP http_status 201) = new batch, charged; 200 = idempotent replay of the existing batch, nothing charged. If status is still running, call get_batch with wait=40.

## Request body

- object
  - `items` object[], required: 1 to 100 keywords. Duplicates (same keyword, domain and lang after normalisation) are merged before billing.
    - `keyword` string, required: Keyword to analyse. Normalised like the free tool: trimmed and lowercased.
    - `domain` string: Google domain for this keyword, e.g. google.fr. Defaults to the top-level domain.
    - `lang` string: Language for this keyword, e.g. fr. Defaults to the top-level lang.
  - `domain` string: Default Google domain for every item. Default google.fr.
  - `lang` string: Default language for every item. Default fr.
  - `name` string: Optional batch name, shown in the 12Backlinks history.
  - `wait` integer: Seconds to wait for the results before answering (0 to 45). Default 0 over REST, 40 over MCP. One analysis takes about 15 seconds.
  - `idempotency_key` string: Recommended. 16 to 128 characters [A-Za-z0-9_-]. Reuse the SAME key with the SAME input after a timeout: the existing batch is returned without a new charge. Same key with a different input: 409.

## Response `200`

Idempotent replay: same idempotency_key and same input, existing batch returned, nothing charged.

- object
  - `batch_id` string
  - `name` string, nullable
  - `source` 'api' | 'ui'
  - `status` 'running' | 'done' | 'partial'
  - `created_at` string, date-time
  - `credits_charged` integer, nullable: Read from the credit ledger; null when it cannot be read (unknown, not zero).
  - `items` object[]
    - `analysis_id` string, nullable
    - `keyword` string
    - `domain` string
    - `lang` string
    - `status` 'pending' | 'running' | 'done' | 'failed'
    - `fail_reason` 'serp_unavailable' | 'backlink_data_unavailable' | 'timeout' | 'invalid_params' | 'launch_failed' | 'analysis_failed' | 'null', nullable
    - `result` object, nullable: null until status is done.
      - `page` object: Towards the ranking page. Referring domains: median and q25 to q75 range of the top 10, median of positions 11 to 30, Mann-Whitney test. null means unknown, never zero.
        - `median_top10` number, nullable
        - `q25_top10` number, nullable
        - `q75_top10` number, nullable
        - `median_rest` number, nullable
        - `significant` boolean, nullable: true when p_value < 0.05: links separate the top 10 from positions 11 to 30.
        - `p_value` number, nullable
      - `domain` object: Towards the root domain of the ranking page. Referring domains: median and q25 to q75 range of the top 10, median of positions 11 to 30, Mann-Whitney test. null means unknown, never zero.
        - `median_top10` number, nullable
        - `q25_top10` number, nullable
        - `q75_top10` number, nullable
        - `median_rest` number, nullable
        - `significant` boolean, nullable: true when p_value < 0.05: links separate the top 10 from positions 11 to 30.
        - `p_value` number, nullable
      - `serp_results` integer, nullable: Number of organic results analysed (positions 1 to 30).
  - `next_step` string: What to do next, e.g. call get_batch with wait=40 while status is running.

## Other responses

- `201`: Batch created and charged.
- `400`: invalid_request: invalid input.
- `401`: unauthorized: missing, malformed or revoked API key.
- `402`: insufficient_credits: with credits_required and credits_available. Nothing launched, nothing charged.
- `404`: not_found: missing or not owned by this account.
- `409`: idempotency_conflict: the idempotency_key was used with a different input.
- `422`: invalid_market: unsupported domain and lang pair, with valid_markets.
- `429`: launch_in_progress: another batch launch is running for this account. Retry after the Retry-After header (seconds); launch batches one at a time.
- `500`: internal_error: unexpected error; retry later, mutations with the same idempotency_key.
- `503`: upstream_unavailable: retry later; mutations with the same idempotency_key.

---

[API](https://skmtc.dev/12backlinks/apis/12backlinks-api.md) · [All operations](https://skmtc.dev/12backlinks/apis/12backlinks-api/llms.txt) · [OpenAPI document](https://skmtc.dev/12backlinks/apis/12backlinks-api/revisions/8936d132d496?raw)
