Quick start
This guide takes you from a developer account to your first charge, in the sandbox: no real money is used. The examples are provided in cURL, JavaScript (Node.js 18 or later), Python (requests library) and PHP (cURL extension). Your language choice is remembered on every page.
-
Create your developer account on the developer dashboard (the “Developer space”): full name, company (optional), phone, email and password, then accept the terms of use. Once your email address is confirmed, your test key is available.
Store it in an environment variable, never in your code:
Terminal window export SAMA_API_KEY="YOUR_TEST_KEY" -
Check the connection to the API:
Terminal window curl -sS https://api.sama.money/v1/health/auth \-H "Authorization: Bearer $SAMA_API_KEY"check.mjs const response = await fetch("https://api.sama.money/v1/health/auth", {headers: { Authorization: `Bearer ${process.env.SAMA_API_KEY}` },});console.log(response.status, await response.json());check.py import osimport requestsresponse = requests.get("https://api.sama.money/v1/health/auth",headers={"Authorization": f"Bearer {os.environ['SAMA_API_KEY']}"},timeout=30,)print(response.status_code, response.json())check.php <?php$ch = curl_init("https://api.sama.money/v1/health/auth");curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,CURLOPT_TIMEOUT => 30,CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SAMA_API_KEY")],]);$body = curl_exec($ch);echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $body, PHP_EOL;curl_close($ch);Expected response:
{"status":"ok","mode":"test"}An error response means the
Authorizationheader is missing, or the key is badly copied. -
Create a first charge: you ask for 5,000 F from a test customer. In the sandbox, the charge stays pending (
pending) until the customer confirms it on their phone.Terminal window curl -sS -X POST https://api.sama.money/v1/charges \-H "Authorization: Bearer $SAMA_API_KEY" \-H "Idempotency-Key: $(uuidgen)" \-H "Content-Type: application/json" \-d '{"client_phone": "22370000000","amount_xof": 5000,"description": "Order 42"}'charge.mjs import { randomUUID } from "node:crypto";const response = await fetch("https://api.sama.money/v1/charges", {method: "POST",headers: {Authorization: `Bearer ${process.env.SAMA_API_KEY}`,"Idempotency-Key": randomUUID(),"Content-Type": "application/json",},body: JSON.stringify({ client_phone: "22370000000", amount_xof: 5000, description: "Order 42" }),});const data = await response.json();if (!response.ok) throw new Error(`${data.error?.code} (request ${data.error?.request_id})`);console.log(data);charge.py import osimport uuidimport requestsresponse = requests.post("https://api.sama.money/v1/charges",headers={"Authorization": f"Bearer {os.environ['SAMA_API_KEY']}","Idempotency-Key": str(uuid.uuid4()),},json={"client_phone": "22370000000", "amount_xof": 5000, "description": "Order 42"},timeout=30,)data = response.json()if not response.ok:raise SystemExit(f"{data['error']['code']} (request {data['error']['request_id']})")print(data)charge.php <?phpfunction uuid_v4(): string {$b = random_bytes(16);$b[6] = chr((ord($b[6]) & 0x0f) | 0x40);$b[8] = chr((ord($b[8]) & 0x3f) | 0x80);return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($b), 4));}$ch = curl_init("https://api.sama.money/v1/charges");curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,CURLOPT_TIMEOUT => 30,CURLOPT_POST => true,CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SAMA_API_KEY"),"Idempotency-Key: " . uuid_v4(),"Content-Type: application/json",],CURLOPT_POSTFIELDS => json_encode(["client_phone" => "22370000000","amount_xof" => 5000,"description" => "Order 42",]),]);$body = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);echo $status, " ", $body, PHP_EOL;The API answers
200with the pending charge:{"reference": "chg_8f3a1c9e2b7d4e60a1c3","object": "charge","mode": "test","amount_xof": 5000,"currency": "XOF","client_phone": "22370000000","status": "pending","description": "Order 42","partner_reference": null,"account": null,"error_message": null,"created": 1790848800}Keep the
reference: it identifies the charge inGET /v1/charges/{reference}. Other fields may be added to the response: ignore the ones you do not know.
For what comes next (registering the address that receives your notifications, simulating the customer’s confirmation in the sandbox, reading back the state of a charge), see the Reference, reserved for registered developers. To go live: Accounts and verification.
Three rules to remember
Section titled “Three rules to remember”- Idempotency: send an
Idempotency-Keyheader (one UUID per operation) on every money-moving operation. Replaying the same request with the same key returns the same result. - Amounts: integers in CFA francs (
amount_xof), with no decimals. - Asynchronous: the customer confirms, not you. Never ship an order for a request that is still
pending: wait for the notification or readGET /v1/charges/{reference}again.
- Collect a payment: the full flow, failure cases included.

