Skip to main content
This guide covers the API flow for converting stablecoins to fiat bank deposits using Payouts.

Prerequisites

Payout lifecycle

1

Get a quote

POST/payouts/quote : Request payout quoteRequest a quote to see the estimated fiat amount and fees before creating a payout.
Request
POST /payouts/quote

{
  "walletId": "wa-5pfuu-9euek-h0odgb6snva8ph3k",
  "asset": {
    "kind": "Erc20",
    "amount": "1000000000",
    "contract": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"
  },
  "fiatCurrency": "USD",
  "provider": "Borderless",
  "country": "US"
}
Response
{
  "provider": "Borderless",
  "asset": {
    "kind": "Erc20",
    "amount": "1000000000",
    "contract": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
    "network": "Polygon",
    "metadata": {
      "symbol": "USDC",
      "decimals": 6,
      "verified": true
    }
  },
  "timestamp": "2025-03-01T12:00:00.000Z",
  "quotes": [
    {
      "offer": {
        "fiatCurrency": "USD",
        "amount": 985.50,
        "fees": 14.50
      }
    }
  ]
}
Quotes are informational — they don’t lock in a rate. The amount field in the quote response is the net fiat the recipient receives after fees.
The quote endpoint does not require a user action signature, so you can request quotes without prompting for user approval.
2

Create a payout

POST/payouts : Create payoutCreate a payout to start the off-ramp process. This requires Borderless-specific fields: your account ID, payment instructions ID (the destination bank account), and a payment purpose.
Request
POST /payouts

{
  "walletId": "wa-5pfuu-9euek-h0odgb6snva8ph3k",
  "asset": {
    "kind": "Erc20",
    "amount": "1000000000",
    "contract": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"
  },
  "fiatCurrency": "USD",
  "provider": "Borderless",
  "country": "US",
  "borderlessAccountId": "your-borderless-account-id",
  "paymentInstructionsId": "your-payment-instructions-id",
  "paymentPurpose": "salary payment",
  "externalId": "invoice-2025-001"
}
Response
{
  "id": "pyt-4ihii-9lonb-tmhjo9bor4odmb5h",
  "walletId": "wa-5pfuu-9euek-h0odgb6snva8ph3k",
  "fiatCurrency": "USD",
  "asset": {
    "kind": "Erc20",
    "amount": "1000000000",
    "contract": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
    "network": "Polygon",
    "metadata": {
      "symbol": "USDC",
      "decimals": 6,
      "verified": true
    }
  },
  "status": "Processing",
  "provider": "Borderless",
  "dateCreated": "2025-03-01T12:01:00.000Z",
  "data": {
    "borderlessAccountId": "your-borderless-account-id",
    "paymentInstructionsId": "your-payment-instructions-id",
    "paymentPurpose": "salary payment",
    "executionStatus": "Initializing",
    "country": "US"
  }
}
Use externalId for idempotency — if you retry with the same externalId, the existing payout is returned instead of creating a duplicate.Payment purposesThe paymentPurpose field must be one of: salary payment, personal remittance, rent payment, property purchase, owned account abroad, advertising expenses, advisory fees, business insurance, construction, delivery fees, education, exports, donation, hotel, loan payment, maintenance expenses, medical expense, office expenses, royalty fees, service charge, shares investment, tax payment, transportation fees, travel, utility bills, other.
3

Wait for action required

After creation, Dfns coordinates with Borderless to obtain a deposit address. When ready, the payout advances to AwaitingPayoutConfirmation and Dfns fires a payout.action.required webhook. Subscribe to the webhook for real-time notification (recommended for automation)You can also poll GET/payouts/{payoutId} (Get payout status) and check for data.executionStatus === "AwaitingPayoutConfirmation".The webhook payload includes the full payout object with the depositAddress in data:
Webhook payload
{
  "kind": "payout.action.required",
  "data": {
    "actionKind": "Confirmation",
    "payout": {
      "id": "pyt-4ihii-9lonb-tmhjo9bor4odmb5h",
      "status": "Processing",
      "data": {
        "executionStatus": "AwaitingPayoutConfirmation",
        "depositAddress": "0x1234567890abcdef1234567890abcdef12345678",
        "..."
      }
    }
  }
}
The payout expires if not confirmed within 24 hours.
4

Confirm the payout

POST/payouts/{payoutId}/action : Create payout actionConfirm the payout by echoing back the transfer details. Dfns validates these match the payout data, then submits the on-chain transfer from your wallet.
Request
POST /payouts/{payoutId}/action

{
  "action": "Confirm",
  "walletId": "wa-5pfuu-9euek-h0odgb6snva8ph3k",
  "transfer": {
    "kind": "Erc20",
    "amount": "1000000000",
    "contract": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
    "to": "0x1234567890abcdef1234567890abcdef12345678"
  }
}
The transfer.to address must match the depositAddress from the payout data, and the amount must match the payout’s asset amount. This is a deliberate confirmation step — you’re approving that the correct amount goes to the correct address.After confirmation, Dfns handles the rest: submitting the transfer, waiting for on-chain confirmation, and monitoring until Borderless confirms fiat disbursement.
Only the user who created the payout can confirm or cancel it.

Cancel a payout

POST/payouts/{payoutId}/action : Create payout action To cancel a payout that hasn’t been confirmed yet:
Request
POST /payouts/{payoutId}/action

{
  "action": "Cancel"
}
Cancellation is only possible while the payout is awaiting confirmation.

Check payout status

GET/payouts/{payoutId} : Get payout status Poll a payout to track its progress:
Request
GET /payouts/{payoutId}
The response includes both the top-level status and the granular data.executionStatus. The top-level status values are:
StatusMeaning
ProcessingPayout is active — waiting for provider instructions, user confirmation, or settlement
CompletedFiat has been disbursed to the bank account
FailedNon-recoverable error
RejectedTransfer was rejected by a Dfns policy
ExpiredTimed out waiting for confirmation (24h) or transfer submission (4h)
CanceledCanceled by the user

Policies

Payouts create a transfer from your wallet to the provider’s deposit address. If you have policies configured on wallet transfers, the transfer may require approval. The top-level status stays Processing, but data.executionStatus changes to PendingPolicyApproval until the policy is resolved.
Last modified on March 5, 2026