---
title: "Submit a signed external-wallet withdrawal"
method: POST
path: "/v1/earn/external-wallet/withdrawals"
tags: ["Earn"]
---

# Submit a signed external-wallet withdrawal

`POST /v1/earn/external-wallet/withdrawals`

The exit mirror of the deposit submit: signature verified over the exact built message, movement recorded before broadcast, Idempotency-Key required, one submission per built transaction.

## Headers

- `x-project-id` string — Selects the active project for this request. Required for session/dashboard callers. Ignored when authenticating with an API key, whose scope is fixed to the key's project.
- `Idempotency-Key` string, required — Idempotency key for safely retrying mutating requests. 1-255 printable ASCII characters; echoed back on the response.

## Request body

- object — Submit the signed bytes back. Requires the Idempotency-Key header; a retry with the same key resolves the original movement instead of moving money twice.
  - `transactionId` string, required — The built transaction being submitted; single-use.
  - `signedTransaction` string, required — Base64 wire bytes of the signed transaction. They must be byte-for-byte the built message with only signatures added.

## Response `200`

Recorded withdrawal movement

- object — Standard success response envelope.
  - `data` object, required
    - `withdrawal` object, required — One recorded external-wallet vault movement.
      - `movementId` string, required
      - `positionId` string, required
      - `provider` string, required
      - `providerReference` string, required
      - `direction` 'deposit' | 'withdrawal', required
      - `status` 'requested' | 'submitted' | 'confirmed' | 'finalized' | 'failed', required — Ledger vocabulary. `confirmed` is optimistic and can still be dropped by a fork; only `finalized` and `failed` are terminal.
      - `signature` string, required — The transaction signature, for explorers.
      - `ownerAddress` string, required — The external wallet: the customer's own Solana address. It signs, owns the shares, and pays the fee; SDP holds no key for it. The pattern is necessary but not sufficient — the string must additionally decode to a 32-byte public key, which no pattern can express, so a well-shaped base58 string that does not decode still answers 400.
      - `amount` string, required — Requested quantity, denominated in `denomination`.
      - `denomination` string, required — Token mint for a deposit; share mint for a withdrawal.
      - `failureReason` string, nullable, required
      - `createdAt` string, date-time, required — ISO 8601 timestamp.
      - `confirmedAt` string, date-time, nullable, required — ISO 8601 timestamp.
      - `settledAt` string, date-time, nullable, required — ISO 8601 timestamp.
      - `replayed` boolean — True when the idempotency key already produced this movement and nothing was re-sent.
  - `meta` object, required — Response metadata.
    - `requestId` string, required — Request identifier for tracing.
    - `timestamp` string, date-time, required — ISO 8601 timestamp.

## Other responses

- `400` — Error
- `401` — Error
- `403` — Error
- `404` — Error
- `409` — Error
- `429` — Error
- `500` — Error
- `503` — Error

## Changes

- **2026-08-28** `13f3098243d6` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/solana/apis/solana-developer-platform-api/changes/v1/earn/external-wallet/withdrawals/post.md)

---

[API](https://skmtc.dev/solana/apis/solana-developer-platform-api.md) · [All operations](https://skmtc.dev/solana/apis/solana-developer-platform-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/solana/solana-developer-platform-api/revisions/aedc48d5b49e/schema)
