Fund Integration Guide (Onboarding API + Fund API)
See core product page here
Setup
In this guide, the Platform is setup to use the Onboarding API (Reliance) plus the Fund API.
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 this is an investment platform that allows "issuers" to source investments from End Customers. Summary of all involved participants:
- Platform (participant_code: PLAT01)
- End Customer (participant_code: CUST01)
- Issuer 1 (participant_code: ISSUR1)
Submit Customer
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
}
]
}
If you fail to indicate that the end customer has agreed to the fund-specific terms, in the signed_agreements
object shown above, /fund
API calls will fail.
Get quote - POST /fund/rfq
Example request
{
"participant_code": "CUST01",
"fund_asset": "USDC.ETH",
"account_label": "ISSUR1"
}
Interpretation of this request - the end customer (CUST01) is funding their account using USDC as the asset and ETH as the blockchain network. And to be specific, the end customer is funding the account for the purposes of investing into the issuer 1's company. The platform uses the optional, free-form account_label field for reconciliation and reporting. The entirety of this fund event and related ledger movements will be tied to issuer 1.
Example response - POST /fund/rfq
{
"participant_code": "CUST01",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency":"USD",
"expiry_timestamp":"",
"request_id":"5155f7c9-95cb-4556-ab89-c178943a7111",
"deposit_address": "0x3A45a60c635E6cD616B1C4510404Eba88116050C",
"account_label":"ISSUR1"
}
End customer initiates on-chain deposit
The end customer is presented with an address on the platform's user interface. They use their Metamask wallet, for example, to trigger a withdrawal into the deposit_address for the amount of their choice. Let's say the deposit is for 1,000 USDC.
Deposit received
The transaction has received the proper amount of on-chain confirmations (for USDC in this case, it is 1) and Zero Hash initiates a series of movements:
Accounts for this example:
account_id | account_owner | account_group | account_label | account_type | asset |
---|---|---|---|---|---|
47a854fa-d0e4-405b-831b-f1a86bbf7988 | CUST01 | PLAT01 | ISSUR1 | available | USDC.ETH |
52c29f2d-8298-4e8c-84bc-7773960bee12 | CUST01 | PLAT01 | ISSUR1 | available | USD |
- Deposit:Using our account nomenclature, the movement would appear as:
account_owner | account_group | account_label | account_type | movement_type | asset | change |
---|---|---|---|---|---|---|
CUST01 | PLAT01 | ISSUR1 | available | deposit | USDC.ETH | +1,000 |
- Conversion:Automatically, Zero Hash will convert the USD to USDC. This technically creates a trade, which has a movement_type of final_settlement:
account_owner | account_group | account_label | account_type | movement_type | asset | change |
---|---|---|---|---|---|---|
CUST01 | PLAT01 | ISSUR1 | available | final_settlement | USDC.ETH | -1,000 |
CUST01 | PLAT01 | ISSUR1 | available | final_settlement | USD | +1,000 |
- Transfer:Automatically, Zero Hash will transfer the USD from the end customer account to the platform's:
account_owner | account_group | account_label | account_type | movement_type | asset | change |
---|---|---|---|---|---|---|
CUST01 | PLAT01 | ISSUR1 | available | transfer | USD | -1,000 |
PLAT01 | PLAT01 | ISSUR1 | available | transfer | USD | +1,000 |
Webhook Event Triggered
The platform can subscribe to a newly built webhook event for this product. It will be triggered at the completion of step 3 above (or step 2 if you are not configured for a subsequent transfer). For more information on webhook messages for Fund, check out webhook documentation.
Platform Queries REST Fund Endpoint
The platform can also retroactively query the GET /fund/transactions
endpoint to view details of all particular fund event.
Example response - GET /fund/transactions
{
"participant_code": "CUST01",
"fund_asset": "USDC.ETH",
"rate": "1",
"quoted_currency":"USD",
"deposit_address": "0x3A45a60c635E6cD616B1C4510404Eba88116050C",
"quantity":"1000",
"notional":"1000",
"fund_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
"fund_timestamp": "1550174574",
"transaction_id": "0x72e399164e29bada83075cd44eacfc40c1656bc35bf38f0cf661bf00dfa3b2b2",
"account_label":"ISSUR1"
}
Payout - Platform initiates a withdrawal request
The platform can then withdraw the USD using the POST /withdrawals/requests endpoint.
Example Request - POST /withdrawals/requests
{
"withdrawal_account_id":"abc12",
"participant_code":"PLAT01",
"amount":"1000",
"asset":"USD",
"account_group":"PLAT01"
}
Reconciliation - platform queries REST movements endpoint
The platform can now query GET /movements?parent_link_id=5155f7c9-95cb-4556-ab89-c178943a7111
in order to view all related ledger movements to this fund event.
Example response - GET /movements?parent_link_id=
{
"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"
}
]
}
Updated 5 days ago