Get a movement

Gets one deposit or withdrawal and refreshes its onchain status when it can.

GET/v1/earn/external-wallet/movements/{movementId}

Use it to track a movement after submit, or to recover a submit whose response was lost. If the chain read fails, you get the last recorded status while SDP keeps reconciling in the background. An atomic movement can show as done at confirmed, but only finalized and failed are final. For settlement: provider_order, chain confirmation is not payout: the provider still has to complete the order.

Requires an API key with the earn.read action.

Path parameters

  • movementId · string · required · min length 1 · max length 128 · example earn_movement_a6aed3f5-4f89-4dc6-9d4b-0864021bd80d

    The movementId a submit returned.

Headers

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

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

Responses

  • 200 Recorded movement

    • data · object · required

      • movement · object · required

        One recorded external-wallet vault movement.

        • settlementOutcome · string · one of delivered, cancelled

        • movementId · string · required · example earn_movement_a6aed3f5-4f89-4dc6-9d4b-0864021bd80d

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

        • provider · string · required · example kamino

        • providerReference · string · required · example 7uib8xGAwkaPz4ZGCA6t8sSEid5Yp9ty13PHUweTypx

        • direction · string · required · one of deposit, withdrawal

        • status · string · required · one of requested, submitted, confirmed, finalized, failed

          The movement's status. requested means SDP recorded the signed transaction but has not yet seen it on the network. confirmed is optimistic and can still be rolled back; only finalized and failed are final.

        • settlement · string · required · one of atomic, provider_order

          How the movement settles. atomic completes in one transaction, so you may show it as done at confirmed while SDP tracks finality. provider_order pays out later through the provider, so chain confirmation alone is not payout: the movement stays confirmed until the provider completes it, and only finalized means it is done.

        • signature · string · required

          The transaction signature, for explorers.

        • ownerAddress · string · required · example 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM

          The customer's wallet address.

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

          Requested quantity, denominated in denomination.

        • denomination · string · required · example 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU

          Token mint for a deposit; share mint for a withdrawal.

        • tokenMint · string · required · example 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU

          The position's deposit-token mint. Show tokenAmount in these units; amount and denomination carry the onchain quantity, which is shares on a withdrawal.

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

          Quantity in tokenMint units. Kamino deposits and all withdrawals require a finalized observation; null beforehand or when the actual debit/payout cannot be observed. Other deposits report their fixed input amount.

        • failureReason · string | null · required

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

          ISO 8601 timestamp.

        • confirmedAt · string | null · required · format date-time · example 2025-01-01T00:00:00.000Z

          ISO 8601 timestamp.

        • settledAt · string | null · required · format date-time · example 2025-01-01T00:00:00.000Z

          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 · 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.read 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.

  • 429 Too Many Requests

    Same fields as 400.

  • 500 Internal Server Error

    Same fields as 400.

  • 503 Service Unavailable

    Same fields as 400.

Example request

curl 'https://api-beta.solana.com/v1/earn/external-wallet/movements/earn_movement_a6aed3f5-4f89-4dc6-9d4b-0864021bd80d' \
  -H "Authorization: Bearer $SDP_API_KEY"
const res = await fetch("https://api-beta.solana.com/v1/earn/external-wallet/movements/earn_movement_a6aed3f5-4f89-4dc6-9d4b-0864021bd80d", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.SDP_API_KEY}`
  }
});
import os, requests

r = requests.get("https://api-beta.solana.com/v1/earn/external-wallet/movements/earn_movement_a6aed3f5-4f89-4dc6-9d4b-0864021bd80d",
  headers={"Authorization": f"Bearer {os.environ['SDP_API_KEY']}"})

Example responses

JSON
{
  "data": {
    "movement": {
      "movementId": "earn_movement_a6aed3f5-4f89-4dc6-9d4b-0864021bd80d",
      "positionId": "earn_position_2f8b6b04-7147-487e-b760-b1caa4fbcb8b",
      "provider": "kamino",
      "providerReference": "C7N2fqV2GvhFghDf5PJSwstyjedjLNCY1cm2Ak7TeU83",
      "direction": "deposit",
      "settlement": "atomic",
      "signature": "3dhkSPLiQZQPXL96fWzMdWJtdbtAffkBKXw2xhsYbV3VNSnYrVAcdx1czsnLsE1ou4SvLecGdSYe4QpAuZdfjJAf",
      "ownerAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
      "amount": "25",
      "denomination": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
      "tokenMint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
      "failureReason": null,
      "createdAt": "2026-11-06T17:57:30.817Z",
      "status": "finalized",
      "tokenAmount": "25",
      "confirmedAt": "2026-11-06T17:57:32.517Z",
      "settledAt": "2026-11-06T17:57:35.623Z"
    }
  },
  "meta": {
    "requestId": "req_example",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}
JSON
{
  "error": {
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "Missing action: earn.read",
    "details": {
      "action": "earn.read"
    }
  },
  "meta": {
    "requestId": "req_example"
  }
}

Error responses use the standard error shape.