> Solana Developer Platform docs, served as Markdown. The [docs index](https://platform.solana.com/docs.md) lists every page and [llms.txt](https://platform.solana.com/docs/ai/llms.txt) the key ones; [SKILL.md](https://platform.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 with the batch's options, 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. 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`. Only recipients that are still `failed` are ever sent, so a retry under a new key never pays anyone twice.

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.

      - **`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 · one of `pending`, `processing`, `confirmed`, `finalized`, `failed`, `awaiting_payment`, `settling`, `completed`, `canceled`, `expired` · 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. A ramp is confirmed once its delivery is verified onchain.

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

        Transaction fee in lamports.

      - **`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.

      - **`rampsMemo`** · `object` · required

        Free-form key-value memo for offchain reconciliation of ramp transfers. At most 20 entries.

        - **`*`** · `string` · min length 1 · max length 256

      - **`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.

      - **`providerReference`** · `string` · example `ramp_quote_example`

        Provider quote or transaction reference used for ramp correlation.

      - **`deliveryMode`** · `string` · one of `hosted`, `manual_instructions`, `session_widget` · example `session_widget`

        Ramp delivery mode. Hosted flows require the customer to complete a provider-hosted UI; manual instructions require the customer to fund displayed instructions; session widgets use a provider SDK session.

      - **`fiatCurrency`** · `string` · example `USD`

        Fiat currency for the ramp leg.

      - **`fiatAmount`** · `string` · example `100.00`

        Quoted fiat amount for the ramp leg: what the customer pays on an on-ramp, the payout quoted on an off-ramp. It never changes after the quote; an off-ramp's final payout is `fiatPayout`.

      - **`fiatPayout`** · `object`

        What the provider reports paying out once it settles an off-ramp sale. Provider-reported: SDP cannot verify a bank payout.

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

          Fiat paid out, in display units. Differs from the quoted `fiatAmount` when the provider re-prices the sale at receipt.

        - **`currency`** · `string` · required · example `USD`

          ISO currency of the payout, as the provider reports it.

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

          When the provider reported the payout.

      - **`deliveryMismatch`** · `object`

        Present while SDP holds a provider-settled ramp in `settling` because the chain contradicts the provider's delivery. A new provider report clears it.

        - **`reason`** · `string` · required · one of `provider_report_mismatch`, `transaction_failed`, `predates_transfer`, `not_delivered`, `amount_mismatch`, `transaction_not_found` · example `amount_mismatch`

          Why the chain contradicts the provider: `provider_report_mismatch` (its report contradicts SDP's record), `transaction_failed`, `predates_transfer` (the transaction landed before the transfer), `not_delivered` (nothing of the quoted asset reached the quoted wallet), `amount_mismatch`, or `transaction_not_found` (no finalized transaction an hour after the report; SDP keeps checking, and a later delivery completes the transfer).

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

          When SDP's delivery check reached this verdict.

        - **`reportedAmount`** · `string` · example `20`

          What the provider reported delivering, in display units.

        - **`observedAmount`** · `string` · example `0.5`

          What the chain shows the quoted wallet received, in display units.

      - **`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`.

## Example request

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

```ts tab="TypeScript"
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": crypto.randomUUID()
  }
});
```

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

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": str(uuid.uuid4())})
```

## 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": 5000,
        "error": "Signature failed",
        "initiatedBy": {
          "type": "api_key"
        },
        "source": "So11111111111111111111111111111111111111112",
        "destination": "So11111111111111111111111111111111111111112",
        "rampsMemo": {
          "invoice": "INV-123",
          "po": "PO-9"
        },
        "amount": "100.00",
        "counterpartyId": "cpty_example",
        "counterpartyDisplayName": "Acme Studio",
        "providerReference": "ramp_quote_example",
        "deliveryMode": "session_widget",
        "fiatCurrency": "USD",
        "fiatAmount": "100.00",
        "fiatPayout": {
          "amount": "20.82",
          "currency": "USD",
          "reportedAt": "2025-01-02T00:00:00.000Z"
        },
        "deliveryMismatch": {
          "reason": "amount_mismatch",
          "checkedAt": "2025-01-02T00:00:00.000Z",
          "reportedAmount": "20",
          "observedAmount": "0.5"
        },
        "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).
