Accounts Receivable Integration Guide
Generate one deposit address for both Merchants and Third Party Payors
zerohash B.V. (EU entity)The following steps should be followed if you're onboarding a Customer to zerohash B.V. (the EU entity)
Base URL changeFor EU API calls, use the following base URL: https://api.zerohash.eu
Overview
Platforms can generate a deposit address for an onboarded Merchant. That address will be capable of receiving two kinds of deposits:
- Account funding (me-to-me): the Merchant funds its own account.
- Third Party Payor deposits: the merchant's customers, businesses or individuals, called Third Party Payors, pay what they owe the merchant, for example to settle an invoice.
zerohash name matches each deposit's Travel Rule information against the Merchant and its approved Third Party Payors. Matched deposits are auto-converted and credited to the Merchant's available balance.
Key Concepts
| Term | Definition |
|---|---|
| Merchant | An onboarded Non-natural Person (NNP) on your platform that receives funds. The merchant is a zerohash customer and the account owner. |
| Third Party Payor | A business or individual that sends funds to a merchant, for example to settle an invoice. It is a separate legal entity from the merchant and is not a zerohash customer. |
| Third Party Payor Allow List | The list of Third Party Payors approved to send funds to a specific merchant. Each payor you onboard is added to the allow list of the merchant identified by merchant_participant_code. |
Setup
In this guide, the Platform is setup to use the zerohash europe B.V. Onboarding API (Reliance) hosted by api.zerohash.eu, along with the zerohash europe B.V.

