Embedded Brokerage (Open Loop)

This guide will walk you through using these APIs to deploy an embedded wallet and trading solution. Using these APIs, you can enable your users to trade, deposit and withdraw tokens.

This walkthrough makes two assumptions:



  1. User trades will be pre-funded, i.e. users will not be maintaining individual fiat balances with Fuze. Instead, the bank or fintech will prefund Fuze directly, and they will settle with their users separately.
  2. Fuze will onboard customers via a KYC reliance model - where Fuze can rely on the KYC data collected and verified by the partner at the time of onboarding.

Other variations of the above assumptions are possible. Feel free to reach out to us.

User Onboarding

Based on the jurisdiction, Fuze requires varying levels of User KYC data in order to create an account. This entire process can be performed via APIs.

User Consent

As a partner, you will have to ensure that the User is shown T&Cs, that include consent to transfer KYC data to Fuze. The User must agree to this on your app or website, before any data is transferred to Fuze via APIs.

Create User on Fuze

Once consent has been taken, you can now create a User on Fuze using this API. Every request will consist the following sets data:

orgUserId: All transactions on Fuze are associated with an orgUserId. This can be any string that uniquely identifies your Users within your systems. Ideally this is a UUID, with no PII. A ledger for every orgUserId is maintained by Fuze, and the balances can be queried at any point.

kyc and tnc: true indicate that you have verified the User’s KYC information, and that the User has agreed to T&Cs (consent to transfer data to Fuze).

kycData: This will be all the KYC data fields of a User. Keep in mind that the list given in the example below is exhaustive. Actual KYC data differs from case to case, and will be based on mutual agreement with Compliance Teams.

In case any of the required fields are absent, Fuze will respond indicating exactly which fields are missing. As mentioned above, whether a given field is mandatory or not will change based on the jurisdiction, and mutual agreement with the compliance teams.

If all the required fields are present, Fuze will respond showing that the User has been created, and that the User is in PENDING state. PENDING indicates that there KYC documents that Fuze should be sent, which we will cover next.

KYC Document Upload

You can now transfer the documents to Fuze using this API. Usually, this would mean a copy of the National ID or a Passport. Other documents can include liveliness check proofs and more. The exact documents required will be configured based on agreement between compliance teams.

To upload a document, you will need to generate an upload link. This is presigned link to object storage to which you can upload your file.

A valid response will contain a url to which you can upload the file.

EDD Documents

In case a particular customer is categorized as high risk, we expect additional documents to be uploaded and EDD conducted. The process is similar to the above, with the only difference being the docCategory and docSubCategory fields.

For example if there are two documents for EDD - a screening result and adverse media search result - then you would need to call the get-upload-link API twice, once for each document.

The actual EDD docs to be transferred will be agreed upon between respective compliance teams. The above docs mentioned are examples.

Once both documents have been uploaded, you will have to inform Fuze that the EDD process is complete. This can be done by calling this API

User Active Callback

Once all files are uploaded, you will receive a webhook indicating that the status of the User has changed to ACTIVE. The webhook will look as follows:

{
  "event": {
    "orgId": 10,
    "entity": "Users",
    "numRetries": 0,
    "updatedAt": "2023-12-14T12:35:02.894Z",
    "createdAt": "2023-12-14T12:35:02.894Z"
  },
  "data": {
    "orgUserId": "barbara_allen",
    "orgId": 10,
    "kyc": true,
    "tnc": true,
    "userStatus": "ACTIVE",
    "userType": "CONSUMER"
  }
}

Separately, you can also query the getUser API, which will give you the current status of the User.

In case the User is in PENDING state, the response will also list the documents that are yet to be transferred to Fuze.

Asset Data

Spot Price

Before placing an order, you can fetch the price of the asset using this API endpoint.

A typical response will look like this:

{
    "code": 200,
    "data": {
        "timestamp": 1746181915265,
        "value": 356247.8757763
    },
    "error": null
}

Historical Prices

In case you want to construct charts in your UX, you can fetch Fuze's historical price data using this API endpoint.

Asset Metadata

You can get metadata on assets, which you can use to enrich the embedded app experience. You can see the API here. A sample response looks as follows:

{
  "code": 200,
  "data": {
    "asset": "BTC",
    "chainsAndNetworks": [
      {
        "chain": "BITCOIN",
        "network": "MAINNET"
      }
    ],
    "policies": {
      "NAME": "BTC",
      "ICON": "https://fuze.finance/symbol/btc.jpg",
      "ASSET_ENABLE": false,
      "LOCAL_CURRENCY": "AED",
      "MARKET_CAP": 100000,
      "CURRENT_PRICE": 1000,
      "HIGH_24HR": 1000,
      "LOW_24HR": 1000,
      "PRICE_CHANGE_PERCENT_24H": 10.1
    }
  },
  "error": null
}

Prefunding

Prefunding essentially means that as a partner, you will deposit fiat with Fuze. These funds will be used to fulfil trades by your consumers. This means that Fuze has no visibility into how you get funds from the consumers, and how you settle with them. Keep in mind that this only pertains to fiat. All crypto will be maintained at a consumer level.

To prefund Fuze, you will need to create an Internal User. You can do so by hitting this API:

The internal user is just a user type that is associated with you, and not any end-user.

Buy Orders

In case of a buy order, you need to ensure that sufficient funds are available in the consumer account to fulfil the transaction. You can choose to transfer the exact amount right before the order, by using the Internal Transfer API.

Once the trade is done, any balance, if any, can be transferred back to your internal user account.

Sell Orders

In case of a sell order, the sale amount will be credited to the consumer's account once the transaction is done. You can then hit the internal transfer API again and move the funds back to your internal account.

