(BETA) Payouts API Integration Guide

Context

The Payouts API lets platforms initiate a compliant stablecoin (or crypto) payout in a single API call. Rather than making four sequential calls to onboard participants, link an external account, and submit a payment, POST /payouts handles all of this in one request.

Participant Roles

RoleDescriptionSupported typesExample participant_code
PlatformThe zerohash partner submitting the API request. Must have a signed MSA contract with zerohash.n/aPLAT01
PayorThe entity or individual submitting payouts on behalf of the Ultimate Payor. Pre-registered via POST /participants/entity/new with zerohash and referenced by participant_code on every request.entity, individualPAYOR1
Ultimate PayorThe entity or individual whose funds are being sent. zerohash creates and manages this participant internally.entity, individualUPAYR1
BeneficiaryThe entity or individual receiving the payout. zerohash creates and manages this participant internally.entity, individualBENEF1

Account Models

The account_model field controls how participants are treated from a regulatory and compliance perspective. Your zerohash account must be configured for a given account model before it can be used.

ModelDescription
fully_disclosedThe Ultimate Payor is a legal zerohash customer, signs zerohash T&Cs, and is subject to KYB/KYC. The Payor does not put this activity within their own licenses.
omnibusThe Payor is a licensed money service business that puts this activity within their own licenses and is the legal zerohash customer. The Ultimate Payor is not a direct zerohash customer.


Pass the account model on every POST /payouts request:

{
  "account_model": "fully_disclosed",
  ...
}

Fund Float Account

