Merchant API
Overview
Via merchant API you can fetch individual or a list of pay widget orders associated with your account.
API servers
Environment | Server URL [SERVER_URL] |
---|---|
Sandbox | https://sandbox-api.fonbnk.com |
Production | https://aten.fonbnk-services.com |
Request Authentication
All requests should be signed using a HMAC256 algorithm and provided clientId
and clientSecret
.
How to get the signature of the request?
- Generate a timestamp (Epoch Unix Timestamp) in milliseconds
- Concatenate the timestamp and the endpoint that is called
{timestamp}:{endpoint}
- Decode the base64 encoded clientSecret
- Compute the SHA256 hash of the concatenated string. Use decoded clientSecret as a key. Convert the result to base64
- Add the clientId, signature, and timestamp to HTTP headers
The following pseudocode example demonstrates and explains how to sign a request
timestamp = CurrentTimestamp();
stringToSign = timestamp + ":" + endpoint;
signature = Base64 ( HMAC-SHA256 ( Base64-Decode ( clientSecret ), UTF8 ( concatenatedString ) ) );
Typescript example
import crypto from "crypto";
const generateSignature = ({
clientSecret,
timestamp,
endpoint,
}: {
clientSecret: string;
timestamp: string;
endpoint: string;
}) => {
let hmac = crypto.createHmac("sha256", Buffer.from(clientSecret, "base64"));
let stringToSign = `${timestamp}:${endpoint}`;
hmac.update(stringToSign);
return hmac.digest("base64");
};
Each request should include the following headers
Header | Description | Example |
---|---|---|
x-client-id | clientId which can be found at the merchant dashboard settings page | 645a20cbaf1d31dbd52c0fda |
x-timestamp | A UNIX timestamp you generate before sending a request to us. Please generate this timestamp right before sending a request to us and re-generate it for every request. | 1663240633 |
x-signature | Computed signature using clientSecret provided to you. | Y90dweZduRFNEF8MsmEUExBg8b8ha= |
API Methods
Get a single pay widget order
Returns a single pay widget order by its ID or orderParams query parameter.
Parameters
Parameter | Description |
---|---|
orderId | id of the order which you could receive via a webhook or iframe events |
orderParams | Value which you provided in the orderParams parameter of the pay widget URL |
Request Example
Request URL
[GET] [SERVER_URL]/api/pay-widget-merchant/order?orderId=6495a7427c8d2a730d97dc6b
Endpoint for signature
/api/pay-widget-merchant/order?orderId=6495a7427c8d2a730d97dc6b
Request Headers
x-client-id: 645a20cbaf1d31dbd52c0fda
x-timestamp: 1663240633
x-signature: Y90dweZduRFNEF8MsmEUExBg8b8ha5SLYHz5uoYO8wA=
Response
A successful request will return the following JSON encoded response
const response = {
"_id": "651e764399a4b360c7eb0178",
"walletType": "SOLANA",
"walletAddress": "53L9ahwHcNnD4F11TqNHQgVUa75WgaCL2WGeiKiK2gCc",
"feePercent": 2.5, // total fee percent (fonbnk fee + partner fee)
"fonbnkFeePercent": 1.5,
"partnerFeePercent": 1,
"gasUsdAmount": 0,
"merchantId": "645a20cbaf1d31dbd52c0fda",
"createdAt": "2023-10-05T08:39:31.691Z",
"buySwap": {
"_id": "651e764399a4b360c7eb016d",
"buyerUserPhone": "380962669394",
"sellerUserPhone": "380960000000",
"amount": 210,
"airtimeAmount": 2100,
"status": "seller_confirmed", // possible values: "initiated", "expired", "buyer_confirmed", "buyer_rejected", "seller_confirmation_pending", "seller_confirmation_failed", "seller_confirmed", "seller_rejected"
"provider": "bank_transfer",
"expiresAt": "2023-10-05T09:39:31.492Z",
"createdAt": "2023-10-05T08:39:31.500Z",
"buyerConfirmedAt": "2023-10-05T08:39:37.027Z",
"countryIsoCode": "NG"
},
"withdrawal": {
"_id": "651e7653db37ee6b74883fe1",
"status": "complete", // possible values: "pending", "complete", "failed"
"withdrawAmount": 2, // amount in USD
"cryptoTotalAmount": 2, //amount in crypto
"transactionHash": "F19TfyGxBgebZt4q8h5bgf9Luabpypm3zSSzWR5ZUp8CKGNvL2r58zqGvWXvKftppiWKszV11jNQtsMUoFppmyb"
},
"feeAmount": 0.05, // total fee amount (fonbnk fee + partner fee)
"localCurrencyFeeAmount": 50, // total fee amount in local currency (fonbnk fee + partner fee)
"fonbnkFeeAmount": 0.03,
"localCurrencyFonbnkFeeAmount": 30,
"partnerFeeAmount": 0.02,
"localCurrencyPartnerFeeAmount": 20,
"networkFeeAmount": 0,
"localCurrencyNetworkFeeAmount": 0,
"resumeUrl": "https://pay.fonbnk.com/swap-status?orderId=651e764399a4b360c7eb0178", // URL where user can resume his order, it point either to the transfer instructions page or to the status page
};
Get a list of pay widget orders
Returns a paginated list of pay widget orders. Filters can be applied to the list by providing query parameters.
Parameters
Strategy | Description |
---|---|
cursor | this parameter should be provided in order to get a next page from the pagination, it should be taken from "nextCursor" response value |
limit | (required) number from 1 to 100, describes how many records should be in each pagination page |
walletType | wallet type of orders, possible values: POLYGON, ETHEREUM, STELLAR, AVALANCHE, SOLANA, ALGORAND, TRON, CELO, BASE, OPTIMISM, NEAR, LISK |
walletAddress | address of wallet |
userPhoneNumber | phone number of the client, should include country code |
swapProvider | provider of a swap, possible values: bank_transfer, mpesa, mobile_money, carrier |
buySwapStatus | status of a swap, possible values: initiated, expired, buyer_confirmed, buyer_rejected, seller_confirmation_pending, seller_confirmation_failed, seller_confirmed, seller_rejected |
withdrawalStatus | status of the USDC/cUSD transfer, possible values: pending, failed, complete |
Request
Request URL
[GET] [SERVER_URL]/api/pay-widget-merchant/orders?limit=1&walletType=POLYGON
Endpoint for signature
/api/pay-widget-merchant/orders?limit=1&walletType=POLYGON
Response
A successful request will return the following JSON encoded response
const response = {
list: [
{
"_id": "651e764399a4b360c7eb0178",
"walletType": "SOLANA",
"walletAddress": "53L9ahwHcNnD4F11TqNHQgVUa75WgaCL2WGeiKiK2gCc",
"feePercent": 2.5, // total fee percent (fonbnk fee + partner fee)
"fonbnkFeePercent": 1.5,
"partnerFeePercent": 1,
"merchantId": "645a20cbaf1d31dbd52c0fda",
"createdAt": "2023-10-05T08:39:31.691Z",
"buySwap": {
"_id": "651e764399a4b360c7eb016d",
"buyerUserPhone": "380962669391",
"sellerUserPhone": "380960000000",
"amount": 210,
"airtimeAmount": 2100,
"status": "seller_confirmed", // possible values: "initiated", "expired", "buyer_confirmed", "buyer_rejected", "seller_confirmation_pending", "seller_confirmation_failed", "seller_confirmed", "seller_rejected"
"provider": "bank_transfer",
"expiresAt": "2023-10-05T09:39:31.492Z",
"createdAt": "2023-10-05T08:39:31.500Z",
"buyerConfirmedAt": "2023-10-05T08:39:37.027Z",
"countryIsoCode": "NG"
},
"withdrawal": {
"_id": "651e7653db37ee6b74883fe1",
"status": "complete", // possible values: "pending", "complete", "failed"
"withdrawAmount": 2, // amount in USD
"withdrawCryptoAmount": 2, // amount in crypto
"transactionHash": "F19TfyGxBgebZt4q8h5bgf9Luabpypm3zSSzWR5ZUp8CKGNvL2r58zqGvWXvKftppiWKszV11jNQtsMUoFppmyb"
},
"feeAmount": 0.05, // total fee amount (fonbnk fee + partner fee) in USD
"localCurrencyFeeAmount": 50, // total fee amount in local currency (fonbnk fee + partner fee)
"fonbnkFeeAmount": 0.03, // fonbnk fee amount in USD
"localCurrencyFonbnkFeeAmount": 30,
"partnerFeeAmount": 0.02, // partner fee amount in USD
"localCurrencyPartnerFeeAmount": 20,
"networkFeeAmount": 0, // network fee amount in USD
"localCurrencyNetworkFeeAmount": 0,
"resumeUrl": "https://pay.fonbnk.com/swap-status?orderId=651e764399a4b360c7eb0178", // URL where user can resume his order, it point either to the transfer instructions page or to the status page
},
],
nextCursor: "646c7e3ce2597a00921e2c53", // cursor for the next page, if there is no next page, this value will be null
};
Get expected price
Returns expected price in USDC, cUSD etc. for a given amount of mobile money and vice versa.
Parameters
Parameter | Description |
---|---|
network | network name, possible values: POLYGON, ETHEREUM, STELLAR, AVALANCHE, SOLANA, ALGORAND, TRON, CELO, BASE, OPTIMISM, NEAR, LISK |
asset | USDC, CUSD, USDT, USDC_E. Default is USDC for every network except CELO, for CELO it's CUSD. |
currency | possible values: usdc, local. If usdc is povided, amount of mobile money required to get this USDC/cUSD amount will be calculated. If local is provided, amount of USDC for provided mobile money will be calculated |
amount | amount of mobile money or USDC/cUSD |
country | country iso code, example: KE for Kenya, NG for Nigeria |
provider | funds source provider, possible values: bank_transfer, mpesa, mobile_money, carrier |
carrierId | (optional) carrier id, provide if need to check for a specific carrier |
Request Example
Request URL
[GET] [SERVER_URL]/api/pay-widget-merchant/price?network=SOLANA¤cy=usdc&amount=5&country=NG&provider=bank_transfer
Endpoint for signature
/api/pay-widget-merchant/price?network=SOLANA¤cy=usdc&amount=5&country=NG&provider=bank_transfer
Request Headers
x-client-id: 645a20cbaf1d31dbd52c0fda
x-timestamp: 1663240633
x-signature: Y90dweZduRFNEF8MsmEUExBg8b8ha5SLYHz5uoYO8wA=
Response
A successful request will return the following JSON encoded response
const response = {
"quoteId": "651e764399a4b360c7eb0178", // unique quote id
"localCurrencyAmount": 5120, // amount of localc currency user should pay
"feePercent": 2.5, // total fee percent (fonbnk fee + partner fee)
"fonbnkFeePercent": 1.5,
"partnerFeePercent": 1,
"totalAmount": 5.12, // amount of USD user will receive before fees
"withdrawAmount": 5, // amount of USD user will receive after fees
"feeAmount": 0.12, // total fee amount in USD (fonbnk fee + partner fee)
"localCurrencyFeeAmount": 120, // total fee amount in local currency (fonbnk fee + partner fee)
"fonbnkFeeAmount": 0.07, // fonbnk fee amount in USD
"localCurrencyFonbnkFeeAmount": 70,
"partnerFeeAmount": 0.05, // partner fee amount in USD
"localCurrencyPartnerFeeAmount": 50,
"networkFeeAmount": 0, // network fee amount in USD
"localCurrencyNetworkFeeAmount": 0,
"cryptoTotalAmount": 5.12, // amount of crypto user will receive before fees
"cryptoWithdrawAmount": 5, // amount of crypto user will receive after fees
"cryptoFeeAmount": 0.12, // total fee amount in crypto (fonbnk fee + partner fee)
"cryptoGasAmount": 0, // network fee in crypto
// deprecated fields below, use fields above instead
"usdcTotalAmount": 5.12, // amount of USDC user will receive before fees
"usdcWithdrawAmount": 5, // amount of USDC user will receive after fees
"usdcFeeAmount": 0.12, // fonbnk service fee
"usdcGasAmount": 0, // network fee
}
Get providers list
Returns a list of countries and their supported providers, each provider has a list of supported mobile carriers(if provider requires it)
Parameters
Parameter | Description |
---|---|
includeLimits | Should limitations data be included in the response. Defaults to true. If limitations are not included the request will be much faster |
Request Example
Request URL
[GET] [SERVER_URL]/api/pay-widget-merchant/providers
Endpoint for signature
/api/pay-widget-merchant/providers
Request Headers
x-client-id: 645a20cbaf1d31dbd52c0fda
x-timestamp: 1663240633
x-signature: Y90dweZduRFNEF8MsmEUExBg8b8ha5SLYHz5uoYO8wA=
Response
A successful request will return the following JSON encoded response
enum WalletType {
POLYGON = "POLYGON",
ETHEREUM = "ETHEREUM",
STELLAR = "STELLAR",
AVALANCHE = "AVALANCHE",
SOLANA = "SOLANA",
ALGORAND = "ALGORAND",
TRON = "TRON",
CELO = "CELO",
LISK = "LISK"
}
type ProviderLimitations = {
[key in WalletType]: {
cryptoLimits: {
// usdc limits
min: number;
max: number;
};
fees: {
feePercent: number; // total fee percent (fonbnk fee + partner fee)
fonbnkFeePercent: number,
partnerFeePercent: number,
gasAmount: number; // gas price of selected network
minFee: number; // minimum fee
};
localCurrency?:
| {
type: "open_range";
max: number;
min: number;
step: number; // step size of currency, for example, if step is 5, then amount can be 5, 10, 15 etc.
withCents?: boolean; // can local currency include cents
}
| {
type: "fixed_list";
values: number[]; // list of supported amounts
withCents?: boolean;
};
};
};
type ProvidersResponse = {
countryIsoCode: "NG";
currencyIsoCode: "NGN";
providers: {
name: "bank_transfer" | "mpesa" | "mobile_money" | "carrier";
description: string;
requiresCarrier: boolean;
limits?: ProviderLimitations; //provider limits if carrier is not required
carriers: {
name: string;
id: string;
limits: ProviderLimitations;
}[];
}[];
}[];
Get order limitations
Returns minimum and maximum amount of order in USDC/cUSD and local currency and applied fees
Parameters
Parameter | Description |
---|---|
network | USDC/cUSD network name, possible values: POLYGON, ETHEREUM, STELLAR, AVALANCHE, SOLANA, ALGORAND, TRON, CELO, BASE, OPTIMISM, NEAR, LISK |
asset | USDC, CUSD, USDT, USDC_E. Default is USDC for every network except CELO, for CELO it's CUSD. |
country | country iso code, example: KE for Kenya, NG for Nigeria |
provider | funds source provider, possible values: bank_transfer, mpesa, mobile_money, carrier |
carrierId | (optional) carrier id, provide if need to check for a specific carrier |
Request Example
Request URL
[GET] [SERVER_URL]/api/pay-widget-merchant/limits?network=SOLANA&country=NG&provider=bank_transfer
Endpoint for signature
/api/pay-widget-merchant/limits?network=SOLANA&country=NG&provider=bank_transfer
Request Headers
x-client-id: 645a20cbaf1d31dbd52c0fda
x-timestamp: 1663240633
x-signature: Y90dweZduRFNEF8MsmEUExBg8b8ha5SLYHz5uoYO8wA=
Response
A successful request will return the following JSON encoded response
type Response = {
"cryptoLimits": { // crypto limits
"min": number,
"max": number
},
"fees": {
"feePercent": number, // total fee percent (fonbnk fee + partner fee)
"fonbnkFeePercent": number,
"partnerFeePercent": number,
"gasAmount": number, // gas price of selected network
"minFee": number // minimum fee
},
localCurrency?: // local currency limits
| {
type: 'open_range';
max: number;
min: number;
step: number; // step size of currency, for example, if step is 5, then amount can be 5, 10, 15 etc.
withCents?: boolean; // can local currency include cents
}
| {
type: 'fixed_list';
values: number[]; // list of supported amounts
withCents?: boolean;
}
}
Endpoints data
Order status
Data from get order
and get orders endpoints contains
buySwap.status
and withdrawal.status
fields which represent the status of the order.
buySwap.status
represents the status of the P2P interaction between the cliend and the agent.
withdrawal.status
represents the status of the cryptocurrency transfer from the fonbnk to the client.
buySwap.status
can have the following values:
- initiated - the order was created and the client has not yet confirmed the payment
- expired - the order has expired
- buyer_confirmed - the client has confirmed the payment
- buyer_rejected - the client has rejected the payment
- seller_confirmation_pending - the agent is confirming the payment
- seller_confirmation_failed - error occurred during the agent's confirmation
- seller_confirmed - the agent has confirmed the payment
- seller_rejected - the agent has rejected the payment
withdrawal.status
can have the following values:
- pending - the transfer is pending
- complete - the transfer is complete
- failed - the transfer has failed