Docs

The Payout object

A Payout object is created when you send funds from a connected account's Zoneless balance to their external Solana wallet. Payouts transfer USDC when you process them with .processAll() or .processBatch(), and typically complete within seconds due to Solana's fast finality.

Attributes

id string

Unique identifier for the object. Zoneless payout IDs are prefixed with po_z_.

object string

String representing the object's type. Objects of the same type share the same value.

account string

The connected account ID this payout belongs to.

Zoneless extension: This field is not present in Stripe's payout object. It identifies which connected account's balance is being debited.

amount integer

The amount (in cents) that transfers to the connected account's wallet.

arrival_date timestamp

Date when the payout arrived at the destination wallet. Due to Solana's speed, this is typically seconds after creation.

Difference from Stripe: Stripe payouts can take days to arrive at a bank account. Zoneless payouts on Solana typically complete within seconds.

automatic boolean

Returns true if the payout is created by an automated payout schedule and false if it's requested manually via the API.

balance_transactionnullable string

ID of the balance transaction that describes the impact of this payout on the connected account's balance.

created timestamp

Time at which the object was created. Measured in seconds since the Unix epoch.

currency string

Three-letter currency code, in lowercase. For Zoneless, this is typically usdc.

Difference from Stripe: Stripe uses ISO currency codes like usd. Zoneless uses usdc for USDC stablecoin payouts.

descriptionnullable string

An arbitrary string attached to the object. Often useful for displaying to users.

destination string

ID of the external wallet the payout is sent to.

Difference from Stripe: Stripe's destination is a bank account or card ID. Zoneless uses an external wallet ID (wa_z_ prefix) representing a Solana wallet address.

failure_codenullable enum

Error code that provides a reason for a payout failure, if available.

Possible enum values
insufficient_fundsThe connected account has insufficient funds in their balance.
wallet_not_foundThe destination wallet could not be found or is invalid.
sanctioned_addressThe destination wallet is on a sanctions list.
blockchain_errorThe Solana blockchain returned an error during transfer.
could_not_processThe payout could not be processed.
declinedThe payout was declined.
invalid_currencyThe currency is not supported.
failure_messagenullable string

Message that provides the reason for a payout failure, if available.

livemode boolean

Has the value true if the object exists in live mode or the value false if the object exists in test mode.

metadata object

Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format.

Zoneless extension: After a successful payout, this object is populated with blockchain transaction details: network, blockchain_tx, viewer_url, gas_fee, and gas_fee_currency.

method enum

The method used to send this payout.

Difference from Stripe: Zoneless defaults to instant since Solana transactions settle in seconds. Stripe defaults to standard for bank transfers.

Possible enum values
instantImmediate transfer to the destination wallet. Default for Zoneless.
standardStandard transfer timing.
source_type string

The source balance this payout came from. Always wallet for Zoneless.

Difference from Stripe: Stripe uses card, bank_account, or fpx. Zoneless uses wallet representing the USDC balance.

statement_descriptornullable string

Extra information about the payout for internal reference. This is stored for record-keeping but does not appear on blockchain transactions.

Difference from Stripe: Bank statement descriptors don't apply to blockchain transactions. This field is retained for API compatibility.

status enum

Current status of the payout.

Possible enum values
pendingThe payout has been created and is waiting to be sent.
processingThe payout is being prepared for blockchain submission.
in_transitThe payout has been submitted to the Solana blockchain and is awaiting confirmation.
paidThe payout has been confirmed on the blockchain.
failedThe payout failed. Check failure_code and failure_message for details.
canceledThe payout was canceled before it was sent.
type string

The destination type. Always wallet for Zoneless USDC payouts.

Difference from Stripe: Stripe uses bank_account or card. Zoneless uses wallet for Solana wallets.

More attributes

THE PAYOUT OBJECT
{
  "id": "po_z_1Nv0FGQ9RKHgCVdK",
  "object": "payout",
  "account": "acct_z_1Nv0FGQ9RKHgCVdK",
  "amount": 110000,
  "arrival_date": 1704067200,
  "automatic": false,
  "balance_transaction": "txn_z_1Nv0FGQ9RKHgCVdK",
  "created": 1704067200,
  "currency": "usdc",
  "description": "Weekly seller payout",
  "destination": "wa_z_1Nv0FGQ9RKHgCVdK",
  "failure_code": null,
  "failure_message": null,
  "livemode": true,
  "metadata": {},
  "method": "instant",
  "platform_account": "acct_z_Platform123abc",
  "source_type": "wallet",
  "statement_descriptor": null,
  "status": "paid",
  "type": "wallet"
}

