Outils de test
Des points d’accès qui simulent l’émetteur de cartes. Ils ne fonctionnent qu’avec une clé de test (mr_test_…) et renvoient 400 test_mode_only sinon.
/v1/test/cardholders/{id}/verificationSimuler une décision de vérificationPOST/v1/test/cards/{id}/authorizationsSimuler un paiement par carteSimuler une décision de vérification Mode test seulement
Approuve ou refuse un titulaire dont la vérification est in_review. Le statut change en quelques secondes et cardholder.kyc_updated est envoyé.
Rôles de la clé : Propriétaire ou Finance
Paramètres de chemin
Identifiant du titulaire.
Corps
La décision à simuler.
approvedrejectedDocument unreadable (simulation)Seulement avec rejected : devient verification.reason. 200 caractères au plus.
Retour
Renvoie l’objet titulaire avec 202 : le résultat suit par webhook.
Erreurs à prévoir
| HTTP | Code | Description |
|---|---|---|
400 | test_ | Les outils de test demandent une clé de test. |
400 | verification_ | L’outil de test demande d’abord une vérification envoyée. |
404 | resource_ | Aucun objet avec cet identifiant dans ce mode. |
curl https://api.monerail.com/v1/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"result": "rejected",
"reason": "Name/dob mismatch"
}'const res = await fetch('https://api.monerail.com/v1/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
result: 'rejected',
reason: 'Name/dob mismatch',
}),
});
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/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
json={
"result": "rejected",
"reason": "Name/dob mismatch",
},
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/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'result' => 'rejected',
'reason' => 'Name/dob mismatch',
]),
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{
"result": "rejected",
"reason": "Name/dob mismatch",
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.monerail.com/v1/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification", 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 = """
{
"result": "rejected",
"reason": "Name/dob mismatch"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification"))
.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/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
result: "rejected",
reason: "Name/dob mismatch",
})
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/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification");
request.Content = JsonContent.Create(new
{
result = "rejected",
reason = "Name/dob mismatch",
});
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": "5df6acd9-4bac-4e19-869c-fcde6b79f389",
"object": "cardholder",
"livemode": false,
"type": "customer",
"first_name": "Awa",
"last_name": "Ndiaye",
"email": "awa@example.com",
"phone": "+237670000999",
"country": "CM",
"city": "Douala",
"birth_date": "1991-02-03",
"id_document": "national_id",
"id_number_last4": "3408",
"verification": {
"status": "in_review",
"reason": null,
"verified_at": null
},
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:09.807Z"
}Simuler un paiement par carte Mode test seulement
Simule un marchand qui débite la carte. Un paiement accepté et ses frais apparaissent sur la carte en quelques secondes, avec un événement card.transaction. Un paiement refusé envoie card.authorization_declined, ne prélève rien et renvoie authorization: null.
Rôles de la clé : Propriétaire ou Finance
Paramètres de chemin
Identifiant de la carte.
Corps
En cents de dollar, jusqu’à 10 000 000.
Nom du marchand, 40 caractères au plus.
approvedIssue du paiement simulé.
approveddeclinedRetour
Renvoie l’objet autorisation de test avec 202 : le résultat suit par webhook.
Erreurs à prévoir
| HTTP | Code | Description |
|---|---|---|
400 | test_ | Les outils de test demandent une clé de test. |
404 | resource_ | Aucun objet avec cet identifiant dans ce mode. |
curl https://api.monerail.com/v1/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 400,
"merchant": "Notion"
}'const res = await fetch('https://api.monerail.com/v1/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 400,
merchant: 'Notion',
}),
});
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/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
json={
"amount": 400,
"merchant": "Notion",
},
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/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MONERAIL_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 400,
'merchant' => 'Notion',
]),
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": 400,
"merchant": "Notion",
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.monerail.com/v1/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations", 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 = """
{
"amount": 400,
"merchant": "Notion"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerail.com/v1/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations"))
.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/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MONERAIL_KEY")}"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
amount: 400,
merchant: "Notion",
})
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/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations");
request.Content = JsonContent.Create(new
{
amount = 400,
merchant = "Notion",
});
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": "test_authorization",
"card": "ce2f0aea-7f87-4cbd-8383-03129d1253e0",
"amount": 400,
"currency": "USD",
"merchant": "Notion",
"status": "approved",
"authorization": "auth_7731"
}