Skip to content

API

Introduction

Welcome to our API documentation! Here, you'll find all the information you need to interact with our payment services. 😃

General Response Structure

All our API responses follow a consistent structure to make things easy and uniform. Here's what you can expect:

  • status: Indicates success (true) or failure (false) of the request.
  • message: A human-readable message explaining the response.
  • data: Contains the details of the response (if any).

Error Responses

When something goes wrong, we'll let you know with an error response. You'll get a status of false, an error code and the message will describe what went wrong.

  • status: Indicates success (true) or failure (false) of the request.
  • message: A human-readable message explaining the response.
  • error_code: An error code in case there is a problem with a payment
  • errors: Field validation errors

API Keys

Make sure to replace sk_test_... with your actual API key. Your API key is your unique identifier, and keep it safe! 🔑

Parameters

When you see :parameter, make sure to replace it with the actual value that you want to pass to the API. For example, :checkout_reference should be replaced with the actual checkout reference.

Example of Invalid API Key Response

If you use an incorrect API key, you'll receive a response like this:

{
    "status": false,
    "message": "Invalid API key"
}

checkouts

What is Checkout?

Checkout is the process by which customers complete their purchase. It involves initializing a payment and redirecting the customer to an authorization URL. 💳

Steps to Accept Payment with the Checkout API

  1. Initialize Checkout: Call the initialization endpoint.
  2. Redirect the Customer: Redirect the customer to the authorization_url returned if the request is successful.

initialize checkout

You can initialize a checkout by making the following request:

POST /v1/payment/checkouts/initialize/
curl --location 'https://api.senfenico.com/v1/payment/checkouts/initialize/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...' \
--data '{
    "email": "customer@mail.com",
    "amount": 600,
    "success_url": "https://example.com/sucess",
    "cancel_url": "https://example.com/cancel"
}'
POST /v1/payment/checkouts/initialize/
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  \"email\": \"customer@mail.com\",\n  \"amount\": 600,\n  \"success_url\": \"https://example.com/sucess\",\n  \"cancel_url\": \"https://example.com/cancel\"\n}");
Request request = new Request.Builder()
.url("https://api.senfenico.com/v1/payment/checkouts/initialize/")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("X-API-KEY", "sk_test_...")
.build();
Response response = client.newCall(request).execute();
POST /v1/payment/checkouts/initialize/
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
    'method': 'POST',
    'hostname': 'api.senfenico.com',
    'path': '/v1/payment/checkouts/initialize/',
    'headers': {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    },
    'maxRedirects': 20
};

var req = https.request(options, function (res) {
    var chunks = [];

    res.on("data", function (chunk) {
        chunks.push(chunk);
    });

    res.on("end", function (chunk) {
        var body = Buffer.concat(chunks);
        console.log(body.toString());
    });

    res.on("error", function (error) {
        console.error(error);
    });
});

var postData = JSON.stringify({
    "email": "customer@mail.com",
    "amount": 600,
    "success_url": "https://example.com/sucess",
    "cancel_url": "https://example.com/cancel"
});

req.write(postData);

req.end();
POST /v1/payment/checkouts/initialize/
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->checkout->initialize([
    'amount' => 1000,
    'success_url' => 'https://yourwebsite.com/success',
    'cancel_url' => 'https://yourwebsite.com/cancel',
]);
POST /v1/payment/checkouts/initialize/
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Checkout.initialize(amount=100, success_url='https://www.website.com/success', cancel_url='http://www.website.com/cancel')
Parameter Type Optional Description
email string Yes Customer's email address
amount int No Amount to charge
success_url string No URL to redirect on success
cancel_url string No URL to redirect if the customer cancels

Sample Response

Checkout initialized
{
    "status": true,
    "message": "Checkout initialized",
    "data": {
        "reference": "chk_de1ca053573c40a29a9fe95e7ad91d7e",
        "authorization_url": "https://api.senfenico.com/v1/checkout_payment/payment_page/chk_de1ca053573c40a29a9fe95e7ad91d7e/",
        "live_mode": false
    }
}
Response Element Type Description
reference string Unique reference for the checkout
authorization_url string URL to redirect the user to proceed with the payment

Note: Redirect the user to authorization_url to proceed with the payment.

fetch checkout

Fetch the details of a specific checkout:

GET /v1/payment/checkouts/:checkout_reference
curl --location 'https://api.senfenico.com/v1/payment/checkouts/{checkout_reference}' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/checkouts/:checkout_reference
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/checkouts/{checkout_reference}")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();

Response response = client.newCall(request).execute();
GET /v1/payment/checkouts/:checkout_reference
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
    'method': 'GET',
    'hostname': 'api.senfenico.com',
    'path': '/v1/payment/checkouts/{checkout_reference}',
    'headers': {
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    },
    'maxRedirects': 20
};

var req = https.request(options, function (res) {
    var chunks = [];

    res.on("data", function (chunk) {
        chunks.push(chunk);
    });

    res.on("end", function (chunk) {
        var body = Buffer.concat(chunks);
        console.log(body.toString());
    });

    res.on("error", function (error) {
        console.error(error);
    });
});

req.end();
GET /v1/payment/checkouts/:checkout_reference
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->checkout->fetch('xxxxxxxx...', []);
GET /v1/payment/checkouts/:checkout_reference
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Checkout.fetch("xxxxxxxx...")

Sample Response

Checkout details retrieved
{
    "status": true,
    "message": "Checkout details retrieved",
    "data": {
        "email": "customer@mail.com",
        "reference": "8872031d-178e-464c-9261-7984f0a313c0",
        "charge_reference": null,
        "amount": 600,
        "success_url": "https://yourwebsite.com/success",
        "cancel_url": "https://yourwebsite.com/cancel",
        "phone": "",
        "provider": "",
        "live_mode": true,
        "created_at": "2023-07-25T19:55:48.223895Z",
        "updated_at": "2023-07-25T19:55:48.223956Z",
        "status": "pending"
    }
}

Checkout Status:

  • pending: Awaiting payment
  • success: Payment successful
  • failed: Payment failed

