Onboarding API + Fund SDK
Instantly fund an account anytime, anywhere - end to end integration guide for the Account Funding product
See core product page here
Setup
In this guide, the Platform is setup to use the Onboarding API (Reliance) plus the Account Funding SDK.

Flow
In this example, the Platform is configured to have the converted USD be automatically transferred to the Platform's account. We'll also assume that the Platform is a CFD brokerage offering stablecoins as a funding mechanism. Summary of all involved participants:
- Platform (participant_code: PLAT01)
- End Customer (participant_code: CUST01)
Webhook configuration
Platforms should be listening to the following webhooks:
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.
Natural vs. Non-natural personPlatforms can choose to onboard end users (ie, Natural Persons) or entities (ie, Non-natural persons). Both examples will be shown below
Submit customer
Natural Person
Example request - POST /participants/customers/new
{
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]",
"phone_number": "9545551234",
"address_one": "1 Main St.",
"address_two": "Suite 1000",
"city": "Chicago",
"zip": "12345",
"jurisdiction_code": "US-IL",
"date_of_birth": "1985-09-02",
"citizenship": "United States",
"tax_id": "123456789",
"risk_rating": "low",
"kyc": "pass",
"kyc_timestamp": 1630623005000,
"sanction_screening": "pass",
"sanction_screening_timestamp": 1630623005000,
"idv": "pass",
"liveness_check": "pass",
"metadata": {}
}zerohash will respond with a participant_code that uniquely identifies the customer.
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"
]
}See more detail on permitted jurisdictions here.
The preferred approach is for the Platform to not allow End 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.
Non-natural person
Partial vs. Full Non-natural personPartial: zerohash offers approved Platforms the ability to submit a stripped-down KYB data packet. This is typically reserved for licensed financial institutions, but is subject to review on a case-by-case basis.
Full: default comprehensive KYB data packet
Partial Non-natural person
To submit a partial non-natural person customer, use the POST /participants/entity/new endpoint. Example request:
{
"request_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"platform_code": "PLAT01",
"legal_name": "Entity A",
"contact_number": "15553765432",
"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",
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"signed_agreements": [
{
"type": "fund_auto_convert",
"region": "us",
"signed_timestamp": 1603378501286
}
]
}Full Non-natural person
To submit a full non-natural person customer, use the POST /participants/entity/new endpoint. Example 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": "account_funding_general",
"region": "us",
"signed_timestamp": 1603378501286
}
]
}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”.
Initialize Account Funding Flow
Retrieve Account Funding JWT token
In order to successfully invoke the Access Token, you'll need to supply a participant_code for the End Customer (see full instructions here). This customer must be in an approved status for this call to succeed. Please note: the correct permission to pass here is fwc.
You may also include an optional reference_id value when generating the token. This ID will be tied to all future webhook calls and Account Funding events within the GET /fund/transactions response.
Presetting Deposit Amounts
You can preset a deposit amount using the deposit_amount and denominated_currency parameters in the client auth token request. This removes the ability for the user to select a deposit amount during the Fund SDK flow and lands the user on the Review screen after selecting the asset they wish to send.
Note: this feature is only available for use with the Auth + Fund SDK flow when Classic Transfer is NOT enabled. Additionally, this value will not be evaluated against Platform-configured periodic transaction limits or Travel Rule limits. Exceeding these limits may cause a transaction failure.
Invoke the Account Funding SDK
Here is where we take over - the front end experience is controlled completely by zerohash.
See SDK guide for technical instructions.
Accept T&Cs
The T&Cs landing page is the first screen that provides an introduction to how the Account Funding experience will work. This screen displays the zerohash User Agreement, Privacy Policy, Regulatory Disclosures, and captures explicit consent for the terms of this product.
Select an asset and network
Allow the customer to select an asset and network. zerohash supports all major crypto and stablecoins across 19+ networks:
Transaction pending
After the customer selects the asset and network, they're then given the deposit instructions (rate, fees if applicable, and the deposit address). At this point, the customer should be navigating to their mobile phone or a different tab on their browser to an external wallet (ie, Coinbase, Robinhood, Metamask, Phantom, etc.) and initiating a transfer from there to the address shown on the screenshot above:
Transaction confirmed
After the blockchain transaction is confirmed on-chain, the frontend will automatically transition to a confirmed state. The customer will be shown a receipt with important data points including amount received, status, and fees (if applicable).
Deposit outcomes and webhooks
Platforms should be listening to the following webhooks for deposit outcomes:
| Scenario | Outcome | Account Funding Webhook |
|---|---|---|
| Deposit received; Fund Event has completed successfully. | Funds immediately converted to fiat and credited | Account Funding webhook with status_reason_code = DEPOSIT_PROCESSED Deposit/Withdraw webhook with state = completed |
| Large deposit received; Pending settlement. Stablecoin deposits over $500k* can be subject to longer processing times to complete conversion to fiat. | Funds temporarily held while processing is completed | Account Funding webhook with Deposit/Withdraw webhook with |
| Deposit received; Above maximum configured amount OR below minimum configured amount | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash branded secondary portal. | Account Funding webhook with status_reason_code = AMOUNT_ABOVE_MAXIMUM OR status_reason_code = AMOUNT_BELOW_MINIMUMDeposit/Withdraw webhook with state = completed |
| Deposit received; Asset not supported | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash branded secondary portal. | Account Funding webhook with status_reason_code = ASSET_NOT_SUPPORTEDDeposit/Withdraw webhook with state = completed |
| Deposit received; Stablecoin depegged | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash branded secondary portal. | Account Funding webhook with status_reason_code = ASSET_DEPEGGEDDeposit/Withdraw webhook with state = completed |
| Deposit received; Platform not enabled OR End Customer not approved | Funds are held and not credited | Account Funding webhook with status_reason_code = PLATFORM_NOT_ENABLED OR status_reason_code = QUARANTINED_DEPOSITDeposit/Withdraw webhook with state = quarantined |
*To enable large stablecoin deposits over $500k, contact your zerohash Relationship Manager.
Query Account Funding transactions
It may be helpful (or likely required) to display crypto or stablecoin deposits in the Transaction History (or like page) on your application. You can use the GET /fund/transactions endpoint to query all completed Account Funding events. View the code recipe for additional assistance.
Customer receives email
zerohash is required to ensure that each Customer receives an email receipt for all transactions. zerohash will handle this and send an email in the following scenarios (same scenarios as webhooks):
- Success
- Failure - Platform not enabled
- Failure - Customer not approved
- Failure - Deposit above maximum
- Failure - Deposit below minimum
- Failure - Asset not supported
- Failure - Stablecoin depegged
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.
Reconciliation
If you're using this product in tandem with our Buy/Sell product, see Account Funding + Buy/Sell Reconciliation.
Platform 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)
Tracking 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: general
- account_type: available
- asset: [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
}
]
}Note that the balance will refresh to 0 each time zerohash initiates the daily settlement wire.
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",
"on_chain_status": "",
"client_withdrawal_request_id": null,
"requested_timestamp": 1727921516403,
"transaction_id": "HND48J83HGR55LLP",
"input_data": null,
"fee_amount": "",
"quoted_fee_amount": null,
"quoted_fee_notional": null,
"trade_id": null,
"quoted_fee_asset": null,
"withdrawal_fee": "",
"parent_link_id": null,
"parent_link_id_source": null
}
]
}See core product page here
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. Account Funding SDK hosted by web-sdk.zerohash.eu.

