Merchant API

Take the Xend Finance services to your customers via a RESTful API and webhooks.

Who is a merchant

A merchant is a registered business that performs savings operations on behalf of their customers. Basically, your account is referred to as a merchant account and you can create your customers’ accounts as sub accounts. Each sub account has access to a personal wallet address and you can perform transactions (transfer, deposit, save, withdraw, and more) on each account.

What is this?

This API is intended for Finance Applications that wish to leverage the Xend Finance savings service and offer it to their end users. You can, via the API, create an account for each of your customers and manage their accounts just the same way a normal user would inside the Xend Finance mobile application to save, earn interest, transfer money, and much more.

Link to Merchant Swagger doc: https://apiprostaging.xend.finance/swagger/merchant/index.html/ Sample nodeJs application: https://github.com/xendfinance/merchant-api-sample

Becoming a merchant

Staging/sandbox environment

  1. Create a merchant account for the sandbox environment by calling the merchant auth endpoint /public/create/sandbox/account with the required email and password. Please check out the swagger documentation for more clarity on the API endpoint.

Production environment

The steps below are for setting up a merchant account in a production environment.

  1. Download the Xend Finance Mobile app.

  2. Register and verify your account using the mobile app with your company email address.

  3. Follow the steps in the mobile app and complete your user profile.

  4. Next, on the mobile app, proceed to the profile section. Then, under Account Security, enable your 2-Factor Authentication.

  5. Next, complete the KYC Verification still in the profile section of the mobile app using CEO profile.

  6. Complete the KYB and business documentation: A link will be provided where you complete our KYB process by uploading your business profile and documents. Ref: https://xend.finance/mobileapp.html

  7. Verify all your provided data for accuracy and authenticity

The return data of the /public/create/sandbox/account and /public/register API will have information on apiKey and apiSecret which you will use to access the rest of the API endpoints for merchants. You can keep them in a safe place where you can easily use them for subsequent merchant API calls.

API Access

To access any authenticated endpoints from the Merchant API you have to add the following properties to the request headers.

  1. authentication: JWT key that is returned to you after logging in.

  2. apisignature: Api signature calculation from the data used to make the HTTP request. An example of how it is calculated can be found in the section "API Signature Calculation"

  3. timestamp: this should be the current timestamp in milliseconds UTC

  4. memberemail: email of the sub-user of the merchant's platform.

  5. merchantcode: merchant user id generated after creating your account.

  6. userlanguage: the language that the responses from the API should be. Use the ISO language name as the value of the field.

  7. authorization: serves as the API captcha. For the test environment, the value is Basic parole.

API Signature Calculation

Merchant API endpoints make use of HMAC SHA256 signatures for authenticating API requests. Hash-based message authentication code (HMAC) is used to verify that a request to our endpoint is coming from a trusted source and that the request has not been tampered with on transit from the source of the request to our servers.

The parameters needed to calculate the API signature include timestamp, clientToken, clientSecret, and the payload of the request. All these values are concatenated in URL encoded format and the hash is calculated with the SHA256 hashing algorithm.

// Example code for calculating API signature
import cryptoJS from 'crypto-js';

const timestamp = '';
const token = '';
const accessSecret = '';

const payload = {
  username: 'bob',
  email: 'bobgas@email.com'
};

const signaturePayload = 'username=bob&email=bobgas@email.com';
const signatureText = `${signaturePayload}&timestamp=${timestamp}&api-key=${token}&api-secret=${accessSecret}`;

const signature = cryptojs.HmacSHA256(signatureText, accessSecret).toString(cryptojs.enc.Hex);

HMAC with Postman

Postman has a feature to add a pre-request script for every request it makes. We have an example of the script to calculate the API signature and add it to your request headers. Remember to add the following variables to Postman, hmac, timestamp, token, accessSecret. https://gist.github.com/nCally/508d449fb5ae8bfee62cde290850d112

JSON Response

Every response body is expected to be JSON data but the API gateway could return unrecognized HTML content with Gateway errors when something goes wrong.