list checkout

Retrieve a list of checkouts:

GET /v1/payment/checkouts
curl --location 'https://api.senfenico.com/v1/payment/checkouts' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/checkouts
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/checkouts")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/checkouts
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
    'method': 'GET',
    'hostname': 'api.senfenico.com',
    'path': '/v1/payment/checkouts',
    'headers': {
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    },
    'maxRedirects': 20
};

var req = https.request(options, function (res) {
    var chunks = [];

    res.on("data", function (chunk) {
        chunks.push(chunk);
    });

    res.on("end", function (chunk) {
        var body = Buffer.concat(chunks);
        console.log(body.toString());
    });

    res.on("error", function (error) {
        console.error(error);
    });
});

req.end();
GET /v1/payment/checkouts
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->checkout->list([]);
GET /v1/payment/checkouts
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Checkout.list()

Sample Response

{
    "status": true,
    "message": "Checkout list retreived",
    "data": [
        {
            "email": "customer@mail.com",
            "reference": "0ecae2d5-4d8d-47d9-98b2-38826c562c37",
            "charge_reference": "822039fa-9cbc-447b-bd3a-b374e06faa40",
            "amount": 3500,
            "success_url": "https://yourwebsite.com/success",
            "cancel_url": "https://yourwebsite.com/cancel",
            "phone": "77xxxxxx",
            "provider": "orange_bf",
            "live_mode": false,
            "created_at": "2023-07-13T11:36:50.827975Z",
            "updated_at": "2023-07-13T11:41:35.663261Z",
            "status": "pending"
        },
        {
            "email": "customer@mail.com",
            "reference": "e222060a-0f49-4759-a400-c241a88f623c",
            "charge_reference": "734c24d4-a379-47a6-8994-1880a3e63af4",
            "amount": 200,
            "success_url": "https://yourwebsite.com/success",
            "cancel_url": "https://yourwebsite.com/cancel",
            "phone": "71xxxxxx",
            "provider": "moov_bf",
            "live_mode": false,
            "created_at": "2023-07-11T22:34:44.375268Z",
            "updated_at": "2023-07-12T01:34:21.373271Z",
            "status": "success"
        }
    ]
}

charges

Charges are all about handling all the payment steps by yourself. It is suitable for mobile or destop apps as it does not require redirection. Here’s how you can accept a payment with the charges endpoints:

  1. Create a Charge: Define the charge details.
  2. Customer Action: The customer MAY have to enter a USSD code to validate the transaction on their phone.
  3. Submit OTP

create a charge

Create a new charge for a payment:

POST /v1/payment/charges/
curl --location 'https://api.senfenico.com/v1/payment/charges/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...' \
--data '{
    "amount": "500",
    "currency": "XOF",
    "payment_method": "mobile_money",
    "payment_method_details": {
        "phone": "76xxxxxx",
        "provider": "orange_bf"
    }
}'
POST /v1/payment/charges/
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  \"amount\": \"500\",\n  \"currency\": \"XOF\",\n  \"payment_method\": \"mobile_money\",\n  \"payment_method_details\": {\n    \"phone\": \"76xxxxxx\",\n    \"provider\": \"orange_bf\"\n  }\n}");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/charges/")
    .method("POST", body)
    .addHeader("Content-Type", "application/json")
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
POST /v1/payment/charges/
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
    'method': 'POST',
    'hostname': 'api.senfenico.com',
    'path': '/v1/payment/charges/',
    'headers': {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    },
    'maxRedirects': 20
};

var req = https.request(options, function (res) {
var chunks = [];

res.on("data", function (chunk) {
    chunks.push(chunk);
});

res.on("end", function (chunk) {
    var body = Buffer.concat(chunks);
    console.log(body.toString());
});

res.on("error", function (error) {
    console.error(error);
});
});

var postData = JSON.stringify({
    "amount": "500",
    "currency": "XOF",
    "payment_method": "mobile_money",
    "payment_method_details": {
        "phone": "76xxxxxx",
        "provider": "orange_bf"
    }
});

req.write(postData);

req.end();
POST /v1/payment/charges/
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->charge->create([
    'amount' => 1000,
    'phone' => '76XXXXXX',
    'provider' => 'orange_bf'
]);
POST /v1/payment/charges/
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Charge.create(amount=2000, phone='65000000', provider='orange_bf')
Parameter Type Optional Description
amount int No Amount to charge
currency string Yes Currency code (default: "XOF")
payment_method string Yes Payment method (default: "mobile_money")
payment_method_details object No Details about the payment method
phone string No your client phone number
provider object No the phone number operator.
Available options:
  • orange_bf
  • moov_bf
  • coris_bf
  • sank_bf

Note on Provider Constraints:

  • For orange_bf: Use an Orange BF phone number (8 digits). Valid prefixes: 04, 05, 06, 07, 54, 55, 56, 57, 64, 65, 66, 67, 74, 75, 76, 77.
  • For moov_bf: Use a Moov BF phone number (8 digits). Valid prefixes: 70, 71, 72, 73, 60, 61, 62, 63, 50, 51, 52, 53, 01, 02, 03.
  • For coris_bf: You can use any Burkina-Faso mobile phone number
  • For sank_bf: You can use any Burkina-Faso mobile phone number

Sample Response

provider:orange_bf sample response
{
    "status": true,
    "message": "Charge attempted",
    "data": {
        "reference": "ch_1ba1b4d1268b41079ee84c777e999f51",
        "status": "send_otp",
        "display_text": "Composez *144*4*6*500# pour obtenir un code OTP, puis entrez-le sur notre plateforme pour finaliser la transaction.",
        "live_mode": false
    }
}
provider:moov_bf sample response
{
    "status": true,
    "message": "Charge attempted",
    "data": {
        "reference": "ch_4f60d14ace534fd19ee3cce88fd6ba73",
        "status": "send_otp",
        "display_text": "Veuillez entrer le code OTP reçu sur votre téléphone pour finaliser la transaction.",
        "live_mode": false
    }
}

