Remittances

This guide serves as a walkthrough for Fuze's C2C Remittance solution.

Fuze allows partners to carry out remittance payments worldwide by taking advantage of stablecoins to settle with local payout partners. This means faster payouts, and highly competitive rates.

Buy local currency

Generate quote

To place an order for local currency, you will first need to generate a quote.

POST /api/v1/payment/remittance/quote

Body Parameters

fromCurrency: The currency you are converting from (required)

toCurrency: The local currency you want to buy (required)

quantity: The amount of currency you want to convert (fromCurrency) (required)

orgUserId: This is a static value which will be provided to you by us (required)

The request would be as follows:

{
  fromCurrency: 'AED',
  toCurrency: 'INR',
  quantity: 100,
  orgUserId: 'org-user'
}

In the response, you will get a quote id and an expiry time, as shown below.

{
	code: 200,
	data: {
	  quoteId: 1,
	  fromCurrency: 'AED',
	  toCurrency: 'INR',
	  quantity: 100,
	  price: 20,
	  expiryTime: 1717332855
	},
	error: null
}

Place order

The quote id can then be used to place the order, using the endpoint below.

POST /api/v1/payment/remittance/payment

Body Parameters

quoteId: The quote id that was created in last api (required)

quantity: The quantity of from currency that was used in last api (required)