Flow
In this example, the Platform is configured to have the converted USD be automatically transferred to the Platform's account. We'll also assume that the Platform is a CFD brokerage offering stablecoins as a funding mechanism. Summary of all involved participants:
- Platform (participant_code: PLAT01)
- End Customer (participant_code: CUST01)
Webhook configuration
Platforms should be listening to the following webhooks:
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. Guidelines for onboarding EU participants can be found here.
Natural vs. Non-natural personPlatforms can choose to onboard end users (ie, Natural Persons) or entities (ie, Non-natural persons). Both examples will be shown below
Submit customer
Natural Person
Example request - POST /participants/customers/new
{
"request_id": "c3d5e7f9-1a2b-4c6d-8e0f-3a5b7c9d1e2f",
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]",
"phone_number": "+33612345678",
"date_of_birth": "1985-09-02",
"address_one": "123 Rue de Rivoli",
"city": "Paris",
"postal_code": "75001",
"jurisdiction_code": "FR-75",
"citizenship_code": "FR",
"tax_residence": {
"jurisdiction_code": "FR-75"
},
"tax_id": "1234567890123",
"id_number_type": "passport",
"id_number": "12AB34567",
"id_issuing_date": "2020-12-16",
"id_expiration_date": "2030-12-15",
"employment_status": "full_time",
"industry": "technology",
"source_of_funds": "salary",
"savings_and_investments": "under_10000",
"risk_rating": "low",
"kyc": "pass",
"kyc_timestamp": 1603378501286,
"sanction_screening": "pass",
"sanction_screening_timestamp": 1603378501286,
"idv": "pass",
"liveness_check": "pass",
"signed_timestamp": 1603378501286,
"self_certification_timestamp": 1667504636159,
"signed_agreements": [
{
"type": "user_agreement",
"region": "eu",
"signed_timestamp": 1603378501286
}
]
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 Prohibited 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"
]
}See more detail on Permitted Jurisdictions here.
The preferred approach is for the Platform to not allow End 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.
Non-natural person
Partial vs. Full Non-natural personPartial: zerohash offers approved Platforms the ability to submit a stripped-down KYB data packet. This is typically reserved for licensed financial institutions, but is subject to review on a case-by-case basis.
Full: default comprehensive KYB data packet
To submit a partial or full non-natural person 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"
}See more detail on EU participant creation 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”.
Whitelist a self-custody sending wallet
A deposit from an address already on the allow list with sufficient information does not undergo additional Travel Rule screening, so it never enters remediation. This optional step is the most effective way to avoid holds entirely, and can be done using the POST /travel-rule/submit endpoint.
Example Request:
{
"address": "0xABC123",
"participant_code": "CUST01",
"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.
Initialize Account Funding Flow
EUR quoted currencyFor zerohash B.V. (EU), you can quote in USD or EUR. The examples on this page use USD. To use EUR, replace the quoted currency and amounts with their EUR equivalents. EUR pairs are available for BTC, ETH, LTC, BCH, XRP and SOL, and amounts in your SDK screens and emails follow the quoted currency.
Retrieve Account Funding JWT token
In order to successfully invoke the Access Token, you'll need to supply a participant_code for the End Customer (see full instructions here). This customer must be in an approved status for this call to succeed. Please note: the correct permission to pass here is fwc.
You may also include an optional reference_id value when generating the token. This ID will be tied to all future webhook calls and Account Funding events within the GET /fund/transactions response.
Use denominated_currency to specify quoted currency (EUR vs USD).
Invoke the Account Funding SDK
Here is where we take over - the front end experience is controlled completely by zerohash.
See SDK guide for technical instructions.
Accept T&Cs
The T&Cs landing page is the first screen that provides an introduction to how the Account Funding experience will work. This screen displays the zerohash User Agreement, Privacy Policy, Regulatory Disclosures, and captures explicit consent for the terms of this product.
Select an asset and network
Allow the customer to select an asset and network. zerohash supports all major crypto and stablecoins across 19+ networks:
Transaction pending
After the customer selects the asset and network, they're then given the deposit instructions (rate, fees if applicable, and the deposit address). At this point, the customer should be navigating to their mobile phone or a different tab on their browser to an external wallet (ie, Coinbase, Robinhood, Metamask, Phantom, etc.) and initiating a transfer from there to the address shown on the screenshot above:
Transaction confirmed
After the blockchain transaction is confirmed on-chain, the frontend will automatically transition to a confirmed state. The customer will be shown a receipt with important data points including amount received, status, and fees (if applicable).
- If a deposit is received missing Travel Rule information, remediation flows will be surfaced inside the Account Funding SDK, and an email will be sent to the customer with an information collection link. Reminder emails are sent after 24 hours.
Deposit outcomes and webhooks
Platforms should be listening to the following webhooks for deposit outcomes:
| Scenario | Outcome | Account Funding Webhook |
|---|---|---|
| Deposit received; Fund Event has completed successfully | Funds immediately converted to fiat and credited | Account Funding webhook with status_reason_code = DEPOSIT_PROCESSED Deposit/Withdraw webhook with state = completed |
| Deposit received; Missing travel rule information on sending wallet | Standard Travel Rule collateral flow: a 48-hour remediation window.
| Account Funding webhook with Deposit/Withdraw webhook with |
| Deposit received; Missing travel rule information on sending wallet; 48 hour timer runs out and information has not been recovered | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash europe branded secondary portal. | Account Funding webhook with Deposit/Withdraw webhook with |
| Deposit received; Missing travel rule information on sending wallet; Travel Rule information submitted and rejected during review | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash europe branded secondary portal. | Account Funding webhook with status_reason_code = TRAVEL_RULE_REVIEW_REJECTEDDeposit/Withdraw webhook with state = recovery_quarantine |
| Large deposit received; Pending settlement. Stablecoin deposits over $500k* can be subject to longer processing times to complete conversion to fiat | Funds temporarily held while processing is completed | Account Funding webhook with Deposit/Withdraw webhook with |
| Deposit received; Above maximum configured amount OR below minimum configured amount | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash branded secondary portal. | Account Funding webhook with status_reason_code = AMOUNT_ABOVE_MAXIMUM OR status_reason_code = AMOUNT_BELOW_MINIMUMDeposit/Withdraw webhook with state = completed |
| Deposit received; Asset not supported | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash branded secondary portal. | Account Funding webhook with status_reason_code = ASSET_NOT_SUPPORTEDDeposit/Withdraw webhook with state = completed |
| Deposit received; Stablecoin depegged | Funds are not converted and are credited to the sender's participant account. The sender can recover funds from the zerohash branded secondary portal. | Account Funding webhook with status_reason_code = ASSET_DEPEGGEDDeposit/Withdraw webhook with state = completed |
| Deposit received; Platform not enabled OR End Customer not approved | Funds are held and not credited | Account Funding webhook with status_reason_code = PLATFORM_NOT_ENABLED OR status_reason_code = QUARANTINED_DEPOSITDeposit/Withdraw webhook with state = quarantined |
*To enable large stablecoin deposits over $500k, contact your zerohash Relationship Manager.
Query Account Funding transactions
It may be helpful (or likely required) to display crypto or stablecoin deposits in the Transaction History (or like page) on your application. You can use the GET /fund/transactions endpoint to query all completed Account Funding events. View the code recipe for additional assistance.
Customer receives email
zerohash is required to ensure that each Customer receives an email receipt for all transactions. zerohash will handle this and send an email in the following scenarios (same scenarios as webhooks):
- Success
- Failure - Travel Rule verification pending
- Failure - Platform not enabled
- Failure - Customer not approved
- Failure - Deposit above maximum
- Failure - Deposit below minimum
- Failure - Asset not supported
- Failure - Stablecoin depegged
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.
Reconciliation
If you're using this product in tandem with our Buy/Sell product, see Account Funding + Buy/Sell Reconciliation.
Platform 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)
Tracking 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: general
- account_type: available
- asset: [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
}
]
}Note that the balance will refresh to 0 each time zerohash initiates the daily settlement wire.
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",
"on_chain_status": "",
"client_withdrawal_request_id": null,
"requested_timestamp": 1727921516403,
"transaction_id": "HND48J83HGR55LLP",
"input_data": null,
"fee_amount": "",
"quoted_fee_amount": null,
"quoted_fee_notional": null,
"trade_id": null,
"quoted_fee_asset": null,
"withdrawal_fee": "",
"parent_link_id": null,
"parent_link_id_source": null
}
]
}Updated about 7 hours ago