Payouts

Payouts move your available balance to financial accounts—mobile money wallets, bank accounts, or internal ledgers. Each payout bundles one or more balance transactions, enforces your configured limits, tracks execution through multiple attempts if needed, and provides complete audit trails from scheduling through settlement. Think of them as withdrawal operations: you specify a destination, a maximum amount, and when you want the transfer to happen—Commerce handles the rest, including retries, status updates, and reconciliation metadata.

The Payout object

Every payout captures the complete withdrawal lifecycle: which financial account receives the funds, the maximum amount you authorized, the actual transferred amount after settlement, execution timing, and a detailed attempt history if retries were needed. The object includes timestamps for every state transition—from creation through scheduling, execution, and final success or failure—giving you precise audit trails for financial reconciliation.

Properties

  • Name
    id
    Type
    string
    Description

    Unique identifier for this payout—use it as your lookup key and reconciliation anchor when tracking disbursements.

  • Name
    destination_id
    Type
    string
    Description

    Financial account that receives (or received) the funds. Must be a verified account in your Commerce account.

  • Name
    status
    Type
    string
    Description

    Current lifecycle state: initialized (created but not scheduled), scheduled (queued for execution), executing (actively processing), succeeded (funds transferred successfully), or failed (execution failed after all retry attempts).

  • max_amountobjectUpper bound you've authorized for this payout. Commerce will never transfer more than this amount, even if your available balance exceeds it. The actual payout amount may be less depending on available balance transactions at execution time.Click or tap to expand
    • Name
      currency
      Type
      string
      Description
      ISO 4217 currency code in lowercase (e.g., ghs, usd)—must match the destination account's currency.
    • Name
      value
      Type
      integer
      Description
      Maximum authorized amount in the smallest currency unit: pesewas for GHS, cents for USD, etc.
  • amountobjectActual amount transferred after execution completes. null until the payout succeeds—once set, this is the exact value that left your balance and arrived at the destination.Click or tap to expand
    • Name
      currency
      Type
      string
      Description
      Matches the destination currency and max_amount currency.
    • Name
      value
      Type
      integer
      Description
      Transferred amount in the smallest currency unit—the sum of all bundled balance transactions.
  • Name
    reference
    Type
    string
    Description

    Your internal identifier for this payout—typically a reconciliation key, batch number, or vendor code from your system. Unique within your Commerce account.

  • Name
    execute_after
    Type
    timestamp
    Description

    Earliest moment we'll start processing this payout. Set this to schedule future disbursements—useful for weekly payroll runs, vendor payment schedules, or time-zone-aligned transfers. Defaults to "now" if not specified.

  • Name
    scheduled_at
    Type
    timestamp|null
    Description

    When the payout was queued for execution. null while in initialized state—moves to a timestamp once scheduled and ready for processing.

  • Name
    initiated_at
    Type
    timestamp
    Description

    When you created this payout record. Always set, regardless of schedule or execution state—your creation audit trail.

  • Name
    executed_at
    Type
    timestamp|null
    Description

    When payout execution began. null until we start actively processing the transfer—this marks the transition from queued to executing.

  • Name
    succeeded_at
    Type
    timestamp|null
    Description

    When funds successfully left your balance and reached the destination. null until the payout completes—after this timestamp, the transfer is final and the funds are no longer in your available balance.

  • Name
    failed_at
    Type
    timestamp|null
    Description

    Set if the payout fails after all retry attempts. null for successful payouts—when present, check latest_error for failure details.

  • latest_attemptobjectMost recent execution attempt. Payouts may retry on transient failures—this object tracks the current or most recent attempt, including its status, amount, and destination. Use this to understand in-progress transfers or diagnose failures.Click or tap to expand
    • Name
      id
      Type
      string
      Description
      Unique identifier for this attempt—useful for debugging with support or checking provider logs.
    • Name
      status
      Type
      string
      Description
      Attempt state: pending (queued), processing (actively transferring), succeeded (completed), or failed (rejected by destination or provider).
    • Name
      destination_id
      Type
      string
      Description
      Financial account used for this attempt—usually matches the payout's destination_id unless failover routing is configured.
    • Name
      amount
      Type
      object
      Description
      Amount for this specific attempt.
      View amount attributesClick or tap to expand
      • Name
        currency
        Type
        string
        Description
        Currency of the transfer attempt.
      • Name
        value
        Type
        integer
        Description
        Amount in smallest currency unit—may differ slightly across retries if balance changes between attempts.
    • Name
      reference
      Type
      string
      Description
      Reference sent to the payout provider for this attempt—crucial for reconciling with provider statements and resolving disputes.
  • latest_errorobjectFailure details when an attempt or the entire payout fails. Contains a structured error type for programmatic handling, a human-readable message, the underlying provider cause if available, and when the error occurred. Use this to diagnose failures and determine if retries make sense.Click or tap to expand
    • Name
      type
      Type
      string
      Description
      Machine-readable error classification: insufficient_funds, invalid_destination, provider_error, rate_limit, etc. Use this for programmatic retry logic.
    • Name
      message
      Type
      string
      Description
      Human-readable explanation suitable for logging or customer support context.
    • Name
      cause
      Type
      string
      Description
      Upstream error code or message from the payout provider—often contains provider-specific details useful for debugging with their support teams.
    • Name
      occurred_at
      Type
      timestamp
      Description
      When this error happened—helps correlate with provider incident reports or system logs.
  • Name
    balance_transactions
    Type
    array
    Description

    Array of balance transaction IDs bundled into this payout. Each ID corresponds to a settled payment that contributed funds to this disbursement. Use these IDs to trace the payout back to specific customer payments and orders—essential for reconciliation, refunds, and financial reporting.