You will fund their float account by sending fiat to the mutually decided-upon bank account. Here are the account details:

  • participant_code: 00SCXM

  • account_group: PLAT01 (replace with your Platform's code)

  • account_label: general

  • account_type: available

  • asset: USD

ℹ️

In Cert, your platform will be pre-funded with Float account funds.

Onboard Payor

⚠️

Approval Required

The Payor PII requirements reflected below require prior approval for your integration. Contact your zerohash representative to begin the review process.

Use the POST /participants/entity/new endpoint to pre-register the Payor.

Note: you must supply a value of originator_entity for onboarding_profile

Request Example - Platform is not planning to have the Payor use the Account Funding product - only Payouts

{
  "onboarding_profile": "originator_entity",
  "legal_name": "Bank Corp.",
  "contact_number": "15553765431",
  "tax_id": "76-5432109",
  "id_issuing_authority": "US",
  "address_one": "2000 McKinney Avenue",
  "address_two": "Suite 1400",
  "city": "Dallas",
  "postal_code": "75201",
  "jurisdiction_code": "US-TX",
  "sanction_screening": "pass",
  "sanction_screening_timestamp": 1718000520000,
  "signed_agreements": [
    {
      "type": "user_agreement",
      "region": "us",
      "signed_timestamp": 1718000520000
    }
  ]
}

Note: The postal_code field is conditionally required; if the provided jurisdiction_code = US-XX , postal_code is required. Else, it is optional.

Response:

{
  "participant_code": "ZH5K9M",
  "participant_name": "Bank Corp.",
  "status": "submitted",
  "kyc_status": "pending",
  "onboarding_profile": "originator_entity",
  "legal_name": "Bank Corp.",
  "contact_number": "15553765431",
  "tax_id": "76-5432109",
  "id_issuing_authority": "US",
  "address_one": "2000 McKinney Avenue",
  "address_two": "Suite 1400",
  "city": "Dallas",
  "postal_code": "75201",
  "jurisdiction_code": "US-TX",
  "sanction_screening": "pass",
  "sanction_screening_timestamp": 1718000520000,
  "signed_agreements": [
    {
      "type": "user_agreement",
      "region": "us",
      "signed_timestamp": 1718000520000
    }
  ]
}

Request Example - Platform is planning to have the Payor use the Account Funding product and the Payouts product. Additional signed_agreement object required

{
  "onboarding_profile": "originator_entity",
  "legal_name": "Bank Corp.",
  "contact_number": "15553765431",
  "tax_id": "76-5432109",
  "id_issuing_authority": "US",
  "address_one": "2000 McKinney Avenue",
  "address_two": "Suite 1400",
  "city": "Dallas",
  "postal_code": "75201",
  "jurisdiction_code": "US-TX",
  "sanction_screening": "pass",
  "sanction_screening_timestamp": 1718000520000,
  "signed_agreements": [
    {
      "type": "user_agreement",
      "region": "us",
      "signed_timestamp": 1718000520000
    },
    {
      "type": "account_funding_general",
      "region": "us",
      "signed_timestamp": 1773759120000
    }
  ]
}

Note: The postal_code field is conditionally required; if the provided jurisdiction_code = US-XX , postal_code is required. Else, it is optional.

Response:

{
  "participant_code": "ZH5K9M",
  "participant_name": "Bank Corp.",
  "status": "submitted",
  "kyc_status": "pending",
  "onboarding_profile": "originator_entity",
  "legal_name": "Bank Corp.",
  "contact_number": "15553765431",
  "tax_id": "76-5432109",
  "id_issuing_authority": "US",
  "address_one": "2000 McKinney Avenue",
  "address_two": "Suite 1400",
  "city": "Dallas",
  "postal_code": "75201",
  "jurisdiction_code": "US-TX",
  "sanction_screening": "pass",
  "sanction_screening_timestamp": 1718000520000,
  "signed_agreements": [
    {
      "type": "user_agreement",
      "region": "us",
      "signed_timestamp": 1718000520000
    },
    {
      "type": "account_funding_general",
      "region": "us",
      "signed_timestamp": 1773759120000
    }
  ]
}

Validate Payout Request

Before submitting a live payout via POST /payouts, you can validate your request payload without executing any actions on the backend. Set "validate": true in the request body.
zerohash performs three checks:

  • Schema validation - all required fields are present and correctly formatted
  • Business logic validation - account model permissibility, required agreements, and other rules
  • Address validation - the destination crypto address is not on zerohash's deny-list and is compatible with the specified blockchain network (e.g., a BTC address for a SOL payout is rejected)

The idempotency key may be omitted when validating.

Request:

{
  "account_model": "fully_disclosed",
  "validate": true,
  "payor": {
    "participant_code": "PAYOR1",
    "payor": {
      "info": {
        "entity": {
          "onboarding_profile": "payouts_payor_ultimate",
          "legal_name": "Acme Corp",
          "contact_number": "15553765432",
          "address_one": "1 Main St.",
          "address_two": "Suite 1000",
          "city": "Chicago",
          "postal_code": "12345",
          "jurisdiction_code": "US-IL",
          "email": "[email protected]",
          "tax_id": "883987654",
          "id_issuing_authority": "US",
          "merchant_category_code": "4511",
          "sanction_screening": "pass",
          "sanction_screening_timestamp": 1603378501286,
          "signed_agreements": [
            {
              "type": "user_agreement",
              "region": "us",
              "signed_timestamp": 1603378501286
            }
          ]
        }
      }
    }
  },
  "beneficiary": {
    "info": {
      "individual": {
        "onboarding_profile": "payouts_beneficiary",
        "first_name": "Jane",
        "last_name": "Smith",
        "date_of_birth": "1990-01-01",
        "address_one": "123 Main St",
        "address_two": "Apt 4B",
        "city": "New York",
        "zip": "10001",
        "jurisdiction_code": "US-NY",
        "tax_id": "123456789",
        "id_issuing_authority": "US"
      }
    },
    "external_account": {
      "info": {
        "network": "SOL",
        "crypto_address": "ab123...",
        "supported_symbols": ["USDC"]
      }
    }
  },
  "payment": {
    "asset": "USDC.SOL",
    "quoted_asset": "USD",
    "total": "100.00",
    "description": "Contractor payout"
  },
  "metadata": {
    "client_ref": "your-internal-ref-id",
    "campaign": "weekly-contractor-payout"
  }
}

Note: The postal_code field in the payor and beneficiary object is conditionally required; if the provided jurisdiction_code = US-XX , postal_code is required. Else, it is optional.

Responses:

StatusMeaning
200 {}All validations passed. Your live request will succeed.
400One or more validations failed. See errors array for details.
// 400 — schema validation failure
{
  "errors": ["zip format is not valid"]
}

// 400 — unexpected field
{
  "errors": ["unexpected field: network_fee_notional"]
}

Initiate Payout - New Participants

Use this pattern when submitting a payout for participants that have not been previously onboarded with zerohash. Provide full PII inline for the Ultimate Payor and Beneficiary. zerohash creates the corresponding participant_code values automatically.

For now - only entity types are supported for the Ultimate Payor. For the Beneficiary, both entity and individual are currently supported

Request - Individual Beneficiary:

{
  "account_model": "fully_disclosed",
  "payor": {
    "participant_code": "PAYOR1",
    "payor": {
      "info": {
        "entity": {
         "onboarding_profile": "payouts_payor_ultimate",
          "legal_name": "Acme Corp",
          "contact_number": "15553765432",
          "address_one": "1 Main St.",
          "address_two": "Suite 1000",
          "city": "Chicago",
          "postal_code": "12345",
          "jurisdiction_code": "US-IL",
          "email": "[email protected]",
          "tax_id": "883987654",
          "id_issuing_authority": "US",
          "merchant_category_code": "4511",
          "sanction_screening": "pass",
          "sanction_screening_timestamp": 1603378501286,
          "signed_agreements": [
            {
              "type": "user_agreement",
              "region": "us",
              "signed_timestamp": 1603378501286
            }
          ]
        }
      }
    }
  },
  "beneficiary": {
    "info": {
      "individual": {
        "onboarding_profile": "payouts_beneficiary",
        "first_name": "Jane",
        "last_name": "Smith",
        "date_of_birth": "1990-01-01",
        "address_one": "123 Main St",
        "address_two": "Apt 4B",
        "city": "New York",
        "zip": "10001",
        "jurisdiction_code": "US-NY",
        "tax_id": "123456789",
        "id_issuing_authority": "US"
      }
    },
    "external_account": {
      "info": {
        "network": "SOL",
        "crypto_address": "ab123...",
        "supported_symbols": ["USDC"]
      }
    }
  },
  "payment": {
    "asset": "USDC.SOL",
    "quoted_asset": "USD",
    "total": "100.00",
    "description": "Contractor payout"
  },
  "metadata": {
    "client_ref": "your-internal-ref-id",
    "campaign": "weekly-contractor-payout"
  }
}

Notes:

  • For the Beneficiary object, the API will respect the following as it relates to the tax_id, id_number_type and id_number fields:
    • If id_issuing_authority = US or PR, then either the tax_id is required OR the id_number_type and the id_number is required
      • the tax_id value may an SSN or ITIN (both are expected to be 9 digits)
    • If id_issuing_authority is not US or PR, then the tax_id is expected to be omitted. And then the API will expect a value for both id_number_type and id_number

Request Entity Beneficiary:

{
  "account_model": "fully_disclosed",
  "payor": {
    "participant_code": "PAYOR1",
    "payor": {
      "info": {
        "entity": {
         "onboarding_profile": "payouts_payor_ultimate",
          "legal_name": "Acme Corp",
          "contact_number": "15553765432",
          "address_one": "1 Main St.",
          "address_two": "Suite 1000",
          "city": "Chicago",
          "postal_code": "12345",
          "jurisdiction_code": "US-IL",
          "email": "[email protected]",
          "tax_id": "883987654",
          "id_issuing_authority": "US",
          "sanction_screening": "pass",
          "sanction_screening_timestamp": 1603378501286,
          "signed_agreements": [
            {
              "type": "user_agreement",
              "region": "us",
              "signed_timestamp": 1603378501286
            }
          ]
        }
      }
    }
  },
  "beneficiary": {
    "info": {
      "entity": {
        "onboarding_profile": "payouts_beneficiary",
        "legal_name": "Contractor LLC",
        "contact_number": "15553765432",
        "address_one": "456 Oak Ave",
        "address_two": "",
        "city": "Austin",
        "postal_code": "73301",
        "jurisdiction_code": "US-TX",
        "tax_id": "123456789",
        "id_issuing_authority": "US",
        "email": "[email protected]"
      }
    },
    "external_account": {
      "info": {
        "network": "SOL",
        "crypto_address": "cd456...",
        "supported_symbols": ["USDC"]
      }
    }
  },
  "payment": {
    "asset": "USDC.SOL",
    "quoted_asset": "USD",
    "total": "500.00",
    "description": "Invoice payment"
  },
  "metadata": {
    "client_ref": "your-internal-ref-id"
  }
}

Response:

// 202
{
  "idempotency_key": "your-idempotency-key",
  "payout_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "pending"
}

Initiate Payout - Existing Participants

If the Ultimate Payor, Beneficiary, and/or external account have already been onboarded in a previous payout, you can reference them by ID instead of re-submitting full PII. Mix and match - any combination of inline PII and reference IDs is supported.

ObjectReference Field
Ultimate Payorpayor.payor.participant_code
Beneficiarybeneficiary.participant_code
Beneficiary external accountbeneficiary.external_account.external_account_id

Request:

{
  "account_model": "fully_disclosed",
  "payor": {
    "participant_code": "PAYOR1",
    "payor": {
      "participant_code": "UPAYOR1"
    }
  },
  "beneficiary": {
    "participant_code": "BENEF1",
    "external_account": {
      "external_account_id": "ea_3b1d8e4a"
    }
  },
  "payment": {
    "asset": "USDC.SOL",
    "quoted_asset": "USD",
    "total": "100.00",
    "description": "Contractor payout"
  },
  "metadata": {
    "client_ref": "your-internal-ref-id",
    "campaign": "weekly-contractor-payout"
  }
}

Response:

// 202
{
  "idempotency_key": "your-idempotency-key",
  "payout_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "pending"
}

Idempotency

POST /payouts is idempotent. Supply an Idempotency-Key header with each request.

  • Same key + same payload → zerohash returns the original response and does not initiate a duplicate payout.
  • Same key + different payload → zerohash returns 400.

The idempotency key is included on all webhook events, GET responses, and reports. You can also query by it directly: GET /payouts?idempotency-key=your-key.

Error Reference

StatusErrorCause
400should have required property 'platform_code'Missing platform_code
400should have required property 'entity_name'Missing entity_name
400<field> format is not validField fails schema format validation
400unexpected field: <field_name>Request body contains an unrecognized field
400idempotency key reused with different payloadSame key submitted with a different body
422asset is currently depegged and conversions are haltedPayout asset is depegged

Query Payout

You can query a Payout record via the GET /payouts endpoint.

Response:

{
  "payout_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "idempotency_key": "client-supplied-uuid",
  "status": "completed",
  "sub_status": "payment.settled",
  "previous_sub_status": "payment.posted",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "failure_reason": null,
  "resources": {
    "payor": {
      "participant_code": "PAYOR1",
      "payor": {
        "participant_code": "ORIG01",
        "status": "approved"
      }
    },
    "beneficiary": {
      "participant_code": "BENEF1",
      "status": "approved",
      "external_account": {
        "external_account_id": "ea_3b1d8e4a",
        "account_nickname": "Max's USDC wallet",
        "status": "approved",
        "details": {
          "network": "SOL",
          "supported_symbols": [
            "USDC"
          ],
          "crypto_address": "ab123...",
          "destination_tag": ""
        },
        "created_at": "2026-05-06T12:01:00Z",
        "updated_at": "2026-05-06T12:01:20Z"
      }
    },
    "payment": {
      "payment_id": "pmt_4c9d2e10",
      "network": "SOL",
      "asset": "USDC",
      "quoted_asset": "USD",
      "total": "100.00",
      "rate": "1.00",
      "destination_amount": "100.00",
      "status": "posted",
      "description": "Monthly payout",
      "payment_details": {
        "withdrawal_request_id": "wr_uuid_xyz",
        "trade_id": "tr_uuid_qrs",
        "on_chain_transaction_id": "0xabc123...",
        "network_fee_notional": "0.00",
        "network_fee_quantity": "0.00"
      },
      "created_at": "2026-05-06T12:01:30Z",
      "updated_at": "2026-05-06T12:01:45Z"
    }
  },
  "account_model": "fully_disclosed"
}

Webhooks

All payout lifecycle events use payload_type: payout.status_updated. After a successful POST /payouts events are emitted in the following sequence. The payout_id and idempotency_key are present on every event.

Event Sequence

#sub_statusPayout status
1null (initial)pending
2payor.payor.submittedpending
3payor.payor.approvedpending
3apayor.payor.rejectedrejected
4beneficiary.submittedpending
5beneficiary.approvedpending
5abeneficiary.pending_approvalpending
5bbeneficiary.rejectedrejected
6beneficiary.external_account.submittedpending
7beneficiary.external_account.approvedpending
7abeneficiary.external_account.rejectedrejected
8payment.submittedpending
9payment.postedpending
10payment.settledcompleted
10apayment.failedfailed

Event payloads

Payout pending (initial)

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": null,
  "previous_sub_status": null,
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": null } },
    "beneficiary": { "participant_code": null, "status": null, "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Ultimate Payor submitted

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "payor.payor.submitted",
  "previous_sub_status": null,
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "submitted", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": null, "status": null, "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Ultimate Payor approved

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "payor.payor.approved",
  "previous_sub_status": "payor.payor.submitted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": null, "status": null, "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Ultimate Payor rejected

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "rejected",
  "sub_status": "payor.payor.rejected",
  "previous_sub_status": null,
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "rejected", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": null, "status": null, "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary submitted

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "beneficiary.submitted",
  "previous_sub_status": "payor.payor.approved",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "submitted", "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary approved

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "beneficiary.approved",
  "previous_sub_status": "beneficiary.submitted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary pending approval

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "beneficiary.pending_approval",
  "previous_sub_status": "beneficiary.submitted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "pending_approval", "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary rejected

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "rejected",
  "sub_status": "beneficiary.rejected",
  "previous_sub_status": "beneficiary.pending_approval",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "rejected", "external_account": { "external_account_id": null, "status": null } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary external account submitted

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "beneficiary.external_account.submitted",
  "previous_sub_status": "beneficiary.approved",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "submitted" } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary external account approved

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "beneficiary.external_account.approved",
  "previous_sub_status": "beneficiary.external_account.submitted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "approved" } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Beneficiary external account rejected

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "rejected",
  "sub_status": "beneficiary.external_account.rejected",
  "previous_sub_status": "beneficiary.external_account.submitted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "status": "approved", "participant_code": "UPAYOR1" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "rejected" } },
    "payment": { "payment_id": null, "on_chain_transaction_id": null, "status": null, "rate": "1.00",
      "destination_amount": "100.00"}
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": null
}