Interpretation of Responses:

  • When the status is send_otp, the user is required to enter an OTP code to complete the transaction. This OTP is usually sent via SMS from their mobile money operator without needing further action from the user. However, in some cases, like with Orange Money, the user may need to manually dial a USSD code as shown in the display_text to receive the OTP.

  • When the status is pay_offline, the user must finalize the payment directly on their mobile phone, typically by executing a USSD code and following the instructions as indicated in the display_text. In this case, no OTP code is required from the user. Once the payment is completed, the integrator will receive a notification if they have subscribed to the appropriate events in the webhook menu on the admin interface.

submit OTP

Submit the OTP for a charge:

POST /v1/payment/charges/submit
curl --location 'https://api.senfenico.com/v1/payment/charges/submit' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...' \
--data '{
    "otp": "839231",
    "charge_reference": "ch_39728149f97a46f1806a694dbb620b23"
}'
POST /v1/payment/charges/submit
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  \"otp\": \"839231\",\n  \"charge_reference\": \"ch_39728149f97a46f1806a694dbb620b23\"\n}");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/charges/submit")
    .method("POST", body)
    .addHeader("Content-Type", "application/json")
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
POST /v1/payment/charges/submit
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
    'method': 'POST',
    'hostname': 'api.senfenico.com',
    'path': '/v1/payment/charges/submit',
    'headers': {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    },
    'maxRedirects': 20
};

var req = https.request(options, function (res) {
var chunks = [];

res.on("data", function (chunk) {
    chunks.push(chunk);
});

res.on("end", function (chunk) {
    var body = Buffer.concat(chunks);
    console.log(body.toString());
});

res.on("error", function (error) {
        console.error(error);
    });
});

var postData = JSON.stringify({
    "otp": "839231",
    "charge_reference": "ch_39728149f97a46f1806a694dbb620b23"
});

req.write(postData);

req.end();
POST /v1/payment/charges/submit
$senfenico->charge->submitOtp([
    'otp' => 123456,
    'charge_reference' => 'ch_39728149f97a46f1806a694dbb620b23',
]);
POST /v1/payment/charges/submit
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Charge.submit_otp(otp="123456", charge_reference="ch_39728149f97a46f1806a694dbb620b23")
Parameter Type Optional Description
otp string No One-Time Password (OTP)
charge_reference string No Reference of the charge

Sample Response

Charge completed successfully
{
    "status": true,
    "message": "charge completed successfully",
    "data": {
        "reference": "ch_39728149f97a46f1806a694dbb620b23",
        "amount": 1000,
        "fees": 3.5,
        "currency": "XOF",
        "transaction_date": "2024-03-18T11:43:47.380565+00:00",
        "ip_address": "172.18.0.1",
        "status": "success",
        "live_mode": false,
        "payment_method": "mobile_money",
        "provider": "orange_bf",
        "cancelled_at": null,
        "cancellation_reason": null,
        "confirmation_attempts": [
            {
                "ip_address": "172.18.0.1",
                "attempt_date": "2024-03-18T11:44:16.683423+00:00",
                "confirmation_status": "success"
            }
        ]
    }
}
OTP submission failed
{
    "status": false,
    "message": "Charge operation failed. The OTP is invalid. Please try again.",
    "error_code": "OTP_INVALID"
}
Response Element Type Description
reference string Reference of the charge
amount int Charged amount
fees float Transaction fees in percent (e.g., 2%)
currency string Currency code ["XOF"]
status string Status of the charge
live_mode bool Indicates if it's a live transaction
payment_method string Payment method ["mobile_money"]
provider string Provider name ["orange_bf", "moov_bf", "coris_bf", "sank_bf"]
cancelled_at null Cancellation time (if any)
cancellation_reason null Reason for cancellation (if any)

fetch charge

Retrieve the details of a specific charge:

GET /v1/payment/charges/:charge_reference
curl --location 'https://api.senfenico.com/v1/payment/charges/{charge_reference}' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/charges/:charge_reference
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/charges/{charge_reference}")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/charges/:charge_reference
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
'method': 'GET',
'hostname': 'api.senfenico.com',
'path': '/v1/payment/charges/{charge_reference}',
'headers': {
    'Accept': 'application/json',
    'X-API-KEY': 'sk_test_...'
},
'maxRedirects': 20
};

var req = https.request(options, function (res) {
    var chunks = [];

    res.on("data", function (chunk) {
        chunks.push(chunk);
    });

    res.on("end", function (chunk) {
        var body = Buffer.concat(chunks);
        console.log(body.toString());
    });

    res.on("error", function (error) {
        console.error(error);
    });
});

req.end();
GET /v1/payment/charges/:charge_reference
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->charge->fetch('xxxxxx...', []);
GET /v1/payment/charges/:charge_reference
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Charge.fetch(charge_reference='xxxxxx...')
Parameter Type Optional Description
charge_reference string No Reference of the charge

Sample Response

Charge retreived
{
    "status": true,
    "message": "Charge attempted",
    "data": {
        "reference": "ch_45a408fd483a4d66b98aeea97aa7c2e2",
        "amount": 1000,
        "fees": "3.50",
        "currency": "XOF",
        "transaction_date": "2024-03-18T12:52:33.569084Z",
        "ip_address": "172.18.0.1",
        "status": "success",
        "live_mode": false,
        "payment_method": "mobile_money",
        "provider": "orange_bf",
        "phone": "76000000",
        "cancelled_at": null,
        "cancellation_reason": null,
        "created_at": "2024-03-18T12:52:33.572801Z",
        "updated_at": "2024-03-18T12:58:04.376754Z",
        "confirmation_attempts": [
            {
                "ip_address": "172.18.0.1",
                "attempt_date": "2024-03-18T12:53:00.220699Z",
                "confirmation_status": "failed"
            },
            {
                "ip_address": "172.18.0.1",
                "attempt_date": "2024-03-18T12:58:04.911978Z",
                "confirmation_status": "success"
            }
        ]
    }
}
Charge not found
{
    "status": false,
    "message": "Charge not found"
}
Response Element Type Description
reference string Reference of the charge
amount int Charged amount
fees string Transaction fees in percent (2 means 2%)
currency string Currency code ["XOF"]
transaction_date string Transaction date and time
status string Status of the charge [success, failed, send_otp, pay_offline, pending, canceled]
live_mode bool Indicates if it's a live transaction
payment_method string Payment method (e.g., "mobile_money")
provider string Provider name (e.g., "orange_bf")
phone string Phone number used for transaction
cancelled_at null Cancellation time (if any)
cancellation_reason null Reason for cancellation (if any)

