# Batches — API reference

Source: https://tenergy.me/docs/api/batches
Last updated: 2026-09-27

One request, many receivers.

| Method | Path | Summary |
|---|---|---|
| `GET` | `/v1/batches` | List batches |
| `POST` | `/v1/batches` | Order for many receivers in one call |
| `GET` | `/v1/batches/{batchId}` | Batch progress |
| `POST` | `/v1/batches/{batchId}/cancel` | Cancel the not-yet-started part of a batch |

Generated from [`openapi.yaml`](https://tenergy.me/openapi.yaml) at build time. Base URL `https://api.tenergy.me/v1`, or `https://api-nile.tenergy.me/v1` on Nile ([Environments](https://tenergy.me/docs/environments)). Every request below is signed as in [Authentication](https://tenergy.me/docs/authentication) unless its **Auth** line says otherwise.

## List batches

`GET /v1/batches` · `listBatches`

**Auth:** API key (HMAC).

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `limit` | query | integer |  |  |
| `cursor` | query | string |  | Opaque cursor from a previous response's `next_cursor`. |

### Responses

| Status | Meaning |
|---|---|
| `200` | OK |
| `401` | Missing, malformed or rejected credentials. |
| `429` | Too many requests. |
| `500` | Something broke on our side. |

#### Response fields

| Field | Type | Required | Description |
|---|---|---|---|
| `data` | array of object (Batch) | yes |  |
| `data[].id` | string | yes |  |
| `data[].client_batch_id` | string \| null |  |  |
| `data[].status` | enum: `queued`, `processing`, `completed`, `partial`, `failed`, `cancelled` | yes | The batch's own state, derived from its items. `partial` means some receivers succeeded and some did not — inspect `items`, never assume all-or-nothing. |
| `data[].items_accepted` | integer | yes |  |
| `data[].summary` | object | yes | Counts by item status. Cheaper to poll than the full item list. |
| `data[].summary.total` | integer |  |  |
| `data[].summary.queued` | integer |  |  |
| `data[].summary.processing` | integer |  |  |
| `data[].summary.completed` | integer |  |  |
| `data[].summary.partial` | integer |  |  |
| `data[].summary.failed` | integer |  |  |
| `data[].summary.insufficient_funds` | integer |  |  |
| `data[].summary.cancelled` | integer |  |  |
| `data[].items` | array of object (BatchItem) | yes |  |
| `data[].items[].receiver` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `data[].items[].tracking_id` | string | yes | `<client_batch_id>:<receiver>` — the identity of one receiver in one batch. |
| `data[].items[].status` | enum: `queued`, `processing`, `completed`, `partial`, `failed`, `insufficient_funds`, `cancelled` | yes |  |
| `data[].items[].resource` | enum: `energy`, `bandwidth`, `activation` |  | `energy` — TRON energy, the resource a TRC-20 transfer consumes. · `bandwidth` — TRON bandwidth (net), consumed by transaction size. · `activation` — one-off account activation; `amount` and `tier` do not apply. |
| `data[].items[].amount` | integer |  |  |
| `data[].items[].tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Rental period. The API sells `5m` and `1h`; `1d` exists but is switched off. `15m`, `3d` and `30d` are retired and never sold — they stay in the enum only so old orders parse. Check `available` on each `GET /v1/prices` row; a tier that is not available is rejected with `2003 tier_unavailable`. |
| `data[].items[].delivered_amount` | integer |  | How much was actually delegated. Below `amount` when `status` is `partial`. |
| `data[].items[].order_ids` | array of string |  | The orders created for this receiver — more than one when a large amount was chunked. These are ordinary orders: inspect and reclaim them individually. |
| `data[].items[].delegate_hashes` | array of string |  |  |
| `data[].items[].charged_amount_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `data[].items[].activation` | object |  |  |
| `data[].items[].bandwidth` | object |  |  |
| `data[].items[].attempts` | integer |  |  |
| `data[].items[].started_at` | string (date-time) \| null |  |  |
| `data[].items[].finished_at` | string (date-time) \| null |  |  |
| `data[].items[].failure` | null \| object |  |  |
| `data[].created_at` | string (date-time) | yes |  |
| `data[].finished_at` | string (date-time) \| null |  |  |
| `next_cursor` | string \| null | yes |  |

## Order for many receivers in one call

`POST /v1/batches` · `createBatch`

**Auth:** API key (HMAC).

Up to 100 receivers per request. For each receiver the platform runs the whole sequence —
activate the address if it is not active, top up its bandwidth if it is short, then deliver
the resource, splitting large amounts into chunks automatically.

The response is **`202 Accepted`**: the batch is queued, nothing is charged yet, and
nothing has been delivered. Read the result from `GET /v1/batches/{id}` or from the
per-order webhooks.

One receiver failing never affects the others, and a failed activation or bandwidth step
does not stop the resource order for that receiver.

Receivers are billed individually, at the price in force when each one is executed — so a
long batch may span a pricing period boundary. Pass `max_price_sun` per item to cap that.

Each receiver produces its own order with its own id, which is what you reclaim, inspect
and reconcile against. `client_batch_id` is the idempotency key for the batch as a whole:
a repeat with the same id and the same body returns the original batch; the same id with a
different body is rejected with `3010 idempotency_conflict`.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `Idempotency-Key` | header | string |  | Client-chosen key making this mutating request safe to retry, 8–128 characters of `A-Z a-z 0-9 . _ : -`. A repeat with the same key and the same body returns the original result; the same key with a different body is rejected with `3010 idempotency_conflict`. Records live for 24 hours. |

### Request body

JSON (`BatchRequest`), required.

| Field | Type | Required | Description |
|---|---|---|---|
| `client_batch_id` | string |  | Your reference for the batch and its idempotency key. Required unless you send the `Idempotency-Key` header; with neither the request is rejected with `2005 idempotency_key_required`. |
| `defaults` | object (BatchItemOptions) |  | Applied to every item that does not override the field itself. |
| `defaults.resource` | enum: `energy`, `bandwidth`, `activation` |  | `energy` — TRON energy, the resource a TRC-20 transfer consumes. · `bandwidth` — TRON bandwidth (net), consumed by transaction size. · `activation` — one-off account activation; `amount` and `tier` do not apply. |
| `defaults.amount` | integer |  |  |
| `defaults.tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Rental period. The API sells `5m` and `1h`; `1d` exists but is switched off. `15m`, `3d` and `30d` are retired and never sold — they stay in the enum only so old orders parse. Check `available` on each `GET /v1/prices` row; a tier that is not available is rejected with `2003 tier_unavailable`. |
| `defaults.activate` | boolean |  |  |
| `defaults.bandwidth` | boolean |  | Top the receiver's bandwidth up when it is short, before delivering energy. |
| `defaults.bandwidth_amount` | integer |  | Bandwidth units to add when the top-up runs. |
| `defaults.max_price_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `defaults.client_order_id_prefix` | string |  | When set, each generated order gets `client_order_id = "<prefix>-<receiver>"`, so your side can reconcile without keeping our ids. |
| `items` | array of object | yes | Duplicate receivers within one batch are rejected with `2006 duplicate_receiver`. |
| `items[].receiver` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `items[].resource` | enum: `energy`, `bandwidth`, `activation` |  | `energy` — TRON energy, the resource a TRC-20 transfer consumes. · `bandwidth` — TRON bandwidth (net), consumed by transaction size. · `activation` — one-off account activation; `amount` and `tier` do not apply. |
| `items[].amount` | integer |  |  |
| `items[].tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Rental period. The API sells `5m` and `1h`; `1d` exists but is switched off. `15m`, `3d` and `30d` are retired and never sold — they stay in the enum only so old orders parse. Check `available` on each `GET /v1/prices` row; a tier that is not available is rejected with `2003 tier_unavailable`. |
| `items[].activate` | boolean |  |  |
| `items[].bandwidth` | boolean |  | Top the receiver's bandwidth up when it is short, before delivering energy. |
| `items[].bandwidth_amount` | integer |  | Bandwidth units to add when the top-up runs. |
| `items[].max_price_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `items[].client_order_id_prefix` | string |  | When set, each generated order gets `client_order_id = "<prefix>-<receiver>"`, so your side can reconcile without keeping our ids. |

Example request body, from the contract (illustrative values):

```json
{
  "client_batch_id": "acme-payout-2026-09-11-01",
  "defaults": {
    "resource": "energy",
    "tier": "1h",
    "amount": 65000,
    "activate": true,
    "bandwidth": true,
    "bandwidth_amount": 400
  },
  "items": [
    {"receiver":"TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"},
    {"receiver":"TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","amount":131000},
    {"receiver":"TYYyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy","bandwidth":false}
  ]
}
```

### Responses

| Status | Meaning |
|---|---|
| `200` | Same `client_batch_id` and same body — the original batch is returned. |
| `202` | Batch accepted and queued. Nothing charged yet. |
| `400` | Malformed request — bad JSON, unknown field, wrong type. |
| `401` | Missing, malformed or rejected credentials. |
| `402` | Not enough balance to cover the order. |
| `409` | The request contradicts the current state of the object. |
| `422` | Syntactically valid but semantically impossible. |
| `429` | Too many requests. |
| `500` | Something broke on our side. |
| `503` | Temporarily unable to serve. On order creation this is fail-secure: nothing was stored and nothing was charged, so retrying verbatim with the same `client_order_id` is safe. |

#### Response fields (`Batch`)

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | yes |  |
| `client_batch_id` | string \| null |  |  |
| `status` | enum: `queued`, `processing`, `completed`, `partial`, `failed`, `cancelled` | yes | The batch's own state, derived from its items. `partial` means some receivers succeeded and some did not — inspect `items`, never assume all-or-nothing. |
| `items_accepted` | integer | yes |  |
| `summary` | object | yes | Counts by item status. Cheaper to poll than the full item list. |
| `summary.total` | integer |  |  |
| `summary.queued` | integer |  |  |
| `summary.processing` | integer |  |  |
| `summary.completed` | integer |  |  |
| `summary.partial` | integer |  |  |
| `summary.failed` | integer |  |  |
| `summary.insufficient_funds` | integer |  |  |
| `summary.cancelled` | integer |  |  |
| `items` | array of object (BatchItem) | yes |  |
| `items[].receiver` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `items[].tracking_id` | string | yes | `<client_batch_id>:<receiver>` — the identity of one receiver in one batch. |
| `items[].status` | enum: `queued`, `processing`, `completed`, `partial`, `failed`, `insufficient_funds`, `cancelled` | yes |  |
| `items[].resource` | enum: `energy`, `bandwidth`, `activation` |  | `energy` — TRON energy, the resource a TRC-20 transfer consumes. · `bandwidth` — TRON bandwidth (net), consumed by transaction size. · `activation` — one-off account activation; `amount` and `tier` do not apply. |
| `items[].amount` | integer |  |  |
| `items[].tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Rental period. The API sells `5m` and `1h`; `1d` exists but is switched off. `15m`, `3d` and `30d` are retired and never sold — they stay in the enum only so old orders parse. Check `available` on each `GET /v1/prices` row; a tier that is not available is rejected with `2003 tier_unavailable`. |
| `items[].delivered_amount` | integer |  | How much was actually delegated. Below `amount` when `status` is `partial`. |
| `items[].order_ids` | array of string |  | The orders created for this receiver — more than one when a large amount was chunked. These are ordinary orders: inspect and reclaim them individually. |
| `items[].delegate_hashes` | array of string |  |  |
| `items[].charged_amount_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `items[].activation` | object |  |  |
| `items[].activation.status` | enum: `planned`, `not_needed`, `done`, `failed`, `skipped` |  |  |
| `items[].activation.hash` | string \| null |  |  |
| `items[].bandwidth` | object |  |  |
| `items[].bandwidth.status` | enum: `planned`, `enough`, `done`, `failed`, `skipped` |  |  |
| `items[].bandwidth.order_id` | string \| null |  |  |
| `items[].bandwidth.skip_reason` | enum: `option_off`, `amount_large` \| null |  | Why the bandwidth step did not run. `option_off` — you disabled it; `amount_large` — a large energy order does not need a bandwidth top-up. |
| `items[].attempts` | integer |  |  |
| `items[].started_at` | string (date-time) \| null |  |  |
| `items[].finished_at` | string (date-time) \| null |  |  |
| `items[].failure` | null \| object |  |  |
| `items[].failure.code` | integer |  |  |
| `items[].failure.slug` | string |  |  |
| `items[].failure.message` | string |  |  |
| `created_at` | string (date-time) | yes |  |
| `finished_at` | string (date-time) \| null |  |  |

## Batch progress

`GET /v1/batches/{batchId}` · `getBatch`

**Auth:** API key (HMAC).

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `batchId` | path | string | yes | Platform id (`bat_…`) or `cid:<client_batch_id>`. |
| `receiver` | query | string |  | Return only the item for this address instead of the whole batch. |

### Responses

| Status | Meaning |
|---|---|
| `200` | OK |
| `401` | Missing, malformed or rejected credentials. |
| `404` | No such object, or it belongs to another account. The two are not distinguished. |
| `429` | Too many requests. |
| `500` | Something broke on our side. |

#### Response fields (`Batch`)

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | yes |  |
| `client_batch_id` | string \| null |  |  |
| `status` | enum: `queued`, `processing`, `completed`, `partial`, `failed`, `cancelled` | yes | The batch's own state, derived from its items. `partial` means some receivers succeeded and some did not — inspect `items`, never assume all-or-nothing. |
| `items_accepted` | integer | yes |  |
| `summary` | object | yes | Counts by item status. Cheaper to poll than the full item list. |
| `summary.total` | integer |  |  |
| `summary.queued` | integer |  |  |
| `summary.processing` | integer |  |  |
| `summary.completed` | integer |  |  |
| `summary.partial` | integer |  |  |
| `summary.failed` | integer |  |  |
| `summary.insufficient_funds` | integer |  |  |
| `summary.cancelled` | integer |  |  |
| `items` | array of object (BatchItem) | yes |  |
| `items[].receiver` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `items[].tracking_id` | string | yes | `<client_batch_id>:<receiver>` — the identity of one receiver in one batch. |
| `items[].status` | enum: `queued`, `processing`, `completed`, `partial`, `failed`, `insufficient_funds`, `cancelled` | yes |  |
| `items[].resource` | enum: `energy`, `bandwidth`, `activation` |  | `energy` — TRON energy, the resource a TRC-20 transfer consumes. · `bandwidth` — TRON bandwidth (net), consumed by transaction size. · `activation` — one-off account activation; `amount` and `tier` do not apply. |
| `items[].amount` | integer |  |  |
| `items[].tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Rental period. The API sells `5m` and `1h`; `1d` exists but is switched off. `15m`, `3d` and `30d` are retired and never sold — they stay in the enum only so old orders parse. Check `available` on each `GET /v1/prices` row; a tier that is not available is rejected with `2003 tier_unavailable`. |
| `items[].delivered_amount` | integer |  | How much was actually delegated. Below `amount` when `status` is `partial`. |
| `items[].order_ids` | array of string |  | The orders created for this receiver — more than one when a large amount was chunked. These are ordinary orders: inspect and reclaim them individually. |
| `items[].delegate_hashes` | array of string |  |  |
| `items[].charged_amount_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `items[].activation` | object |  |  |
| `items[].activation.status` | enum: `planned`, `not_needed`, `done`, `failed`, `skipped` |  |  |
| `items[].activation.hash` | string \| null |  |  |
| `items[].bandwidth` | object |  |  |
| `items[].bandwidth.status` | enum: `planned`, `enough`, `done`, `failed`, `skipped` |  |  |
| `items[].bandwidth.order_id` | string \| null |  |  |
| `items[].bandwidth.skip_reason` | enum: `option_off`, `amount_large` \| null |  | Why the bandwidth step did not run. `option_off` — you disabled it; `amount_large` — a large energy order does not need a bandwidth top-up. |
| `items[].attempts` | integer |  |  |
| `items[].started_at` | string (date-time) \| null |  |  |
| `items[].finished_at` | string (date-time) \| null |  |  |
| `items[].failure` | null \| object |  |  |
| `items[].failure.code` | integer |  |  |
| `items[].failure.slug` | string |  |  |
| `items[].failure.message` | string |  |  |
| `created_at` | string (date-time) | yes |  |
| `finished_at` | string (date-time) \| null |  |  |

## Cancel the not-yet-started part of a batch

`POST /v1/batches/{batchId}/cancel` · `cancelBatch`

**Auth:** API key (HMAC).

Removes from the queue every receiver that has not been picked up yet. Receivers already
being processed are **not** interrupted — part of their resource may already be paid for.
Cancel is best-effort on the remainder.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `batchId` | path | string | yes |  |

### Responses

| Status | Meaning |
|---|---|
| `200` | OK |
| `401` | Missing, malformed or rejected credentials. |
| `404` | No such object, or it belongs to another account. The two are not distinguished. |
| `429` | Too many requests. |
| `500` | Something broke on our side. |

#### Response fields

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | yes |  |
| `cancelled` | integer | yes | How many receivers were removed from the queue. |