Flow
The following example illustrates a Platform configuration where incoming stablecoin deposits are name matched to the Merchant or a Third Party Payor, then automatically converted to USD and subsequently swept to the Platform’s master ledger account.
Webhook configuration
Talk to your zerohash representative to have your Platform configured for the following webhooks:
- Onboarding
- Account Funding
- Travel Rule
Onboarding via API (Reliance)
The Platform will use an external, non-zerohash KYC provider to perform proper verification of the Customer. After a successful verification, pass the results to zerohash via API.
Submit Merchant
Non-natural person
To submit the Merchant as a zerohash customer, use the POST /participants/entity/new endpoint.
Example request:
{
"entity_type": "corporation",
"platform_code": "PLAT01",
"entity_name": "Entity Name",
"legal_name": "Legal Name",
"contact_number": "+15557778888",
"date_established": "1985-09-02",
"address_one": "123 Main St.",
"city": "Paris",
"postal_code": "12345",
"tax_id": "000-00-0000",
"id_issuing_authority": "US",
"risk_rating": "low",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"signed_timestamp": 1603378501286,
"signed_agreements": [
{
"region": "eu",
"type": "fund_auto_convert",
"signed_timestamp": 1603378501286
}
],
"submitter_email": "[email protected]",
"control_persons": [
{
"sanction_screening": "pass",
"kyc": "pass",
"name": "John Smith",
"email": "[email protected]",
"address_one": "123 Main St.",
"city": "Paris",
"postal_code": 12345,
"jurisdiction_code": "US-IL",
"date_of_birth": "1985-09-02",
"phone_number": "+15557778888",
"citizenship_code": "PT",
"tax_id": "000-00-0000",
"id_number_type": "eu_drivers_license",
"id_number": 123456789,
"id_issuing_authority": "PT",
"sanction_screening_timestamp": 1603378501286,
"kyc_timestamp": 1603378501286
}
],
"beneficial_owners": [
{
"sanction_screening": "pass",
"kyc": "pass",
"name": "John Smith",
"email": "[email protected]",
"address_one": "123 Main St.",
"city": "Paris",
"postal_code": 12345,
"jurisdiction_code": "US-IL",
"date_of_birth": "1985-09-02",
"phone_number": "+15557778888",
"citizenship_code": "PT",
"tax_id": "000-00-0000",
"id_number_type": "eu_drivers_license",
"id_number": 123456789,
"sanction_screening_timestamp": 1603378501286,
"kyc_timestamp": 1603378501286
}
],
"chamber_of_commerce_number": "KVK-12345678",
"activity_locations": [
"PT, FR"
],
"entity_source_of_funds": "crypto_activities",
"declaration_no_foreseeable_changes": true,
"reason_for_business_relationship": "Digital asset custody and trading services for institutional clients",
"board_members": [
{
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"id_issuing_authority": "US",
"id_number": 123456789,
"id_number_type": "us_passport",
"tax_id": "000-00-0000",
"citizenship_code": "US",
"place_of_birth_country_code": "US",
"place_of_birth_name": "Chicago",
"date_of_birth": "1985-09-02",
"jurisdiction_code": "US-IL",
"postal_code": 12345,
"city": "Chicago",
"address_one": "123 Main St.",
"email": "[email protected]",
"last_name": "Smith",
"first_name": "John"
}
],
"country": "IRL",
"id_number": "549300TRWGQX5XMHYZ82",
"expected_annual_volume": "over_500k",
"id_number_type": "legal_entity_identifier"
}
'zerohash will respond with a participant_code that uniquely identifies the customer. See more detail on EU participant creation here.
If you fail to indicate that the End Customer has agreed to the account funding-specific terms, in the signed_agreements object shown above, /fund API calls will fail.
There may be situations where the Platform is restricted from submitting Customers who reside in non-permitted jurisdictions. The Platform will receive an error that looks like:
{
"errors": [
"The submitting platform is not allowed to operate in the participant's resident state",
"participant is not in an allowed jurisdiction"
]
}The preferred approach is for the Platform to not allow customers to onboard on their side (through a feature flag, for example). However, if a request with a Customer in a blocked jurisdiction does get submitted to zerohash via API, the Platform should fail gracefully and display a descriptive error message on-screen.
See more detail on permitted jurisdictions here.
Idempotency
You can make your requests idempotent by using the request_id field. If a subsequent call is made with a previously used request_id, then the request would fail with an error code 400, error message “requestID already used with different participant data”.
Submit Third Party Payor
Non-natural person
To onboard a business as a Third Party Payor, use the POST /participants/entity/new endpoint with onboarding_profile set to third_party_payor.
| Field | Required | Description |
|---|---|---|
onboarding_profile | Yes | Must be third_party_payor |
merchant_participant_code | Yes | Participant code of the merchant (NNP) the payor is paying |
legal_name | Yes | Registered legal business name |
dba_name | Yes | Trading or DBA name |
address_one | Yes | Legal address, line 1 |
address_two | No | Legal address, line 2 |
city | Yes | City |
postal_code | Yes | Postal code |
country | Yes | Country of the legal address |
email | Yes | Business email |
contact_number | No | Business phone number |
legal_entity_identifier or company_registration_number or tax_id | Yes, one of | LEI or Company Registration Number or TIN |
incorporation_address.jurisdiction_code | Yes | ISO 3166-2 jurisdiction of incorporation, used to validate the jurisdiction |
date_established | Yes | Date of incorporation |
merchant_category_code | Yes | Payor's MCC |
sanction_screening | No | Sanction screening result. Approved platforms only, see below |
sanction_screening_timestamp | No | Time the platform ran the screening. Required if sanction_screening is sent |
Example Request:
{
"onboarding_profile": "third_party_payor",
"merchant_participant_code": "MERCH01",
"legal_name": "Acme Supplies B.V.",
"dba_name": "Acme Supplies",
"address_one": "1 Example Street",
"city": "Amsterdam",
"postal_code": "1011AB",
"country": "Netherlands",
"email": "[email protected]",
"legal_entity_identifier": "5493001KJTIIGC8Y1R12",
"company_registration_number": "12345678",
"incorporation_address": { "jurisdiction_code": "NL-NH" },
"date_established": "2015-04-01",
"merchant_category_code": "5045",
"request_id": "8f14e45f-ceea-4672-a0a2-5f1c3e2b9d10"
}Natural persons
To onboard an individual, use the POST /participants/customers/new endpoint with onboarding_entity set to third_party_payor.
Example Request:
{
"onboarding_entity": "third_party_payor",
"merchant_participant_code": "MERCH01",
"first_name": "Jane",
"last_name": "Doe",
"dba_name": "Jane Doe Consulting",
"email": "[email protected]",
"address_one": "1 Example Street",
"city": "Amsterdam",
"postal_code": "1011AB",
"jurisdiction_code": "NL-NH",
"citizenship_code": "NL",
"date_of_birth": "1985-01-01",
"id_number_type": "passport",
"id_number": "X0000000",
"tax_id": "000000000",
"merchant_category_code": "7392",
"request_id": "3c59dc04-8b2e-4f1a-9d6e-2a7b5c4e1f22"
}For either payor type, if a required field is missing, the request fails and the response names the missing fields. The payor is not added to the allow list for that merchant. Fix the request and resubmit.
Sanction Screening
By default, zerohash runs its sanction screening controls on every Third Party Payor submitted. Approved platforms can screen payors themselves and pass the result in sanction_screening and sanction_screening_timestamp. Ask your zerohash representative about approval.
Whitelist a self-custody sending wallet
If the Third Party Payor pays from a self-custody wallet, whitelist the sending address with the POST /travel-rule/submit endpoint before the payor sends funds. Deposits from hosted wallets send Travel Rule information through the Travel Rule network, so no whitelisting is needed.
{
"address": "0xABC123",
"participant_code": "PAYOR1",
"address_owner_type": "business",
"business_pii": {
"legal_entity_name": "Business XYZ",
"legal_entity_identifier": "123456789",
"legal_entity_address": "1 Example St, Dublin"
},
"wallet_type": "self_custody"
}Find more information on Travel Rule here.
Create or reuse a deposit address
Third Party Payors can pay into the same deposit address that a Merchant uses for me-to-me Account Funding deposits. There is no separate address type for Accounts Receivable deposits. To create one, use the POST /fund/rfq endpoint.
The same address takes both:
- Me-to-me deposits from the Merchant
- Third Party Payor deposits from any whitelisted payor
Example Request:
{
"participant_code":"MERCH1",
"fund_asset":"USDC.ETH",
"client_fund_id":"abc123"
}Notes:
- See
client_fund_idrelease notes on behavior here.
Example Response:
{
"message": {
"request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
"participant_code": "MERCH1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"expiry_timestamp": null,
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"deposit_fee_bps": 100,
"subsequent_deposit_fee_floor": "1.00",
"first_deposit_fee_floor": "1.00",
"minimum_deposit": "1",
"maximum_deposit": "500000",
"reference_id": "abc123"
}
}Merchant or Third Party Payor deposits crypto or stablecoins
You should now be prompting the Merchant to use the deposit_address from the above response. The address doesn't expire, so the Merchant can print it on every invoice. Any amount within the standard minimum and maximum thresholds is accepted. All deposits made to this address will be auto-converted to USD and transferred to your account on our ledger.
Deposit outcomes and webhooks
When a deposit reaches a Merchant's address, zerohash name matches its Travel Rule information against the Merchant's AML record and every Third Party Payor on that Merchant's allow list. The Travel Rule information comes either from the Travel Rule network or from a whitelisted self-custody wallet.
| Condition | Outcome | Webhook |
|---|---|---|
| Travel Rule information matches the merchant | Deposit is converted and credited to available | Account Funding webhook with sender = merchant's participant code (me-to-me) |
| Travel Rule information matches a Third Party Payor on the Merchant's Allow List | Deposit is converted and credited to available | Account Funding webhook with sender = Third Party Payor's participant code |
| Travel Rule information matches neither | Funds are held and not credited | Name match failure webhook |
| No Travel Rule information received | Standard Travel Rule collateral flow: a 48-hour remediation window. Once the information is collected, the name match runs as above. Find more information on Travel Rule information remediation here. | None until the name match runs |
See Account Funding Transaction Updates for a full list of webhooks. The sender attribute will return the participant code of the entity that actually sent the funds. Use it to tell a Third Party Payor deposit from a me-to-me deposit and to match it to an open receivable.
Travel Rule Information Matches the Merchant
The deposit has passed compliance and travel rule checks, received the proper amount of on-chain confirmations, and Travel Rule information has been name matched to the Merchant's AML.
Example Webhook:
{
"participant_code": "MERCH1",
"sender": "MERCH1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"source_address": "3xJ9KzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr",
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"quantity": "500",
"notional": "495.00",
"fund_id": "a1b2c3d4-5678-9012-abcd-ef1234567890",
"fund_timestamp": 1745262000000000000,
"deposit_timestamp": 1745261950000000000,
"transaction_id": "4vJ9GKzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr2xJ9KzymPqfHBqp2fG",
"account_label": "general",
"success": true,
"reason": "Deposit processed",
"reference_id": "abc123",
"raw_fee_bps": "100",
"deposit_fee_bps": "100",
"raw_fee_notional": "5.00",
"deposit_fee_notional": "5.00",
"source": {}
}Travel Rule Information Matches a Third Party Payor on the Merchant's Allow List
The deposit has passed compliance and travel rule checks, received the proper amount of on-chain confirmations, and Travel Rule information has been name matched to a Third Party Payor on the Merchant's allow list.
Example Webhook:
{
"participant_code": "MERCH1",
"sender": "PAYOR1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"source_address": "3xJ9KzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr",
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"quantity": "500",
"notional": "495.00",
"fund_id": "a1b2c3d4-5678-9012-abcd-ef1234567890",
"fund_timestamp": 1745262000000000000,
"deposit_timestamp": 1745261950000000000,
"transaction_id": "4vJ9GKzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr2xJ9KzymPqfHBqp2fG",
"account_label": "general",
"success": true,
"reason": "Deposit processed",
"reference_id": "abc123",
"raw_fee_bps": "100",
"deposit_fee_bps": "100",
"raw_fee_notional": "5.00",
"deposit_fee_notional": "5.00",
"source": {}
}Travel Rule Information Matches Neither
The deposit has passed compliance and travel rule checks, received the proper amount of on-chain confirmations, but Travel Rule information cannot be name matched to a Third Party Payor or the Merchant's AML.
Example Webhook:
{
"platform_code": "PLAT01",
"participant_code": "MERCH1",
"fund_asset": "USDC",
"quoted_currency": "USD",
"source_address": "0x3A45a60c62EE6cD616B1C4510404Eba88116044I",
"deposit_address": "0x34f53Aea3ba8b60B0ed19106baF43A4f3F73f248",
"quantity": "100",
"fund_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"deposit_timestamp": 1750412525409770895,
"transaction_id": "a07407e8f98c21b037b4aa0cbc852b8489c5e122fcc3d4b33b7827d0605ad8ff",
"account_label": "general",
"success": false,
"status_reason_code": "SENDER_NOT_VERIFIED",
"reason" : "The travel rule information available for the deposit could not be name matched to the participant or an approved third party payor. The deposit has not been converted to fiat and the crypto has been credited to the customer's account",
"raw_fee_bps": "0",
"deposit_fee_bps": "0",
"raw_fee_notional": "0.00",
"deposit_fee_notional": "0.00"
}No Travel Rule Information Received
When a deposit is received, zerohash checks whether the sending wallet's Travel Rule information is available and meets TFR requirements, against Notabene, TRUST and the zerohash allow list.
- If the check passes, the deposit is credited to the customer and converted to fiat where applicable. Nothing further happens.
- If it fails, the deposit is held in collateral, a 48-hour timer begins, and your Platform receives a webhook. Platfroms have two options for Travel Rule information remediation paths for collecting the missing information within this window. Read more here. Example Travel Rule webhook:
{
"account_id": "da885ef0-49f0-5cfd-adcf-08488b8d04b3",
"amount": "500",
"asset": "ETH",
"deposit_id": "3af60e44-be66-4c7a-ab07-e324ec1760e3",
"participant_code": "MERCH1",
"platform_code": "YTOEKD",
"received_address": "0xdff7a4d40869F420fC21e04f02d8597A70c11726",
"source_address": "0xe3940dFC61e7E097b72c66892aC01aBa0Ae6a391",
"state": "pending_compliance_review",
"state_reason": "required_travel_rule_info",
"timestamp": 1790871269101,
"transaction_hash": "0xb863467b6eade708f804ddf64ecc8ef25b01fb2824fa8abad046dfda14c00b8b"
}- When Travel Rule information cannot be recovered, the funds must be recovered by the sender. Read more on fund recovery options here.
Email receipts
If email notifications are on for your Platform, zerohash sends the Merchant and email receipt with the details of the deposit received, including the amount, asset type, sender, and status. The email names the Third Party Payor by legal name. Receipts go only to the Merchant, never to a Third Party Payor.
Query transactions
You can retroactively query the GET /fund/transactions endpoint to view details of prior deposit events. View the code recipe for additional assistance. Example response:
{
"message": [
{
"participant_code": "MERCH1",
"sender": "PAYOR1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"source_address": "3xJ9KzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr",
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"quantity": "500",
"notional": "500",
"success": true,
"status_reason": "",
"status_reason_code": "DEPOSIT_PROCESSED",
"fund_timestamp": 1745262000000,
"deposit_timestamp": 1745261950000,
"transaction_id": "4vJ9GKzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr2xJ9KzymPqfHBqp2fG",
"account_label": "general",
"fund_id": "a1b2c3d4-5678-9012-abcd-ef1234567890",
"is_first_deposit": true,
"raw_fee_bps": "100",
"deposit_fee_bps": "100",
"raw_fee_notional": "5",
"deposit_fee_notional": "5",
"deposited_asset": "USDC.SOL",
"reference_id": "abc123"
}
],
"page": 1,
"page_size": 50,
"total_pages": 1
}Reconciliation - query the movements endpoint
The platform can query GET /movements in order to view all related ledger movements to a deposit event.
Example response - GET /movements
{
"message": [
{
"movement_timestamp": 1550174570000,
"account_id": "47a854fa-d0e4-405b-831b-f1a86bbf7988",
"movement_id": "5d4d962d-dc37-4ddc-b0c5-b8980d1d4421",
"movement_type": "deposit",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "1000"
},
{
"movement_timestamp": 1550174571000,
"account_id": "47a854fa-d0e4-405b-831b-f1a86bbf7988",
"movement_id": "3d4d962d-dc37-4ddc-b0c5-b8980d1d4422",
"movement_type": "final_settlement",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "-1000"
},
{
"movement_timestamp": 1550174572000,
"account_id": "52c29f2d-8298-4e8c-84bc-7773960bee12",
"movement_id": "80818b7b-92ec-4882-a371-a59fb3f8bce0",
"movement_type": "final_settlement",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "1000"
},
{
"movement_timestamp": 1550174573000,
"account_id": "52c29f2d-8298-4e8c-84bc-7773960bee12",
"movement_id": "80818b7b-92ec-4882-a371-a59fb3f8bce0",
"movement_type": "transfer",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "-1000"
},
{
"movement_timestamp": 1550174574000,
"account_id": "77c29f2d-8298-4e8c-84bc-7773960bee10",
"movement_id": "80818b7b-92ec-4882-a371-a59fb3f8bce0",
"movement_type": "transfer",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "1000"
}
]
}Deposit returns
IMPORTANT: You cannot rely on the deposit’s source address as the return destination. Blockchain transactions are not inherently bidirectional, and returning funds to the sender address may result in loss of funds or failed deliveries.Some Platforms may choose to pair their zerohash integration with their own transaction monitoring tools. In situations where zerohash accepts a deposit, but the Platform’s monitoring logic flags and rejects it, the Platform may opt to return the deposit by using the POST /withdrawal/requests endpoint.
The required flow is to always request and confirm a return address directly from the customer before initiating the return.
Please speak to a zerohash sales engineer for guidance if interested in this flow.
Settlement
zerohash will, one time per day, send a fiat settlement wire to the Platform where the amount represents the sum of all converted deposits from the prior trading session. Here is the settlement schedule:
| Session | Start | End | Expected Settlement Time* |
|---|---|---|---|
| Monday | Monday 9:00a EST | Tuesday 8:59:59a EST | Tuesday EOD |
| Tuesday | Tuesday 9:00a EST | Wednesday 8:59:59a EST | Wednesday EOD |
| Wednesday | Wednesday 9:00a EST | Thursday 8:59:59a EST | Thursday EOD |
| Thursday | Thursday 9:00a EST | Friday 8:59:59a EST | Friday EOD |
| Friday | Friday 9:00a EST | Monday 8:59:59a EST | Monday EOD |
During US holidays, Platforms should expect their settlements to arrive by EOD on the next business day. For example, for the August 30th 2024 session, the settlement will arrive by Tuesday EOD (because Monday was Labor Day)
Manual settlement initiation
Platforms can manually initiate settlements outside of the settlement schedule using POST /withdrawals/requests endpoint. Example request:
{
"asset": "USD",
"participant_code": "PLAT01",
"amount": "50000",
"account": {
"type": "INTERNATIONAL_FIAT",
"name": "Primary (1234)",
"account_number": "1231234",
"swift_code": "123456789",
"beneficiary_name": "John Doe",
"bank_name": "BMO Harris",
"intermediary_bank_account_number": "1231234",
"intermediary_bank_name": "IntermedTracking the settlement amount
The recommended way to track the impending settlement amount is to query the GET /accounts/{account\_id} endpoint. In order to retrieve the correct account_id to use in that call, use the following query parameters when hitting the GET /accounts endpoint:
participant_code: [your platform code]account_group: [your platform code]account_label: generalaccount_type: availableasset: [fiat currency code, typically "USD"]
Use the account_id in the response to query associated accounts. Example response:
{
"message": [
{
"asset": "USD"
"account_owner": "PLAT01",
"account_type": "available",
"account_group": "PLAT01",
"account_label": "general",
"balance": "25000",
"account_id": "af063ca6-836f-4677-8ebf-edbe1d049938",
"last_update": 1727214271011
}
]
}Retroactively querying settlements in the past
Platform settlements are technically a withdrawal. In order to query settlements from the past, use the GET /withdrawals/requests endpoint. The response will show all withdrawals made from the Platform's account, or one of your Customer's (Customer withdrawals are extremely rare and reserved for edge case Account Funding failures only).
In order to filter for withdrawals made from the Platform account only, query GET /withdrawals/requests using the participant_code query parameter, where the value is the Platform's platform code:
Example GET /withdrawals/requests?participant_code=PLAT01 response:
{
"message": [
{
"id": "152b8276-0585-45ec-bf62-85e134b3ff43",
"withdrawal_account_id": 346030,
"participant_code": "PLAT01",
"account_group": "PLAT01",
"account_label": null,
"requestor_participant_code": "PLAT01",
"asset": "USDC.SOL",
"requested_amount": "25000",
"settled_amount": "25000",
"gas_price": null,
"status": "SETTLED",
"
zerohash LLC (US entity)The following steps should be followed if you're onboarding a Custopmer to zerohash LLC (the US entity)
Overview
Platforms can generate a deposit address for an onboarded Merchant. That address will be capable of receiving two kinds of deposits:
- Account funding (me-to-me): the Merchant funds its own account.
- Third Party Payor deposits: the merchant's customers, businesses or individuals, called Third Party Payors, pay what they owe the merchant, for example to settle an invoice.
zerohash name matches each deposit's Travel Rule information against the Merchant and its whitelisted Third Party Payors. Matched deposits are auto-converted and credited to the Merchant's available balance.
$3,000 min. per deposit for Third Party Payors (zerohash LLC US entity only)For Platforms onboarded to zerohash LLC (the US entity), Third Party Payors are supported only for deposits over $3,000, as we cannot guarantee Travel Rule information will be available to name match under that amount in the US. Standard maximum thresholds apply.
Key Concepts
| Term | Definition |
|---|---|
| Merchant | An onboarded Non-natural Person (NNP) on your platform that receives funds. The merchant is a zerohash customer and the account owner. |
| Third Party Payor | A business or individual that sends funds to a merchant, for example to settle an invoice. It is a separate legal entity from the merchant and is not a zerohash customer. |
| Third Party Payor Allow List | The list of Third Party Payors approved to send funds to a specific merchant. Each payor you onboard is added to the allow list of the merchant identified by merchant_participant_code. |
Setup
In this guide, the Platform is setup to use the zerohash europe B.V. Onboarding API (Reliance) hosted by api.zerohash.eu, along with the zerohash europe B.V.

Flow
The following example illustrates a Platform configuration where incoming stablecoin deposits are name matched to the Merchant or a Third Party Payor, then automatically converted to USD and subsequently swept to the Platform’s master ledger account.
Webhook configuration
Talk to your zerohash representative to have your Platform configured for the following webhooks:
- Onboarding
- Account Funding
- Travel Rule
Onboarding via API (Reliance)
The Platform will use an external, non-zerohash KYC provider to perform proper verification of the Customer. After a successful verification, pass the results to zerohash via API.
Submit Merchant
Non-natural person
To submit the Merchant as a zerohash customer, use the POST /participants/entity/new endpoint.
Sample Request:
{
"request_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"platform_code": "PLAT01",
"entity_name": "Entity A",
"legal_name": "Entity A",
"contact_number": "15553765432",
"website": "https://entitya.com",
"date_established": "2020-01-15",
"entity_type": "llc",
"address_one": "1 Main St.",
"address_two": "Suite 1000",
"city": "Chicago",
"postal_code": "12345",
"jurisdiction_code": "US-IL",
"tax_id": "883987654",
"id_issuing_authority": "United States",
"risk_rating": "low",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"signed_timestamp": 1603378501286,
"submitter_email": "[email protected]",
"control_persons": [
{
"name": "Jane Smith",
"first_name": "Jane",
"last_name": "Smith",
"email": "[email protected]",
"address_one": "1 Main St.",
"city": "Chicago",
"postal_code": "12345",
"jurisdiction_code": "US-IL",
"citizenship_code": "US",
"date_of_birth": "1985-06-15",
"tax_id": "123456789",
"id_number_type": "ssn",
"id_number": "123456789",
"id_issuing_authority": "United States",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"control_person": 1,
"kyc": "pass",
"kyc_timestamp": 1603378501286
}
],
"beneficial_owners": [
{
"name": "Jane Smith",
"first_name": "Jane",
"last_name": "Smith",
"email": "[email protected]",
"address_one": "1 Main St.",
"city": "Chicago",
"postal_code": "12345",
"jurisdiction_code": "US-IL",
"citizenship_code": "US",
"date_of_birth": "1985-06-15",
"tax_id": "123456789",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"beneficial_owner": 25,
"kyc": "pass",
"kyc_timestamp": 1603378501286
}
],
"signed_agreements": [
{
"type": "fund_auto_convert",
"region": "us",
"signed_timestamp": 1603378501286
}
]
}Example Response:
{
"message": {
"platform_code": "PLAT01",
"participant_code": "WFG012",
"status": "submitted",
"entity_name": "Entity A",
"legal_name": "Entity A",
"subdomain": "",
"address_one": "1 Main St.",
"address_two": "Suite 1000",
"jurisdiction_code": "US-IL",
"city": "Chicago",
"postal_code": "12345",
"date_established": "2020-01-15",
"risk_rating": "low",
"risk_vendor": "unknown",
"entity_type": "llc",
"metadata": {},
"signed_timestamp": 1603378501000,
"tax_id": "883987654",
"contact_number": "15553765432",
"website": "https://entitya.com",
"id_issuing_authority": "United States",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501000,
"expected_annual_volume": "unknown",
"submitter_email": "[email protected]",
"submitter_first_name": "",
"submitter_last_name": "",
"submitter_title": "",
"id_number_type": "",
"id_number": "",
"self_certification_timestamp": 0,
"control_persons": [
{
"user_code": "USHJ7K",
"first_name": "Jane",
"middle_name": "",
"last_name": "Smith",
"name": "Jane Smith",
"email": "[email protected]",
"address_one": "1 Main St.",
"address_two": "",
"city": "Chicago",
"state_or_province": "",
"postal_code": "12345",
"country": "",
"jurisdiction_code": "US-IL",
"date_of_birth": "1985-06-15",
"place_of_birth_name": "",
"place_of_birth_country_code": "",
"citizenship": "",
"citizenship_code": "US",
"tax_id": "123456789",
"id_number_type": "ssn",
"id_number": "123456789",
"id_issuing_authority": "United States",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501000,
"role": "",
"control_person": 1,
"kyc": "pass",
"kyc_timestamp": 1603378501286
}
],
"beneficial_owners": [
{
"user_code": "BOWN3R",
"beneficial_owner": 25,
"first_name": "Jane",
"middle_name": "",
"last_name": "Smith",
"name": "Jane Smith",
"email": "[email protected]",
"address_one": "1 Main St.",
"address_two": "",
"city": "Chicago",
"state_or_province": "",
"postal_code": "12345",
"country": "",
"jurisdiction_code": "US-IL",
"date_of_birth": "1985-06-15",
"place_of_birth_name": "",
"place_of_birth_country_code": "",
"citizenship": "",
"citizenship_code": "US",
"tax_id": "123456789",
"id_number_type": "ssn",
"id_number": "",
"id_issuing_authority": "",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501000,
"role": "",
"kyc": "pass",
"kyc_timestamp": 1603378501286
}
],
"signed_agreements": [
{
"type": "fund_auto_convert",
"signed_timestamp": 1603378501,
"region": "us"
}
],
"b_notice_receipt": false,
"is_w_form_certified": false,
"physical_delivery": false,
"signature": "",
"payee_exemption": 0,
"is_not_subject_backup_withholding": false,
"fatca_reporting_exemption": 0,
"dba_name": "",
"other_entity_type": ""
}
}zerohash will respond with a participant_code that uniquely identifies the customer. See more detail on EU participant creation here.
If you fail to indicate that the End Customer has agreed to the account funding-specific terms, in the signed_agreements object shown above, /fund API calls will fail.
There may be situations where the Platform is restricted from submitting Customers who reside in non-permitted jurisdictions. The Platform will receive an error that looks like:
{
"errors": [
"The submitting platform is not allowed to operate in the participant's resident state",
"participant is not in an allowed jurisdiction"
]
}The preferred approach is for the Platform to not allow customers to onboard on their side (through a feature flag, for example). However, if a request with a Customer in a blocked jurisdiction does get submitted to zerohash via API, the Platform should fail gracefully and display a descriptive error message on-screen.
See more detail on permitted jurisdictions here.
Idempotency
You can make your requests idempotent by using the request_id field. If a subsequent call is made with a previously used request_id, then the request would fail with an error code 400, error message “requestID already used with different participant data”.
Submit Third Party Payor
Non-natural person
To onboard a business as a Third Party Payor, use the POST /participants/entity/new endpoint with onboarding_profile set to third_party_payor.
| Field | Required | Description |
|---|---|---|
onboarding_profile | Yes | Must be third_party_payor |
merchant_participant_code | Yes | Participant code of the merchant (NNP) the payor is paying |
legal_name | Yes | Registered legal business name |
dba_name | Yes | Trading or DBA name |
address_one | Yes | Legal address, line 1 |
address_two | No | Legal address, line 2 |
city | Yes | City |
postal_code | Yes | Postal code |
country | Yes | Country of the legal address |
email | Yes | Business email |
contact_number | No | Business phone number |
legal_entity_identifier or company_registration_number or tax_id | Yes, one of | LEI or Company Registration Number or TIN |
incorporation_address.jurisdiction_code | Yes | ISO 3166-2 jurisdiction of incorporation, used to validate the jurisdiction |
date_established | Yes | Date of incorporation |
merchant_category_code | Yes | Payor's MCC |
sanction_screening | No | Sanction screening result. Approved platforms only, see below |
sanction_screening_timestamp | No | Time the platform ran the screening. Required if sanction_screening is sent |
Example Request:
{
"onboarding_profile": "third_party_payor",
"merchant_participant_code": "MERCH01",
"legal_name": "Acme Supplies B.V.",
"dba_name": "Acme Supplies",
"address_one": "1 Example Street",
"city": "Amsterdam",
"postal_code": "1011AB",
"country": "Netherlands",
"email": "[email protected]",
"legal_entity_identifier": "5493001KJTIIGC8Y1R12",
"company_registration_number": "12345678",
"incorporation_address": { "jurisdiction_code": "NL-NH" },
"date_established": "2015-04-01",
"merchant_category_code": "5045",
"request_id": "8f14e45f-ceea-4672-a0a2-5f1c3e2b9d10"
}Natural persons
To onboard an individual, use the POST /participants/customers/new endpoint with onboarding_entity set to third_party_payor.
Example Request:
{
"onboarding_entity": "third_party_payor",
"merchant_participant_code": "MERCH01",
"first_name": "Jane",
"last_name": "Doe",
"dba_name": "Jane Doe Consulting",
"email": "[email protected]",
"address_one": "1 Example Street",
"city": "Amsterdam",
"postal_code": "1011AB",
"jurisdiction_code": "NL-NH",
"citizenship_code": "NL",
"date_of_birth": "1985-01-01",
"id_number_type": "passport",
"id_number": "X0000000",
"tax_id": "000000000",
"merchant_category_code": "7392",
"request_id": "3c59dc04-8b2e-4f1a-9d6e-2a7b5c4e1f22"
}For either payor type, if a required field is missing, the request fails and the response names the missing fields. The payor is not added to the allow list for that merchant. Fix the request and resubmit.
Sanction Screening
By default, zerohash runs its sanction screening controls on every Third Party Payor submitted. Approved platforms can screen payors themselves and pass the result in sanction_screening and sanction_screening_timestamp. Ask your zerohash representative about approval.
Whitelist a self-custody sending wallet
If the Third Party Payor pays from a self-custody wallet, whitelist the sending address with the POST /travel-rule/submit endpoint before the payor sends funds. Deposits from hosted wallets send Travel Rule information through the Travel Rule network, so no whitelisting is needed.
{
"address": "0xABC123",
"participant_code": "PAYOR1",
"address_owner_type": "business",
"business_pii": {
"legal_entity_name": "Business XYZ",
"legal_entity_identifier": "123456789",
"legal_entity_address": "1 Example St, Dublin"
},
"wallet_type": "self_custody"
}Find more information on Travel Rule here.
Create or reuse a deposit address
Third Party Payors can pay into the same deposit address that a Merchant uses for me-to-me Account Funding deposits. There is no separate address type for Accounts Receivable deposits. To create one, use the POST /fund/rfq endpoint.
The same address takes both:
- Me-to-me deposits from the Merchant
- Third Party Payor deposits from any whitelisted payor
Example Request:
{
"participant_code":"MERCH1",
"fund_asset":"USDC.ETH",
"client_fund_id":"abc123"
}Notes:
- See
client_fund_idrelease notes on behavior here.
Example Response:
{
"message": {
"request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
"participant_code": "MERCH1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"expiry_timestamp": null,
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"deposit_fee_bps": 100,
"subsequent_deposit_fee_floor": "1.00",
"first_deposit_fee_floor": "1.00",
"minimum_deposit": "1",
"maximum_deposit": "500000",
"reference_id": "abc123"
}
}Merchant or Third Party Payor deposits crypto or stablecoins
You should now be prompting the Merchant to use the deposit_address from the above response. The address doesn't expire, so the Merchant can print it on every invoice. Any amount within the standard minimum and maximum thresholds is accepted. All deposits made to this address will be auto-converted to USD and transferred to your account on our ledger.
Deposit outcomes and webhooks
When a deposit reaches a Merchant's address, zerohash name matches its Travel Rule information against the Merchant's AML record and every Third Party Payor on that Merchant's allow list. The Travel Rule information comes either from the Travel Rule network or from a whitelisted self-custody wallet.
| Condition | Outcome | Webhook |
|---|---|---|
| Travel Rule information matches the merchant | Deposit is converted and credited to available | Account Funding webhook with sender = merchant's participant code (me-to-me) |
| Travel Rule information matches a Third Party Payor on the Merchant's Allow List | Deposit is converted and credited to available | Account Funding webhook with sender = Third Party Payor's participant code |
| Travel Rule information matches neither | Funds are held and not credited | Name match failure webhook |
| No Travel Rule information received | Standard Travel Rule collateral flow: a 48-hour remediation window. Once the information is collected, the name match runs as above. Find more information on Travel Rule information remediation here. | None until the name match runs |
See Account Funding Transaction Updates for a full list of webhooks. The sender attribute will return the participant code of the entity that actually sent the funds. Use it to tell a Third Party Payor deposit from a me-to-me deposit and to match it to an open receivable.
Travel Rule Information Matches the Merchant
The deposit has passed compliance and travel rule checks, received the proper amount of on-chain confirmations, and Travel Rule information has been name matched to the Merchant's AML.
Example Webhook:
{
"participant_code": "MERCH1",
"sender": "MERCH1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"source_address": "3xJ9KzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr",
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"quantity": "500",
"notional": "495.00",
"fund_id": "a1b2c3d4-5678-9012-abcd-ef1234567890",
"fund_timestamp": 1745262000000000000,
"deposit_timestamp": 1745261950000000000,
"transaction_id": "4vJ9GKzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr2xJ9KzymPqfHBqp2fG",
"account_label": "general",
"success": true,
"reason": "Deposit processed",
"reference_id": "abc123",
"raw_fee_bps": "100",
"deposit_fee_bps": "100",
"raw_fee_notional": "5.00",
"deposit_fee_notional": "5.00",
"source": {}
}Travel Rule Information Matches a Third Party Payor on the Merchant's Allow List
The deposit has passed compliance and travel rule checks, received the proper amount of on-chain confirmations, and Travel Rule information has been name matched to a Third Party Payor on the Merchant's allow list.
Example Webhook:
{
"participant_code": "MERCH1",
"sender": "PAYOR1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"source_address": "3xJ9KzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr",
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"quantity": "500",
"notional": "495.00",
"fund_id": "a1b2c3d4-5678-9012-abcd-ef1234567890",
"fund_timestamp": 1745262000000000000,
"deposit_timestamp": 1745261950000000000,
"transaction_id": "4vJ9GKzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr2xJ9KzymPqfHBqp2fG",
"account_label": "general",
"success": true,
"reason": "Deposit processed",
"reference_id": "abc123",
"raw_fee_bps": "100",
"deposit_fee_bps": "100",
"raw_fee_notional": "5.00",
"deposit_fee_notional": "5.00",
"source": {}
}Travel Rule Information Matches Neither
The deposit has passed compliance and travel rule checks, received the proper amount of on-chain confirmations, but Travel Rule information cannot be name matched to a Third Party Payor or the Merchant's AML.
Example Webhook:
{
"platform_code": "PLAT01",
"participant_code": "MERCH1",
"fund_asset": "USDC",
"quoted_currency": "USD",
"source_address": "0x3A45a60c62EE6cD616B1C4510404Eba88116044I",
"deposit_address": "0x34f53Aea3ba8b60B0ed19106baF43A4f3F73f248",
"quantity": "100",
"fund_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"deposit_timestamp": 1750412525409770895,
"transaction_id": "a07407e8f98c21b037b4aa0cbc852b8489c5e122fcc3d4b33b7827d0605ad8ff",
"account_label": "general",
"success": false,
"status_reason_code": "SENDER_NOT_VERIFIED",
"reason" : "The travel rule information available for the deposit could not be name matched to the participant or an approved third party payor. The deposit has not been converted to fiat and the crypto has been credited to the customer's account",
"raw_fee_bps": "0",
"deposit_fee_bps": "0",
"raw_fee_notional": "0.00",
"deposit_fee_notional": "0.00"
}No Travel Rule Information Received
When a deposit is received, zerohash checks whether the sending wallet's Travel Rule information is available and meets TFR requirements, against Notabene, TRUST and the zerohash allow list.
- If the check passes, the deposit is credited to the customer and converted to fiat where applicable. Nothing further happens.
- If it fails, the deposit is held in collateral, a 48-hour timer begins, and your Platform receives a webhook. Platfroms have two options for Travel Rule information remediation paths for collecting the missing information within this window. Read more here. Example Travel Rule webhook:
{
"account_id": "da885ef0-49f0-5cfd-adcf-08488b8d04b3",
"amount": "500",
"asset": "ETH",
"deposit_id": "3af60e44-be66-4c7a-ab07-e324ec1760e3",
"participant_code": "MERCH1",
"platform_code": "YTOEKD",
"received_address": "0xdff7a4d40869F420fC21e04f02d8597A70c11726",
"source_address": "0xe3940dFC61e7E097b72c66892aC01aBa0Ae6a391",
"state": "pending_compliance_review",
"state_reason": "required_travel_rule_info",
"timestamp": 1790871269101,
"transaction_hash": "0xb863467b6eade708f804ddf64ecc8ef25b01fb2824fa8abad046dfda14c00b8b"
}- When Travel Rule information cannot be recovered, the funds must be recovered by the sender. Read more on fund recovery options here.
Email receipts
If email notifications are on for your Platform, zerohash sends the Merchant and email receipt with the details of the deposit received, including the amount, asset type, sender, and status. The email names the Third Party Payor by legal name. Receipts go only to the Merchant, never to a Third Party Payor.
Query transactions
You can retroactively query the GET /fund/transactions endpoint to view details of prior deposit events. View the code recipe for additional assistance. Example response:
{
"message": [
{
"participant_code": "MERCH1",
"sender": "PAYOR1",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency": "USD",
"source_address": "3xJ9KzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr",
"deposit_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"quantity": "500",
"notional": "500",
"success": true,
"status_reason": "",
"status_reason_code": "DEPOSIT_PROCESSED",
"fund_timestamp": 1745262000000,
"deposit_timestamp": 1745261950000,
"transaction_id": "4vJ9GKzymPqfHBqp2fGKoHtBcEn7LP5gSYNzGKS1vJcBr2xJ9KzymPqfHBqp2fG",
"account_label": "general",
"fund_id": "a1b2c3d4-5678-9012-abcd-ef1234567890",
"is_first_deposit": true,
"raw_fee_bps": "100",
"deposit_fee_bps": "100",
"raw_fee_notional": "5",
"deposit_fee_notional": "5",
"deposited_asset": "USDC.SOL",
"reference_id": "abc123"
}
],
"page": 1,
"page_size": 50,
"total_pages": 1
}Reconciliation - query the movements endpoint
The platform can query GET /movements in order to view all related ledger movements to a deposit event.
Example response - GET /movements
{
"message": [
{
"movement_timestamp": 1550174570000,
"account_id": "47a854fa-d0e4-405b-831b-f1a86bbf7988",
"movement_id": "5d4d962d-dc37-4ddc-b0c5-b8980d1d4421",
"movement_type": "deposit",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "1000"
},
{
"movement_timestamp": 1550174571000,
"account_id": "47a854fa-d0e4-405b-831b-f1a86bbf7988",
"movement_id": "3d4d962d-dc37-4ddc-b0c5-b8980d1d4422",
"movement_type": "final_settlement",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "-1000"
},
{
"movement_timestamp": 1550174572000,
"account_id": "52c29f2d-8298-4e8c-84bc-7773960bee12",
"movement_id": "80818b7b-92ec-4882-a371-a59fb3f8bce0",
"movement_type": "final_settlement",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "1000"
},
{
"movement_timestamp": 1550174573000,
"account_id": "52c29f2d-8298-4e8c-84bc-7773960bee12",
"movement_id": "80818b7b-92ec-4882-a371-a59fb3f8bce0",
"movement_type": "transfer",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "-1000"
},
{
"movement_timestamp": 1550174574000,
"account_id": "77c29f2d-8298-4e8c-84bc-7773960bee10",
"movement_id": "80818b7b-92ec-4882-a371-a59fb3f8bce0",
"movement_type": "transfer",
"transfer_type": null,
"deposit_reference_id": null,
"withdrawal_request_id": null,
"parent_link_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"trade_id": null,
"change": "1000"
}
]
}Deposit returns
IMPORTANT: You cannot rely on the deposit’s source address as the return destination. Blockchain transactions are not inherently bidirectional, and returning funds to the sender address may result in loss of funds or failed deliveries.Some Platforms may choose to pair their zerohash integration with their own transaction monitoring tools. In situations where zerohash accepts a deposit, but the Platform’s monitoring logic flags and rejects it, the Platform may opt to return the deposit by using the POST /withdrawal/requests endpoint.
The required flow is to always request and confirm a return address directly from the customer before initiating the return.
Please speak to a zerohash sales engineer for guidance if interested in this flow.
Settlement
zerohash will, one time per day, send a fiat settlement wire to the Platform where the amount represents the sum of all converted deposits from the prior trading session. Here is the settlement schedule:
| Session | Start | End | Expected Settlement Time* |
|---|---|---|---|
| Monday | Monday 9:00a EST | Tuesday 8:59:59a EST | Tuesday EOD |
| Tuesday | Tuesday 9:00a EST | Wednesday 8:59:59a EST | Wednesday EOD |
| Wednesday | Wednesday 9:00a EST | Thursday 8:59:59a EST | Thursday EOD |
| Thursday | Thursday 9:00a EST | Friday 8:59:59a EST | Friday EOD |
| Friday | Friday 9:00a EST | Monday 8:59:59a EST | Monday EOD |
During US holidays, Platforms should expect their settlements to arrive by EOD on the next business day. For example, for the August 30th 2024 session, the settlement will arrive by Tuesday EOD (because Monday was Labor Day)
Manual settlement initiation
Platforms can manually initiate settlements outside of the settlement schedule using POST /withdrawals/requests endpoint. Example request:
{
"asset": "USD",
"participant_code": "PLAT01",
"amount": "50000",
"account": {
"type": "INTERNATIONAL_FIAT",
"name": "Primary (1234)",
"account_number": "1231234",
"swift_code": "123456789",
"beneficiary_name": "John Doe",
"bank_name": "BMO Harris",
"intermediary_bank_account_number": "1231234",
"intermediary_bank_name": "IntermedTracking the settlement amount
The recommended way to track the impending settlement amount is to query the GET /accounts/{account\_id} endpoint. In order to retrieve the correct account_id to use in that call, use the following query parameters when hitting the GET /accounts endpoint:
participant_code: [your platform code]account_group: [your platform code]account_label: generalaccount_type: availableasset: [fiat currency code, typically "USD"]
Use the account_id in the response to query associated accounts. Example response:
{
"message": [
{
"asset": "USD"
"account_owner": "PLAT01",
"account_type": "available",
"account_group": "PLAT01",
"account_label": "general",
"balance": "25000",
"account_id": "af063ca6-836f-4677-8ebf-edbe1d049938",
"last_update": 1727214271011
}
]
}Retroactively querying settlements in the past
Platform settlements are technically a withdrawal. In order to query settlements from the past, use the GET /withdrawals/requests endpoint. The response will show all withdrawals made from the Platform's account, or one of your Customer's (Customer withdrawals are extremely rare and reserved for edge case Account Funding failures only).
In order to filter for withdrawals made from the Platform account only, query GET /withdrawals/requests using the participant_code query parameter, where the value is the Platform's platform code:
Example GET /withdrawals/requests?participant_code=PLAT01 response:
{
"message": [
{
"id": "152b8276-0585-45ec-bf62-85e134b3ff43",
"withdrawal_account_id": 346030,
"participant_code": "PLAT01",
"account_group": "PLAT01",
"account_label": null,
"requestor_participant_code": "PLAT01",
"asset": "USDC.SOL",
"requested_amount": "25000",
"settled_amount": "25000",
"gas_price": null,
"status": "SETTLED",
"Updated about 4 hours ago