> Solana Developer Platform docs, served as Markdown. The [docs index](https://platform-beta.solana.com/docs.md) lists every page and [llms.txt](https://platform-beta.solana.com/docs/ai/llms.txt) the key ones; [SKILL.md](https://platform-beta.solana.com/SKILL.md) has the rules for building on SDP.

# Retry a transfer batch's failed recipients

Sends the batch's failed recipients again, from the same source wallet, and no other recipient.

`POST /v1/payments/transfer-batches/{batchId}/retry`

A failed recipient was not paid: its transaction never reached the network or the network rejected it. Recipients still `pending` or `processing` may land and are never sent again. Each resent recipient keeps its row and links to its new chunk transfer.

Takes no body and requires an `Idempotency-Key`. A retry with the same key sends nothing again: while its response is stored, it returns that saved response, and after a server error or once the response has expired, the batch as it stands. Read the batch's current state with `GET /v1/payments/transfer-batches/{batchId}`, and use a new key for each retry you mean to send.

Any credential that may send from the batch's wallet can retry it. Each recipient is paid the address the batch recorded for it. Only recipients that are still `failed` are ever sent, so a retry under a new key never pays anyone twice.

Returns `409`, sending nothing: `TRANSFER_BATCH_NOTHING_TO_RETRY` when the batch has no failed recipients (while it is `processing`, its unsent recipients become `failed` only once its request can no longer send them), `TRANSFER_BATCH_RETRY_CLAIMED` when a concurrent retry claimed them first, and `TRANSFER_BATCH_DESTINATION_CHANGED` (`details.recipientIds`) when a failed recipient's counterparty account has changed its address since (send that recipient in a new batch). A native SOL retry is refused with `409` `AMOUNT_BELOW_RENT_MINIMUM`, as create is, when a failed recipient would still be paid less than the rent-exempt minimum at an address with no account; its recipients stay `failed`.

Requires an [API key](/docs/developing-with-sdp/authentication) with the `transfer_batches.execute` action.

## Path parameters

- **`batchId`** · `string` · required · min length 1 · example `xbatch_example`

  Transfer batch identifier.

## Headers

- **`x-project-id`** · `string` · min length 1 · example `prj_example`

  Required for dashboard sessions. API keys use their assigned project.

- **`Idempotency-Key`** · `string` · required

  Use a unique 1–255 printable ASCII key per operation. Reuse it with the same request on retries. An in-flight attempt returns `409`; a changed request returns `422`. [Retry and recovery rules](/docs/developing-with-sdp/idempotency).

## Responses

- **`200`** Failed recipients resent

  - **`data`** · `object` · required

    Transfer batch response payload.

    - **`batch`** · `object` · required

      Transfer batch details.

      - **`id`** · `string` · required · example `xbatch_example`

        Transfer batch identifier.

      - **`organizationId`** · `string` · required · min length 1 · example `org_example`

        Organization identifier.

      - **`projectId`** · `string` · required · min length 1 · example `prj_example`

        Project identifier for the transfer batch.

      - **`externalId`** · `string | null` · required · example `payroll_2026_06_30`

        Caller-provided batch correlation ID.

      - **`sourceCustodyWalletId`** · `string | null` · required · example `cwlt_example`

        Exact source SDP Wallet ID, or null for unresolved legacy batches.

      - **`sourceProviderWalletId`** · `string` · required · min length 1 · example `privy_wallet_123`

        Source Provider wallet ID retained as evidence.

      - **`sourceAddress`** · `string` · required · min length 32 · max length 44 · example `So11111111111111111111111111111111111111112`

        Source custody wallet address.

      - **`token`** · `string` · required · example `SOL`

        Token symbol or mint address.

      - **`status`** · `string` · required · one of `pending`, `processing`, `confirmed`, `failed`, `partially_failed`, `archived` · example `processing`

        Transfer batch status.

      - **`totalAmount`** · `string | null` · required · example `1000.00`

        Total requested batch amount in UI units, when computed.

      - **`recipientCount`** · `integer` · required · example `20`

        Number of recipient rows in the batch.

      - **`transactionCount`** · `integer` · required · example `1`

        Number of Solana transaction chunks for the batch.

      - **`createdAt`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

        ISO 8601 timestamp.

      - **`updatedAt`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

        ISO 8601 timestamp.

    - **`recipients`** · `object[]`

      Recipient rows for the batch, included on detail responses.

      - **`id`** · `string` · required

        Transfer batch recipient identifier.

      - **`batchId`** · `string` · required

        Parent transfer batch identifier.

      - **`transferId`** · `string | null` · required · min length 1 · example `xfr_example`

        Payment transfer chunk that settled this recipient, once assigned.

      - **`externalId`** · `string | null` · required · example `payroll_row_001`

        Caller-provided recipient correlation ID.

      - **`counterpartyId`** · `string` · required · example `cpty_example`

        Counterparty identifier for the recipient.

      - **`counterpartyAccountId`** · `string` · required · example `cpacct_example`

        Counterparty account identifier for the recipient.

      - **`destination`** · `string` · required · min length 32 · max length 44 · example `So11111111111111111111111111111111111111112`

        Resolved Solana destination address.

      - **`amount`** · `string` · required · example `100.00`

        Token amount in UI units (decimal string).

      - **`status`** · `string` · required · one of `pending`, `processing`, `confirmed`, `failed`, `archived` · example `pending`

        Transfer batch recipient status.

      - **`error`** · `string | null` · required

        Recipient-level failure reason, when available. A recipient the source wallet could not fund reads "The wallet used for this payment does not have enough funds. Add funds and try again."

      - **`createdAt`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

        ISO 8601 timestamp.

      - **`updatedAt`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

        ISO 8601 timestamp.

    - **`transfers`** · `object[]`

      Payment transfer chunk records associated with this batch.

      - **`fireblocks`** · `object`

        Native Fireblocks transfer tracking. A processing payment may await approval in Fireblocks; network fees are paid by its source vault. A missing transaction ID means submission is still being reconciled. Do not create a replacement payment while its outcome is unknown.

        - **`transactionId`** · `string | null` · required

        - **`status`** · `string` · required

        - **`subStatus`** · `string | null` · required

      - **`id`** · `string` · required · min length 1 · example `xfr_example`

        Transfer identifier (SDP record ID, not the on-chain signature).

      - **`organizationId`** · `string` · required · min length 1 · example `org_example`

        Organization identifier.

      - **`custodyWalletId`** · `string | null` · required · example `cwlt_example`

        Exact SDP Wallet ID associated with the persisted transfer, or null for unresolved legacy and observed rows.

      - **`providerWalletId`** · `string` · required · min length 1 · example `privy_wallet_123`

        Provider wallet ID retained as evidence; not an execution selector.

      - **`projectId`** · `string` · min length 1 · example `prj_example`

        Project identifier for the transfer.

      - **`type`** · `string` · required · example `transfer`

        Transfer type.

      - **`kind`** · `string` · required

        Dashboard transaction kind derived from the transfer type and originating Payments resource.

      - **`direction`** · `string` · required · one of `inbound`, `outbound` · example `outbound`

        Transfer direction.

      - **`status`** · `string` · required · example `confirmed`

        Transfer status.

      - **`signature`** · `string | null` · required · example `sig_example`

        Solana transaction signature (tx id/hash).

      - **`serializedTx`** · `string | null` · required · min length 1 · example `base64_tx_example`

        Base64-encoded transaction payload, if available. Always null for transfer batch chunks, whose signed bytes stay server-side.

      - **`slot`** · `integer | null` · required · example `123456`

        Slot number, if confirmed.

      - **`blockTime`** · `string | null` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

        Block time, if confirmed.

      - **`confirmedAt`** · `string` · format `date-time` · example `2025-01-01T00:00:00.000Z`

        When SDP confirmed the transfer on chain.

      - **`fee`** · `integer | null` · required · example `0`

        Network fee the source wallet paid, in lamports: 0 when SDP sponsored the transaction, null when not known.

      - **`error`** · `string | null` · required · example `Signature failed`

        Error message if the transaction failed.

      - **`initiatedBy`** · `object`

        Initiator that triggered the transfer.

        - **`type`** · `string` · required · one of `api_key`, `user`, `system` · example `api_key`

          Initiator type.

        - **`id`** · `string`

          Initiator identifier if applicable.

        - **`display`** · `string`

          Human-friendly label for the initiator.

      - **`source`** · `string` · min length 32 · max length 44 · example `So11111111111111111111111111111111111111112`

        Source wallet address.

      - **`destination`** · `string` · min length 32 · max length 44 · example `So11111111111111111111111111111111111111112`

        Destination wallet address.

      - **`memo`** · `string` · max length 256

        Optional memo for the transfer.

      - **`token`** · `string`

        Token symbol or mint address.

      - **`amount`** · `string` · example `100.00`

        Token amount in UI units (decimal string).

      - **`counterpartyId`** · `string` · example `cpty_example`

        Counterparty tied to the transfer record, when available.

      - **`counterpartyDisplayName`** · `string` · example `Acme Studio`

        Current display name of the counterparty tied to the transfer.

      - **`risk`** · `object`

        Optional risk evaluation for the transfer.

        - **`provider`** · `string` · required · example `trm`

          Risk scoring provider.

        - **`score`** · `string` · required · example `0.12`

          Provider-specific risk score.

        - **`level`** · `string` · required · one of `low`, `medium`, `high`, `unknown` · example `low`

          Risk level classification.

        - **`evaluatedAt`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

          Timestamp when risk was evaluated.

      - **`createdAt`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

        Creation timestamp.

      - **`updatedAt`** · `string` · required · format `date-time` · example `2025-01-02T00:00:00.000Z`

        Last update timestamp.

  - **`meta`** · `object` · required

    Response metadata.

    - **`requestId`** · `string` · required · min length 1 · example `req_example`

      Request identifier for tracing.

    - **`timestamp`** · `string` · required · format `date-time` · example `2025-01-01T00:00:00.000Z`

      ISO 8601 timestamp.

- **`400`** Bad Request

  - **`error`** · `object` · required

    Standard error payload.

    - **`code`** · `string` · required

      Machine-readable error code.

    - **`message`** · `string` · required

      Human-readable error message.

    - **`details`** · `object`

      Optional error details for debugging.

      - **`*`** · `any`

  - **`meta`** · `object`

    - **`requestId`** · `string` · min length 1 · example `req_example`

      Request identifier for tracing.

- **`401`** Unauthorized

  Same fields as `400`.

- **`403`** Forbidden. Requires the `transfer_batches.execute` action: an API key must hold it (a module's `manage` or `execute` also covers its `read`), and a signed-in member's organization role must include it. Without it the error is INSUFFICIENT_PERMISSIONS and `error.details.action` names the action. Any other 403 names its own reason.

  Same fields as `400`.

- **`404`** Not Found

  Same fields as `400`.

- **`409`** Conflict

  Same fields as `400`.

- **`422`** Unprocessable Entity

  Same fields as `400`.

- **`500`** Internal Server Error

  Same fields as `400`.

- **`502`** Bad Gateway

  Same fields as `400`.

- **`503`** Service Unavailable

  Same fields as `400`.

## Example request

```bash tab="cURL"
IDEMPOTENCY_KEY=$(uuidgen)
curl -X POST 'https://api.solana.com/v1/payments/transfer-batches/xbatch_example/retry' \
  -H "Authorization: Bearer $SDP_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY"
```

```ts tab="TypeScript"
// Reuse this key when you retry this request.
const idempotencyKey = crypto.randomUUID();
const res = await fetch("https://api.solana.com/v1/payments/transfer-batches/xbatch_example/retry", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SDP_API_KEY}`,
    "Idempotency-Key": idempotencyKey
  }
});
```

```python tab="Python"
import os, requests, uuid