{
    "data": {},
    "status": "success",
    "status_code": 200,
    "message": "action completed",
    "error_code": "",
    "action": null,
    "message_language_code": "",
    "error_details": null
}
  • data: the data returned by the response can be user profile and token, for example, in the login endpoint. The data can be an empty object {}, empty array [], or null.

  • status: The action status enum (success, failed). E.g. if login fail, status will be failed status_code: this is the request header status code. A failed request can have any error code based on section 1 A.

  • error_code: Error code based on error documentation, each error for example if during registration we discover a user trying to use a temporary email address, the error code is documented such that even the public can read our error documentation and know what it means. So, invalid email address can be error code 0001. Ref: Error Code Documentation

  • action: this defines an action that could be taken after an error is returned. E.g. load_2fa_login REF: Response Action Documentation. Secondly, it can return the field, causing the error. E.g. if you are doing authentication and providing email and password. The action can be =”password” meaning that the error is caused by param “password”.

  • message: this is the error message that is shown to the user. This can be, e.g., “wrong username and password”. It is returned for every request.

  • response_details: here comes the debug message and log for the developer; this should never be shown to the user, as the developer can easily discover what he is doing wrong here. E.g., if you pass the user phone number as a string instead of number and the API rejects it, the ‘message’ will say: “something is wrong, try again later.”, but the ‘response_details’ will say, “Please phone number must be set as number,”. The response detail actually comes with error logs.

  • message_language_code: every response comes with language code which is the response.message (front-end can use the language code to switch the message shown to the user based on language preference of the user). The API may return only English ‘message’ for the user – with this code corresponding to the language code doc so the code can be used for translation.

  • Translation: for languages, users can pass language code in every request and the API will return the message in their language (see language code documentation). Also, the language code is returned in the response. Front-end can use the language code to make translations on the app. REF: language code doc

Language filter is passed thus:

User.profile.userlanguage = eng (user must have set language in his profile)

Post.Header.userlanguage = eg (Pass language in header in each request to return error messages in that language.) NB: language in header overrides user language in profile.

Request Body and Query

Every POST/PUT/PATCH/DELETE Requests will reject Query Strings.

Pass Query Strings to GET Request only.

Also, POST/PUT/PATCH/DELETE Requests do not want to expect URL params or query strings.

NB: what is query string, query param, body param?

Here: https:website.com/url/{query_param}/?query_string=id

Date in body param must be posted in this format: eg expiry_time: "2022-04-09 06:05:05"

Limits and quotas on API requests

  • 50,000 requests per project per day, which can be increased

  • 10 queries per second (QPS) per IP address. (And 100 requests per 100 seconds per member) — when your request limit is reached, header status can be 503

API request is limited/hr you are advised to manage how you query the API to avoid exhausting the limits.

Response header status

The response header status codes are described in the table below.

Pagination

Every endpoint with pagination will have data, thus:

DATA."itemsList[]"
// Here, array of the items returned and their content field are self-explanatory
 DATA."paginator": {
        "itemCount": 9,
        "perPage": 2,
        "pageCount": 5,
        "currentPage": 1,
        "pagingCounter": 1,
        "hasPrevPage": false,
        "hasNextPage": true,
        "prev": null,
        "next": 2
      }
 // Here, 
 // itemCount = total number of items. Others are self-explanatory.
 // prev = previous page number

Switching page in pagination

Set query params:

  1. pageId | INT (the page you wish to load: default is 1)

  2. perPage | INT (number of items you want to return on each page.. Default is 18, or 20)

  3. sort | String (ENUM >> desc,asc) (sort order for the items) default = desc

NB: Please check swagger swagger/doc/index.html/#/APP_INFO for sample pagination data (GET/info/app/pagination/sample THANKS)

Auto Save (Flexible & Fixed)

Auto save means the user sets his auto save configuration such that once funds enter the wallet we can auto save it to the savings plan either flexible or fixed.

NB: auto fixed savings overrides flexibles savings (should the user enable both on any wallet)

Globally, we can enable or disable auto saving in the entire system.

On each Currency we can enable / disable auto save too.

How autosave works

User sets auto save config in his wallets. Any time the fund enters the user wallet we create a job to auto save the fund in 12 hrs. If in 12 hrs time we try to auto save the fund and the fund is no longer there, we drop the job process. *Fixed savings require the user to select the savings profile that the auto save will top up the fund or leave it empty for a new one to be created.

*users are not allowed to select fixed saving profile yet

Auto save config settings

Call back & Webhooks

Edit profile and set your webhook URL. We enable only one URL with module filters. What we offer here is an Unauthenticated POST RESTful webhook over HTTPS only.

NB: callbacks are not guaranteed.

Webhook parameters

WhatsApp Integration Community

Join now! You can get instant answers and also get a test BUSD on SANDBOX. https://chat.whatsapp.com/KH7sK3082GP4igCqySC81F

Notes

  1. The database time zone is UTC.

  2. Here's the link to the swagger documentation.

  3. A sample node.js app of the Merchant API integration.

Last updated