`orgUserId: This is a static value which will be provided to you by us (required)

The request would be as follows

{
  quoteId: 1,
  quantity: 100,
  orgUserId: 'org-user'
}

A successful response will look as follows

{
	code: 200,
	data: {
	  uuid: '21a0194f-709e-4c62-8590-464ddb9abd8f',
	  fromCurrency: 'AED',
	  toCurrency: 'INR',
	  quantity: 100,
	  status: 'PENDING'
	},
	error: null
}

Fetch order

You can then fetch the status of the order using this API endpoint.

POST /api/v1/payment/remittance/payment/fetch

{
    "uuid": "21a0194f-709e-4c62-8590-464ddb9abd8f"
}

A successful response will look as follows:

{
    "code": 200,
    "data": {
        "uuid": "21a0194f-709e-4c62-8590-464ddb9abd8f",
        "fromCurrency": "AED",
        "toCurrency": "INR",
        "quantity": 100,
        "status": "COMPLETED"
    },
    "error": null
}

In case the order fails, the response will look as follows:

{
    "code": 200,
    "data": {
        "uuid": "21a0194f-709e-4c62-8590-464ddb9abd8f",
        "fromCurrency": "AED",
        "toCurrency": "INR",
        "quantity": 100,
        "status": "REJECTED"
    },
    "error": null
}

Fetch balance

At any given point, you can fetch your current balances using the API below.

GET /api/v1/payment/remittance/org/balance

A successful response will look as follows:

{
    "code": 200,
    "data": {
        "balance": [
            {
                "currency": "INR",
              	"value": 1712.84,
		"creditLimit": 0
            },
            {
                "currency": "USD",
              	"value": 999980,
		"creditLimit": 100000
            }
        ]
    },
    "error": null
}

The value is the total available to use for swaps or payouts. This can include a credit limit given to you. The difference between the value and the credit limit is the excess or deficit.

Verify Beneficiary

You can then verify the beneficiary using this API endpoint.

POST/api/v1/payment/remittance/beneficiary/verify

{
    "receiverClientIdentifier": "RECEIVER_1",
    "currency": "INR",
    "accountType": "BANK",
    "country": "IN",
    "accountData": {
        "accountNumber": "1234567890",
        "ifscCode": "AMDN0000104",
        "name": "Beneficiary Test",
        "bankAccountType": "NRO/SAVINGS"
    }
}

receiverClientIdentifier: The unique identifier for the beneficiary (required)

currency: The local currency of the beneficiary (required)

accountType: Type of payout method. A list of payout methods for each corridor, and respective account data, will shared separately. (required)

country: Country of the beneficiary (required)

accountNumber: Bank account number of the beneficiary (required)

ifscCode: IFSC code of the bank account (required)

name: Full name of the beneficiary (required)

bankAccountType: Type of bank account. 'NRO/SAVINGS' or 'NRE' is supported for India. (optional)

In case a beneficiary verification is completed, the responses will look as follows:

{
    "code": 200,
    "data": {
        "status": "ACTIVE",
        "clientIdentifier": "RECEIVER_1"
    },
    "error": null
}
{
    "code": 200,
    "data": {
        "status": "INACTIVE",
        "clientIdentifier": "RECEIVER_1"
    },
    "error": null
}

Beneficiary verification can result in the following statuses:

ACTIVE - The beneficiary details have been successfully verified and are correct.

INACTIVE - The beneficiary details could not be verified or are incorrect.

If beneficiary verification is not immediately completed, we will return a pending state:

{
    "code": 200,
    "data": {
        "status": "PENDING",
        "clientIdentifier": "RECEIVER_1"
    },
    "error": null
}

** Webhooks will be there as well for any state change **

Creating a Payout

POST/api/v1/payment/remittance/payout/create-with-details

Fuze has a single API which takes the following data:

  • Originator KYC data
  • Beneficiary Payment Instrument Details
  • Payout Amount and associated data

In the example below, it assumes an INR Payout.

{
    "email":"[email protected]",
    "name":"test",
    "address":"1-A, Baker's street",
    "nationality":"INDIAN",
    "idType":"EID",
    "idNumber":"123456",
    "senderClientIdentifier":"SENDER_1",
    "country":"AE",
    "dob":"1990-09-09",
    "clientOrderId":"REMIT_1",
    "amount":100,
    "purpose":"SALARY",
    "account":{
        "receiverClientIdentifier":"RECEIVER_1",
        "currency":"INR",
        "accountType":"BANK",
        "country":"IN",
        "phoneNumber":"+971501234567",
        "address":"Tax Street",
        "dob":"1990-01-15",
        "nationality":"IN",
        "idType":"PASSPORT",
        "idNumber":"AB1234567",
        "accountData":{
            "accountNumber":"1234567890",
            "ifscCode":"AMDN0000104",
            "name":"Test",
            "bankAccountType":"NRO/SAVINGS"
        }
    }
}

For an UPI payout (applicable only in the case of INR) :

{
    "email": "[email protected]",
    "name": "test",
    "address": "1-A, Baker's street",
    "nationality": "INDIAN",
    "idType": "EID",
    "idNumber": "123456",
    "type": "ORIGINATOR",
    "senderClientIdentifier": "SENDER_UPI_20Mar_1",
    "country": "AE",
    "dob": "1990-09-09",
    "clientOrderId": "ORDER_UPI_20Mar_001",
    "amount": 101,
    "purpose": "SALARY",
    "account": {
        "address": "Bangalore, India",
        "idType": "PASSPORT",
        "idNumber": "ABCD1234",
        "nationality": "INDIAN",
        "dob": "1990-09-09",
        "receiverClientIdentifier": "RECEIVER_UPI_20Mar_001",
        "currency": "INR",
        "accountType": "UPI",
        "country": "IN",
        "accountData": {
            "upiId": "test01@oktest",
            "name": "Test",
            "bankAccountType": "NRO/SAVINGS"
        }
    }
}

Body Parameters

name: Full name of the originator (required)

email : Email address of the originator (optional - but either one of email or phone number is mandatory.)

phoneNumber: Phone number of the originator (optional - but either one of email or phone number is mandatory.)

address: Address of the originator (required)

nationality: Nationality of the originator (required)

country: Country where the originator is sending funds from / Country in which Id is issued. Country codes will be 2 alphabets (based on the ISO 3166 standard) (required)

idType: Name of ID, for example “EID” (required)

idNumber: ID number collected (required)

senderClientIdentifier: A unique identifier for the originator passed by you (required)

dob: Date of birth of the originator (required) (format: YYYY-MM-DD)

receiverClientIdentifier: The unique identifier for the beneficiary (required)

currency: The local currency of the beneficiary (required)

accountType: Type of payout method. A list of payout methods for each corridor, and respective account data, will shared separately. (required)

country: Country of the beneficiary (required)

relationship: Relationship between beneficiary and originator. This list can be different for different countries, and will be shared separately. (optional)

clientOrderId: An idempotency key to avoid duplicate requests (required)

amount: The amount of local currency that needs to be sent (required)

purpose: Purpose of transfer from originator to beneficiary (required)

accountData: Account data of the beneficiary. This data is validated by Fuze based on the type passed above. In the example below, the bank details for an Indian account are listed:

accountNumber: Bank account number of the beneficiary (required)

ifscCode: IFSC code of the bank account (required)

upiId : In the case of UPI, the upiId of the beneficiary is required

name: Full name of the beneficiary (required)

bankAccountType: Type of bank account. 'NRO/SAVINGS' or 'NRE' is supported for India. (optional)

phoneNumber: Phone number of the beneficiary (optional)

The response would look as follows:

{
    "code": 200,
    "data": {
        "payoutId": 28863,
        "amount": 10,
        "currency": "INR",
        "payoutStatus": "PENDING",
        "createdAt": "2025-06-26T11:43:11.952Z",
        "paymentReferenceNumber": "",
        "paymentDate": "",
        "clientOrderId": "Sender1",
        "name": "test",
        "email": "[email protected]",
        "senderStatus": "ACTIVE",
        "senderClientIdentifier": "SENDER_1",
        "receiverClientIdentifier": "RECEIVER_1"
    },
    "error": null
}

Error and rejection scenarios

The following error codes will be received if the payout request cannot be placed. In such cases, the status will not move to pending. Instead the response to the request will contain the following error codes. Currency-specific payout failure reasons will be shared separately for each corridor:

code : 400, message : 'amount must not be less than 1'

code : 400, message : 'Invalid currency'

code : 400, message : 'clientOrderId must be shorter than or equal to 128 characters,clientOrderId should not be empty,clientOrderId must be a string'

code : 400, message : 'purpose must be shorter than or equal to 36 characters,purpose should not be empty,purpose must be a string'

code : 400, message : 'Payout already exists'

In case there's a failure thanks to a local payout partner outage, the payout will move to pending state first. So you will receive a webhook with failure reason. In some countries, there can be a variation of a pending state where more data is required for AML reasons, the documentation and process flow for which will be shared separately.

Payout Status

You can then fetch the status of the payout using this API endpoint.

POST/api/v1/payment/remittance/payout/fetch/

{
    "clientOrderId": "Test1"
}

In case a payout is successful, the response will look as below

{
    "code": 200, 
    "data": {
            "status": "COMPLETED",
            "currency": "INR",
            "amountDeducted": -10,
            "amountSent": -10,
            "createdAt": "2025-03-03T11:03:33.879Z",
            "referenceId": "Bank-12345",
            "paymentReferenceNumber": "123456",
            "paymentDate": "2025-03-03T11:03:33.879Z",
            "clientOrderId": 'Test1'
    },
    "error": null
}

Payouts have the following statuses:

COMPLETED - The payout has been successfully processed.

PENDING - The payout is still being processed

FAILED - The payout was rejected by Fuze. For example, if data passed is invalid. Unlike other failure states, this is a synchronous response.

CANCELED - The payout was sent to a downstream payout partner - but it was rejected by them.

REVERSED - The payout was initially marked as successfully processed, but has since been marked as failed.

EXPIRED - The payout was in Pending state for a long time, and has been expired by Fuze.

Webhooks

You can configure webhooks for all of the above status events. Webhook data will match what you'd get if you directly inquire the Payout Status API. Sample webhooks are below.

Pending

{
    "event": {
        "orgId": 12938,
        "entity": "BankTransfers",
        "eventType": "PAYOUT_PROCESSED",
        "numRetries": 0,
        "createdAt": "2025-07-01T06:46:50.330Z",
        "updatedAt": "2025-07-01T06:46:50.330Z"
    },
    "data": {
        "status": "PENDING",
        "currency": "INR",
        "amountDeducted": -10,
        "amountSent": -10,
        "createdAt": "2025-06-30T09:11:23.296Z",
        "referenceId": "BK-2025-06-30-1751274683121-6677915",
        "paymentReferenceNumber": "BK-2025-06-30-1751274683121-6677915",
        "paymentDate": "",
        "clientOrderId": "Test1"
    }
}

Completed

{
    "event": {
        "orgId": 12938,
        "entity": "BankTransfers",
        "eventType": "PAYOUT_PROCESSED",
        "numRetries": 0,
        "createdAt": "2025-07-01T06:46:50.330Z",
        "updatedAt": "2025-07-01T06:46:50.330Z"
    },
    "data": {
        "status": "COMPLETED",
        "currency": "INR",
        "amountDeducted": -10,
        "amountSent": -10,
        "createdAt": "2025-06-30T09:11:23.296Z",
        "referenceId": "BK-2025-06-30-1751274683121-6677915",
        "paymentReferenceNumber": "BK-2025-06-30-1751274683121-6677915",
        "paymentDate": "",
        "clientOrderId": "Test1"
    }
}

Canceled

{
    "event": {
        "orgId": 12938,
        "entity": "BankTransfers",
        "eventType": "PAYOUT_PROCESSED",
        "numRetries": 0,
        "createdAt": "2025-07-01T06:46:50.330Z",
        "updatedAt": "2025-07-01T06:46:50.330Z"
    },
    "data": {
        "status": "CANCELED",
        "currency": "INR",
        "amountDeducted": -10,
        "amountSent": -10,
        "createdAt": "2025-06-30T09:11:23.296Z",
        "referenceId": "BK-2025-06-30-1751274683121-6677915",
        "paymentReferenceNumber": "BK-2025-06-30-1751274683121-6677915",
        "paymentDate": "",
        "clientOrderId": "Test1",
        "reason": "Insufficient balance"
    }
}

Reversed

{
    "event": {
        "orgId": 12938,
        "entity": "BankTransfers",
        "eventType": "PAYOUT_PROCESSED",
        "numRetries": 0,
        "createdAt": "2025-07-01T06:46:50.330Z",
        "updatedAt": "2025-07-01T06:46:50.330Z"
    },
    "data": {
        "status": "REVERSED",
        "currency": "INR",
        "amountDeducted": -10,
        "amountSent": -10,
        "createdAt": "2025-06-30T09:11:23.296Z",
        "referenceId": "BK-2025-06-30-1751274683121-6677915",
        "paymentReferenceNumber": "BK-2025-06-30-1751274683121-6677915",
        "paymentDate": "",
        "clientOrderId": "Test1",
        "reason": "Bank gateway error"
    }
}

The failure reasons mentioned above are generic. They will differ from corridor to corridor, and will be shared by us separately.

📘

FAILED - This will not have a webhook as it is a synchronous response - because the payout was rejected by Fuze.


Error Codes

These error codes are generic in nature, indicating that their occurrence in a production environment reflects an underlying system issue rather than a standard integration error. Should you encounter these errors, please escalate the matter to Fuze immediately to facilitate appropriate debugging and resolution. It is imperative that you refrain from initiating refunds or executing other routine financial operations upon encountering these errors.

Error Codes:

400 - For any other validation errors.

401 - Unauthorized: This is returned when the API key is invalid.

404 - Not Found: This is returned when the requested resource is not found or the endpoint is incorrect.

500 - Internal Server Error: This is returned when there is an issue with the server.


Refunds

When to Refund

Consider a transaction as failed only under these circumstances:

  • If payout creation failed with a 5xx error code, and a subsequent fetch payout request also returned a 404.

  • If on getting a webhook against a clientOrderId, you get the following statuses against the clientOrderId: REVERSED, CANCELED or FAILED.

  • If on fetching transaction status against a clientOrderId, you get the following status against the clientOrderId: REVERSED, CANCELED or FAILED.

Note: If a payout has failed to create, you can either refund or retry, based on your internal workflow.


When to NOT Refund

Refunds must NOT be initiated in any of the following scenarios. These cases do NOT indicate a transaction failure and must be escalated to Fuze immediately.

Fetch Payout / Fetch Transaction Status Errors

If a fetch payout or fetch transaction status request returns any of the following error codes:

404 Not Found 500 Internal Server Error

These responses indicate that the final state of the payout is unknown or still being processed. The transaction must not be treated as failed.

Required action:

  • Escalate the issue to Fuze for investigation
  • Continue polling or wait for a webhook update

Generic Error Codes Without Terminal Status

If any of the following error codes are returned at any stage of the flow, without an explicit terminal status (REVERSED, CANCELLED, FAILED):

400 - For any other validation errors.

401 - Unauthorized: This is returned when the API key is invalid.

404 - Not Found: This is returned when the requested resource is not found or the endpoint is incorrect.

500 - Internal Server Error: This is returned when there is an issue with the server.

These errors represent integration, configuration, or transient system issues, and do not confirm payout failure.