Create a payout

To send funds from a connected account's balance to their Solana wallet, create a new payout object. The connected account's balance must cover the payout amount. If it doesn't, you receive an "Insufficient Funds" error.

ENDPOINTS
POST /v1/payouts

Parameters

amount integer Required

A positive integer in cents representing how much to payout.

currency string

Three-letter currency code, in lowercase. Defaults to usdc.

Difference from Stripe: Zoneless uses usdc for USDC stablecoin payouts.

description string

An arbitrary string attached to the object. Often useful for displaying to users.

destination string

The ID of an external wallet to send the payout to. If not provided, uses the account's default external wallet.

Difference from Stripe: Stripe uses bank account or card IDs. Zoneless uses external wallet IDs (wa_z_ prefix).

metadata object

Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata.

method enum

The method used to send this payout. Defaults to instant.

Possible enum values
instantImmediate transfer (default).
standardStandard transfer timing.
statement_descriptor string

A string for internal reference (up to 22 characters). This is stored for record-keeping but does not appear on blockchain transactions.

Returns

Returns a Payout object if the call succeeds. The payout is created in pending status and must be processed separately using payouts.processAll(), payouts.processBatch(), or the build/broadcast endpoints to send it on-chain.

POST/v1/payouts
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

const payout = await zoneless.payouts.create({
  amount: 110000,
  currency: 'usdc',
}, {
  zonelessAccount: 'acct_z_1Nv0FGQ9RKHgCVdK',
});
RESPONSE
{
  "id": "po_z_1Nv0FGQ9RKHgCVdK",
  "object": "payout",
  "account": "acct_z_1Nv0FGQ9RKHgCVdK",
  "amount": 110000,
  "arrival_date": 1704067200,
  "automatic": false,
  "balance_transaction": "txn_z_1Nv0FGQ9RKHgCVdK",
  "created": 1704067200,
  "currency": "usdc",
  "description": null,
  "destination": "wa_z_1Nv0FGQ9RKHgCVdK",
  "failure_code": null,
  "failure_message": null,
  "livemode": true,
  "metadata": {},
  "method": "instant",
  "platform_account": "acct_z_Platform123abc",
  "source_type": "wallet",
  "statement_descriptor": null,
  "status": "pending",
  "type": "wallet"
}

Update a payout

Updates the specified payout by setting the values of the parameters you pass. Parameters not provided are left unchanged. This request only accepts the metadata as arguments.

ENDPOINTS
POST /v1/payouts/:id

Parameters

metadata object

Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata.

Returns

Returns the Payout object if the update succeeds. This call raises an error if update parameters are invalid.

POST/v1/payouts/:id
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

const payout = await zoneless.payouts.update(
  'po_z_1Nv0FGQ9RKHgCVdK',
  {
    metadata: {
      order_id: '6735',
    },
  }
);
RESPONSE
{
  "id": "po_z_1Nv0FGQ9RKHgCVdK",
  "object": "payout",
  "account": "acct_z_1Nv0FGQ9RKHgCVdK",
  "amount": 110000,
  "arrival_date": 1704067200,
  "automatic": false,
  "balance_transaction": "txn_z_1Nv0FGQ9RKHgCVdK",
  "created": 1704067200,
  "currency": "usdc",
  "description": null,
  "destination": "wa_z_1Nv0FGQ9RKHgCVdK",
  "failure_code": null,
  "failure_message": null,
  "livemode": true,
  "metadata": {
    "order_id": "6735"
  },
  "method": "instant",
  "platform_account": "acct_z_Platform123abc",
  "source_type": "wallet",
  "statement_descriptor": null,
  "status": "paid",
  "type": "wallet"
}

Retrieve a payout

Retrieves the details of an existing payout. Supply the unique payout ID from either a payout creation request or the payout list. Zoneless returns the corresponding payout information.

ENDPOINTS
GET /v1/payouts/:id

Parameters

No parameters.

Returns

Returns a Payout object if you provide a valid identifier. Raises an error otherwise.

GET/v1/payouts/:id
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