POST/payouts/schedule

Schedule a payout

Create and schedule a payout to move funds from your available balance to a financial account. The API validates the destination exists in your Commerce account, checks that your reference is unique, and enforces your configured payout limits before queuing the transfer. Once scheduled, Commerce handles execution timing, retry logic, and balance transaction bundling automatically.

You'll typically call this endpoint when hitting a payout threshold (weekly settlements, minimum balance triggers), fulfilling vendor payments, or implementing scheduled disbursement runs. The payout executes at or after execute_after—set it to "now" for immediate transfers or schedule future disbursements for specific times.

The response includes the payout ID and initial status—use the ID with the lookup endpoint to monitor execution progress, check attempt history, and retrieve the final transferred amount once the payout completes.

Request attributes

  • Name
    destination_id
    Type
    string
    Description

    Financial account that receives the funds. Must be a verified account in your Commerce account—the API validates ownership and that the account isn't archived. The destination's currency determines the payout currency.

  • Name
    reference
    Type
    string
    Description

    Your unique identifier for this payout. Use this for reconciliation with your internal systems—typically a batch number, payment run ID, or vendor code. Must be unique within your Commerce account; duplicate references are rejected.

  • Name
    max_amount
    Type
    integer
    Description

    Maximum amount you authorize for this payout, in the smallest currency unit (pesewas for GHS, cents for USD, etc.). The actual payout amount may be less depending on available balance transactions at execution time, but will never exceed this limit. Must fall within your account's configured min/max payout thresholds.

  • Name
    execute_after
    Type
    timestamp
    Description

    Optional. Earliest time we'll start processing this payout—ISO 8601 format in UTC. Defaults to "now" if omitted, meaning the payout executes immediately. Set this to schedule future disbursements: "2025-04-15T09:00:00Z" for a specific time, or calculate relative times in your application for recurring schedules.

Request

POST
/payouts/schedule
curl https://api.zebo.dev/payouts/schedule \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "destination_id": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0",
    "reference": "PAYOUT-APR-15",
    "max_amount": 250000,
    "execute_after": "2025-04-15T09:00:00Z"
  }'

