Cardholders
A cardholder is the person a card is issued to: a member of your team or one of your customers. The card issuer verifies their identity before any card is issued.
/v1/cardholdersCreate a cardholderPOST/v1/cardholders/{id}/verificationSubmit identity verificationGET/v1/cardholders/{id}Retrieve a cardholderGET/v1/cardholdersList cardholdersThe cardholder object
Attributes
Unique identifier (UUID).
true for live objects, false for test objects.
Always cardholder.
team for your own staff, customer for your customers.
teamcustomerInternational format.
ISO 3166-1 alpha-2.
YYYY-MM-DD.
Identity document type.
national_idpassportdriver_licensevoters_cardLast 4 characters of the document number. The full number is never returned.
Identity verification by the card issuer. A card can only be issued once status is verified.
Show child attributes
pendingin_reviewverifiedrejectedWhy it was rejected.
When it was verified.
true when the document photos sent on creation are on file: the verification can be submitted without sending them again.
Creation time, ISO 8601 (UTC).
Last change, ISO 8601 (UTC).
{
"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": "pending",
"reason": null,
"verified_at": null,
"documents_on_file": true
},
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}Create a cardholder
Creates the cardholder with verification.status pending. A photo of the identity document is required (documents): it is checked before anything is created and reused by the identity verification. Then submit the identity verification.
Key roles: Owner or Finance
Body
Exactly as on the identity document. 1 to 50 characters: letters (accents allowed), spaces, apostrophes, periods and hyphens.
Same rules as first_name.
Valid address, up to 200 characters. Unique per business.
Country of residence, ISO 3166-1 alpha-2, among: CM, GA, TD, CG, CF, CD, CI, SN, BJ, TG, BF, ML, NE, GN, NG, GH, KE, UG, TZ, RW, ZM, ZA. Otherwise country_unsupported.
teamteamcustomerMobile number in international E.164 format (+237670000999). A national number gets the country code of country. The national part must have the length used in that country, otherwise phone_invalid. Returned normalized.
YYYY-MM-DD, a real date, exactly as on the document. The cardholder must be at least 18 (cardholder_underage).
national_idDocument used for verification. In Ghana, national_id is the Ghana Card. A passport needs its photo page only; the other documents need both sides.
national_idpassportdriver_licensevoters_cardDocument number, as printed (upper-cased). Passport: 6 to 9 letters or digits, no spaces. Other documents: 4 to 30 characters among letters, digits, spaces, / and -. Optional here, required by the verification. Only its last 4 characters are returned.
Optional. 2 to 60 characters, no digits.
Home address, kept with the cardholder: line1, line2, city, state, postal_code. The verification asks for it again.
Photos of the identity document, as base64 or data:image/…;base64, URIs. JPEG or PNG, 4 MB each at most, at least 600 × 400 px. Missing: parameter_missing; unreadable, too large or too small: document_invalid. param names the side.
Show child attributes
Front side (photo page of a passport).
Back side. Required, except for a passport.
Returns
Returns the new cardholder object with 201.
Errors worth handling
| HTTP | Code | Description |
|---|---|---|
400 | parameter_missing | A required parameter is missing. See param. |
400 | parameter_invalid | A parameter has the wrong type or value. See param. |
400 | document_invalid | A document image is not accepted: JPEG or PNG only, 4 MB at most, at least 600 × 400 px. param names the side. |
400 | phone_invalid | The number cannot be read as an international number. |
400 | country_unsupported | This country is not open for this currency. See Coverage. |
400 | cardholder_underage | The cardholder must be at least 18 years old. |
400 | id_document_unsupported | Unsupported identity document type. |
403 | permission_denied | The key’s creator does not have the role required for this operation. |
409 | cardholder_exists | A cardholder already uses this email. |
429 | rate_limited | A rate limit was reached. Wait for Retry-After seconds. See Rate limits. |
curl https://api.monerails.com/v1/cardholders \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45" \
-d '{
"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",
"documents": {
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…"
}
}'const res = await fetch('https://api.monerails.com/v1/cardholders', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45',
},
body: JSON.stringify({
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',
documents: {
front: 'data:image/jpeg;base64,/9j/4AAQ…',
back: 'data:image/jpeg;base64,/9j/4AAQ…',
},
}),
});
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.monerails.com/v1/cardholders",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}", "Idempotency-Key": "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45"},
json={
"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",
"documents": {
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…",
},
},
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.monerails.com/v1/cardholders');
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([
'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',
'documents' => [
'front' => 'data:image/jpeg;base64,/9j/4AAQ…',
'back' => 'data:image/jpeg;base64,/9j/4AAQ…',
],
]),
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{
"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",
"documents": map[string]any{
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…",
},
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.monerails.com/v1/cardholders", 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 = """
{
"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",
"documents": {
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…"
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerails.com/v1/cardholders"))
.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.monerails.com/v1/cardholders")
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({
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",
documents: {
front: "data:image/jpeg;base64,/9j/4AAQ…",
back: "data:image/jpeg;base64,/9j/4AAQ…",
},
})
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.monerails.com/v1/cardholders");
request.Headers.Add("Idempotency-Key", "a1f3c9e2-5b7d-4c21-9f80-3e6b2d1c7a45");
request.Content = JsonContent.Create(new
{
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",
documents = new
{
front = "data:image/jpeg;base64,/9j/4AAQ…",
back = "data:image/jpeg;base64,/9j/4AAQ…",
},
});
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": "pending",
"reason": null,
"verified_at": null,
"documents_on_file": true
},
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}Submit identity verification
Sends the identity details and document images to the card issuer. Returns 202 with verification.status in_review. The decision arrives with the cardholder.kyc_updated event. After a rejection, call it again with corrected details. If the cardholder is already verified, returns 200 with no change; while a review is in progress, documents are not sent again. The first name, last name and birth date must match the document exactly. Verification is per business: a person already verified by another business is verified again for yours. Limited to 5 calls per cardholder per 24 hours.
Key roles: Owner or Finance
Path parameters
ID of the cardholder.
Body
Document number, same rules as on creation (passport: 6 to 9 letters or digits; other documents: 4 to 30 characters).
YYYY-MM-DD, 18 or older. Defaults to the cardholder’s birth_date.
City of birth, as on the document. 2 to 60 characters, no digits.
Home address. Accents are accepted and sent without them.
Show child attributes
3 to 100 characters: letters, digits, spaces and , . - only.
Optional. Same characters as line1, up to 100.
2 to 60 characters, no digits.
Region, province or state. 2 to 60 characters, no digits.
Optional. 1 to 10 letters, digits, spaces or hyphens. Leave it out where there is none.
Photos of the document, as base64 or data:image/…;base64, URIs. JPEG or PNG, 4 MB each at most, at least 600 × 400 px (document_invalid otherwise). Sharp, uncropped, without glare, with the whole document visible. Optional when the photos were sent on creation (verification.documents_on_file); if sent, they replace them.
Show child attributes
Front side (photo page of a passport).
Back side. Required, except for a passport.
Only if the cardholder has none. Same rules as on creation.
Returns
Returns the cardholder object with 202: the outcome follows by webhook.
Errors worth handling
| HTTP | Code | Description |
|---|---|---|
400 | parameter_missing | A required parameter is missing. See param. |
400 | parameter_invalid | A parameter has the wrong type or value. See param. |
400 | phone_invalid | The number cannot be read as an international number. |
400 | document_invalid | A document image is not accepted: JPEG or PNG only, 4 MB at most, at least 600 × 400 px. param names the side. |
400 | cardholder_underage | The cardholder must be at least 18 years old. |
402 | identity_already_registered | The card issuer already holds this identity for a pending or completed verification. Contact support. |
402 | verification_declined | The card issuer declined the verification submission. Check the details and document images, then submit again. |
403 | permission_denied | The key’s creator does not have the role required for this operation. |
429 | rate_limited | A rate limit was reached. Wait for Retry-After seconds. See Rate limits. |
curl https://api.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"id_number": "CM12345678",
"birth_date": "1991-02-03",
"place_of_birth": "Douala",
"address": {
"line1": "12 rue Joss",
"city": "Douala",
"state": "Littoral"
},
"documents": {
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…"
}
}'const res = await fetch('https://api.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MONERAIL_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
id_number: 'CM12345678',
birth_date: '1991-02-03',
place_of_birth: 'Douala',
address: {
line1: '12 rue Joss',
city: 'Douala',
state: 'Littoral',
},
documents: {
front: 'data:image/jpeg;base64,/9j/4AAQ…',
back: 'data:image/jpeg;base64,/9j/4AAQ…',
},
}),
});
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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification",
headers={"Authorization": f"Bearer {os.environ['MONERAIL_KEY']}"},
json={
"id_number": "CM12345678",
"birth_date": "1991-02-03",
"place_of_birth": "Douala",
"address": {
"line1": "12 rue Joss",
"city": "Douala",
"state": "Littoral",
},
"documents": {
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…",
},
},
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.monerails.com/v1/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([
'id_number' => 'CM12345678',
'birth_date' => '1991-02-03',
'place_of_birth' => 'Douala',
'address' => [
'line1' => '12 rue Joss',
'city' => 'Douala',
'state' => 'Littoral',
],
'documents' => [
'front' => 'data:image/jpeg;base64,/9j/4AAQ…',
'back' => 'data:image/jpeg;base64,/9j/4AAQ…',
],
]),
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{
"id_number": "CM12345678",
"birth_date": "1991-02-03",
"place_of_birth": "Douala",
"address": map[string]any{
"line1": "12 rue Joss",
"city": "Douala",
"state": "Littoral",
},
"documents": map[string]any{
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…",
},
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, "https://api.monerails.com/v1/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 = """
{
"id_number": "CM12345678",
"birth_date": "1991-02-03",
"place_of_birth": "Douala",
"address": {
"line1": "12 rue Joss",
"city": "Douala",
"state": "Littoral"
},
"documents": {
"front": "data:image/jpeg;base64,/9j/4AAQ…",
"back": "data:image/jpeg;base64,/9j/4AAQ…"
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.monerails.com/v1/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.monerails.com/v1/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({
id_number: "CM12345678",
birth_date: "1991-02-03",
place_of_birth: "Douala",
address: {
line1: "12 rue Joss",
city: "Douala",
state: "Littoral",
},
documents: {
front: "data:image/jpeg;base64,/9j/4AAQ…",
back: "data:image/jpeg;base64,/9j/4AAQ…",
},
})
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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification");
request.Content = JsonContent.Create(new
{
id_number = "CM12345678",
birth_date = "1991-02-03",
place_of_birth = "Douala",
address = new
{
line1 = "12 rue Joss",
city = "Douala",
state = "Littoral",
},
documents = new
{
front = "data:image/jpeg;base64,/9j/4AAQ…",
back = "data:image/jpeg;base64,/9j/4AAQ…",
},
});
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,
"documents_on_file": true
},
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:09.807Z"
}Retrieve a cardholder
Key roles: Every role
Path parameters
ID of the cardholder.
Returns
Returns the cardholder object.
curl https://api.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389 \
-H "Authorization: Bearer $MONERAIL_KEY"const res = await fetch('https://api.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389', {
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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389",
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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389');
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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389", 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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389"))
.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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389")
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.monerails.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389");
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": "verified",
"reason": null,
"verified_at": "2026-10-30T13:47:09.807Z"
},
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}List cardholders
Newest first.
Key roles: Every role
Query parameters
20Number of objects to return, 1 to 100.
Cursor: the ID of the last object of the previous page.
Returns
Returns a list object: data holds up to limit cardholder objects, and has_more tells whether more follow.
curl "https://api.monerails.com/v1/cardholders?limit=10" \
-H "Authorization: Bearer $MONERAIL_KEY"const res = await fetch('https://api.monerails.com/v1/cardholders?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.monerails.com/v1/cardholders",
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.monerails.com/v1/cardholders?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.monerails.com/v1/cardholders?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.monerails.com/v1/cardholders?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.monerails.com/v1/cardholders?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.monerails.com/v1/cardholders?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/cardholders",
"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": "pending",
"reason": null,
"verified_at": null,
"documents_on_file": true
},
"created_at": "2026-10-30T13:47:06.394Z",
"updated_at": "2026-10-30T13:47:06.394Z"
}
],
"has_more": false
}