API
Introduction
Bienvenue dans notre documentation API ! Ici, vous trouverez toutes les informations dont vous avez besoin pour interagir avec notre api de paiement. 😃
Structure Générale des Réponses
Toutes nos réponses d'API suivent une structure cohérente pour rendre les choses faciles et uniformes. Voici ce à quoi vous pouvez vous attendre :
- status: Indique le succès (
true
) ou l'échec (false
) de la requête. - message: Un message expliquant la réponse
- data: Contient les détails de la réponse (le cas échéant).
Réponses d'Erreur
Lorsque quelque chose ne va pas, nous vous le ferons savoir avec une réponse d'erreur. Vous obtiendrez un statut de false, le code d'erreur et le message décrira ce qui a mal tourné.
- status: Indique le succès (
true
) ou l'échec (false
) de la requête. - message: Un message expliquant la réponse
- error_code: Un code d'erreur, en cas d'erreur lié à la fonction de paiement
- errors: Erreurs de validation des valeur transmise
Clés API🔑
Assurez-vous de remplacer sk_test_...
par votre véritable clé API. Votre clé API est votre identifiant unique, et gardez-la en sécurité !
Paramètres
Lorsque vous voyez :parameter
, , assurez-vous de le remplacer par la valeur réelle que vous souhaitez passer à l'API. Par exemple, :checkout_reference
doit être remplacé par la vraie référence d'un checkout.
Exemple de Réponse pour Clé API Invalide
Si vous utilisez une clé API incorrecte, vous recevrez une réponse comme celle-ci :
checkouts
C'est quoi un Checkout?
Le checkout est le processus par lequel vos clients finalisent leurs achats. Il implique l'initialisation du checkout et la redirection du client vers une URL d'autorisation qui vous est retourné.
Étapes pour Accepter un Paiement avec l'API de checkout
- Initialisation du Checkout: Appeler le endpoint d'initialisation.
- Redirection du client: Rediriger le client sur
authorization_url
retourné quand la requête est OK.
Initialisation du Checkout
Vous pouvez initialiser un checkout à l'aide de la requête suivante:
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"
}'
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();
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();
Parametre | Type | Optionel | Description |
---|---|---|---|
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
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:
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();
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();
Sample Response
{
"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 paymentsuccess
: Payment successfulfailed
: Payment failed
list checkout
Retrieve a list of 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();
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();
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/admin",
"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
Les charges permettent de gérer l'ensemble des étapes de paiement par vous-même. Elles sont adaptées aux applications mobiles ou de bureau puisqu'elles ne requièrent pas de redirection. Voici comment accepter un paiement via les points d'accès charges
:
- Création d'une charge : Renseigner les détails de la charge.
- Action du client : Il se peut que le client doive saisir un code USSD sur son téléphone pour confirmer la transaction. Cette étape varie selon l'opérateur.
- Soumission du OTP
create a charge
Create a new charge for a payment:
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"
}
}'
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();
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();
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:
|
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. - Pour
coris_bf
: Vous pouvez utiliser n'importe quelle numero de téléphone portable burkinabè - Pour
sank_bf
: Vous pouvez utiliser n'importe quelle numero de téléphone portable burkinabè
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
}
}
Interpretation of Responses:
-
Lorsque le statut est
send_otp
, l'utilisateur doit saisir un code OTP (One-Time Password) pour finaliser la transaction. En général, cet OTP est envoyé par SMS par son opérateur, sans qu'aucune action supplémentaire ne soit nécessaire. Cependant, dans certains cas, comme avec Orange Money, l'utilisateur devra composer un code USSD indiqué dans le display_text pour recevoir le code OTP. -
Lorsque le statut est
pay_offline
, l'utilisateur doit finaliser le paiement directement depuis son téléphone, en exécutant un code USSD et en suivant les instructions affichées dans le display_text. Dans ce cas, aucun code OTP n'est requis. L'intégrateur sera informé une fois le paiement terminé, à condition qu'il ait souscrit aux événements appropriés dans le menu webhook de l'interface d'administration.
submit OTP
Submit the OTP for a charge:
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"
}'
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();
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();
Parameter | Type | Optional | Description |
---|---|---|---|
otp | string | No | One-Time Password (OTP) |
charge_reference | string | No | Reference of the charge |
Sample Response
{
"status": true,
"message": "charge completed successfully",
"data": {
"reference": "ch_39728149f97a46f1806a694dbb620b23",
"amount": 1000,
"fees": 3.5,
"currency": "XOF",
"transaction_date": "2024-08-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-08-18T11:44:16.683423+00:00",
"confirmation_status": "success"
}
]
}
}
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:
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();
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();
Parameter | Type | Optional | Description |
---|---|---|---|
charge_reference | string | No | Reference of the charge |
Sample Response
{
"status": true,
"message": "Charge attempted",
"data": {
"reference": "ch_45a408fd483a4d66b98aeea97aa7c2e2",
"amount": 1000,
"fees": "3.50",
"currency": "XOF",
"transaction_date": "2024-08-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-08-18T12:52:33.572801Z",
"updated_at": "2024-08-18T12:58:04.376754Z",
"confirmation_attempts": [
{
"ip_address": "172.18.0.1",
"attempt_date": "2024-08-18T12:53:00.220699Z",
"confirmation_status": "failed"
},
{
"ip_address": "172.18.0.1",
"attempt_date": "2024-08-18T12:58:04.911978Z",
"confirmation_status": "success"
}
]
}
}
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:
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();
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);
});
Sample Response
{
"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
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();
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();
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
}
}
}
}
available vs pending Balance:
available
: Ce solde correspond aux fonds qui sont immédiatement accessibles. Ces fonds sont prêts pour des transactions. Aucune restriction n'est appliquée à ce solde.pending
: Ce solde inclut les fonds qui sont en cours de transfert ou de règlement. Ces montants ne sont pas disponibles pour utilisation.
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
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"
}'
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();
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);
});
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
{
"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"
}
}
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.
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"
}
]
}'
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();
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);
});
$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'
]
]
]);
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
{
"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."
]
}
}
]
}
(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.
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();
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);
});
Sample Response
{
"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:
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();
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);
});
Sample Response
{
"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.
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();
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);
});
Parameter | Type | Optional | Description |
---|---|---|---|
amount | int | No | Amount to settlement |
Sample Response
{
"status": true,
"message": "Settlement 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 | - | Settlement amount |
settlement_fees | int | - | Settlement 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
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();
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);
});
Sample Response
{
"status": true,
"message": "Settlement 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.
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();
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);
});
Sample Response
{
"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.
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();
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);
});
Sample Response
{
"status": true,
"message": "Settlement 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
}
}
(You can refer to the previously explained attributes for this cancel response as they remain the same.)
Tester votre intégration
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
Cette documentation de l'API offre un aperçu des endpoint disponibles pour gérer les paiements avec l'API de Senfenico. En suivant les directives et exemples fournis, vous pouvez intégrer Senfenico dans votre application et commencer à accepter les paiements de manière fluide.
Si vous avez des questions ou besoin d'assistance supplémentaire, n'hésitez pas à contacter l'équipe de support de Senfenico à contact@senfenico.com
.