Payment submitted

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "payment.submitted",
  "previous_sub_status": "beneficiary.external_account.approved",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "participant_code": "UPAYOR1", "status": "approved" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "approved" } },
    "payment": {
      "payment_id": "pmt_abc123",
      "description": "Contractor payout",
      "asset": "USDC",
      "quoted_asset": "USD",
      "total": "100.00",
      "rate": "1.00",
      "destination_amount": "100.00",
      "status": "submitted",
      "network": "SOL",
      "payment_details": {
        "withdrawal_request_id": null,
        "trade_id": "tr_abc123",
        "on_chain_transaction_id": null,
        "network_fee_notional": null,
        "network_fee_quantity": null
      }
    }
  },
  "timestamp": "2026-05-06T12:06:00Z",
  "failure_reason": null
}

Payment posted

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "pending",
  "sub_status": "payment.posted",
  "previous_sub_status": "payment.submitted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "participant_code": "UPAYOR1", "status": "approved" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "approved" } },
    "payment": {
      "payment_id": "pmt_abc123",
      "description": "Contractor payout",
      "asset": "USDC",
      "quoted_asset": "USD",
      "total": "100.00",
      "rate": "1.00",
      "destination_amount": "100.00",
      "status": "posted",
      "network": "SOL",
      "payment_details": {
        "withdrawal_request_id": "wr_xyz456",
        "trade_id": "tr_abc123",
        "on_chain_transaction_id": null,
        "network_fee_notional": null,
        "network_fee_quantity": null
      }
    }
  },
  "timestamp": "2026-05-06T12:07:15Z",
  "failure_reason": null
}