const payout = await zoneless.payouts.retrieve('po_z_1Nv0FGQ9RKHgCVdK');
RESPONSE
{
  "id": "po_z_1Nv0FGQ9RKHgCVdK",
  "object": "payout",
  "account": "acct_z_1Nv0FGQ9RKHgCVdK",
  "amount": 110000,
  "arrival_date": 1704067200,
  "automatic": false,
  "balance_transaction": "txn_z_1Nv0FGQ9RKHgCVdK",
  "created": 1704067200,
  "currency": "usdc",
  "description": "Weekly seller payout",
  "destination": "wa_z_1Nv0FGQ9RKHgCVdK",
  "failure_code": null,
  "failure_message": null,
  "livemode": true,
  "metadata": {
    "network": "solana-mainnet",
    "blockchain_tx": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
    "viewer_url": "https://solscan.io/tx/5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
    "gas_fee": 5000,
    "gas_fee_currency": "SOL"
  },
  "method": "instant",
  "platform_account": "acct_z_Platform123abc",
  "source_type": "wallet",
  "statement_descriptor": null,
  "status": "paid",
  "type": "wallet"
}

List all payouts

Returns a list of existing payouts sent to connected account wallets. The payouts return in sorted order, with the most recently created payouts appearing first.

ENDPOINTS
GET /v1/payouts

Parameters

arrival_date object

Only return payouts that arrived during the given date interval.

created object

Only return payouts that were created during the given date interval.

destination string

The ID of an external wallet—only return payouts sent to this wallet.

ending_before string

A cursor for use in pagination. ending_before is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with po_z_bar, your subsequent call can include ending_before=po_z_bar in order to fetch the previous page of the list.

limit integer

A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.

starting_after string

A cursor for use in pagination. starting_after is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with po_z_foo, your subsequent call can include starting_after=po_z_foo in order to fetch the next page of the list.

status enum

Only return payouts that have the given status.

Possible enum values
pending
processing
in_transit
paid
failed
canceled

Returns

A dictionary with a data property that contains an array of up to limit payouts, starting after payout starting_after. Each entry in the array is a separate Payout object. If no other payouts are available, the resulting array is empty.

GET/v1/payouts
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

const payouts = await zoneless.payouts.list({
  limit: 3,
});
RESPONSE
{
  "object": "list",
  "url": "/v1/payouts",
  "has_more": false,
  "data": [
    {
      "id": "po_z_1Nv0FGQ9RKHgCVdK",
      "object": "payout",
      "account": "acct_z_1Nv0FGQ9RKHgCVdK",
      "amount": 110000,
      "arrival_date": 1704067200,
      "automatic": false,
      "balance_transaction": "txn_z_1Nv0FGQ9RKHgCVdK",
      "created": 1704067200,
      "currency": "usdc",
      "description": null,
      "destination": "wa_z_1Nv0FGQ9RKHgCVdK",
      "failure_code": null,
      "failure_message": null,
      "livemode": true,
      "metadata": {},
      "method": "instant",
      "platform_account": "acct_z_Platform123abc",
      "source_type": "wallet",
      "statement_descriptor": null,
      "status": "paid",
      "type": "wallet"
    }
  ]
}

Cancel a payout

You can cancel a previously created payout if its status is pending. Zoneless refunds the funds to the connected account's available balance. You cannot cancel payouts that have already been sent to the blockchain.

ENDPOINTS
POST /v1/payouts/:id/cancel

Parameters

No parameters.

Returns

Returns the Payout object with status set to canceled if the cancellation succeeds. Returns an error if the payout has already been sent or is not in pending status.

POST/v1/payouts/:id/cancel
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

const payout = await zoneless.payouts.cancel('po_z_1Nv0FGQ9RKHgCVdK');
RESPONSE
{
  "id": "po_z_1Nv0FGQ9RKHgCVdK",
  "object": "payout",
  "account": "acct_z_1Nv0FGQ9RKHgCVdK",
  "amount": 110000,
  "arrival_date": 1704067200,
  "automatic": false,
  "balance_transaction": "txn_z_1Nv0FGQ9RKHgCVdK",
  "created": 1704067200,
  "currency": "usdc",
  "description": null,
  "destination": "wa_z_1Nv0FGQ9RKHgCVdK",
  "failure_code": null,
  "failure_message": null,
  "livemode": true,
  "metadata": {},
  "method": "instant",
  "platform_account": "acct_z_Platform123abc",
  "source_type": "wallet",
  "statement_descriptor": null,
  "status": "canceled",
  "type": "wallet"
}

Build a payout batch

Build an unsigned batch payout transaction for multiple pending payouts. This enables self-custodial payouts where your platform signs transactions locally using your Solana wallet.

ENDPOINTS
POST /v1/payouts/build

Parameters

payouts array Required

Array of payout IDs to include in the batch transaction. Maximum 10 payouts per batch.

Zoneless-specific: This endpoint is unique to Zoneless and enables self-custodial payout processing where your platform signs transactions locally.

Returns

Returns a payout_batch_build object containing the unsigned transaction (base64-encoded), the blockhash, estimated fees, and the payout objects included in the batch.