Response

{
  "payout": {
    "id": "po_yQ2wXm5Dc7Pk9Ls1Vn0RgHaB",
    "destination_id": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0",
    "reference": "PAYOUT-APR-15",
    "status": "scheduled",
    "max_amount": { "currency": "ghs", "value": 250000 },
    "amount": null,
    "execute_after": "2025-04-15T09:00:00Z",
    "scheduled_at": "2025-04-14T18:32:11.000Z",
    "initiated_at": "2025-04-14T18:32:10.000Z"
  }
}

POST/payouts/lookup

Lookup a payout

Fetch the current state of a payout to monitor execution progress, check attempt history, and retrieve the final transferred amount. You'll typically use this after scheduling a payout to poll for completion, after receiving a webhook notification to get full details, or during reconciliation to match platform records with bank statements.

The response includes all lifecycle timestamps (initiated, scheduled, executed, succeeded/failed), the complete latest attempt object showing current or most recent execution state, any error details if the payout failed, and the array of balance transaction IDs that were bundled into the transfer. Use this data to trace funds from customer payments through to bank arrival.

Request attributes

  • Name
    payout_id
    Type
    string
    Description

    Payout identifier returned when you scheduled the payout. This is your primary lookup key—store it in your system for status checks and reconciliation.

Request

POST
/payouts/lookup
curl https://api.zebo.dev/payouts/lookup \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "payout_id": "po_yQ2wXm5Dc7Pk9Ls1Vn0RgHaB"
  }'

Response

{
  "payout": {
    "id": "po_yQ2wXm5Dc7Pk9Ls1Vn0RgHaB",
    "status": "executing",
    "destination_id": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0",
    "amount": { "currency": "ghs", "value": 240000 },
    "initiated_at": "2025-04-14T18:32:10.000Z",
    "executed_at": "2025-04-15T09:01:05.000Z",
    "latest_attempt": {
      "id": "po_atm_9sW2Vg6DyQ1Lr8Kc3PxBmHa",
      "status": "processing",
      "destination_id": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0",
      "amount": { "currency": "ghs", "value": 240000 },
      "reference": "PAYOUT-APR-15"
    },
    "balance_transactions": [
      "bal_txn_Za2bL9kPxV1c4Gs7Ju0DrQhn",
      "bal_txn_Ps8wC1nDf5m9Qh2Vt6YkRgLb"
    ]
  }
}

POST/payouts/settings

Get payout settings

Check your current payout configuration to understand when automatic settlements run and where funds land for each currency. This endpoint returns your payout schedule (how often settlements happen, which day of the week, aging specifications) and your destinations map (which financial account receives funds for each supported currency).

Use this when building dashboards that show payout timing, when onboarding new team members who need to understand your settlement flow, or before scheduling manual payouts to confirm destination accounts are configured correctly. No request body needed—just authenticate and call.

The response includes complete schedule details (interval, timing, aging specifications, settlement rules) and a destinations object mapping currency codes to financial account IDs. If you haven't configured a destination for a currency yet, it won't appear in the map—you'll need to set one with /payouts/set_destinations before automatic payouts can run for that currency.

For a deep dive into what each field means and how to use them, see the Understand payout settings guide.

Request

POST
/payouts/settings
curl https://api.zebo.dev/payouts/settings \
  -H "Authorization: Bearer {token}"

Response

{
  "settings": {
    "fx_enabled": false,
    "schedule": {
      "name": "weekly",
      "type": "automatic",
      "interval": "weekly",
      "schedule_on": "sunday",
      "aging_spec": {
        "t_plus": "168h",
        "label": "168_hours",
        "abide": "strictly"
      },
      "description": "Automatic weekly payout. Default."
    },
    "destinations": {
      "ghs": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0"
    }
  }
}

POST/payouts/set_destinations

Set payout destinations