list charges

Retrieve a list of all the charges:

GET /v1/payment/charges
curl --location 'https://api.senfenico.com/v1/payment/charges' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/charges
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/charges")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/charges
var request = require('request');
var options = {
    'method': 'GET',
    'url': 'https://api.senfenico.com/v1/payment/charges',
    'headers': {
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    }
};
request(options, function (error, response) {
if (error) throw new Error(error);
    console.log(response.body);
});
GET /v1/payment/charges
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->charge->list([]);
GET /v1/payment/charges
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Charge.list()

Sample Response

Charge list retreived
{
    "status": true,
    "message": "Charge list retreived",
    "data": [
        {
            "reference": "01b6f627-6123-43e7-89a7-4fcb9079b173",
            "amount": 500,
            "fees": "2.00",
            "currency": "XOF",
            "transaction_date": "2023-07-27T10:26:50.563219Z",
            "ip_address": "172.23.0.1",
            "status": "success",
            "live_mode": false,
            "payment_method": "mobile_money",
            "provider": "orange_bf",
            "phone": "77xxxxxx",
            "cancelled_at": null,
            "cancellation_reason": null,
            "created_at": "2023-07-27T10:26:50.571137Z",
            "updated_at": "2023-07-27T10:27:19.402034Z",
            "confirmation_attempts": [
                {
                    "ip_address": "172.23.0.1",
                    "attempt_date": "2023-07-27T10:27:19.385100Z",
                    "confirmation_status": "success"
                }
            ]
        },
        {
            "reference": "285a232b-a3b0-4af4-92f3-9c07d10aa13c",
            "amount": 500,
            "fees": "2.00",
            "currency": "XOF",
            "transaction_date": "2023-07-14T12:02:10.115968Z",
            "ip_address": "127.0.0.1",
            "status": "success",
            "live_mode": false,
            "payment_method": "mobile_money",
            "provider": "orange_bf",
            "phone": "77xxxxxx",
            "cancelled_at": null,
            "cancellation_reason": null,
            "created_at": "2023-07-14T12:02:10.128193Z",
            "updated_at": "2023-07-14T12:03:59.453015Z",
            "confirmation_attempts": [
                {
                    "ip_address": "127.0.0.1",
                    "attempt_date": "2023-07-14T12:03:59.403481Z",
                    "confirmation_status": "success"
                },
                {
                    "ip_address": "127.0.0.1",
                    "attempt_date": "2023-07-14T12:04:52.029977Z",
                    "confirmation_status": "failed"
                },
                {
                    "ip_address": "127.0.0.1",
                    "attempt_date": "2023-07-14T12:12:23.276340Z",
                    "confirmation_status": "failed"
                }
            ]
        },
    ]
}

(You can refer to the previously explained attributes for this list as they remain the same.)

balance

Retrieve the current balance information:

fetch user balance

GET /v1/payment/balances
curl --location 'https://api.senfenico.com/v1/payment/balances' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/balances
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/balances")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();                 

Response response = client.newCall(request).execute();
GET /v1/payment/balances
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
    'method': 'GET',
    'hostname': 'api.senfenico.com',
    'path': '/v1/payment/balances',
    'headers': {
        'Accept': 'application/json',
        'X-API-KEY': 'sk_test_...'
    },
    'maxRedirects': 20
};

var req = https.request(options, function (res) {
    var chunks = [];

    res.on("data", function (chunk) {
        chunks.push(chunk);
    });

    res.on("end", function (chunk) {
        var body = Buffer.concat(chunks);
        console.log(body.toString());
    });

    res.on("error", function (error) {
        console.error(error);
    });
});

req.end();
GET /v1/payment/balances
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->balance->fetch([]);
GET /v1/payment/balances
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Balance.fetch()

Sample Response

sample response
{
    "status": true,
    "message": "Balance retrieved",
    "data": {
        "collection_balances": {
            "available": 18692.0,
            "pending": 5000.0,
            "currency": "XOF"
        },
        "transfer_balances": {
            "total_available": 0.0,
            "total_pending": 0.0,
            "orange_money_bf": {
                "available": 0.0,
                "pending": 0.0
            },
            "moov_money_bf": {
                "available": 0.0,
                "pending": 0.0
            },
            "sank_money_bf": {
                "available": 0.0,
                "pending": 0.0
            }
        }
    }
}

Balance vs Usable Balance:

  • available: This represents the funds that are immediately accessible for use. These funds are ready for transactions. There are no restrictions on the use of this balance.
  • pending: This includes funds that are in the process of being transferred or settled. These amounts are not available for use.

transfers

Overview

With Senfenico, you have two distinct types of balances: Collection Balance and Transfer Balance. When you collect or receive payments, the funds are credited to your Collection Balance. Conversely, when you send money, i.e., make a transfer, the amount is deducted from your Transfer Balance. It’s essential to ensure that your Transfer Balance has sufficient funds to cover the intended transfer.

At present, each wallet type maintains its own separate Transfer Balance:

  • Orange Money Transfer Balance
  • Moov Money Transfer Balance
  • Sank Money Transfer Balance

Transfer Balance Management

In the short term, we aim to provide a unified Transfer Balance across all wallets. In the medium term, our goal is to unify the Collection and Transfer Balances into a single, seamless balance. However, for now, you must individually top up each Transfer Balance to make transfers to the corresponding wallet.

For example, to transfer funds to a Moov Africa Burkina Faso account, you must ensure your Moov BF Transfer Balance has sufficient funds. The same applies to Orange Money and Sank Money.

