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 Fund 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
Talk to your zerohash representative to have your Platform configured for the following webhooks:
- Onboarding
- Fund
Onboarding
Submit customer
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 Zero Hash via API. 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",
"state": "IL",
"zip": "12345",
"country": "United States",
"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",
"signed_timestamp": 1630623005000,
"metadata": {},
"signed_agreements": [
{
"type": "fund_auto_convert",
"region": "us",
"signed_timestamp": 1712008721000
}
]
}
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 certain jurisdictions (ie, New York). 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 Zero Hash via API, the Platform should fail gracefully and display a descriptive error message on-screen.
Fund
Retrieve Fund JWT token
In order to successfully invoke the Access Token, you'll need to supply a participant_code for the Customer (see full instructions here). Please note that this customer must be in an approved status for this call to succeed. Please note: the correct permission to pass here is fwc.
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.
You may also include an optional reference_id value when generating the token. This ID will be tied to all future webhook calls and fund events within the GET /fund/transactions response.
Landing page and Product intro
The 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 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 front end will automatically transition to a confirmed state. The customer will be shown a receipt with important data points:
Success case - receive webhook
Upon a successful deposit and immediate and automatic conversion to fiat, the Platform will receive a webhook (link to core webhook page):
{
"participant_code": "CUST01",
"fund_asset": "USDC",
"rate": "1",
"quoted_currency": "USD",
"source_address": "0xd3c5967d94d79F17bDc493401c33f7e8897c5f83",
"deposit_address": "0x34f53Aea3ba8b60B0ed19106baF43A4f3F73f244",
"quantity": "7.47",
"notional": "6.47",
"fund_id": "363b5b15-02bd-4797-892f-8baa4eec60d2",
"fund_timestamp": 1750404905186631445,
"deposit_timestamp": 1750404905037719568,
"transaction_id": "0xcd9e98ae631cf7cfcf4d351374337a55096abd01d9637303aaef31d5c0766562",
"account_label": "general",
"success": true,
"reference_id": "c098e59b-8023-4477-8b63-68fda3c53a39"
}
Failure cases - receive webhook
Platform not enabled
If the Platform discontinues their support for the Fund product, or otherwise no longer is configured to use the product, here is the webhook that the Platform will receive:
{
"participant_code": "CUST01",
"fund_asset": "USDC.ETH",
"quoted_currency": "USD",
"source_address": "0x3A45a60c62EE6cD616B1C4510404Eba88116044I",
"deposit_address": "0x3A45a60c635E6cD616B1C4510404Eba88116050C",
"quantity": "500",
"fund_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"deposit_timestamp": 1750404905037719568,
"transaction_id": "a07407e8f98c21b037b4aa0cbc852b8489c5e122fcc3d4b33b7827d0605ad8ff",
"account_label": "general",
"success": false,
"reason" : "Your platform is no longer configured to use this product. The deposit has not been converted to fiat and the crypto has been credited to the customer's account"
}
Customer not approved
If the Customer has transitioned to a status other than approved (which could be as a result of a routine Zero Hash Compliance review) and they make a deposit, here is the webhook that the Platform will receive:
{
"participant_code": "CUST01",
"fund_asset": "USDC.ETH",
"quoted_currency": "USD",
"source_address": "0x3A45a60c62EE6cD616B1C4510404Eba88116044I",
"deposit_address": "0x3A45a60c635E6cD616B1C4510404Eba88116050C",
"quantity": "500",
"fund_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"deposit_timestamp": 1750404905037719568,
"transaction_id": "a07407e8f98c21b037b4aa0cbc852b8489c5e122fcc3d4b33b7827d0605ad8ff",
"account_label": "general",
"success": false,
"reason" : "This participant is not in an approved state. The deposit has not been converted to fiat and the crypto has been credited to the customer's account"
}
Deposit above maximum
If a Customer deposits an amount above the maximum configured amount, here is the webhook that the Platform will receive:
{
"participant_code": "CUST01",
"fund_asset": "USDC",
"source_address": "0xd3c5967d94d79F17bDc493401c33f7e8897c5f88",
"deposit_address": "0x34f53Aea3ba8b60B0ed19106baF43A4f3F73f248",
"quantity": "26.900000",
"fund_id": "99c2fc0a-3a28-4aa4-adbf-8743a0c362fo",
"deposit_timestamp": 1750413892268466189,
"transaction_id": "0xa06b16064984eb35b170f53896eb3263e1ac4d1bd79f592d9a0e993c58278629",
"account_label": "general",
"success": false,
"reason": "deposit above maximum threshold. The deposit has not been converted to fiat and the crypto has been credited to the customer's account"
}
Deposit below minimum
If a Customer deposits an amount below the minimum configured amount, here is the webhook that the Platform will receive:
{
"participant_code": "CUST01",
"fund_asset": "USDC",
"source_address": "0xd3c5967d94d79F17bDc493401c33f7e8897c5f81",
"deposit_address": "0x34f53Aea3ba8b60B0ed19106baF43A4f3F73f242",
"quantity": "0.990000",
"fund_id": "43a29512-fa42-4d17-a2d1-1db8adbc969d",
"deposit_timestamp": 1750412525409770895,
"transaction_id": "0x67e1f4744b8d7970a94ef277cebcca29d30081fd49f80d5f1d7ef0a98a58b6a3",
"account_label": "general",
"success": false,
"reason": "deposit below minimum threshold. The deposit has not been converted to fiat and the crypto has been credited to the customer's account"
}
Asset not supported
It's possible (albeit rare) that an asset is supported by the Fund product and is later removed. Here is the webhook that the Platform will receive in this scenario:
{
"participant_code": "CUST01",
"fund_asset": "AAVE",
"source_address": "0xd3c5967d94d79F17bDc493401c33f7e8897c5f89",
"deposit_address": "0x34f53Aea3ba8b60B0ed19106baF43A4f3F73f249",
"quantity": "0.038458410203610700",
"fund_id": "983b1f3e-d765-45e7-9c0d-6880b46230do",
"deposit_timestamp": 1750409584995943453,
"transaction_id": "0x12708481e7fa507c97399d30dbd78195b3bd57cdfe65b9dbef4738a83c452a69",
"account_label": "general",
"success": false,
"reason": "asset deposited is not supported by the fund workflow. The deposit has not been converted to fiat and the crypto has been credited to the customer's account"
}
Stablecoin depegged
Historically, and rarely, stablecoins have become depegged from their reserve currency. In this event, Zero Hash will not be converting deposits into fiat. Here is the webhook that the Platform will receive in this scenario:
{
"participant_code": "CUST01",
"fund_asset": "USDC.DOTHUB",
"source_address": "5Frg83Nvor1hocqKeEgWY4GSH4DcjageJfGDUuXdYR9Xd2mt",
"deposit_address": "5EwkTCkqkSKA2DuweCm3hKLR1EhcdYLcSdN8NMxUDmmtNaHt",
"quantity": "1.490000",
"fund_id": "3a05f013-6364-4423-8573-e66d9bfdc147",
"deposit_timestamp": 1750419470756259744,
"transaction_id": "0xdfb0dfcb37a89ad4b3499c5c54acc603a2b547cdda5c2d5218131359f0e580d4",
"account_label": "general",
"success": false,
"reason": "USDC.DOTHUB conversions are currently halted. The deposit has not been converted to fiat and the crypto has been credited to the customer's account"
}
Query Fund 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 Fund events. View the code recipe for additional assistance.
Customer receives email
Zero Hash is required to ensure that each Customer receives an email receipt for all transactions. Zero Hash 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 the "Account Funding + Buy/Sell Reconciliation" page.
Platform settlement
Zero Hash 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: generalaccount_type: availableasset: [fiat currency code, typically "USD"]
Use the account_id in the response, ie af063ca6-836f-4677-8ebf-edbe1d049938, to query GET /accounts/af063ca6-836f-4677-8ebf-edbe1d049938. 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 Zero Hash 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
}
]
}
Auth
zerohash offers the ability for end user's to link custodial or non-custodial accounts via our Auth feature. adding on auth requires:
- The Platform to sign a separate "Auth Addendum"
- zerohash to make a simple configuration change on the back-end to enable this feature
Adding Auth requires no additional technical changes to your integration - abide by the above integration steps.
UX Flow
Landing page and Product intro
Menu screen
The Menu screen allows the customer select the Auth integration centralized exchange or non-custodial wallet to link and ultimately pull funds from.

Enter exchange credentials
Depending on what is selected, the Auth integration-specific sign-in flow will be triggered

Exchange - 2FA
Depending on the user's settings at the exchange or wallet, they will be asked to complete some form of 2FA (ie, SMS, Authenticator, Passkey, etc)

Select Asset
zerohash will display the user's current balances at the selected exchange:

Enter amount
The customer will now specify the amount of crypto/stablecoins to deposit:

Review
The customer will be asked to review the details of the deposit:

2FA
Depending on the user's exchange configuration, it is typical for user's to be forced to perform another 2FA assertion before any money movement takes place. Example screen:

Deposit processing
The deposit has now been broadcasted on-chain and is en-route to zerohash. The customer can choose to stay on this screen to monitor the progress, or navigate away (navigating away from this screen will not affect the completion of the deposit):

Deposit failed
EXTREMELY RARE
The below screen will display after the above Processing screen in the following 2 scenarios:
- The connected-accounts' (ie, Coinbase) systems failed to process the deposit
- The blockchain that the asset was sent on-chain was down
In both cases, the user's account at the connected account will be re-credited, and the user is expected to try their transaction again.

Deposit completed

Updated 9 days ago
