Transactions
The shared shape of every transaction, its statuses, the preconditions to accept, the money fields in the response, and the common errors
A transaction moves value out of or into your organisation. There are three types:
| Type | type value | Guide |
|---|---|---|
| Crypto-to-fiat (off-ramp) | FIAT | Crypto-to-Fiat |
| Crypto-to-crypto | CRYPTO | Crypto-to-Crypto |
| Fiat-to-crypto (on-ramp) | ONRAMP | On-Ramp |
This page covers what the three have in common. Read it first, then follow the guide for your type.
The Common Shape
- Create the transaction with
POST /transactions. It starts inDRAFT. - Update it if needed with
PUT /transactions/:id. - Validate it with
POST /transactions/:id/validate(crypto-to-fiat and crypto-to-crypto). - Submit it with
POST /transactions/:id/submit. For crypto-to-fiat this fetches a live quote. The transaction moves toWAITING_ACCEPTANCE. - Accept it with
POST /transactions/:id/accept. For crypto-to-fiat you must accept before the quote expires. Crypto-to-crypto has no accept call: your wallet executes the payment on-chain instead. - Poll
GET /transactions/:iduntil the transaction reaches a final status.
A transaction holds up to 30 payments. Each payment is one payout to one destination.
Before You Start
These conditions apply to the submit and accept calls:
- Confirmed account. Otherwise: 403
Account is not confirmed. - Active organisation. The organisation's
operationalStatusmust beACTIVE. Otherwise accept returns 401Organisation operational status does not permit this action. Read the status fromGET /users/me, underselectedOrganisation. - Authorised role. The API user must have the
authorizedmember role. Aviewergets 401Your user does not have enough permission to perform this actionon accept and on the allowance check. - Two-factor authentication off for the integration user. With 2FA on, calls can fail with 401
2FA session expired. Please login again. Use a dedicated integration user with 2FA turned off. - The sending wallet is an organisation wallet. For crypto-to-fiat and crypto-to-crypto, the
walletAddressyou send from must be one of your organisation's own wallets, added withPOST /organisations/:organisationId/add-wallet. A beneficiary wallet does not work. See Wallets. - Receivers and destinations exist. Register receivers, bank accounts and beneficiary wallets first. See Setup.
Updating a Transaction
PUT /transactions/:id takes the same body as create. It is allowed while the transaction is DRAFT, WAITING_ACCEPTANCE or FAILED. Otherwise it returns 400 Transaction is not in DRAFT,FAILED,WAITING_ACCEPTANCE status.
Two rules to know:
- The payments array is replaced wholesale. The server deletes every existing payment and creates the ones you send. Always send the full list, not only the payment you changed.
- An update resets the transaction to
DRAFT. A quoted transaction loses its quote. Validate and submit again.
DELETE /transactions/:id removes a transaction in DRAFT or WAITING_ACCEPTANCE.
Statuses
The transaction status field takes these values:
| Status | Meaning | Final? |
|---|---|---|
DRAFT | Created or edited. Not yet submitted. | No |
INTERNAL_DRAFT | Used internally by Skyline. Never returned in your transaction list. | No |
WAITING_ACCEPTANCE | Submitted. Crypto-to-fiat: quoted and waiting for your accept. Crypto-to-crypto: waiting for your on-chain payment. On-ramp: waiting for you to confirm the bank transfer. | No |
FAILED | Something went wrong: an invalid payment, an expired quote or an accept error. statusInfo holds the reason. | No. Fix the cause and submit again. |
PROCESSING | Accepted. Skyline is executing the transaction. | No |
RELEASED | The payout has been released and is on its way. | No |
COMPLETED | Settled. | Yes |
REJECTED_BY_SKYLINE | Rejected by Skyline's review. | Yes |
Only COMPLETED and REJECTED_BY_SKYLINE are final. Transitions are not strictly linear: PROCESSING can go straight to COMPLETED, and RELEASED can return to PROCESSING or move to FAILED.
Each entry in payments has its own status: DRAFT, WAITING_ACCEPTANCE, PROCESSING_PAYMENT, RELEASED, FAILED, COMPLETED or REJECTED. In a transaction with several payments, one payment can fail while the others complete. Check each payment's status and statusInfo.
Tracking a Transaction
The API does not send webhooks. Poll GET /transactions/:id and read status.
- Poll every 30 to 60 seconds. The detail response can be up to 30 seconds old, so faster polling gains nothing.
- Stop at
COMPLETEDorREJECTED_BY_SKYLINE. - Treat
FAILEDas a signal to act, not as the end.
GET /transactions/:id returns the full transaction with its payments embedded and network populated. There is no separate payments endpoint. It returns 403 for a transaction that belongs to another organisation.
Listing Transactions
GET /transactions returns results, page_total and total for your organisation.
| Query parameter | Description |
|---|---|
limit | Page size. Default 20, maximum 250. |
offset | Number of results to skip. Default 0. |
status | One or more statuses, comma-separated. |
type | One or more types, comma-separated: FIAT, CRYPTO, ONRAMP. |
from, to | Creation date range, ISO 8601. |
searchTerm | Free-text search over receiver, token and currency names. |
tokens, currencies | Filter by token or currency name, comma-separated. |
sortBy | createdAt, status or token. Default: newest first. |
direction | 1 ascending or -1 descending. Applies with sortBy. |
Money Fields in the Response
All amounts are decimal strings. Use them exactly as returned. Do not round them.
| Field | Meaning |
|---|---|
tokensToSend | The total debited from your wallet, in token units. It includes the commission and the banking fee. |
totalCommission | Skyline's commission. For crypto-to-fiat it is in the token you pay with. |
totalBankingFee | The banking fee for the fiat payout. For crypto-to-fiat it is in the token you pay with. |
payments[].amount | What the payment delivers. Crypto-to-fiat: the fiat amount the receiver gets, in the bank account's currency. Crypto-to-crypto: the token amount. On-ramp: the fiat amount you transfer. |
payments[].commission, payments[].bankingFee, payments[].tokensToSend | The same figures for one payment. |
expiresAt | When the current quote expires (crypto-to-fiat). |
For crypto-to-fiat, tokensToSend is the token amount converted for the payout, plus totalBankingFee, plus totalCommission. The fees are added on top. Crypto-to-crypto carries no commission, so tokensToSend is the sum of the payment amounts.
The server computes every fee and ignores any commission, fee or tokensToSend value sent in a request. The only fee input is bankingFeesOption on each fiat payment:
| Value | Who bears the banking fee |
|---|---|
OUR (default) | You. The fee is added to tokensToSend. |
SHA | Shared between you and the receiver. |
BEN | The receiver. |
Errors
Errors return JSON with statusCode and message. message can be a string or an array of strings. Some errors also carry a code. Unknown fields in a request body are rejected with 400.
| Status | Message or code | When | What to do |
|---|---|---|---|
| 400 | Transaction is not in … status. | The call is not allowed in the current status. | Read the transaction and follow the status table. |
| 400 | Trading pair … is not available | Create or update with a token and currency that cannot be traded. | Choose another token or currency. |
| 403 | Token not supported | Unknown token or tokenIsoCode. | Use an isoCode from GET /tokens. |
| 400 | Reason must contain between 2 and 140 characters… | Invalid payment reason (non-GBP payout). | See the reason rules in Crypto-to-Fiat. |
| 400 | Reason must not exceed 18 characters… | Invalid payment reason for a GBP payout. | As above. |
| 400 | Minimum payment amount is $… | A USD payment is below your organisation's minimum. | Raise the amount or contact Skyline. |
| 400 | Wallet with address … not found in organisation | The sending wallet is not an organisation wallet (allowance check). | Add it with POST /organisations/:organisationId/add-wallet. |
| 403 | Wallet not found | Same, at submit. | As above. |
| 403 | WALLET_NOT_WHITELISTED or a screening message | A wallet has not passed screening or ownership verification. | Complete verification. See Wallets. |
| 400 | Not enough balance | The sending wallet holds less than tokensToSend. | Fund the wallet and submit again. |
| 400 | Delegated allowance is below the transaction total | The token approval is too low. | Approve again, then submit again. |
| 400 | We are not able to process the transaction due to external market conditions | No payment could be executed at accept. | Submit again later. |
| 400 | code ACCEPT_RATE_PENDING | A payment has no quote yet. | Submit again, then accept. |
| 409 | code ACCEPT_BINDING_MISMATCH | The transaction changed after you read its review context. | Read it again and review before accepting. |
| 500 | Internal server error | Accept after the quote expired. | Submit again for a new quote, then accept. |
| 401 | Organisation operational status does not permit this action | The organisation is not ACTIVE. | Contact Skyline. |
| 401 | Your user does not have enough permission to perform this action | The API user is not authorized. | Ask an organisation admin to change the role. |
| 403 | Account is not confirmed | The user account is not confirmed. | Confirm the account on the platform. |
| 403 | This organisation must be active in order to continue. | The organisation, user or member is inactive. | Contact Skyline. |
Accept errors fail the transaction. Almost every accept error, including an expired quote, moves the transaction to FAILED. ACCEPT_BINDING_MISMATCH, ACCEPT_RATE_PENDING and the wallet screening errors leave the status unchanged. From FAILED, call submit again: it re-quotes and returns the transaction to WAITING_ACCEPTANCE.
A rejected create still leaves a record. If a payment is invalid, create returns 400 with the reason, and the transaction is stored as FAILED with the reason in statusInfo. Fix it with PUT /transactions/:id.
Documents
For a transaction in PROCESSING, RELEASED or COMPLETED:
POST /transactions/:id/invoicereturns an invoice PDF.POST /transactions/:id/statementreturns a statement PDF.
Wallets
Add organisation wallets and prove you own them, add beneficiary wallets, and know which wallet a transaction can send from or pay to
Crypto-to-Fiat Transactions
Pay a receiver's bank account in fiat from stablecoins in your organisation wallet, from lookups to token approval, quote, accept and settlement