single transfer

POST /v1/payment/transfers/
curl --location 'https://api.senfenico.com/v1/payment/transfers/' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: sk_live_...' \
--data '{
    "amount": 100,
    "recipient_phone": "63xxxxxx",
    "recipient_wallet": "sank_bf",
    "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064"
}'
POST /v1/payment/transfers/
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\r\n    \"amount\": 100,\r\n    \"recipient_phone\": \"63xxxxxx\",\r\n    \"recipient_wallet\": \"sank_bf\",\r\n    \"ext_id\": \"98b96ea4-210d-4ea0-9b03-8d7fd96e4064\"\r\n}");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/transfers/")
    .method("POST", body)
    .addHeader("Content-Type", "application/json")
    .addHeader("X-API-KEY", "sk_live_...")
    .build();
Response response = client.newCall(request).execute();
POST /v1/payment/transfers/
const axios = require('axios');
let data = JSON.stringify({
    "amount": 100,
    "recipient_phone": "63xxxxxx",
    "recipient_wallet": "sank_bf",
    "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064",
});

let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://api.senfenico.com/v1/payment/transfers/',
headers: { 
    'Content-Type': 'application/json', 
    'X-API-KEY': 'sk_live_...'
},
data : data
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
POST /v1/payment/transfers/
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->transfer->create([
    'amount' => 100,
    'recipient_phone' => '72184746',
    'recipient_wallet' => 'moov_bf',
    'ext_id' => '98b96ea4-210d-4ea0-9b03-8d7fd96e4064'
]);
POST /v1/payment/transfers/
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Transfer.create(
    amount=100,
    recipient_phone='63000000',
    recipient_wallet='sank_bf',
    ext_id='98b96ea4-210d-4ea0-9b03-8d7fd96e4064'
)
Parameter Type Optional Description
amount int No The amount you wish to transfer. (min: 100)
recipient_phone string No The phone number of the recipient.
recipient_wallet string Yes (Optional) The wallet to which the transfer is being made. If not provided, Senfenico will determine the wallet based on the recipient’s phone number. For example, a Moov BF number will automatically direct the transfer to a Moov BF wallet, and the same logic applies to Orange Money. Available options : [orange_bf, moov_bf, sank_bf]
ext_id string Yes External ID

Sample Response

Transfer has been queued
{
    "status": true,
    "message": "Transfer has been queued",
    "data": {
        "reference": "tr_ef733c5a98b04a51b00773256d8b8f2f",
        "amount": 100,
        "fees": 1.5,
        "recipient_phone": "63000000",
        "currency": "XOF",
        "ip_address": "172.18.0.1",
        "status": "pending",
        "live_mode": true,
        "recipient_wallet": "sank_bf",
        "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064",
        "created_at": "2024-03-21T21:08:33.336879Z"
    }
}
Insufficient balance
{
    "status": false,
    "message": "Insufficient balance for Sank BF transfer including fees.",
    "error_code": "INSUFFICIENT_FUNDS"
}
Response Element Type Description
reference string Reference of the transfer
amount int Transfered amount
fees string Transaction fees in percent (2 means 2%)
recipient_phone string Phone number used for transaction
currency string Currency code ["XOF"]
status string Status of the charge [success, failed, pending]
live_mode bool Indicates if it's a live transaction
recipient_wallet string recipient wallet [orange_bf, moov_bf, sank_bf]
ext_id string Unique external identifier provided by the client for tracking and referencing this transfer within their own system. Typically generated using methods like UUID.

bulk transfer

Senfenico supports bulk transfers, allowing you to process multiple transfers in a single request. However, please note the following constraints:

  • Batch Size: Limited to 100 transfers per request. If you require a larger batch size, please contact our support team.
  • Rate Limit: You cannot call the bulk transfer endpoint more than 5 times per second.
