Withdrawals
Withdrawal history
GET /v2/withdrawals
List withdrawals
Every debit from the account, newest first. One withdrawal is one row, fee included: the fee is reported as fee ON the withdrawal it belongs to, never as a separate row, so summing total over this list is the account’s outflow with no double-counting and no filtering needed.
The NETWORK_FEE and TRANSFER_FEE sub-types exist in the enum but are Skipo’s own accounting for the gas it pays, booked against a Skipo-internal account — they never appear on a customer’s list.
Amounts default to rebased; the always-present base block carries the settled figures. fee is the flat fee Skipo charges, NOT the blockchain network fee, which Skipo absorbs.
Parámetros
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
page | query | integer | no | Default: 1. |
limit | query | integer | no | Default: 25. |
assetSymbol | query | string | no | |
status | query | string | no | |
subType | query | INTERNAL | EXTERNAL_CRYPTO | EXTERNAL_FIAT_BANK | EXTERNAL_FIAT_REDPAY | NETWORK_FEE | TRANSFER_FEE | no | |
assetFormat | query | AssetFormat | no | How to express tokenised-equity (xStock) amounts. rebased (default) = underlying equity (real shares); base = settled SPV tokens, i.e. what moved on chain and in the ledger. No effect on other assets. |
startDate | query | string | no | ISO-8601 start date. |
endDate | query | string | no | ISO-8601 end date. |
Respuestas
| Código | Descripción | Cuerpo |
|---|---|---|
200 | Éxito. | data: WithdrawalResource[] · pagination: PaginationMeta |
401 | application/problem+json (RFC 9457) — branch on code, not on the status: unauthorized (not retryable), key_expired (not retryable), key_revoked (not retryable). | — |
403 | application/problem+json (RFC 9457) — branch on code, not on the status: insufficient_scope (not retryable), ip_not_allowed (not retryable), api_access_disabled (not retryable). | — |
429 | application/problem+json (RFC 9457) — branch on code, not on the status: rate_limited (retryable). | — |
500 | application/problem+json (RFC 9457) — branch on code, not on the status: internal_error (retryable). | — |
502 | application/problem+json (RFC 9457) — branch on code, not on the status: downstream_unavailable (retryable). | — |
503 | application/problem+json (RFC 9457) — branch on code, not on the status: maintenance (retryable). | — |
POST /v2/withdrawals
Create a withdrawal
Money movement — requires a Tier-2 signed request (X-API-Key header + signed Authorization JWT), not a bare bearer key.
Fees. By default amount is the total DEBITED and the destination receives amount − fee, as on Binance, Kraken, Coinbase and OKX — so sweeping a balance is one call: send the balance. Set feeMode: "add" to make amount the figure that ARRIVES, debiting amount + fee. The response reports amount (sent), fee and total (debited) either way.
The fee is per chain, and this body does not name one. The chain is whatever the destination contact is registered on. Read the fee from GET /v2/assets → networks[].withdrawalFee matched on the contact’s crypto.networkId — the asset-level withdrawalFee reports the cheapest chain and will understate any other.
Rejections move nothing: the balance is checked before any funds are held. If a withdrawal fails after it is accepted, the full total — amount and fee — returns to the balance.
Autenticación: Petición firmada (Tier-2)
Cuerpo de la petición — CreateWithdrawalDto
Respuestas
| Código | Descripción | Cuerpo |
|---|---|---|
201 | Creado. | WithdrawalResource |
400 | application/problem+json (RFC 9457) — branch on code, not on the status: validation_error (not retryable). | — |
401 | application/problem+json (RFC 9457) — branch on code, not on the status: unauthorized (not retryable), key_expired (not retryable), key_revoked (not retryable), invalid_signature (not retryable), clock_skew (retryable), nonce_reused (retryable). | — |
403 | application/problem+json (RFC 9457) — branch on code, not on the status: insufficient_scope (not retryable), ip_not_allowed (not retryable), api_access_disabled (not retryable), two_factor_required (not retryable). | — |
422 | application/problem+json (RFC 9457) — branch on code, not on the status: unprocessable (not retryable). | — |
429 | application/problem+json (RFC 9457) — branch on code, not on the status: rate_limited (retryable). | — |
500 | application/problem+json (RFC 9457) — branch on code, not on the status: internal_error (retryable). | — |
502 | application/problem+json (RFC 9457) — branch on code, not on the status: downstream_unavailable (retryable). | — |
503 | application/problem+json (RFC 9457) — branch on code, not on the status: maintenance (retryable). | — |
GET /v2/withdrawals/{id}
Get a withdrawal by id
Takes the same assetFormat as the list. A PENDING withdrawal has no transactionHash YET — it appears on a later read once the transaction is broadcast, so poll this or subscribe to withdrawal.status.updated rather than treating the initial null as final.
Parámetros
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
id | path | string | sí | |
assetFormat | query | AssetFormat | no | How to express tokenised-equity (xStock) amounts. rebased (default) = underlying equity (real shares); base = settled SPV tokens, i.e. what moved on chain and in the ledger. No effect on other assets. |
Respuestas
| Código | Descripción | Cuerpo |
|---|---|---|
200 | Éxito. | WithdrawalResource |
401 | application/problem+json (RFC 9457) — branch on code, not on the status: unauthorized (not retryable), key_expired (not retryable), key_revoked (not retryable). | — |
403 | application/problem+json (RFC 9457) — branch on code, not on the status: insufficient_scope (not retryable), ip_not_allowed (not retryable), api_access_disabled (not retryable). | — |
404 | application/problem+json (RFC 9457) — branch on code, not on the status: not_found (not retryable). | — |
429 | application/problem+json (RFC 9457) — branch on code, not on the status: rate_limited (retryable). | — |
500 | application/problem+json (RFC 9457) — branch on code, not on the status: internal_error (retryable). | — |
502 | application/problem+json (RFC 9457) — branch on code, not on the status: downstream_unavailable (retryable). | — |
503 | application/problem+json (RFC 9457) — branch on code, not on the status: maintenance (retryable). | — |
Esquemas
CreateWithdrawalDto
| Campo | Tipo | Descripción |
|---|---|---|
assetSymbol | string | Asset to withdraw, as the SETTLED asset code. ⚠️ Unlike every read endpoint, this one does NOT accept the rebased ticker of a tokenised equity: amount here is in settled units and the body declares no assetFormat, so accepting NVDAX would move a different quantity than the one you signed. Sending it is rejected with the settled code and the conversion. Ej.: BTC. |
amount | string | Amount to withdraw, as a positive decimal string. How it is read against the fee depends on feeMode, which defaults to deduct: amount is the total DEBITED from the balance and the destination receives amount − fee. To sweep a balance, send the balance. The fee is per CHAIN and the chain comes from the contact, not from this body — read it from GET /v2/assets → networks[].withdrawalFee, matched on the contact’s crypto.networkId. The asset-level withdrawalFee is the cheapest chain’s and will understate a withdrawal over any other one. Ej.: 0.05. |
feeMode (opcional) | any | How amount relates to the withdrawal fee. deduct (default) — amount is the total debited; the destination receives amount − fee. This is what Binance, Kraken, Coinbase and OKX do, and it is what makes sweeping a balance a single call. add — amount is what the destination receives; the balance is debited amount + fee. Use it when the arriving figure must be exact — settling an invoice, a payroll line, topping an address to a specific number. ⚠️ add was the behaviour of this endpoint before feeMode existed. Either value is fully supported; the response is identical in shape and always reports all three of amount (sent), fee and total (debited), so neither mode requires the caller to re-derive anything. No effect on internal transfers or bank payouts, which carry no fee — set it unconditionally rather than branching on the destination type. |
contactId (opcional) | string | Destination contact id (a whitelisted address/account). |
contactReference (opcional) | string | Destination contact reference/alias. |
PaginationMeta
| Campo | Tipo | Descripción |
|---|---|---|
page | number | Ej.: 1. |
limit | number | Ej.: 25. |
totalItems | number | Ej.: 100. |
totalPages | number | Ej.: 4. |
Problem
| Campo | Tipo | Descripción |
|---|---|---|
type | string | Stable problem-type URI. Resolves to docs for this error. Ej.: https://docs.skipo.com/errors/rate_limited. |
title | string | Short, human-readable summary (stable, English). Ej.: Rate limit exceeded. |
status | number | HTTP status code. Ej.: 429. |
code | string | Stable machine-readable error code (equals the last path segment of type). Ej.: rate_limited. |
retryable | boolean | Whether retrying the identical request may succeed. Ej.: true. |
detail (opcional) | string | Human-readable, possibly localized detail. |
instance (opcional) | string | The request path that produced the error. |
traceId (opcional) | string | Trace id — joins BigQuery api_request and Cloud Logging. |
WithdrawalBaseRepresentation
| Campo | Tipo | Descripción |
|---|---|---|
asset | string | null | Asset code of the settled token. Populated on every read, including a rebased one — the rebased ticker maps back to the settled code through the maintainers snapshot. null only if that lookup misses, which means the asset is unknown to the snapshot rather than that the code was unobtainable. It is never the underlying ticker: a plausible-looking wrong code is worse than an obvious gap when reconciling against a webhook. Ej.: USDT. |
amount | string | Amount withdrawn excluding the fee, in settled units. Positive magnitude. Ej.: 1954.78138064. |
fee | string | Skipo withdrawal fee, in settled units. Positive magnitude. Ej.: 0.5. |
total | string | Total debited (amount + fee), in settled units. Positive magnitude. Ej.: 1955.28138064. |
WithdrawalResource
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Withdrawal id. Use it to re-fetch this withdrawal and to match its ledger entry (source.id). Ej.: 9bba6d71-5966-4045-962f-77a737e14226. |
type | string | Ej.: WITHDRAWAL. |
subType | INTERNAL | EXTERNAL_CRYPTO | EXTERNAL_FIAT_BANK | EXTERNAL_FIAT_REDPAY | NETWORK_FEE | TRANSFER_FEE | |
assetSymbol | string | Asset code of the withdrawal. Ej.: USDT. |
amount | string | Amount withdrawn, excluding the fee. Positive magnitude, in assetSymbol. Ej.: 1954.78138064. |
fee | string | The withdrawal fee charged by Skipo, in assetSymbol. A flat fee — NOT the blockchain network fee, which Skipo absorbs. Positive magnitude. Ej.: 0.5. |
total | string | Total debited from the balance (amount + fee). Positive magnitude, in assetSymbol. Ej.: 1955.28138064. |
status | string | Ej.: COMPLETED. |
createdAt | string | Ej.: 2026-07-16T16:58:54.216Z. |
transactionHash | string | null | On-chain transaction hash, when this withdrawal had one. null otherwise — an off-chain withdrawal (bank payout, internal transfer) never has one, and an on-chain withdrawal that has not been broadcast yet does not have one YET, so a PENDING withdrawal reports null and the hash appears on a later read. Top-level so that reading it never requires branching on subType. It is the same value as withdrawalData.transactionHash, which remains for the sub-types that already published it; this field additionally covers on-chain sub-types that carry a hash but publish no withdrawalData block. NOT a bank reference: on a fiat payout this is always null, even though the underlying record may hold the bank's own transaction id. Do not assume a 0x prefix — BTC, Solana and Tron hashes have none. Ej.: 0x8b3275b467d90d99bd99bb7bfec9402e393ce870d741131a9d69a7d42640ac5b. |
bankReference | string | null | The bank's or payment provider's own reference for this payout, when one was recorded. null on every non-fiat withdrawal, and null on a fiat withdrawal that carries no reference (the large majority — 73 of 14,502 bank payouts on prod have one). It is recorded when the payout is confirmed, so a PENDING bank withdrawal reports null. The counterpart of transactionHash: a withdrawal settles either on a chain or through a bank, so at most one of the two fields is ever populated. Free-form and short (3-19 characters, not always numeric) — it is whatever the bank supplied, so treat it as an opaque string for reconciliation, never parse it. Ej.: null. |
assetFormat | any | Which representation the top-level money fields are expressed in. Echoes what the request RESOLVED to, so a response that took the default is as self-describing as one that asked. POST /v2/withdrawals always answers base: a creation returns the figures as booked. Ej.: rebased. |
multiplier | string | Rebase factor as it stood when the withdrawal was created — not today. "1" when no scaling applies. base.amount x multiplier = amount when assetFormat is rebased. "1" is NOT a claim that the asset does not rebase; read GET /v2/assets for its class. Ej.: 1. |
base | WithdrawalBaseRepresentation | |
withdrawalData | object | Sub-type-specific details. The keys depend on transactionSubType, so branch on that rather than probing for fields. For EXTERNAL_CRYPTO this carries the CANONICAL chain identity, the same five fields GET /v2/assets[].networks and GET /v2/contacts publish — networkId (BSC, ETH, TRON), networkName, networkNativeAsset, evmChainId and assetType (the token standard, BEP20/ERC20/TRC20). Join on networkId: it is the one field that means the same thing on every v2 resource, so a movement, an asset and a saved destination line up without parsing prose. ⚠️ networkSymbol has been REMOVED from this block. It was the raw stored value and it disagreed with itself across the estate — 164,192 movements say BEP20 for the same chain 1,614 call BSC, and it also carried values that are not networks (INTERNAL, FIAT_NETWORK) and prose (Dogecoin, XRP Ledger). networkId replaces it and is a stable key. networkName above is the human-readable form. The canonical fields are always present on an EXTERNAL_CRYPTO movement and are null when the chain cannot be resolved, so the shape never changes underneath you. |
Volver a la referencia de endpoints. Ver también: Paginación · Errores · Ids y correlación.