# Reuse this key when you retry this request.
idempotency_key = str(uuid.uuid4())
r = requests.post("https://api.solana.com/v1/payments/transfer-batches/xbatch_example/retry",
  headers={"Authorization": f"Bearer {os.environ['SDP_API_KEY']}", "Idempotency-Key": idempotency_key})
```

## Example responses

```json tab="200"
{
  "data": {
    "batch": {
      "id": "xbatch_example",
      "organizationId": "org_example",
      "projectId": "prj_example",
      "externalId": "payroll_2026_06_30",
      "sourceCustodyWalletId": "cwlt_example",
      "sourceProviderWalletId": "privy_wallet_123",
      "sourceAddress": "So11111111111111111111111111111111111111112",
      "token": "SOL",
      "status": "processing",
      "totalAmount": "1000.00",
      "recipientCount": 20,
      "transactionCount": 1,
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    },
    "recipients": [
      {
        "id": "_example",
        "batchId": "batch_example",
        "transferId": "xfr_example",
        "externalId": "payroll_row_001",
        "counterpartyId": "cpty_example",
        "counterpartyAccountId": "cpacct_example",
        "destination": "So11111111111111111111111111111111111111112",
        "amount": "100.00",
        "status": "pending",
        "error": "example",
        "createdAt": "2025-01-01T00:00:00.000Z",
        "updatedAt": "2025-01-01T00:00:00.000Z"
      }
    ],
    "transfers": [
      {
        "fireblocks": {
          "transactionId": "transaction_example",
          "status": "example",
          "subStatus": "example"
        },
        "id": "xfr_example",
        "organizationId": "org_example",
        "custodyWalletId": "cwlt_example",
        "providerWalletId": "privy_wallet_123",
        "projectId": "prj_example",
        "type": "transfer",
        "kind": "example",
        "direction": "outbound",
        "status": "confirmed",
        "signature": "sig_example",
        "serializedTx": "base64_tx_example",
        "slot": 123456,
        "blockTime": "2025-01-01T00:00:00.000Z",
        "confirmedAt": "2025-01-01T00:00:00.000Z",
        "fee": 0,
        "error": "Signature failed",
        "initiatedBy": {
          "type": "api_key"
        },
        "source": "So11111111111111111111111111111111111111112",
        "destination": "So11111111111111111111111111111111111111112",
        "amount": "100.00",
        "counterpartyId": "cpty_example",
        "counterpartyDisplayName": "Acme Studio",
        "risk": {
          "provider": "trm",
          "score": "0.12",
          "level": "low",
          "evaluatedAt": "2025-01-01T00:00:00.000Z"
        },
        "createdAt": "2025-01-01T00:00:00.000Z",
        "updatedAt": "2025-01-02T00:00:00.000Z"
      }
    ]
  },
  "meta": {
    "requestId": "req_example",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}
```

```json tab="403"
{
  "error": {
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "Missing action: transfer_batches.execute",
    "details": {
      "action": "transfer_batches.execute"
    }
  },
  "meta": {
    "requestId": "req_example"
  }
}
```

Error responses use the [standard error shape](/docs/reference/conventions/errors).
