Build a withdrawal request transaction

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

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

A solver queue request escrows shares; an operator redemption converts shares into an intermediate token that the operator settles later. Neither transaction pays the customer. Save the withdrawalRequestId the submit returns and track the request until it is fulfilled, canceled, or failed.

Requires an API key with the earn.execute 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 keyed asynchronous withdrawal request. A solver request escrows shares; an operator redemption converts them into the provider's intermediate token, or delegates intermediate the owner already holds. Neither action pays assets.

Any of:

  • object

    • positionId · string · required · min length 1 · max length 128 · example earn_position_2f8b6b04-7147-487e-b760-b1caa4fbcb8b

      The position's ID, from the positions list or the deposit submit response.

    • shares · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 10

      Shares to place in the withdrawal request, in share units.

    • mechanism · string · always solverQueue

      Selects the solver queue, which is also the default when omitted. Operator redemptions must set mechanism explicitly.

    • discountBps · integer · required · min 0 · max 10000 · example 25

      Discount offered to a solver, in basis points. It must stay inside the live queueAsset minimum and maximum.

    • deadlineSeconds · integer · required · greater than 0 · max 7776000 · example 86400

      Solver window after maturity, in seconds. It must stay inside the live queueAsset minimum and maximum.

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

  • object

    • positionId · string · required · min length 1 · max length 128 · example earn_position_2f8b6b04-7147-487e-b760-b1caa4fbcb8b

      The position's ID, from the positions list or the deposit submit response.

    • shares · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 10

      Shares to place in the withdrawal request, in share units.

    • mechanism · string · required · always operatorRedemption

      Selects an operator redemption, which takes no solver discount or deadline.

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

  • object

    • positionId · string · required · min length 1 · max length 128 · example earn_position_2f8b6b04-7147-487e-b760-b1caa4fbcb8b

      The position's ID, from the positions list or the deposit submit response.

    • intermediateAmount · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 2000

      Intermediate token the owner already holds outside any request (such as a cancelled request's wYLDS) to redeem at par, in that token's units. Send instead of shares, never with it.

    • mechanism · string · required · always operatorRedemption

      Selects an operator redemption, which takes no solver discount or deadline.

    • 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 withdrawal request transaction

    • data · object · required

      • transaction · object · required

        Any of:

        • mechanism: "solverQueue"

          • 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

          • action · string · required · always request

          • mechanism · string · required · always solverQueue

          • requestAddress · string · required

            Provider request account address.

          • shares · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 25

            Positive decimal string with at least one non-zero digit; never a float.

          • assets · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 25

            Positive decimal string with at least one non-zero digit; never a float.

          • discountBps · integer · required · min 0 · max 10000

          • maturityTimestamp · string · required · pattern ^\d+$

          • deadlineTimestamp · string · required · pattern ^\d+$

        • mechanism: "operatorRedemption"

          • 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

          • action · string · required · always request

          • mechanism · string · required · always operatorRedemption

          • requestAddress · string · required

            Provider request account address.

          • shares · string · required · max length 128 · pattern ^\d+(\.\d+)?$ · example 10

            Position shares the request burns, in share units; "0" when it redeems intermediate the owner already holds.

          • assets · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 25

            Positive decimal string with at least one non-zero digit; never a float.

          • intermediateMint · string · required · min length 32 · max length 44 · pattern ^[1-9A-HJ-NP-Za-km-z]{32,44}$ · example 2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo

            Base58 Solana mint address.

          • intermediateAmount · string · required · max length 128 · pattern ^(?=.*[1-9])\d+(\.\d+)?$ · example 25

            Positive decimal string with at least one non-zero digit; never a float.

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

  • 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-transactions' \
  -H "Authorization: Bearer $SDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "positionId": "earn_position_0432ffeb-c574-4b11-80dc-a09defb68fcc",
    "mechanism": "solverQueue",
    "shares": "15",
    "discountBps": 10,
    "deadlineSeconds": 60
  }'
const res = await fetch("https://api-beta.solana.com/v1/earn/external-wallet/withdrawal-request-transactions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SDP_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "positionId": "earn_position_0432ffeb-c574-4b11-80dc-a09defb68fcc",
    "mechanism": "solverQueue",
    "shares": "15",
    "discountBps": 10,
    "deadlineSeconds": 60
  })
});
import os, requests

r = requests.post("https://api-beta.solana.com/v1/earn/external-wallet/withdrawal-request-transactions",
  headers={"Authorization": f"Bearer {os.environ['SDP_API_KEY']}"},
  json={
    "positionId": "earn_position_0432ffeb-c574-4b11-80dc-a09defb68fcc",
    "mechanism": "solverQueue",
    "shares": "15",
    "discountBps": 10,
    "deadlineSeconds": 60
  })

Example responses

JSON
{
  "data": {
    "transaction": {
      "transactionId": "earn_external_wallet_withdrawal_request_transaction_54c50679-1b52-494d-84fa-106df66452ff",
      "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",
      "action": "request",
      "mechanism": "solverQueue",
      "shares": "15",
      "assets": "14.985",
      "discountBps": 10,
      "maturityTimestamp": "1793991049",
      "deadlineTimestamp": "1793991109"
    }
  },
  "meta": {
    "requestId": "req_example",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}
JSON
{
  "error": {
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "Missing action: earn.execute",
    "details": {
      "action": "earn.execute"
    }
  },
  "meta": {
    "requestId": "req_example"
  }
}

Error responses use the standard error shape.