Build a cancellation transaction

Builds an unsigned transaction that cancels a withdrawal request, for the customer's wallet to sign.

POST/v1/earn/external-wallet/withdrawal-request-cancel-transactions

A solver queue request can be canceled only at expiredCancelable, because a solver may fulfill it until its deadline; before then the build returns 409 CONFLICT. An operator redemption that allows cancellation can be canceled while pending, which leaves the customer holding the intermediate token, not the original shares. Requires earn.manage. Cancellation stays available without production access and while Earn is disabled; a suspended organization still cannot authenticate.

Requires an API key with the earn.manage action.

Headers

  • x-project-id · string · min length 1 · example prj_example

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

Request body

application/json · required

Build a cancellation for the customer's wallet to sign. A solver queue request becomes cancelable at expiredCancelable; an operator redemption that allows cancellation can be canceled while pending.

  • withdrawalRequestId · string · required · min length 1 · max length 128 · example earn_vault_withdrawal_request_3c905ad2-c92c-4258-9675-1899c41569b9

  • feePayer · string · min length 32 · max length 44 · pattern ^[1-9A-HJ-NP-Za-km-z]{32,44}$ · example 3nMFwZXwY1s1M5s8vYAHqd4wGs4iSxXE4LRoUMMYqEgF

    Pay for this transaction from a wallet your backend controls instead of the customer's. The named address becomes the fee payer: it pays the network fee, funds any share-account rent, and must sign alongside the customer. Co-sign on your backend before you submit. The build returns 400, naming the fee payer, when it cannot pay. Sending the customer's own address keeps the default: the customer pays and signs alone.

Responses

  • 200 Unsigned cancellation transaction

    • data · object · required

      • transaction · object · required

        A cancellation for the customer's wallet to sign.

        • transactionId · string · required · example earn_external_wallet_transaction_e7a88258-1d19-48f3-8d0e-81fefa4bf3b3

        • transaction · string · required

          Base64 wire bytes of the unsigned transaction. Add every required signature without changing the message, then submit through SDP. The blockhash bounds when the network can first accept it; retain the original signed bytes for recovery.

        • lastValidBlockHeight · string · required · example 361186610

          Last block height at which the network can first accept this transaction. This is a block height, not a slot or timestamp.

        • sponsored · boolean · required · example false

          Always false: SDP does not pay an external wallet's fees. The customer's wallet pays, or the feePayer you name.

        • ownerAddress · string · required · example 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM

          The customer's wallet address.

        • feePayer · string · example 3nMFwZXwY1s1M5s8vYAHqd4wGs4iSxXE4LRoUMMYqEgF

          The feePayer your build request named. When present, the transaction needs the fee payer's signature as well as the customer's: co-sign on your backend before you submit, or the submit refuses it. When omitted, the customer signs alone and pays the fee.

        • provider · string · required · example kamino

        • providerReference · string · required · example 7uib8xGAwkaPz4ZGCA6t8sSEid5Yp9ty13PHUweTypx

          The strategy's onchain address at the provider. It identifies the instrument; never send funds to it.

        • tokenMint · string · required · example 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU

        • shareMint · string · required · example hXm2xSRF5PLKGMrTvAWqKhR76MuJX5dAabeSChkjqu2

        • positionId · string · required · example earn_position_2f8b6b04-7147-487e-b760-b1caa4fbcb8b

        • withdrawalRequestId · string · required · example earn_vault_withdrawal_request_3c905ad2-c92c-4258-9675-1899c41569b9

        • action · string · required · always cancel

        • mechanism · string · required · one of solverQueue, operatorRedemption

        • requestAddress · string · required

          Provider request account address.

    • 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 earn.manage 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.

  • 429 Too Many Requests

    Same fields as 400.

  • 500 Internal Server Error

    Same fields as 400.

  • 501 The provider does not support this operation.

    • error · object · required

      Standard error payload.

      • code · string · required

      • 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.

  • 503 Service Unavailable

    Same fields as 400.

Example request

curl -X POST 'https://api-beta.solana.com/v1/earn/external-wallet/withdrawal-request-cancel-transactions' \
  -H "Authorization: Bearer $SDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "withdrawalRequestId": "earn_vault_withdrawal_request_3c905ad2-c92c-4258-9675-1899c41569b9"
  }'
const res = await fetch("https://api-beta.solana.com/v1/earn/external-wallet/withdrawal-request-cancel-transactions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SDP_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "withdrawalRequestId": "earn_vault_withdrawal_request_3c905ad2-c92c-4258-9675-1899c41569b9"
  })
});
import os, requests

r = requests.post("https://api-beta.solana.com/v1/earn/external-wallet/withdrawal-request-cancel-transactions",
  headers={"Authorization": f"Bearer {os.environ['SDP_API_KEY']}"},
  json={
    "withdrawalRequestId": "earn_vault_withdrawal_request_3c905ad2-c92c-4258-9675-1899c41569b9"
  })

Example responses

JSON
{
  "data": {
    "transaction": {
      "transactionId": "earn_external_wallet_withdrawal_request_transaction_9a3c1e27-5d84-4f0b-b6e2-7f19c4a8d035",
      "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
      "lastValidBlockHeight": "361187340",
      "sponsored": false,
      "ownerAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
      "provider": "veda",
      "providerReference": "3wbKP5UGLT7gAZBAsLjvPC1NbfnWKtT3Dq7cniMWkzfU",
      "tokenMint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
      "shareMint": "CdV7pjj6WANsdasKsBvdKAn7qJL7cQ2Q3CJMBEe13WAV",
      "positionId": "earn_position_0432ffeb-c574-4b11-80dc-a09defb68fcc",
      "requestAddress": "DKw4pYcvXNLs91RssedGFznWRpbvPttp2AAwNCG7fQRz",
      "withdrawalRequestId": "earn_vault_withdrawal_request_3c905ad2-c92c-4258-9675-1899c41569b9",
      "action": "cancel",
      "mechanism": "solverQueue"
    }
  },
  "meta": {
    "requestId": "req_example",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}
JSON
{
  "error": {
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "Missing action: earn.manage",
    "details": {
      "action": "earn.manage"
    }
  },
  "meta": {
    "requestId": "req_example"
  }
}

Error responses use the standard error shape.