Payment settled

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "completed",
  "sub_status": "payment.settled",
  "previous_sub_status": "payment.posted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "participant_code": "UPAYOR1", "status": "approved" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "approved" }},
    "payment": {
      "payment_id": "pmt_abc123",
      "description": "Contractor payout",
      "asset": "USDC",
      "quoted_asset": "USD",
      "total": "100.00",
      "rate": "1.00",
      "destination_amount": "100.00",
      "status": "settled",
      "network": "SOL",
      "payment_details": {
        "withdrawal_request_id": "wr_xyz456",
        "trade_id": "tr_abc123",
        "on_chain_transaction_id": "0xabc123...",
        "network_fee_notional": "0.01",
        "network_fee_quantity": "0.0000000384712"
      }
    }
  },
  "timestamp": "2026-05-06T12:08:45Z",
  "failure_reason": null
}

Payment failed

{
  "payout_id": "payout_abc123",
  "idempotency_key": "your-idempotency-key",
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:01:45Z",
  "status": "failed",
  "sub_status": "payment.failed",
  "previous_sub_status": "payment.posted",
  "resources": {
    "payor": { "participant_code": "PAYOR1", "payor": { "participant_code": "UPAYOR1", "status": "approved" } },
    "beneficiary": { "participant_code": "BENEF1", "status": "approved", "external_account": { "external_account_id": "ea_xyz789", "status": "approved" } },
    "payment": {
      "payment_id": "pmt_abc123",
      "on_chain_transaction_id": "0xabc123...",
      "status": "failed"
    }
  },
  "timestamp": "2026-05-06T12:01:30Z",
  "failure_reason": "on_chain_transaction_failed"
}