Skip to main content
POST
/
v2
/
portfolios
/
{portfolioId}
/
withdraw
curl --request POST \
  --url 'https://api.glider.fi/v2/portfolios/01JWZEE2MF30KVRMRX53N88VA4/withdraw' \
  --header 'x-api-key: gldr_sk_your_api_key' \
  --header 'Content-Type: application/json' \
  --data '{
    "message": {
      "portfolioId": "01JWZEE2MF30KVRMRX53N88VA4",
      "recipientAccountId": "eip155:1:0x4444444444444444444444444444444444444444",
      "assets": [
        {
          "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
          "amountRaw": "1000500000"
        }
      ],
      "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
      "expiresAt": 1744898400
    },
    "signature": "0xabc..."
  }'
{
  "success": true,
  "data": {
    "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4",
    "submittedAt": "2026-04-17T12:05:00.000Z"
  }
}
Stage 2 of the v2 withdrawal flow. Accepts the message object returned by stage 1 verbatim, plus the user’s signature over the typed data. The server reconstructs the EIP-712 hash, verifies the signer is the portfolio owner, re-checks live onchain balances, and dispatches the transfer onchain.
  • Auth: x-api-key header (required)
  • Scope: portfolios:withdraw
Temporary constraint: recipientAccountId must resolve to the portfolio owner’s address. Third-party recipients are not yet supported; any other recipient returns 400 API_211 INVALID_RECIPIENT. The examples below use a placeholder address — substitute your portfolio’s owner address when testing.

Idempotency

Keyed on (tenantId, apiKeyId, "POST /v2/portfolios/:id/withdraw", nonce). Retries with the same message + signature replay the cached 202 response. Retries with the same nonce but a different body return 409 IDEMPOTENCY_KEY_CONFLICT — fix the client, don’t retry. Two parallel requests with the same body: one reserves and proceeds, the other sees 409 IDEMPOTENCY_IN_PROGRESS — retry the identical body after 2–3 seconds. If stage 2 fails after reserving the idempotency row (e.g., transient RPC failure during signature verification, or balance drops below the requested amount between stages), the row is released so the integrator can re-submit the same message + signature once the transient issue resolves. This is different from enrollment semantics where failed rows stay in-flight until TTL.

Polling for onchain status

The response returns operationId. Poll GET /v2/portfolios/{portfolioId}/operations/{operationId} until the operation reaches a terminal (completed / failed / cancelled) state.

Common error responses

  • 400 API_216 WITHDRAWAL_AUTHORIZATION_EXPIRED — signed authorization’s expiresAt is in the past. Restart the flow via stage 1.
  • 400 API_217 INVALID_WITHDRAWAL_SIGNATURE — signature does not recover to the portfolio owner. Almost always a client bug.
  • 400 API_210 INSUFFICIENT_BALANCE — balance dropped below amountRaw between stage 1 and stage 2. Restart stage 1 to issue a fresh authorization.
  • 400 API_214 WITHDRAWAL_PORTFOLIO_MISMATCHmessage.portfolioId doesn’t match the URL path.
  • 400 API_213 WITHDRAWAL_CHAIN_MISMATCH — at least one asset is on a different chain than recipientAccountId.
  • 400 API_215 PORTFOLIO_HAS_NO_VAULT_ON_CHAIN — portfolio has no vault deployed on the recipient’s chain.
  • 400 API_212 DUPLICATE_WITHDRAW_ASSET — two or more assets in assets share the same assetId.
  • 400 API_211 INVALID_RECIPIENT — zero address, vault self-transfer, or non-EVM namespace.
  • 404 API_200 PORTFOLIO_NOT_FOUNDportfolioId doesn’t exist or belongs to a different tenant (can surface at stage 2 if the portfolio was archived/reassigned between stages).
  • 409 API_007 IDEMPOTENCY_IN_PROGRESS — another request with the same nonce is still running. Retry the identical body.
  • 409 API_008 IDEMPOTENCY_KEY_CONFLICT — nonce reused with a different body. Don’t retry; restart stage 1.
  • 503 API_506 SIGNATURE_VERIFIER_UNAVAILABLE — the RPC backing ERC-1271 verification is temporarily unavailable. Safe to retry; the idempotency row has been released.
curl --request POST \
  --url 'https://api.glider.fi/v2/portfolios/01JWZEE2MF30KVRMRX53N88VA4/withdraw' \
  --header 'x-api-key: gldr_sk_your_api_key' \
  --header 'Content-Type: application/json' \
  --data '{
    "message": {
      "portfolioId": "01JWZEE2MF30KVRMRX53N88VA4",
      "recipientAccountId": "eip155:1:0x4444444444444444444444444444444444444444",
      "assets": [
        {
          "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
          "amountRaw": "1000500000"
        }
      ],
      "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
      "expiresAt": 1744898400
    },
    "signature": "0xabc..."
  }'
{
  "success": true,
  "data": {
    "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4",
    "submittedAt": "2026-04-17T12:05:00.000Z"
  }
}