Skip to main content
Send funds to a recipient’s registered wallet using payout sessions and executions. For collection, see Collect with Node.js.
API Reference: Payout session · Payout · Payout status
Payouts require a fully verified merchant account. If you receive 403, see Forbidden / unverified.

Prerequisites

  • Node.js 18+ with fetch (or undici)
  • Recipient party and counterparty (or create them first)
  • Payment account for the recipient with operation_type=PAYOUT
  • Merchant passcode verification (required on payout execute)
  • Server-side only — never expose Client Secret in the browser

Flow overview

  1. Authenticate → Bearer token
  2. Ensure party / counterparty exist
  3. POST /v1/payment-accounts/create?operation_type=PAYOUT
  4. POST /v1/sessions/payout with payout_account_id, amount, currency
  5. POST /v1/executions/payout with session_id, payout_account_id, reference_id, and passcode
  6. GET /v1/status/payout/:reference_id

Steps

1

Authenticate

const BASE_URL = "https://api.heydollr.app";

const tokenRes = await fetch(`${BASE_URL}/v1/jwt/client/obtain/token`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    client_id: process.env.DOLLR_CLIENT_ID,
    client_secret: process.env.DOLLR_CLIENT_SECRET,
  }),
});
const tokenData = await tokenRes.json();
const headers = {
  Authorization: `Bearer ${tokenData.access_token}`,
  "Content-Type": "application/json",
};
2

Payment account (recipient wallet)

const account = await fetch(
  `${BASE_URL}/v1/payment-accounts/create?operation_type=PAYOUT`,
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      account_name: "Beneficiary MTN Wallet",
      provider: "MTN_MOMO_LBR",
      method: "MTN_MOMO_LBR",
      party_id: partyId,
      country_code: "LR",
      insensitive_account_number: "231771234567",
    }),
  }
).then((r) => r.json());
Use MMO prediction to resolve method and provider from phone when possible.
3

Payout session

const session = await fetch(`${BASE_URL}/v1/sessions/payout`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    payout_account_id: account.id,
    amount: 100.0,
    currency: "USD",
  }),
}).then((r) => r.json());
The session response includes expires_at and wallet_id (the source wallet Dollr debits). You do not send wallet_id or expires_at on create.
4

Execute payout

const referenceId = crypto.randomUUID();

const execution = await fetch(`${BASE_URL}/v1/executions/payout`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    session_id: String(session.id),
    payout_account_id: String(account.id),
    reference_id: referenceId,
    passcode: {
      token: {
        phone: "231771234567",
        code: process.env.MERCHANT_PASSCODE,
      },
      device: {
        name: "Payout Server",
        type: "SERVER",
        platform: "NODE",
        user_agent: "dollr-payout/1.0",
        client_ip: "203.0.113.10",
      },
    },
  }),
}).then((r) => r.json());
Persist referenceId in your database before awaiting the response. The passcode object is required — it verifies the merchant authorizing the payout.
5

Poll status

const status = await fetch(
  `${BASE_URL}/v1/status/payout/${referenceId}`,
  { headers }
).then((r) => r.json());

console.log(status.status); // PENDING → PROCESSING → COMPLETED | FAILED
Do not submit a second payout with a new reference_id while status is PROCESSING.

Passcode payload

FieldRequiredDescription
passcode.token.codeYesMerchant passcode
passcode.token.phoneNo*Phone tied to the passcode
passcode.token.user_idNo*User identifier alternative to phone
passcode.device.nameYesDevice label for audit
passcode.device.typeYese.g. SERVER, MOBILE
passcode.device.platformYese.g. NODE, IOS
passcode.device.user_agentYesClient user agent string
passcode.device.client_ipYesOriginating IP address
* Provide phone or user_id on token as required by your merchant account setup.

Obtain your payout passcode

  1. Log in to merchant.heydollr.app
  2. Go to Settings → Security (or Profile → Passcode)
  3. Create or reset your merchant passcode
  4. Use the same phone in passcode.token.phone as registered in the portal
If passcode settings are not visible, your account may need full verification — see Forbidden 403. Troubleshooting: Payout passcode errors.

Wallet funding

Payouts debit your Dollr wallet (wallet_id appears on the session response). Ensure sufficient balance before executing — see Insufficient wallet balance.
Last modified on June 23, 2026