POST/v1/payouts/build
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

// Build an unsigned transaction for multiple payouts
const buildResult = await zoneless.payouts.build({
  payouts: [
    'po_z_1Nv0FGQ9RKHgCVdK',
    'po_z_2Xw1GHR0SKIiDWeL'
  ]
});

console.log(buildResult.unsigned_transaction);
console.log(buildResult.total_amount); // 160000 cents
RESPONSE
{
  "object": "payout_batch_build",
  "unsigned_transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAHDw...",
  "estimated_fee_lamports": 5000,
  "blockhash": "GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi",
  "last_valid_block_height": 158436852,
  "payouts": [
    {
      "id": "po_z_1Nv0FGQ9RKHgCVdK",
      "object": "payout",
      "account": "acct_z_1Nv0FGQ9RKHgCVdK",
      "amount": 110000,
      "status": "pending"
    },
    {
      "id": "po_z_2Xw1GHR0SKIiDWeL",
      "object": "payout",
      "account": "acct_z_2Xw1GHR0SKIiDWeL",
      "amount": 50000,
      "status": "pending"
    }
  ],
  "total_amount": 160000,
  "recipients_count": 2
}

Broadcast a payout batch

Broadcast a signed batch payout transaction to the Solana network. This endpoint submits your signed transaction and updates all included payouts to paid or failed status.

ENDPOINTS
POST /v1/payouts/broadcast

Parameters

signed_transaction string Required

The signed Solana transaction as a base64-encoded string. Sign the unsigned transaction from the build endpoint using your platform's Solana wallet.

payouts array Required

Array of payout IDs included in the transaction. Must match the payouts used in the build request.

This is used to verify the transaction contents and update payout statuses after broadcasting.

blockhash string Required

The blockhash used when building the transaction. Pass the blockhash value returned by the build endpoint.

last_valid_block_height integer Required

The last valid block height for the transaction. Pass the last_valid_block_height value returned by the build endpoint.

Returns

Returns a payout_batch_broadcast object containing the transaction signature, status, viewer URL, and the updated payout objects. All payouts will have their status set to paid on success or failed if the transaction failed.

Webhooks

After broadcasting, Zoneless sends payout.paid or payout.failed webhook events for each payout in the batch.

POST/v1/payouts/broadcast
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

// After signing the transaction from build()
const result = await zoneless.payouts.broadcast({
  signed_transaction: signedTxBase64,
  payouts: [
    'po_z_1Nv0FGQ9RKHgCVdK',
    'po_z_2Xw1GHR0SKIiDWeL'
  ],
  blockhash: buildResult.blockhash,
  last_valid_block_height: buildResult.last_valid_block_height,
});

console.log(result.signature); // Solana tx signature
console.log(result.viewer_url); // Link to Solscan
RESPONSE
{
  "object": "payout_batch_broadcast",
  "signature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
  "status": "paid",
  "viewer_url": "https://solscan.io/tx/5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
  "payouts": [
    {
      "id": "po_z_1Nv0FGQ9RKHgCVdK",
      "object": "payout",
      "account": "acct_z_1Nv0FGQ9RKHgCVdK",
      "amount": 110000,
      "status": "paid",
      "metadata": {
        "network": "solana-mainnet",
        "blockchain_tx": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
        "viewer_url": "https://solscan.io/tx/5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"
      }
    },
    {
      "id": "po_z_2Xw1GHR0SKIiDWeL",
      "object": "payout",
      "account": "acct_z_2Xw1GHR0SKIiDWeL",
      "amount": 50000,
      "status": "paid",
      "metadata": {
        "network": "solana-mainnet",
        "blockchain_tx": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
        "viewer_url": "https://solscan.io/tx/5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"
      }
    }
  ]
}

Using SDK helper functions

For most use cases, the SDK provides helper functions that handle the entire build-sign-broadcast flow in a single call. These are the recommended way to process payouts.

processBatch()

Process up to 10 pending payouts in a single batch. Returns a has_more flag indicating if more payouts remain.

processAll()

Process all pending payouts automatically, handling multiple batches until none remain. Returns an array of results, one per batch.

SDK HELPER FUNCTIONS
import { Zoneless } from '@zoneless/node';
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');

// Process up to 10 pending payouts
const result = await zoneless.payouts.processBatch(
  process.env.SOLANA_SECRET_KEY
);

console.log(`Processed ${result.payouts.length} payouts`);
console.log(`Transaction: ${result.signature}`);

if (result.has_more) {
  console.log('More payouts pending...');
}