Encaissements
Un encaissement demande à un client de payer depuis son portefeuille mobile money. Le client valide sur son téléphone, ou saisit un code à usage unique que vous transmettez avec authorize. Suivez le résultat avec les webhooks.
/v1/collectionsCréer un encaissementGET/v1/collections/{id}Consulter un encaissementGET/v1/collectionsLister les encaissementsPOST/v1/collections/{id}/authorizeValider avec un codePOST/v1/collections/{id}/resend_otpRenvoyer le codeThe collection object
Attributs
Identifiant unique (UUID).
true en production, false en mode test.
Toujours collection.
Où en est l’encaissement. succeeded, failed et expired sont définitifs.
pendingrequires_otpprocessingsucceededfailedexpiredMontant demandé au client, en unités mineures.
Code devise ISO 4217.
Frais Monerail, connus une fois l’encaissement réussi.
Montant crédité sur votre solde (amount − fee), connu une fois l’encaissement réussi.
Le client qui paie.
Voir les attributs
Nom du client.
Numéro mobile money, format international sans +.
Code pays ISO 3166-1 alpha-2.
Code de l’opérateur mobile money, par exemple MTN ou ORANGE.
Votre description.
Votre propre référence, telle qu’envoyée à la création.
Paires clé-valeur jointes à la création.
Ce que le client doit faire ensuite, ou null. type vaut customer_approval (valider sur le téléphone ; ussd_code en secours), otp (envoyez le code avec authorize ; si ussd_code est présent, le client le compose pour obtenir le code) ou redirect (envoyez le client sur url pour valider).
Voir les attributs
Type d’action.
customer_approvalotpredirectConsigne de l’opérateur, à afficher à votre client.
Code USSD que le client compose : en secours pour customer_approval, pour obtenir le code pour otp.
redirect seulement : page de paiement à ouvrir pour le client.
failed ou expired, si l’encaissement n’a pas abouti. Le partenaire de paiement ne donne pas de motif plus précis pour les encaissements.
failedexpiredMotif lisible, quand il est disponible.
Date de création, ISO 8601 (UTC).
Dernière modification, ISO 8601 (UTC).
{
"id": "3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61",
"object": "collection",
"livemode": false,
"status": "pending",
"amount": 5000,
"currency": "XAF",
"fee": null,
"net": null,
"customer": {
"name": "Awa Ndiaye",
"phone": "237670000999",
"country": "CM"
},
"operator": "MTN",
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
},
"next_action": {
"type": "customer_approval",
"message": "A payment request was sent. The customer enters their PIN.",
"ussd_code": "*126#"
},
"failure_code": null,
"failure_message": null,
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}Créer un encaissement
Envoie une demande de paiement sur le téléphone du client. Renvoie 201 avec l’encaissement, ou 202 si l’opérateur n’a pas encore accusé réception (l’encaissement est alors processing ; le résultat arrive par webhook).
Rôles de la clé : Propriétaire, Finance ou Développeur
Corps
Montant en unités mineures de currency (francs entiers pour XAF, XOF et GNF ; centimes pour CDF, par multiples de 100). Entier seulement.
Code ISO 4217. Les encaissements en NGN ne sont pas disponibles et renvoient 400 currency_unsupported.
XAFXOFGNFCDFKESGHSUGXTZSRWFNuméro mobile money du client. Format international (237670000000 ou +237 670 00 00 00), ou format local si country est connu.
Code opérateur issu de Lister les opérateurs, par exemple MTN, ORANGE, WAVE, MPESA.
Le client qui paie.
Voir les attributs
Nom du client, 2 à 80 caractères.
Code ISO 3166-1 alpha-2. Obligatoire pour encaisser dans un autre pays que le pays principal de la devise : XAF vaut CM par défaut (aussi GA, TD, CG, CF), XOF vaut SN (aussi CI, BJ, TG, BF, ML, NE), GNF vaut GN, CDF vaut CD. Voir Couverture.
500 caractères au plus.
Votre propre référence, 64 caractères au plus : lettres, chiffres et _ . : / -.
Jusqu’à 20 paires clé-valeur. Clés de 40 caractères au plus (A-Z a-z 0-9 _ . -), valeurs enregistrées en texte, 500 caractères au plus.
Retour
Renvoie le nouvel objet encaissement avec 201, ou 202 quand le résultat n’est pas encore définitif.
Erreurs à prévoir
| HTTP | Code | Description |
|---|---|---|
400 | currency_ | Cette devise n’est pas ouverte. |
400 | country_ | Ce pays n’est pas ouvert pour cette devise. Voir Couverture. |
400 | operator_ | Opérateur inconnu, ou refusé par le partenaire de paiement pour cette devise. |
400 | phone_ | Le numéro ne peut pas être lu comme un numéro international. |
400 | test_ | Mode test : utilisez un des numéros de test de ce pays. Voir Tests. |
403 | permission_ | Le créateur de la clé n’a pas le rôle requis pour cette opération. |
429 | rate_ | Une limite de débit est atteinte. Attendez Retry-After secondes. Voir Limites de débit. |
503 | provider_ | Ce service n’est pas encore ouvert dans ce mode. |
curl https://api.monerail.com/v1/collections \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45" \
-d '{
"amount": 5000,
"currency": "XAF",
"phone": "237670000999",
"operator": "MTN",
"customer": {
"name": "Awa Ndiaye"
},
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
}
}'const res = await fetch('https://api.monerail.com/v1/collections', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45',
},
body: JSON.stringify({
amount: 5000,
currency: 'XAF',
phone: '237670000999',
operator: 'MTN',
customer: {
name: 'Awa Ndiaye',
},
description: 'Order 42',
client_reference: 'order_42',
metadata: {
order_id: '42',
},
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.monerail.com/v1/collections",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}", "Idempotency-Key": "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45"},
json={
"amount": 5000,
"currency": "XAF",
"phone": "237670000999",
"operator": "MTN",
"customer": {
"name": "Awa Ndiaye",
},
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42",
},
},
timeout=30,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data)<?php
$ch = curl_init('https://api.monerail.com/v1/collections');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
'Content-Type: application/json',
'Idempotency-Key: a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 5000,
'currency' => 'XAF',
'phone' => '237670000999',
'operator' => 'MTN',
'customer' => [
'name' => 'Awa Ndiaye',
],
'description' => 'Order 42',
'client_reference' => 'order_42',
'metadata' => [
'order_id' => '42',
],
]),
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
print_r($data);package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
payload, err := json.Marshal(map[string]any{
"amount": 5000,
"currency": "XAF",
"phone": "237670000999",
"operator": "MTN",
"customer": map[string]any{
"name": "Awa Ndiaye",
},
"description": "Order 42",
"client_reference": "order_42",
"metadata": map[string]any{
"order_id": "42",
},
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.monerail.com/v1/collections", bytes.NewReader(payload))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MONERAIL_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
if res.StatusCode >= 400 {
panic(fmt.Sprint(data["error"]))
}
fmt.Println(data)
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
String body = """
{
"amount": 5000,
"currency": "XAF",
"phone": "237670000999",
"operator": "MTN",
"customer": {
"name": "Awa Ndiaye"
},
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/collections"))
.header("Authorization", "Bearer " + System.getenv("MONERAIL_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException(response.body());
}
System.out.println(response.body()); // parse with your JSON library (Jackson, Gson…)
}
}require "json"
require "net/http"
uri = URI("https://api.monerail.com/v1/collections")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
req["Content-Type"] = "application/json"
req["Idempotency-Key"] = "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45"
req.body = JSON.generate({
amount: 5000,
currency: "XAF",
phone: "237670000999",
operator: "MTN",
customer: {
name: "Awa Ndiaye",
},
description: "Order 42",
client_reference: "order_42",
metadata: {
order_id: "42",
},
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
raise "#{data["error"]["code"]}: #{data["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
puts datausing System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MONERAIL_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.monerail.com/v1/collections");
request.Headers.Add("Idempotency-Key", "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45");
request.Content = JsonContent.Create(new
{
amount = 5000,
currency = "XAF",
phone = "237670000999",
@operator = "MTN",
customer = new
{
name = "Awa Ndiaye",
},
description = "Order 42",
client_reference = "order_42",
metadata = new
{
order_id = "42",
},
});
using var response = await http.SendAsync(request);
var data = await response.Content.ReadFromJsonAsync<JsonElement>();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(data.GetProperty("error").GetProperty("message").GetString());
}
Console.WriteLine(data);{
"id": "3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61",
"object": "collection",
"livemode": false,
"status": "pending",
"amount": 5000,
"currency": "XAF",
"fee": null,
"net": null,
"customer": {
"name": "Awa Ndiaye",
"phone": "237670000999",
"country": "CM"
},
"operator": "MTN",
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
},
"next_action": {
"type": "customer_approval",
"message": "A payment request was sent. The customer enters their PIN.",
"ussd_code": "*126#"
},
"failure_code": null,
"failure_message": null,
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}Consulter un encaissement
Renvoie l’encaissement. S’il est encore en attente, Monerail interroge d’abord le partenaire de paiement : cet appel sert donc aussi au suivi (toutes les quelques secondes au plus).
Rôles de la clé : Tous les rôles
Paramètres de chemin
Identifiant de l’encaissement.
Retour
Renvoie l’objet encaissement.
curl https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61 \
-H "Authorization: Bearer $MONERAIL_KEY"const res = await fetch('https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61', {
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data);import os
import requests
res = requests.get(
"https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
timeout=30,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data)<?php
$ch = curl_init('https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
],
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
print_r($data);package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MONERAIL_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
if res.StatusCode >= 400 {
panic(fmt.Sprint(data["error"]))
}
fmt.Println(data)
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61"))
.header("Authorization", "Bearer " + System.getenv("MONERAIL_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException(response.body());
}
System.out.println(response.body()); // parse with your JSON library (Jackson, Gson…)
}
}require "json"
require "net/http"
uri = URI("https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
raise "#{data["error"]["code"]}: #{data["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
puts datausing System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MONERAIL_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.monerail.com/v1/collections/3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61");
using var response = await http.SendAsync(request);
var data = await response.Content.ReadFromJsonAsync<JsonElement>();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(data.GetProperty("error").GetProperty("message").GetString());
}
Console.WriteLine(data);{
"id": "3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61",
"object": "collection",
"livemode": false,
"status": "succeeded",
"amount": 5000,
"currency": "XAF",
"fee": 125,
"net": 4875,
"customer": {
"name": "Awa Ndiaye",
"phone": "237670000999",
"country": "CM"
},
"operator": "MTN",
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
},
"next_action": null,
"failure_code": null,
"failure_message": null,
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:09.807Z"
}Lister les encaissements
Du plus récent au plus ancien.
Rôles de la clé : Tous les rôles
Paramètres de requête
20Nombre d’objets à renvoyer, de 1 à 100.
Curseur : l’identifiant du dernier objet de la page précédente.
Retour
Renvoie un objet liste : data contient jusqu’à limit objets collection, et has_more indique s’il en reste.
curl "https://api.monerail.com/v1/collections?limit=10" \
-H "Authorization: Bearer $MONERAIL_KEY"const res = await fetch('https://api.monerail.com/v1/collections?limit=10', {
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data);import os
import requests
res = requests.get(
"https://api.monerail.com/v1/collections",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
params={"limit": 10},
timeout=30,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data)<?php
$ch = curl_init('https://api.monerail.com/v1/collections?limit=10');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
],
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
print_r($data);package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://api.monerail.com/v1/collections?limit=10", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MONERAIL_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
if res.StatusCode >= 400 {
panic(fmt.Sprint(data["error"]))
}
fmt.Println(data)
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/collections?limit=10"))
.header("Authorization", "Bearer " + System.getenv("MONERAIL_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException(response.body());
}
System.out.println(response.body()); // parse with your JSON library (Jackson, Gson…)
}
}require "json"
require "net/http"
uri = URI("https://api.monerail.com/v1/collections?limit=10")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
raise "#{data["error"]["code"]}: #{data["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
puts datausing System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MONERAIL_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.monerail.com/v1/collections?limit=10");
using var response = await http.SendAsync(request);
var data = await response.Content.ReadFromJsonAsync<JsonElement>();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(data.GetProperty("error").GetProperty("message").GetString());
}
Console.WriteLine(data);{
"object": "list",
"url": "/v1/collections",
"data": [
{
"id": "3b8f6c1e-2a47-4d1b-9e35-7c0a9d2f4e61",
"object": "collection",
"livemode": false,
"status": "succeeded",
"amount": 5000,
"currency": "XAF",
"fee": 125,
"net": 4875,
"customer": {
"name": "Awa Ndiaye",
"phone": "237670000999",
"country": "CM"
},
"operator": "MTN",
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
},
"next_action": null,
"failure_code": null,
"failure_message": null,
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:09.807Z"
}
],
"has_more": false
}Valider avec un code
Pour les encaissements en requires_otp : transmet le code à usage unique reçu par SMS par le client, ou obtenu en composant next_action.ussd_code. L’encaissement passe à processing, puis à son statut final. Dans les pays où le client génère le code, 3 essais sont permis.
Rôles de la clé : Propriétaire, Finance ou Développeur
Paramètres de chemin
Identifiant de l’encaissement.
Corps
Le code, 4 à 8 chiffres.
Retour
Renvoie l’objet encaissement.
Erreurs à prévoir
| HTTP | Code | Description |
|---|---|---|
400 | otp_ | Code erroné, mal formé ou expiré. |
402 | otp_ | Code erroné, mal formé ou expiré. |
400 | otp_ | Cet encaissement n’attend pas de code (déjà validé, ou pas de code requis). |
curl https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"otp": "123456"
}'const res = await fetch('https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
otp: '123456',
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
json={
"otp": "123456",
},
timeout=30,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data)<?php
$ch = curl_init('https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'otp' => '123456',
]),
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
print_r($data);package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
payload, err := json.Marshal(map[string]any{
"otp": "123456",
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize", bytes.NewReader(payload))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MONERAIL_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
if res.StatusCode >= 400 {
panic(fmt.Sprint(data["error"]))
}
fmt.Println(data)
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
String body = """
{
"otp": "123456"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize"))
.header("Authorization", "Bearer " + System.getenv("MONERAIL_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException(response.body());
}
System.out.println(response.body()); // parse with your JSON library (Jackson, Gson…)
}
}require "json"
require "net/http"
uri = URI("https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
otp: "123456",
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
raise "#{data["error"]["code"]}: #{data["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
puts datausing System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MONERAIL_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/authorize");
request.Content = JsonContent.Create(new
{
otp = "123456",
});
using var response = await http.SendAsync(request);
var data = await response.Content.ReadFromJsonAsync<JsonElement>();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(data.GetProperty("error").GetProperty("message").GetString());
}
Console.WriteLine(data);{
"id": "9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40",
"object": "collection",
"livemode": false,
"status": "processing",
"amount": 2000,
"currency": "XAF",
"fee": null,
"net": null,
"customer": {
"name": "Awa Ndiaye",
"phone": "237690000002",
"country": "CM"
},
"operator": "ORANGE",
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
},
"next_action": null,
"failure_code": null,
"failure_message": null,
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:09.807Z"
}Renvoyer le code
Demande à l’opérateur d’envoyer un nouveau code au client. Là où le client génère le code avec un code USSD, rien n’est envoyé : réaffichez next_action.ussd_code.
Rôles de la clé : Propriétaire, Finance ou Développeur
Paramètres de chemin
Identifiant de l’encaissement.
Retour
Renvoie l’objet encaissement.
curl -X POST https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp \
-H "Authorization: Bearer $MONERAIL_KEY"const res = await fetch('https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data);import os
import requests
res = requests.post(
"https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
timeout=30,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data)<?php
$ch = curl_init('https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
],
CURLOPT_POSTFIELDS => '',
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
print_r($data);package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodPost, "https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MONERAIL_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
if res.StatusCode >= 400 {
panic(fmt.Sprint(data["error"]))
}
fmt.Println(data)
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp"))
.header("Authorization", "Bearer " + System.getenv("MONERAIL_KEY"))
.POST(HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException(response.body());
}
System.out.println(response.body()); // parse with your JSON library (Jackson, Gson…)
}
}require "json"
require "net/http"
uri = URI("https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
raise "#{data["error"]["code"]}: #{data["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
puts datausing System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MONERAIL_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.monerail.com/v1/collections/9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40/resend_otp");
using var response = await http.SendAsync(request);
var data = await response.Content.ReadFromJsonAsync<JsonElement>();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(data.GetProperty("error").GetProperty("message").GetString());
}
Console.WriteLine(data);{
"id": "9e2d4a7b-61c3-4f08-8b5e-2d7f1a3c9b40",
"object": "collection",
"livemode": false,
"status": "requires_otp",
"amount": 2000,
"currency": "XAF",
"fee": null,
"net": null,
"customer": {
"name": "Awa Ndiaye",
"phone": "237690000002",
"country": "CM"
},
"operator": "ORANGE",
"description": "Order 42",
"client_reference": "order_42",
"metadata": {
"order_id": "42"
},
"next_action": {
"type": "otp",
"message": "The customer received a one-time code by SMS."
},
"failure_code": null,
"failure_message": null,
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}