GET /v1/payment/transfers/bulk/
curl --location 'https://api.senfenico.com/v1/payment/transfers/bulk/' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: sk_live_...' \
--data '{
    "transfers": [
        {
            "amount": 100,
            "recipient_phone": "65xxxxxx",
            "recipient_wallet": "orange_bf"
        },
        {
            "amount": 100,
            "recipient_phone": "63xxxxxx"
        }
    ]
}'
GET /v1/payment/transfers/bulk/
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\r\n    \"transfers\": [\r\n        {\r\n            \"amount\": 100,\r\n            \"recipient_phone\": \"65xxxxxx\",\r\n            \"recipient_wallet\": \"orange_bf\"\r\n        },\r\n        {\r\n            \"amount\": 100,\r\n            \"recipient_phone\": \"63xxxxxx\"\r\n        }\r\n    ]\r\n}");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/transfers/bulk/")
    .method("POST", body)
    .addHeader("Content-Type", "application/json")
    .addHeader("X-API-KEY", "sk_live_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/transfers/bulk/
const axios = require('axios');
let data = JSON.stringify({
"transfers": [
    {
        "amount": 100,
        "recipient_phone": "65xxxxxx",
        "recipient_wallet": "orange_bf"
    },
    {
        "amount": 100,
        "recipient_phone": "63xxxxxx"
    }
]
});

let config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/transfers/bulk/',
    headers: { 
        'Content-Type': 'application/json', 
        'X-API-KEY': 'sk_live_...'
    },
    data : data
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
GET /v1/payment/transfers/bulk/
$senfenico = new \Senfenico\Senfenico('sk_test_...');

$senfenico->transfer->bulkCreate([
    'transfers' => [
        [
            'amount' => 100,
            'recipient_phone' => '65xxxxxx',
            'recipient_wallet' => 'orange_bf'
        ],
        [
            'amount' => 100,
            'recipient_phone' => '63xxxxxx',
            'ext_id' => '98b96ea4-210d-4ea0-9b03-8d7fd96e4064'
        ]
    ]
]);
GET /v1/payment/transfers/bulk/
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Transfer.bulk_create(
    transfers=[
        {"amount": 100, "recipient_phone": "65xxxxxx", "recipient_wallet": "orange_bf"},
        {"amount": 100, "recipient_phone": "63xxxxxx", "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064"}
    ]
)

Sample Response

2 transfers queued for processing
{
    "status": true,
    "message": "2 transfers queued for processing",
    "failed_transfers": []
}
1 transfers queued
{
    "status": true,
    "message": "1 transfers queued for processing",
    "failed_transfers": [
        {
            "data": {
                "amount": 100,
                "recipient_phone": "63xxxxxx",
                "recipient_wallet": null,
                "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064"
            },
            "errors": {
                "non_field_errors": [
                    "Insufficient balance for Moov BF transfer including fees."
                ]
            }
        }
    ]
}
Bad reauest
{
    "status": false,
    "message": "Maximum of 100 transfers allowed per request",
    "error_code": "BATCH_SIZE_LIMIT_EXCEEDED"
}

(You can refer to the previously explained attributes for this list as they remain the same.)

list transfers

This endpoint is used to retrieve a list of all transfers.

GET /v1/payment/transfers
curl --location 'https://api.senfenico.com/v1/payment/transfers/' \
--header 'X-API-KEY: sk_live_...'
GET /v1/payment/transfers
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/transfers/")
    .method("GET", body)
    .addHeader("X-API-KEY", "sk_live_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/transfers
const axios = require('axios');

let config = {
    method: 'get',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/transfers/',
    headers: { 
        'X-API-KEY': 'sk_live_...'
    }
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
GET /v1/payment/transfers
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$transfers = $senfenico->transfer->list([]);
GET /v1/payment/transfers
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Transfer.list()

Sample Response

settlement list retrieved
{
    "status": true,
    "message": "Transfer list retrieved",
    "data": [
        {
            "reference": "tr_61242504fdf24d1b9f5344deed8657f9",
            "amount": 100,
            "fees": "1.50",
            "currency": "XOF",
            "ip_address": "172.18.0.1",
            "status": "pending",
            "live_mode": true,
            "recipient_wallet": "orange_bf",
            "recipient_phone": "65xxxxxx",
            "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064",
            "created_at": "2024-03-21T13:34:34.268389Z"
        },
        {
            "reference": "tr_f93b234379994c4498c0014d87936dae",
            "amount": 100,
            "fees": "1.50",
            "currency": "XOF",
            "ip_address": "172.18.0.1",
            "status": "pending",
            "live_mode": true,
            "recipient_wallet": "orange_bf",
            "recipient_phone": "76xxxxxx",
            "ext_id": "73b96ea4-210d-4ea0-9b03-8d7fd96e4052",
            "created_at": "2024-03-21T13:22:51.139807Z"
        }
    ]
}

(You can refer to the previously explained attributes for this list as they remain the same.)

fetch single transfer

You can fetch details of a single transfer using this endpoint:

GET /v1/payment/transfers/:transfer_reference
curl --location 'https://api.senfenico.com/v1/payment/transfers/tr_61242504fdf24d1b9f5344deed8657f9' \
--header 'X-API-KEY: sk_live_...'
GET /v1/payment/transfers/:transfer_reference
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/transfers/tr_61242504fdf24d1b9f5344deed8657f9")
    .method("GET", body)
    .addHeader("X-API-KEY", "sk_live_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/transfers/:transfer_reference
const axios = require('axios');

let config = {
    method: 'get',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/transfers/tr_61242504fdf24d1b9f5344deed8657f9',
    headers: { 
        'X-API-KEY': 'sk_live_...'
    }
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
GET /v1/payment/transfers/:transfer_reference
$senfenico = new \Senfenico\Senfenico('sk_test_...');

$senfenico->transfer->fetch('tr_c6ddbab683424a8e8b906b46da52aea8', []);
GET /v1/payment/transfers/:transfer_reference
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Transfer.fetch("tr_61242504fdf24d1b9f5344deed8657f9")

Sample Response

Transfer details retrieved
{
    "status": true,
    "message": "Transfer details retrieved",
    "data": {
        "reference": "tr_61242504fdf24d1b9f5344deed8657f9",
        "amount": 100,
        "fees": "1.50",
        "currency": "XOF",
        "ip_address": "172.18.0.1",
        "status": "pending",
        "live_mode": true,
        "recipient_wallet": "orange_bf",
        "recipient_phone": "65xxxxxx",
        "created_at": "2024-03-21T13:34:34.268389Z",
        "ext_id": "98b96ea4-210d-4ea0-9b03-8d7fd96e4064",
    }
}

(You can refer to the previously explained attributes for this list as they remain the same.)

Important Considerations Transfers in Senfenico are processed asynchronously. Therefore, we strongly advise you to implement webhooks to monitor the status of your transfers in real-time. This ensures that your application can respond to transfer updates promptly and accurately.

settlements

Settlements allow you to transfer funds from your account to a designated payment account. Use this section to manage settlements.

create settlement

This endpoint is used to create a settlement to a designated payment account.

Note: If a payment account is not created, the settlement creation request will fail because the system needs to know where to send the money. You can create a payment account from the administration interface in the business setting menu.

POST /v1/payment/settlements/
curl --location 'https://api.senfenico.com/v1/payment/settlements/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...' \
--data '{
    "amount": "1000"
}'
POST /v1/payment/settlements/
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  \"amount\": \"1000\"\n}");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/settlements/")
    .method("POST", body)
    .addHeader("Content-Type", "application/json")
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
POST /v1/payment/settlements/
const axios = require('axios');
let data = JSON.stringify({
    "amount": "1000"
});

let config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/settlements/',
    headers: { 
        'Content-Type': 'application/json', 
        'Accept': 'application/json', 
        'X-API-KEY': 'sk_test_...', 
    },
    data : data
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
POST /v1/payment/settlements/
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->settlement->create([
    'amount' => 5000
]);
POST /v1/payment/settlements/
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Settlement.create(amount=5000)
Parameter Type Optional Description
amount int No Amount to settlement

Sample Response

Payout created
{
    "status": true,
    "message": "Payout created",
    "data": {
        "reference": "d1b19637-3cce-45e7-898b-265ddfbc981c",
        "amount": 1000,
        "settlement_fees": 2,
        "currency": "XOF",
        "status": "processing",
        "live_mode": false,
        "created_at": "2023-07-30T19:23:01.658300Z",
        "updated_at": "2023-07-30T19:23:01.659013Z",
        "account_type": "bank",
        "iban": null,
        "rib": "YOUR RIB",
        "bank_name": null,
        "bank_address": null,
        "account_holder_name": null,
        "account_holder_address": null,
        "swift_bic_code": null,
        "provider": null,
        "phone": null,
        "usdt_wallet_address": null
    }
}
Response Element Type Possible Values Description
reference string - Reference of the settlement
amount int - Payout amount
settlement_fees int - Payout fees
currency string "XOF" Currency code
status string "processing", "in_transit", "success", "cancelled" Status of the settlement
live_mode bool true, false Indicates if it's a live transaction
account_type string "bank", "mobile", "usdt" Account type
rib string - RIB of the bank
other banking details null - Other banking information as null if not provided

fetch settlement

This endpoint is used to retrieve the details of a specific settlement

GET /v1/payment/settlements/:settlement_reference
curl --location 'https://api.senfenico.com/v1/payment/settlements/{settlement_reference}' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/settlements/:settlement_reference
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/settlements/{settlement_reference}")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/settlements/:settlement_reference
const axios = require('axios');

let config = {
    method: 'get',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/settlements/{settlement_reference}',
    headers: { 
        'Accept': 'application/json', 
        'X-API-KEY': 'sk_test_...', 
    }
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
GET /v1/payment/settlements/:settlement_reference
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->settlement->fetch('xxxxxx...', []);
GET /v1/payment/settlements/:settlement_reference
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Settlement.fetch(settlement_reference="xxxxx...")

Sample Response

Payout retrieved
{
    "status": true,
    "message": "Payout retrieved",
    "data": {
        "reference": "dc5a902d-a4eb-4025-b4f1-3c9b30468b64",
        "amount": 1000,
        "settlement_fees": 2,
        "currency": "XOF",
        "status": "processing",
        "live_mode": false,
        "created_at": "2023-07-30T20:42:31.147100Z",
        "updated_at": "2023-07-30T20:42:31.147612Z",
        "account_type": "bank",
        "iban": null,
        "rib": "YOUR RIB",
        "bank_name": null,
        "bank_address": null,
        "account_holder_name": null,
        "account_holder_address": null,
        "swift_bic_code": null,
        "provider": null,
        "phone": null,
        "usdt_wallet_address": null
    }
}

(You can refer to the previously explained attributes for this list as they remain the same.)

list settlements

This endpoint is used to retrieve a list of all settlements.

GET /v1/payment/settlements
curl --location 'https://api.senfenico.com/v1/payment/settlements' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...'
GET /v1/payment/settlements
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/settlements")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();
Response response = client.newCall(request).execute();
GET /v1/payment/settlements
const axios = require('axios');

let config = {
    method: 'get',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/settlements',
    headers: { 
        'Accept': 'application/json', 
        'X-API-KEY': 'sk_test_...', 
    }
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
GET /v1/payment/settlements
<?php
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->settlement->list([]);
GET /v1/payment/settlements
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Settlement.list()

Sample Response

settlement list retrieved
{
    "status": true,
    "message": "settlement list retrieved",
    "data": [
        {
            "reference": "c067a1ce-0112-44d0-bd1f-ed1c004ee98b",
            "amount": 1000,
            "settlement_fees": 2,
            "currency": "XOF",
            "status": "in_transit",
            "live_mode": false,
            "created_at": "2023-07-30T20:59:33.794435Z",
            "updated_at": "2023-07-30T21:11:43.494159Z",
            "account_type": "bank",
            "iban": null,
            "rib": "YOUR RIB",
            "bank_name": null,
            "bank_address": null,
            "account_holder_name": null,
            "account_holder_address": null,
            "swift_bic_code": null,
            "provider": null,
            "phone": null,
            "usdt_wallet_address": null
        }
    ]
}

(You can refer to the previously explained attributes for this list as they remain the same.)

cancel settlement

This endpoint is used to cancel a specific settlement. A settlement can only be canceled if it's in 'processing' status.

GET /v1/payment/settlements/{settlement_reference}/cancel/
curl --location 'https://api.senfenico.com/v1/payment/settlements/{settlement_reference}/cancel/' \
--header 'Accept: application/json' \
--header 'X-API-KEY: sk_test_...' \
--header 'Cookie: csrftoken=OikaoS1C0Byqwl75MmMDTbgiKoESKNK1'
GET /v1/payment/settlements/{settlement_reference}/cancel/
OkHttpClient client = new OkHttpClient().newBuilder()
    .build();

MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
    .url("https://api.senfenico.com/v1/payment/settlements/{settlement_reference}/cancel/")
    .method("GET", body)
    .addHeader("Accept", "application/json")
    .addHeader("X-API-KEY", "sk_test_...")
    .build();

Response response = client.newCall(request).execute();
GET /v1/payment/settlements/{settlement_reference}/cancel/
const axios = require('axios');

let config = {
    method: 'get',
    maxBodyLength: Infinity,
    url: 'https://api.senfenico.com/v1/payment/settlements/{settlement_reference}/cancel/',
    headers: { 
        'Accept': 'application/json', 
        'X-API-KEY': 'sk_test_...', 
    }
};

axios.request(config)
.then((response) => {
    console.log(JSON.stringify(response.data));
})
.catch((error) => {
    console.log(error);
});
GET /v1/payment/settlements/{settlement_reference}/cancel/
$senfenico = new \Senfenico\Senfenico('sk_test_...');
$senfenico->settlement->cancel('xxxxxx...', []);
GET /v1/payment/settlements/{settlement_reference}/cancel/
import senfenico
senfenico.api_key = 'sk_test_...'

senfenico.Settlement.cancel(settlement_reference="xxxxxx...")

Sample Response

Payout cancelled
{
    "status": true,
    "message": "Payout cancelled",
    "data": {
        "reference": "dc5a902d-a4eb-4025-b4f1-3c9b30468b64",
        "amount": 1000,
        "settlement_fees": 2,
        "currency": "XOF",
        "status": "cancelled",
        "live_mode": false,
        "created_at": "2023-07-30T20:42:31.147100Z",
        "updated_at": "2023-07-30T20:57:18.909852Z",
        "account_type": "bank",
        "iban": null,
        "rib": "YOUR RIB",
        "bank_name": null,
        "bank_address": null,
        "account_holder_name": null,
        "account_holder_address": null,
        "swift_bic_code": null,
        "provider": null,
        "phone": null,
        "usdt_wallet_address": null
    }
}
Payout can only be cancelled if it's in 'processing' status
{
    "status": false,
    "message": "Validation error: [\"Payout can only be cancelled if it's in 'processing' status.\"]"
}

(You can refer to the previously explained attributes for this cancel response as they remain the same.)

Testing your integration

Before going live with your integration, we recommend thoroughly testing it to ensure everything works as expected. To facilitate this, we've provided test numbers and balances that you can use to simulate transactions.

provider phone amount OTP
orange_bf 76000000 1000 123456
orange_bf 77000000 1500 123456
orange_bf 65000000 2000 123456
moov_bf 70000000 1000 123456
moov_bf 71000000 1500 123456
moov_bf 72000000 2000 123456
coris_bf 72000000 1000 123456
coris_bf 75000000 1500 123456
coris_bf 68000000 2000 123456
sank_bf 72000000 1000 123456
sank_bf 75000000 1500 123456
sank_bf 68000000 2000 123456

For testing transfers, you can initiate a transfer to any valid Burkina Faso number. We've topped up your test transfer balances with 100,000 FCFA for each wallet, giving you ample room to test the feature.

We recommend using the same numbers listed above for payment testing to ensure consistency across your tests.

Once you've successfully tested your integration and are satisfied with the results, you can proceed to use your live API key for real transactions.

Error Codes

In this section, you will find a comprehensive list of error codes that our API might return. Each error code is accompanied by a brief description of the issue, both in English and French, to help you understand and resolve any issues that may arise during integration or usage.

Error Codes Overview When something goes wrong with an API request, you will receive an error response that includes the following fields:

  • status: Always false for error responses.
  • message: A human-readable message explaining the response.
  • error_code: A unique code identifying the error.
  • description: A detailed description of the error.
  • description_fr: La description dĂ©taillĂ©e de l'erreur en français.

Below is a list of possible error codes along with their descriptions:

Code Description Description(fr)
BATCH_SIZE_LIMIT_EXCEEDED The request exceeds the maximum batch size of 100 items. Please reduce the number of items in the batch and try again. La requĂȘte dĂ©passe la taille maximale autorisĂ©e de 100 Ă©lĂ©ments. Veuillez rĂ©duire le nombre d'Ă©lĂ©ments dans le lot et rĂ©essayer.
RATE_LIMIT_EXCEEDED You have exceeded the rate limit for API requests. Please wait before making further requests. Vous avez dĂ©passĂ© la limite de taux pour les requĂȘtes API. Veuillez patienter avant de faire d'autres requĂȘtes.
UNSUPPORTED_PROVIDER UNSUPPORTED_PROVIDER UNSUPPORTED_PROVIDER
OTP_INVALID The OTP is invalid. Please try again. OTP invalide fournies. Veuillez vérifier et réessayer.
OTP_EXPIRED The OTP has expired. Please request a new one. Le code OTP a expiré. Veuillez en demander un nouveau.
OTP_STILL_VALID The current OTP is still valid. Please use the existing OTP or wait until it expires to request a new one. Le code OTP actuel est toujours valide. Veuillez utiliser le code OTP existant ou attendre qu'il expire pour en demander un nouveau.
INSUFFICIENT_FUNDS Account holder does not have enough funds to complete this transaction. Le titulaire du compte n'a pas suffisamment de fonds pour effectuer cette transaction.
INVALID_ACCOUNT The phone number is not valid or is not associated with an account with operator. Please check the phone number and try again. Le numéro de téléphone n'est pas valide ou n'est pas associé à un compte chez l'opérateur. Veuillez vérifier le numéro de téléphone et réessayer.
NETWORK_ERROR A network error occurred. Please try again later. Une erreur de réseau est survenue. Veuillez réessayer plus tard.
CHARGE_NOT_FOUND Charge with the given reference not found. La transaction avec la référence donnée est introuvable.
INTERNAL_ERROR An internal error occurred. Please try again later. Une erreur interne est survenue. Veuillez réessayer plus tard.
UNKNOWN_ERROR An unknown error occurred. Please try again later. Une erreur inconnue est survenue. Veuillez réessayer plus tard.
TRANSACTION_NOT_FOUND Transaction not found. Transaction introuvable.
UNAUTHORIZED_CHARGE_PROVIDER You are not authorized to charge this provider. If you think this is an error, please contact Senfenico team. Vous n'ĂȘtes pas autorisĂ© Ă  collecter les paiement de cet opĂ©rateur. Si vous pensez qu'il s'agit d'une erreur, veuillez contacter l'Ă©quipe de Senfenico.
EXTERNAL_API_ERROR The OTP is invalid. Please try again. An error occurred with an external API. Please try again later or contact support if the issue persists. Veuillez réessayer plus tard ou contacter le support si le problÚme persiste.
INVALID_DATA Invalid data provided. Please check the input and try again. Données invalides fournies. Veuillez vérifier les données saisies et réessayer.

Once you've successfully tested your integration, you can proceed to use your live API key for real transactions

Conclusion

This API documentation provides an overview of the available endpoints for managing checkouts and charges with Senfenico's payment API. By following the guidelines and examples provided, you can integrate Senfenico into your application and start accepting payments seamlessly.

If you have any questions or need further assistance, please contact Senfenico's support team at contact@senfenico.com.