Quickstart Guide (Sandbox)
A quick introduction to building with HIFI API in sandbox environment
Introduction
Welcome to the HIFI Quickstart Guide!
In this guide, we will walk you through the process of creating a user, passing KYC to unlock rails, adding onramp/offramp accounts, doing onramps, crypto transfers, and offramps. By following along, you'll gain a clear understanding of how our endpoints work and how to integrate them into your application.
To get started, you'll need an API key, which you can get by signing up in the Dashboard.
You'll have two different API keys for two different HIFI environments. Today we'll start in the Sandbox environment with the sandbox API key. You can follow our Sandbox guide to generate a sandbox API key.
Let's first create a user!
User
A user object can represent either an individual or a business. All the available rails, accounts, onramps, offramps, transfer, etc, are associated with a user object.
To create a HIFI user, you need to provide a basic set of user information. The user must also review and accept HIFI's Terms and Service to obtain a valid signed agreement ID, which signifies a legally binding agreement to use our service.
A successfully created user will have provisioned wallets and be granted access to our on-chain functionalities.
Get a Valid Signed Agreement ID
To get HIFI's Terms and Service page, you can call the Generate Terms of Service Link endpoint. You will need to pass in an idempotencyKey
, which can be any UUID. This idempotencyKey
will be used as your signed agreement ID.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/tos-link \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"idempotencyKey": "8cb49537-bcf9-41b1-8d8c-c9c200d7341b",
"redirectUrl": "http://redirect.url.com/tosredirect"
}
'
Response:
{
"url": "https://dashboard.hifibridge.com/accept-terms-of-service?sessionToken=536bb03a-8ac9-4ba7-b928-461007ecf6eb&templateId=2fb2da24-472a-4e5b-b160-038d9dc82a40&sandbox=true",
"signedAgreementId": "8cb49537-bcf9-41b1-8d8c-c9c200d7341b"
}
You will get a response object back containing the url
and the signedAgreementId
. The url
directs you to HIFI's Terms of Service page. The signedAgreementId
is the idempotencyKey
you passed in, which will be valid only after you accept the Terms of Service.
HIFI's Terms of Service page:
![HIFI's default terms of service template. This page can be whitelabled with your organizations logo and brand colors.](https://files.readme.io/47eda49-image.png)
Create User
Now that we have the user's valid signedAgreementId
and basic personal information, we can create a user by calling the Create User endpoint. We have provided all the basic personal information with dummy values in the curl request.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/users \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"type": "individual",
"firstName": "Post",
"lastName": "Man",
"email": "postman@gmail.com",
"dateOfBirth": "1997-02-17",
"address": {
"addressLine1": "Example St 1.",
"addressLine2": "Apt 123",
"city": "Hoboken",
"stateProvinceRegion": "NJ",
"postalCode": "07030",
"country": "USA"
},
"signedAgreementId": "8cb49537-bcf9-41b1-8d8c-c9c200d7341b"
}'
Response:
{
"id": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"type": "individual",
"email": "postman@gmail.com",
"name": "Post Man",
"wallets": {
"INDIVIDUAL": {
"POLYGON_AMOY": {
"address": "0xa99F0308604Af7526Bb69FD0F292993B948161b5"
}
}
}
}
Let's take a moment to understand the response:
- The
id
is the user ID, which should be saved for future API calls for this particular user. - The
wallets
object contains all the wallet types and addresses provisioned for the user.
We have successfully created a user with the user id: f4fd2f10-2577-45cc-9e06-07ac9a74eb51
.
KYC
After successfully creating a user, the user needs to decide which rails to unlock and submit KYC to enable access to those rails. We currently support the following rails:
- USD_EURO: Onramp and offramp services for USD and EURO.
- SOUTH_AMERICA_LIGHT: Offramp services for the South American region, including BRL, MXN, COP, and ARS, with a lower transaction limit.
- SOUTH_AMERICA_STANDARD: Offramp services for the South American region, including BRL, MXN, COP, and ARS, with a higher transaction limit.
To read more about the rails we support, click here.
To read more about KYC in detail, click here.
All rails can be unlocked through our KYC endpoints. To unlock, for example, the USD_EURO rail, follow these steps:
- Gather the required KYC information for the USD_EURO rail by either consulting our KYC documentation or using the Retrieve KYC Requirements endpoint.
- Update the user's KYC information using the Update KYC Information endpoint.
- Submit the user's KYC information through the Submit KYC endpoint to unlock the rail.
- Check the user's KYC status for the USD_EURO rail via the Retrieve KYC Status endpoint.
Let's go through each of these steps in detail to unlock the USD_EURO rail.
Retrieve KYC Requirements
The Retrieve KYC Requirements endpoint provides the required and optional KYC fields needed to unlock a specific rail, as well as any invalid or missing KYC information the user currently holds, assuming they intend to submit KYC for this rail. This information helps identify what needs to be updated via the Update KYC endpoint before submitting KYC for the rail. By using this helper endpoint, you can programmatically retrieve details that are also available in our KYC documentation.
Let's get the KYC requirements for USD_EURO rails by calling the Retrieve KYC Requirements endpoint and passing in USD_EURO as the rails and the userId.
Request:
curl --request GET \
--url 'https://sandbox.hifibridge.com/v2/users/f4fd2f10-2577-45cc-9e06-07ac9a74eb51/kyc/requirements?rails=USD_EURO' \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456'
Response:
{
"userId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"rails": "USD_EURO",
"type": "individual",
"required": {
"firstName": "string",
"lastName": "string",
"email": "string",
"phone": "string",
"address": {
"required": {
"addressLine1": "string",
"city": "string",
"stateProvinceRegion": "string",
"postalCode": "string",
"country": "string"
},
"optional": {
"addressLine2": "string"
}
},
"dateOfBirth": "date",
"taxIdentificationNumber": "string",
"govIdType": "string",
"govIdFrontUrl": "string",
"govIdBackUrl": "string",
"govIdCountry": "string",
"proofOfAddressType": "string",
"proofOfAddressUrl": "string"
},
"optional": {
"sofEuQuestionnaire": {
"required": {
"actingAsIntermediary": "boolean",
"employmentStatus": "string",
"expectedMonthlyPayments": "string",
"mostRecentOccupation": "string",
"primaryPurpose": "string",
"sourceOfFunds": "string"
},
"optional": {
"primaryPurposeOther": "string"
}
}
},
"invalidKycFields": {
"message": "fields are either missing or invalid",
"fields": {
"email": "missing",
"phone": "missing",
"taxIdentificationNumber": "missing",
"govIdType": "missing",
"govIdFrontUrl": "missing",
"govIdBackUrl": "missing",
"govIdCountry": "missing",
"proofOfAddressType": "missing",
"proofOfAddressUrl": "missing"
}
}
}
Let's take a moment to understand the response:
- The
required
fields represents all the mandatory KYC information needed for the USD_EURO rails KYC application. - The
optional
fields represents all the additional KYC information that is not mandatory but may be provided for the USD_EURO rails KYC application. - The
invalidKycFields
represent any fields that must be corrected before the KYC application can proceed for the USD_EURO rail. From the response, we can see that the user still have multiple missing KYC fields that needs to be provided before they can submit their KYC application for the rail.
Now that we know the missing KYC fields the user needs to provide for the rail, we can proceed with updating the user's KYC information to address these gaps.
Update KYC
To update the user's KYC information, you can use the Update KYC endpoint.
Let's update the user's KYC information. We have provided all the needed KYC fields with dummy values in the curl request.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/users/f4fd2f10-2577-45cc-9e06-07ac9a74eb51/kyc \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"firstName": "Post",
"lastName": "Man",
"dateOfBirth": "1998-03-22",
"email": "postman@hifibridge.com",
"phone": "+1234567890",
"address": {
"addressLine1": "Example St 1.",
"addressLine2": "Apt 123",
"city": "Hoboken",
"stateProvinceRegion": "NJ",
"postalCode": "07030",
"country": "USA"
},
"taxIdentificationNumber": "123456789",
"govIdType": "PASSPORT",
"govIdFrontUrl": "https://picsum.photos/1000/1000",
"govIdBackUrl": "https://picsum.photos/1000/1000",
"govIdCountry": "USA",
"proofOfAddressType": "UTILITY_BILL",
"proofOfAddressUrl": "https://picsum.photos/1000/1000",
"ipAddress": "108.28.159.21"
}'
Response:
{
"userId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"kycInfo": {
"type": "individual",
"firstName": "Post",
"lastName": "Man",
"email": "postman@hifibridge.com",
"phone": "+1234567890",
"address": {
"city": "Hoboken",
"country": "USA",
"postalCode": "07030",
"addressLine1": "Example St 1.",
"addressLine2": "Apt 123",
"stateProvinceRegion": "NJ"
},
"dateOfBirth": "1998-03-22T00:00:00+00:00",
"taxIdentificationNumber": "123456789",
"govIdCountry": "USA",
"govIdType": "PASSPORT",
"govIdFrontUrl": "https://picsum.photos/1000/1000",
"govIdBackUrl": "https://picsum.photos/1000/1000",
"proofOfAddressUrl": "https://picsum.photos/1000/1000",
"proofOfAddressType": "UTILITY_BILL",
"ipAddress": "108.28.159.21",
"sofEuQuestionnaire": null
}
}
The response contains the latest KYC information the user holds after the update. This same set of information can also be retrieved using the Retrieve KYC information endpoint.
We have successfully updated the user's KYC information and can now proceed with submitting the KYC application to unlock the USD_EURO rails.
Submit KYC
To submit the KYC information the user currently holds for the USD_EURO rails, we can use the Submit KYC endpoint.
The Submit KYC endpoint submits the existing KYC information stored for the user to the specified rail. If you want to submit any new KYC data that the user doesn't currently hold, you must first update the user's KYC information using the Update KYC endpoint before calling Submit KYC.
Let's submit the user's KYC information to unlock the USD_EURO rails. This can be done by calling the Submit KYC endpoint and providing the userId
and the rails
.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/users/f4fd2f10-2577-45cc-9e06-07ac9a74eb51/kyc/submissions \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '{"rails":"USD_EURO"}'
Response:
{
"USD_EURO": {
"status": "PENDING",
"warnings": [],
"message": "",
"onRamp": {
"usd": {
"achPush": {
"status": "PENDING",
"warnings": [],
"message": ""
},
"achPull": {
"status": "PENDING",
"warnings": [],
"message": ""
}
},
"euro": {
"sepa": {
"status": "INACTIVE",
"warnings": [],
"message": "SEPA onRamp will be available in near future"
}
}
},
"offRamp": {
"usd": {
"ach": {
"status": "PENDING",
"warnings": [],
"message": ""
}
},
"euro": {
"sepa": {
"status": "PENDING",
"warnings": [],
"message": ""
}
}
}
}
}
The returned object includes the overall KYC status for the user's USD_EURO rail and granular statuses for each individual rail. After submission, the KYC status will initially be set to "PENDING"
. The user can either call the Retrieve KYC Status endpoint or wait for webhook events to receive updates on the user's latest KYC status for that rail.
Retrieve KYC Status
To get the KYC status for a specific rails, the user can call the Retrieve KYC Status endpoint.
Let's Get the KYC status for the user's USD_EURO rail by passing in the userId
and the rails
in the query param.
Request:
curl --request GET \
--url 'https://sandbox.hifibridge.com/v2/users/f4fd2f10-2577-45cc-9e06-07ac9a74eb51/kyc/status?rails=USD_EURO' \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456'
Response:
{
"status": "ACTIVE",
"warnings": [],
"message": "",
"onRamp": {
"usd": {
"achPush": {
"status": "ACTIVE",
"warnings": [],
"message": ""
},
"achPull": {
"status": "ACTIVE",
"warnings": [],
"message": ""
}
},
"euro": {
"sepa": {
"status": "INACTIVE",
"warnings": [],
"message": "SEPA onRamp will be available in near future"
}
}
},
"offRamp": {
"usd": {
"ach": {
"status": "ACTIVE",
"warnings": [],
"message": ""
}
},
"euro": {
"sepa": {
"status": "ACTIVE",
"warnings": [],
"message": ""
}
}
}
}
The returned object will contain the user's latest KYC status for the USD_EURO rail, which will be "ACTIVE"
if KYC is approved. In the sandbox environment, KYC approval should occur automatically.
Account
After creating a user who has passed KYC, you can add onramp or offramp accounts for them to enable onramp or offramp transfers. The USD_EURO rail supports services for both onramp and offramp.
- Onramp account: A bank account used as the source for the onramping process. For example, during onramping, fiat currency from the onramp account is converted into stablecoin.
- Offramp account: A bank account used as the destination for the offramping process. For example, during offramping, stablecoin is converted into fiat currency and sent to the offramp account.
We will now add both onramp and offramp accounts for the user.
Add Onramp Account
A Virtual Account is an onramp account created by our system to facilitate onramping. Users can deposit fiat money into the virtual account, and the deposited funds are automatically converted into stablecoin. To create a virtual account for the user, you can call the Create a virtual account endpoint with the user id.
The parameters you pass in will determine the rail you want this onramp virtual account to support. For example, passing the sourceCurrency
as usd
, destinationCurrency
as usdc
, and destinationChain
as POLYGON
, will allow the user to deposit usd
into the virtual bank account to onramp to usdc
on POLYGON
.
Let's make a Create a virtual account call using the user id we created earlier, with the parameters we just mentioned:
Request
curl --request POST \
--url https://sandbox.hifibridge.com/v2/users/f4fd2f10-2577-45cc-9e06-07ac9a74eb51/virtual-accounts \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"sourceCurrency": "usd",
"destinationCurrency": "usdc",
"destinationChain": "POLYGON"
}
'
Response
{
"message": "Virtual account for US_ACH_WIRE created successfully",
"account": {
"virtualAccountId": "a83de52e-7741-442d-8406-f1e65c07fdc6",
"userId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"paymentRails": [
"ach_push",
"wire"
],
"sourceCurrency": "usd",
"destinationChain": "POLYGON_AMOY",
"destinationCurrency": "usdc",
"destinationWalletAddress": "0x3b17b0Cc70116F0aD0c0960FcD628E7ff85cb351",
"railStatus": "activated",
"depositInstructions": {
"bankName": "Bank of Nowhere",
"routingNumber": "101019644",
"accountNumber": "900602808842",
"bankAddress": "1800 North Pole St., Orlando, FL 32801"
}
}
}
Let's take a look at the response, focusing on the virtual account
object:
- The
virtualAccountId
is the unique identifier for the newly created virtual account. This ID should be saved for future retrieval of account information, including deposit instructions and micro-deposit details required by the institution. - The
paymentRails
indicates the payment methods supported by this virtual account. - The
sourceCurrency
,destinationChain
, anddestinationCurrency
together represents the complete onramp rail. In our case, anyusd
deposited into the virtual account will be converted tousdc
and sent todestinationWalletAddress
on thePOLYGON_AMOY
blockchain. - The
railStatus
reflects whether this virtual account is active for onramping. - IMPORTANT: The
depositInstructions
object contains the bank account details that the user needs to deposit fiat into for onramping.
Link Plaid Account for USD Onramp
You can also link a Plaid account to the virtual account for ACH pull by making a Create a Plaid USD onramp account call with a Plaid processor token. For this guide, we've provided you with a Plaid processor token in the request fields. If you'd like to learn how to generate a Plaid processor token, you can follow the Plaid guide.
Please note that linking a Plaid USD account alone will not allow you to onramp, as onramping requires a virtual account. If you've been following this guide and have already made a Create a virtual account call earlier, then a virtual account has already been created for you. If you don't have a virtual account yet, please go to the previous step and create a virtual account first.
In essence, linking a plaid account for USD onramp allows you to ACH pull funds from the user's Plaid bank account whenever they want to onramp, eliminating the need for manual deposits into the virtual account.
Now, let's call the Create a Plaid USD onramp account endpoint using the user ID we created earlier to link a Plaid account:
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/users/f4fd2f10-2577-45cc-9e06-07ac9a74eb51/accounts \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"rail": "onramp",
"type": "plaid",
"plaid": {
"accountType": "checking",
"plaidProcessorToken": "processor-sandbox-f47b37c9-e416-48ae-b0df-8e22a6d5bc00",
"bankName": "Bank of America"
}
}
'
Response:
{
"status": "ACTIVE",
"invalidFields": [],
"message": "Bank account added successfully",
"id": "8ff3c91f-54e9-45ea-939b-23523ecc4ae4"
}
The id
returned in the response object is the unique identifier for the linked Plaid account for USD onramp. This ID should be saved for future use whenever you want to initiate an onramp through an ACH pull from the Plaid account.
Add Offramp Account
To offramp, you can add a USD offramp bank account by making an Create a USD Offramp Bank Account (ACH) call or an Create a USD Offramp Bank Account (Wire) call, depending on whether you want to offramp via ACH or WIRE transfer.
Let's add a USD offramp bank account for ACH. To do this, you'll need to provide your bank account details. However, for the purpose of this guide, we've pre-configured the bank account details for you, so all you need to do is call the Create a USD Offramp Bank Account (ACH) endpoint:
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/users/userId/accounts \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"rail": "offramp",
"type": "us",
"accountHolder": {
"type": "individual",
"address": {
"addressLine1": "123 Main St.",
"city": "New York",
"stateProvinceRegion": "NY",
"postalCode": "10001",
"country": "USA"
},
"name": "Post Man",
"email": "postman@hifibridge.com",
"phone": "+18572719334"
},
"us": {
"transferType": "ach",
"currency": "usd",
"accountNumber": "483102217874",
"routingNumber": "021000322",
"bankName": "Chase"
}
}
'
Response:
{
"status": "ACTIVE",
"invalidFields": [],
"message": "Account created successfully",
"id": "583eb259-e78b-4f0c-a4b5-a8957876fa6f"
}
The id
returned in the response object is the unique identifier for the USD offramp bank account (ACH). This ID should be saved for future use whenever you want to initiate an offramp through an ACH push.
Transfer
After creating both onramp and offramp accounts, the user can now perform three types of transfers/conversions:
- Onramp Fiat to Stablecoin: Convert fiat currency from an onramp bank account to stablecoin.
- Stablecoin Transfer: Transfer stablecoin between users or wallet addresses.
- Offramp Stablecoin to Fiat: Convert stablecoin to fiat currency and send it to an offramp bank account.
In this section of the quick start guide, we will walk through the entire transfer flow from onramp to offramp between two users. The first user (User A) will be the user we just created, and the second user (User B) will be an existing user we've provided for the purpose of this guide.
Here's how the entire transfer flow will look like in three steps:
- Onramp $1 USD from User A's Plaid bank account to User A's wallet as 1 USDC.
- Transfer the 1 USDC from User A's wallet to User B's wallet.
- Offramp User B's 1 USDC to User B's bank account as $1 USD.
Please note that in the sandbox environment, no real money movement occurs, so the onramping and offramping won't actually process real funds. However, all the request and response examples will provide a clear overview of how the transfer occurs.
Onramp $1 USD to 1 USDC
To onramp fiat to stable coin, you will make a Create an onramp call.
Let's take a look at the request fields:
- The
requestId
is a unique identifier for the onramp request, ensuring that a request is processed only once to prevent duplicates. - The
source.userId
represents the user from whom we are onramping, and thesource.accountId
is the onramp account owned bysource.userId
. In our case,source.userId
will be User A, and thesource.accountId
is the Plaid USD onramp account id that we obtained earlier. - The
destination.userId
represents the user who is receiving the onramped stablecoin. In our case, this will be User B's user id. - The
source.amount
,source.currency
,destination.currency
, anddestination.chain
specify that we are onramping $1usd
tousdc
on thePOLYGON
blockchain.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/onramps \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"source": {
"currency": "usd",
"userId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"accountId": "8ff3c91f-54e9-45ea-939b-23523ecc4ae4",
"amount": 1
},
"destination": {
"currency": "usdc",
"chain": "POLYGON",
"userId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51"
},
"requestId": "10ab138d-0377-4deb-bb03-32829560ccc5"
}
'
Response:
{
"transferType": "FIAT_TO_CRYPTO",
"transferDetails": {
"id": "2ec9f234-2e29-4d46-8592-9614624b531e",
"requestId": "10ab138d-0377-4deb-bb03-32829560ccc5",
"sourceUserId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"destinationUserId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"transactionHash": null,
"chain": "POLYGON_AMOY",
"sourceCurrency": "usd",
"amount": 1,
"destinationCurrency": "usdc",
"sourceAccountId": "8ff3c91f-54e9-45ea-939b-23523ecc4ae4",
"createdAt": "2024-11-25T20:48:10.716761+00:00",
"updatedAt": "2024-11-25T20:48:14.136+00:00",
"status": "CONFIRMED",
"sourceUser": {
"email": "postman@hifibridge.com",
"lastName": "Man",
"firstName": "Post",
"businessName": null
},
"destinationUser": {
"email": "postman@hifibridge.com",
"lastName": "Man",
"firstName": "Post",
"businessName": null
},
"sourceAccount": {
"id": "8ff3c91f-54e9-45ea-939b-23523ecc4ae4",
"accountNumber": "0000",
"routingNumber": "011401533",
"bankName": "Bank of America"
},
"fee": null,
"failedReason": null
}
}
Let's take a look at the response object, focusing on the transferDetails
object:
- The
id
is a unique identifier for this transfer, which you can save to get the most up-to-date transfer status through the Retrieve an onramp endpoint. - The
status
represents the transfer status, which will be"CONFIRMED"
automatically in sandbox environment. In production, you will want to either register a webhook or poll the Retrieve an onramp endpoint to monitor the status until the transfer is"CONFIRMED"
. To learn more about transfer statuses, click here. - The rest of the fields are the same as the request fields you provided when calling the endpoint.
Transfer 1 USDC Between Wallets
After the onramp transfer is confirmed, User A will have 1 USDC in their wallet. Now we can transfer the 1 USDC from User A's wallet to User B's wallet. To do this, we can call the Create a crypto transfer endpoint.
Let's take a look at the request fields:
- The
requestId
is a unique identifier for the transfer request, ensuring that a request is processed only once to prevent duplicates. - The
source.userId
represents the user who wants to send the stablecoin. In our case, this is User A's user id. - The
destination.userId
represents the user who will receive the stablecoin. In our case, this is User B's user id. - The
chain
,currency
, andamount
fields indicate that we are sending 1usdc
on thePOLYGON
blockchain.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/wallets/transfers \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"source": {
"userId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51"
},
"destination": {
"userId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87"
},
"requestId": "a40ea2aa-7937-4be9-bb1f-b75f1489bcc6",
"amount": 1,
"currency": "usdc",
"chain": "POLYGON"
}
'
Response:
{
"transferType": "CRYPTO_TO_CRYPTO",
"transferDetails": {
"id": "c4bd341c-ac41-4aec-9987-db46ec06e225",
"requestId": "a40ea2aa-7937-4be9-bb1f-b75f1489bcc6",
"senderUserId": "f4fd2f10-2577-45cc-9e06-07ac9a74eb51",
"recipientUserId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87",
"recipientAddress": "0xa99F0308604Af7526Bb69FD0F292993B948161b5",
"chain": "POLYGON_AMOY",
"currency": "usdc",
"amount": 1,
"amountIncludeDeveloperFee": 1,
"transactionHash": null,
"createdAt": "2024-11-25T20:49:51.614744+00:00",
"updatedAt": "2024-11-25T20:49:51.614744+00:00",
"status": "CREATED",
"contractAddress": "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582",
"failedReason": null,
"recipient": {
"email": "someone@hifibridge.com",
"lastName": "One",
"firstName": "Some",
"businessName": null
},
"sender": {
"email": "postman@hifibridge.com",
"lastName": "Man",
"firstName": "Post",
"businessName": null
},
"fee": null
}
}
Let's take a look at the response object, focusing on the transferDetails
object:
- The
id
is a unique identifier for this transfer, which you can save to get the most up-to-date transfer status using the Retrieve a crypto transfer endpoint. - The
status
represents the transfer status, which initially appears as"CREATED"
. You will want to either register a webhook or poll the Retrieve a crypto transfer endpoint to monitor the latest transfer status until the transfer is"CONFIRMED"
. - The
transactionHash
is the transaction hash on the blockchain, which you can use to check the transaction status online with a blockchain explorer. - The
contractAddress
represents the smart contract address that facilitates the stablecoin transfer between wallets. - The
failedReason
will show the reason if the transfer fails. - The
sender
andrecipient
objects provide detailed information about the sender and recipient users. - The rest of the fields are the same as the request fields you provided when calling the endpoint.
Offramp 1 USDC to $ 1 USD
After transferring 1 USDC from User A's wallet to User B's wallet, we can offramp the 1 USDC to User B's offramp bank account. To do this, we can call the Create an offramp endpoint.
Let's take a look at the request fields:
- The
requestId
is a unique identifier for the transfer request, ensuring that a request is processed only once to prevent duplicates. - The
source.userId
represents the user from whom we want to offramp. In our case, this is User B's user id. - The
destination.userId
represents the user receiving the offramp funds, and thedestination.accountId
is the receiving offramp account owned bydestination.userId
. In our case, thedestination.userId
will be User B's user id, and thedestination.accountId
will be User B's USD offramp account id. - The
chain
,source.currency
,destination.currency
, andsource.amount
fields indicate that we are converting 1usdc
on thePOLYGON
blockchain tousd
and sending thatusd
todestination.accountId
.
Request:
curl --request POST \
--url https://sandbox.hifibridge.com/v2/offramps \
--header 'accept: application/json' \
--header 'authorization: Bearer zpka_123456' \
--header 'content-type: application/json' \
--data '
{
"source": {
"currency": "usdc",
"chain": "POLYGON",
"userId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87",
"amount": 1
},
"destination": {
"currency": "usd",
"accountId": "c4eb5722-c25f-4d6e-a3b7-85207ad8461c",
"userId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87",
},
"requestId": "b08e27be-c086-4b84-a321-307ed9f265e1"
}
'
Response:
{
"transferType": "CRYPTO_TO_FIAT",
"transferDetails": {
"id": "36d00eb0-8fd4-4f7a-baab-3cf8b42687d8",
"requestId": "b08e27be-c086-4b84-a321-307ed9f265e1",
"sourceUserId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87",
"destinationUserId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87",
"chain": "POLYGON_AMOY",
"sourceCurrency": "usdc",
"amount": 1,
"amountIncludeDeveloperFee": 1,
"destinationCurrency": "usd",
"liquidationAddress": null,
"destinationAccountId": "c4eb5722-c25f-4d6e-a3b7-85207ad8461c",
"transactionHash": null,
"createdAt": "2024-11-25T20:50:50.473353+00:00",
"updatedAt": "2024-11-25T20:50:51.462+00:00",
"status": "CREATED",
"contractAddress": "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582",
"sourceUser": {
"email": "someone@hifibridge.com",
"lastName": "One",
"firstName": "Some",
"businessName": null
},
"destinationUser": {
"email": "someone@hifibridge.com",
"lastName": "One",
"firstName": "Some",
"businessName": null
},
"destinationAccount": {
"id": "c4eb5722-c25f-4d6e-a3b7-85207ad8461c",
"accountOwnerName": "Some One",
"bankName": "Chase",
"accountNumber": "483101817824",
"routingNumber": "021000021",
"accountType": "us",
"businessIdentifierCode": null,
"bankCountry": null,
"iban": null,
"beneficiaryFirstName": "Henry",
"beneficiaryLastName": "Wu"
},
"failedReason": null,
"fee": null,
"conversionRate": {
"validFrom": "2024-11-25T20:50:51.459Z",
"toCurrency": "usd",
"validUntil": "2024-11-25T20:51:21.459Z",
"fromCurrency": "usdc",
"conversionRate": 1
}
}
}
Let's take a look at the response object, focusing on the transferDetails
object:
- The
id
is a unique identifier for this transfer, which you can save to get the most up-to-date transfer status using the Retrieve an offramp endpoint. - The
status
represents the transfer status, which initially appears as"CREATED"
. You will want to either register a webhook or poll the Retrieve an offramp endpoint to get the latest transfer status until the transfer is"CONFIRMED"
. - The
liquidationAddress
is a wallet address created by our system to facilitate offramping and is tied todestinationAccountId
. Stablecoins that are sent to this liquidation address will be converted to fiat currency and sent to the corresponding offramp bank account. - The
transactionHash
is the transaction hash on the blockchain, which you can use to check the transaction status online with a blockchain explorer. - The
contractAddress
represent the smart contract address that facilitates the stablecoin transfer between wallets. - The
failedReason
will show the reason if the transfer fails. - The
sourceUser
anddestinationUser
objects provide detail information about the sender and recipient users. - The
destinationAccount
object provides detailed information about the offramp bank account. - The
conversionRate
object provides the conversion rate information between the source and destination currencies. - The rest of the fields are the same as the request fields you provided when calling the endpoint.
Congratulations 🎉! You've successfully navigated several key processes, including creating a user, submitting KYC to unlock rails, adding onramp/offramp accounts, and transferring funds between users. We hope this guide has provided you with a solid understanding of how to utilize HIFI's API endpoints to manage digital currency transfers seamlessly. If you have any further questions or need additional support, please refer to our documentation or contact our support team. Happy coding!
Updated about 1 month ago