List positions

Lists one customer wallet's live positions, one page at a time.

GET/v1/earn/external-wallet/positions

ownerAddress is required. A wallet with no positions in your project (never deposited, fully withdrawn, or held under another organization) returns an empty positions list, not 404. Live fields are left out, never set to zero, when the provider read is unavailable.

Requires an API key with the earn.read action.

Query parameters

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

    The customer's wallet address: an external wallet, so SDP holds no key for it. It signs, owns the shares, and pays the network fee unless the build names a feePayer. It must decode to a 32-byte public key; a base58 string that matches the pattern but does not decode returns 400.

  • limit · integer · min 1 · max 100 · default 20

    Page size, from 1 to 100. Defaults to 20.

  • before · string · min length 1

    The previous page's nextCursor. Omit it for the first page.

Headers

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

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

Responses

  • 200 One page of positions

    • data · object · required

      • ownerAddress · string · required · example 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM

        The customer's wallet address.

      • positions · object[] · required

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

        • ownerAddress · string · required · example 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM

          The customer's wallet address.

        • provider · string · required · example kamino

        • providerReference · string · required · example 7uib8xGAwkaPz4ZGCA6t8sSEid5Yp9ty13PHUweTypx

          The strategy's onchain address.

        • label · string · required · example Allez USDC

        • tokenMint · string · required · example 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU

        • shareMint · string · required · example hXm2xSRF5PLKGMrTvAWqKhR76MuJX5dAabeSChkjqu2

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

          ISO 8601 timestamp.

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

          ISO 8601 timestamp.

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

          Live share balance. Absent when the live read is unavailable; never zero-filled.

        • withdrawableShares · string · max length 128 · pattern ^\d+(\.\d+)?$ · example 25.42

          Shares you can withdraw right now. Absent when the live read is unavailable.

        • unlockTimestamp · string | null · pattern ^\d+$ · example 1789722000

          Unix time, in seconds, when locked shares become withdrawable. Null or absent when no lock applies. To tell an unavailable read apart, check shares.

        • tokenValue · string · max length 128 · pattern ^\d+(\.\d+)?$ · example 25.42

          Live value of the position in the deposit token (tokenMint), as the provider reports it: shares times the rate for rate-based strategies, or a withdrawal quote for the whole position for quote-based providers such as Veda and Ondo. A quote already includes spread and price impact, so it does not scale to other share amounts. It is a deposit-token amount, not a share count or a USD conversion; every Earn deposit token is a USD stablecoin, so at par it reads as dollars. Absent when the live read is unavailable.

        • parIntermediate · object

          The operator redemption's intermediate token the wallet holds outside any open request, such as Hastra wYLDS after a canceled operator redemption. It belongs to this position and is not included in tokenValue. Present only while non-zero.

          • mint · string · required · example 8fr7WGTVFszfyNWRMXj6fRjZZAnDwmXwEpCrtzmUkdih

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

            Live decimal value returned by the vault provider; never a float.

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

            Zero while the provider has frozen the token account.

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

            Value in the position's deposit token (tokenMint).

      • hasMore · boolean · required

      • nextCursor · string | null · required

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

  • 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/positions?ownerAddress=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM' \
  -H "Authorization: Bearer $SDP_API_KEY"
const res = await fetch("https://api-beta.solana.com/v1/earn/external-wallet/positions?ownerAddress=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", {
  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/positions?ownerAddress=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
  headers={"Authorization": f"Bearer {os.environ['SDP_API_KEY']}"})

Example responses

JSON
{
  "data": {
    "ownerAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
    "positions": [
      {
        "id": "earn_position_2f8b6b04-7147-487e-b760-b1caa4fbcb8b",
        "ownerAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
        "provider": "kamino",
        "providerReference": "C7N2fqV2GvhFghDf5PJSwstyjedjLNCY1cm2Ak7TeU83",
        "label": "Kamino Vault USDC",
        "tokenMint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
        "shareMint": "CeirL1mAehaM6g2EccgMUQwohNfnuyicskVQ4r9ekXk6",
        "createdAt": "2026-11-06T17:57:30.817Z",
        "closedAt": null,
        "shares": "24.975",
        "withdrawableShares": "24.975",
        "tokenValue": "25.031"
      }
    ],
    "hasMore": false,
    "nextCursor": null
  },
  "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.