Configure where automatic payouts land for each currency. Map GHS to your mobile money wallet, USD to your bank account, and so on—each currency routes to its own destination.

Call this when setting up payouts for the first time, switching settlement accounts, or adding new currencies. To remove a currency's destination, send an empty string. Currencies you omit keep their existing values.

Rules

  • Each currency key must be supported (currently ghs—see studio.zebo.dev/specs/currencies for the complete list).
  • Each financial account must exist in your Commerce account and belong to you.
  • Each financial account's currency must match its map key. You can't send GHS payouts to a USD account.
  • Each financial account must have push operations enabled—accounts without push configuration can't receive payouts.

Request attributes

  • Name
    destinations
    Type
    object
    Description

    Map of currency codes (lowercase) to financial account IDs. Pass an empty string as the value to clear a currency's destination.

Request

POST
/payouts/set_destinations
curl https://api.zebo.dev/payouts/set_destinations \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "destinations": {
      "ghs": "fa_H3cNv7pQf9WbLt2mJs6yXrPq4Kz1Vd5G0aEiUo"
    }
  }'

Response

{
  "settings": {
    "fx_enabled": false,
    "schedule": {
      "name": "weekly",
      "type": "automatic",
      "interval": "weekly",
      "schedule_on": "sunday",
      "aging_spec": {
        "t_plus": "168h",
        "label": "168_hours",
        "abide": "strictly"
      },
      "description": "Automatic weekly payout. Default."
    },
    "destinations": {
      "ghs": "fa_H3cNv7pQf9WbLt2mJs6yXrPq4Kz1Vd5G0aEiUo"
    }
  }
}

POST/payouts/disable

Disable automatic payouts

Switch your payout schedule from automatic to manual mode. This stops scheduled automatic settlements—Commerce won't create new payouts until you manually call /payouts/schedule or re-enable automatic payouts.

Use this when you need temporary control over payout timing: during financial audits, when coordinating with accounting periods, or when testing new settlement flows. Your existing scheduled payouts continue executing normally—this only prevents new automatic payouts from being created.

The response includes your updated settings with the schedule switched to manual mode. Your destination mappings remain unchanged—when you re-enable automatic payouts, funds will continue routing to the same financial accounts.

Request

POST
/payouts/disable
curl https://api.zebo.dev/payouts/disable \
  -H "Authorization: Bearer {token}"

Response

{
  "settings": {
    "schedule": {
      "name": "manual",
      "type": "manual",
      "description": "Manual payout",
      "interval": "never",
      "schedule_on": "never"
    },
    "destinations": {
      "ghs": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0"
    }
  }
}

POST/payouts/enable

Enable automatic payouts

Switch your payout schedule from manual to automatic mode. This resumes scheduled automatic settlements on the default weekly cadence—Commerce will create payouts automatically every Sunday for funds that have aged at least 7 days.

Use this when you're ready to resume predictable settlement flows after a period of manual control. Your payout destinations remain unchanged—GHS payouts route to your configured GHS account, USD to your USD account, and so on.

The response includes your updated settings with the schedule switched back to the default weekly automatic mode. Any manual payouts you've already scheduled complete normally—enabling automatic mode doesn't affect existing in-flight transfers.

Request

POST
/payouts/enable
curl https://api.zebo.dev/payouts/enable \
  -H "Authorization: Bearer {token}"

Response

{
  "settings": {
    "fx_enabled": false,
    "schedule": {
      "name": "weekly",
      "type": "automatic",
      "interval": "weekly",
      "schedule_on": "sunday",
      "aging_spec": {
        "t_plus": "168h",
        "label": "168_hours",
        "abide": "strictly"
      },
      "description": "Automatic weekly payout. Default."
    },
    "destinations": {
      "ghs": "fa_Q90wZdd2P7W8hJ1cN9Mx4Rk5sVWBvY3L6pTz8q0"
    }
  }
}

Was this page helpful?