Placing Orders

Once you've ensured that the user has sufficient balance, you can go ahead and place an order.

Order API

Click here for the API Reference

You can now place orders against the orgUserId.

To place an order, you will need to pass the orgUserId, along with the symbol, quantity and the operation.

orgUserId: The user.
symbol: The currency pair you want to trade. quantity: The amount of tokens (digital asset) to buy or sell. quoteQuantity: The amount of base currency (USD/AED) to buy or sell. operation: BUY or SELL clientOrderId: Optional idempotency key which ensures the same order is not placed twice.

So if you want to buy 0.01 BTC for barbara_allen_2, you pass the request below:


{
    "orgUserId": "barbara_allen_2",
    "symbol": "BTC_USD",
    "operation": "BUY",
    "quantity": 0.01,
    "quoteQuantity": 0.01,
    "clientOrderId": '5468bbb7-5e5f-425c-a6eb-b89e19a0298a',
}

Or you could send an order of quoteQuantity.

{
    "orgUserId": "barbara_allen_2",
    "symbol": "BTC_USD",
    "operation": "BUY",
    "quoteQuantity": 100,
    "clientOrderId": '5468bbb7-5e5f-425c-a6eb-b89e19a0298a',
}

A successful response will contain an id which can be used to query the status of the order later.

{
    "code": 200,
    "data": {
        "id": 107,
        "orgId": 28,
        "orgUserId": "barbara_allen_2",
        "symbol": "BTC_USD",
        "side": "BUY",
        "quantity": 0.01,
        "rejectionReason": null,
        "filled": 0
    },
    "error": null
}

Check Order Status

Orders are almost always instant. Nonetheless, you can set up a web hook that will notify you whether the transaction was successful. We’ve covered more details about our webhooks here .

To check the status of the order, using REST and this API endpoint

{
    "code": 200,
    "data": {
        "id": 107,
        "clientOrderId": "5468bbb7-5e5f-425c-a6eb-b89e19a0298a",
        "orgId": 28,
        "orgUserId": "barbara_allen_2",
        "symbol": "BTC_USD",
        "price": 0,
        "averagePrice": 26749.08,
        "side": "BUY",
        "quantity": 0.01,
        "filled": 0.01,
        "status": "COMPLETED",
        "rejectionReason": null,
        "createdAt": "2023-06-08T07:53:11.688Z",
        "updatedAt": "2023-06-08T07:53:12.658Z"
    },
    "error": null
}

List Orders

You can now fetch the order history of a user by passing the orgUserId on this endpoint

In the response, you will get a list of all orders made by a user. You can use this data to create a transaction history view for your users.

{
    "code": 200,
    "data": [
        {
            "id": 105,
            "orgId": 28,
            "orgUserId": "barbara_allen_2",
            "symbol": "ETH_USD",
            "price": 0,
            "averagePrice": 0,
            "side": "BUY",
            "quantity": 0.01,
            "filled": 0,
            "status": "REJECTED",
            "rejectionReason": "ETH is disabled for trading",
            "createdAt": "2023-06-08T07:51:32.051Z",
            "updatedAt": "2023-06-08T07:51:32.447Z"
        },
        {
            "id": 107,
            "orgId": 28,
            "orgUserId": "barbara_allen_2",
            "symbol": "BTC_USD",
            "price": 0,
            "averagePrice": 26749.08,
            "side": "BUY",
            "quantity": 0.01,
            "filled": 0.01,
            "status": "COMPLETED",
            "rejectionReason": null,
            "createdAt": "2023-06-08T07:53:11.688Z",
            "updatedAt": "2023-06-08T07:53:12.658Z"
        }
    ],
    "error": null
}

Crypto Transfers

This section runs through the entire process of allowing your users to deposit and withdraw tokens. The first concept here is that of a counterparty.

Counter parties

A counter party is an individual or business outside of Fuze, who is either sending funds to a Fuze customer, or receiving funds from one. For regulatory reasons, all counterparty data needs to be stored and screened.

Hence, adding a counterparty is a separate step. In case the wallet belongs to the user themselves, a counter party can be created with the type self.

A counter party only needs to be created once. Once done, there can be one or more wallet addresses mapped to them. We've covered this here in more detail.

Adding a counter party

The first step is to therefore add a counterpart, which can be done using this API

Deposits

Creating a Fuze deposit wallet

When you create a deposit wallet, you need to specify the token and chain. You also need to specify where the funds will be coming from (the counter party). We do this to make Travel Rule enforcement seamless. If not, we'd have to ask on every new wallet seen, which is more disruptive.

For each counterparty, including self, you can create a new deposit address using this API

Think of these deposit address as virtual bank accounts. They finally point to the same underlying balance, but is useful for tracking purposes.

Deposit receipt

Once created, the deposit address can be shared by the user. On receipt of a deposit, webhooks will be triggered so that you can notify the customer. The balances will be updated automatically. Webhook details are covered here.

Withdrawals

Whitelisting an external wallet

Before funds can be withdrawn to any wallet, they first need to be whitelisted on Fuze. The whitelisting process screens the wallet address, and associated with a verified counter party which was added on the previous step. The association is done by passing the counter party id.

  • A wallet can be added for whitelisting using this API
  • Since there's a screening involved, some wallet may take time to get whitelisted. Status updates will be shared via webhooks. Alternatively, you can fetch the status here.

Sending funds out

Funds can be sent out to any external wallet that is whitelisted. Withdrawal processing can take time - depending on the network congestion and other factors.

  • You can trigger a withdrawal using this API
  • Since a withdrawal can take time, status updates will be shared via webhooks. Alternatively, you can check the status of a withdrawal using this API