Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.centryos.xyz/llms.txt

Use this file to discover all available pages before exploring further.

Endpoint

  • Method: POST
  • URL: {{LIQUIDITY_URL}}/v1/ext/linked-accounts/:currency/:linkedAccountId/withdrawal
  • Auth: Bearer {{accessToken}} (scope external.apis)
  • Rate limit: 1 withdrawal per minute per user (and IP). Returns 429 if exceeded.

Path Parameters

ParameterTypeRequiredDescription
currencystringYesCurrency code. Supported: USD only.
linkedAccountIdstringYesUUID of the linked payout account (bank or card) to send funds to. Must be a valid UUID of an existing linked account associated with the authenticated entity. See Link Bank Account, Link Card Account, or Link International Bank Account for how to link an account.

Headers

HeaderRequiredDescription
AuthorizationYesBearer <token> with scope external.apis.
Content-TypeYesapplication/json.

Request Body

FieldTypeRequiredDescription
amountnumberYesPayout amount in dollars (e.g. 100.50 for $100.50 USD). Must be > 0.
walletTypestringYesMust be "SPEND" (uppercase). Withdrawal is from the SPEND wallet tied to the linked account.
reasonstringNoOptional reason or reference for the payout (e.g. "Contractor payment").
routingTypestringNoOnly required when requesting a real-time payment. Pass "RTP" to use real-time payment rails. Omit for standard bank transfer (default). Ignored for card linked accounts. Allowed values: ACH, RTP, WIRE, BANK.
transactionTypestringNoIf "payout" (case-insensitive), treated as PAYMENT flow; otherwise defaults to PAYOUT.
Note: MFA is not required. Do not send mfaCode.

Request

curl -X POST "{{LIQUIDITY_URL}}/v1/ext/linked-accounts/USD/{{linkedAccountId}}/withdrawal" \
  -H "Authorization: Bearer {{accessToken}}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100.50,
    "walletType": "SPEND",
    "reason": "Contractor payment"
  }'
To request a real-time payment instead of a standard bank transfer:
curl -X POST "{{LIQUIDITY_URL}}/v1/ext/linked-accounts/USD/{{linkedAccountId}}/withdrawal" \
  -H "Authorization: Bearer {{accessToken}}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100.50,
    "walletType": "SPEND",
    "reason": "Contractor payment",
    "routingType": "RTP"
  }'

Response (200)

{
  "success": true,
  "message": "Payment queued",
  "data": {
    "id": "<transaction-uuid>",
    "status": "<TransactionStatus>",
    "fees": "<fee amount as string>",
    "amount": "<total debit amount (amount + fees) as string>"
  }
}

Response Fields

FieldTypeDescription
successbooleanWhether the request succeeded.
messagestringStatus message (e.g. "Payment queued").
data.idstringTransaction UUID for tracking.
data.statusstringTransaction status. See statuses below.
data.feesstringFee amount charged as a string.
data.amountstringTotal amount debited (payout amount + fees) as string.

Transaction Statuses

StatusMeaning
SUCCESSPayout dispatched successfully.
PENDINGPayout accepted and in progress; final confirmation is asynchronous.
AWAITING_APPROVALPayout requires internal approval before it is processed. Funds are not debited yet. You will receive a webhook or can poll the transaction status endpoint once approved.

Error (4xx / 5xx)

{
  "success": false,
  "message": "<error detail>",
  "fatal": true
}

Error Cases

SituationHTTPMessage / cause
Missing or invalid amount400Validation error — amount is required and must be a positive number.
Missing or invalid walletType400walletType must be "SPEND" (uppercase).
Invalid routingType400Only ACH, RTP, WIRE, BANK are allowed.
Unauthorized / wrong scope401Invalid or expired token, or missing external.apis scope.
Linked account not found404Wrong linkedAccountId or account not accessible by this entity.
Application token expired400Payment-link token is expired or inactive.
Amount mismatch (payment link)400Merchant-funded withdrawal: body amount does not match the token amount.
Insufficient balance400"Insufficient Funds #912" — SPEND wallet balance is too low.
Payout not enabled403Payouts are not enabled for this account. Contact support.
Failed to process payout500The payment processor rejected the disbursement. Verify that the linked account is active, within transaction limits, and that the recipient details are correct. If the issue persists, contact support with the transaction ID.
Rate limit exceeded4291 withdrawal per minute per user. Retry after 60 seconds.

Payout Types

The payout method is determined by the type of linked account. For bank accounts, you can optionally override to real-time payment by passing routingType: "RTP".
Linked account typeroutingType in bodyResult
BankOmitted (default)Standard bank transfer.
Bank"RTP"Real-time payment.
Bank"ACH" or "BANK"Standard bank transfer.
Bank"WIRE"Wire transfer.
CardAny or omittedPush-to-card; routingType is ignored.

Validation Rules

  • amount — Required. Number greater than 0.
  • walletType — Required. Must be "SPEND" (uppercase).
  • reason — Optional. String.
  • routingType — Optional. If provided, must be one of: ACH, RTP, WIRE, BANK. Omit for default bank transfer behaviour.
  • currency — From path parameter. Must be USD.
  • linkedAccountId — From path parameter. Must be a valid UUID of a linked account for the authenticated entity.
  • MFA — Not required. Do not include mfaCode.
If the request is made in the context of a payment link with withdrawalSource === 'MERCHANT_WALLET':
  • The amount in the body must exactly match the amount on the application token; otherwise returns 400 "Malformed request".
  • On success, the application token is invalidated immediately and cannot be reused.

Notes

  • The linked account must be associated with the authenticated entity’s SPEND wallet.
  • A success response means the payout has been queued or dispatched. Final settlement may be asynchronous — use the transaction status endpoint or webhooks to confirm.
  • No idempotency keys are supported. Implement client-side deduplication if needed.
  • Rate limited to 1 request per minute per user.