Skip to content

Initialize a payment

POST/v1/payments/initialize

Creates a new payment transaction. If an operator is specified, the payment is processed immediately. Otherwise, a checkout URL is returned.

Headers

HeaderRequiredDescription
AuthorizationYesBearer zyn_test_... or Bearer zyn_live_...
Content-TypeYesapplication/json
X-Idempotency-KeyNoUUID v4 to avoid duplicates

Parameters

ParametreTypeRequisDescription
amountnumberRequisPayment amount (minimum: 1, maximum: 10,000,000)
currencystringRequisISO 4217 currency code (e.g. XOF, XAF, GHS)
descriptionstringRequisPayment description (max 255 characters)
return_urlstringRequisRedirect URL after payment (max 500 characters)
customerobjectRequisCustomer information
customer.emailstringRequisCustomer email address (max 255)
customer.first_namestringRequisCustomer first name (max 100)
customer.last_namestringRequisCustomer last name (max 100)
customer.phonestringOptionnelInternational phone number (regex ^\+?[0-9]{8,15}$)
customer.countrystringOptionnelISO 3166-1 alpha-2 country code
metadataobjectOptionnelCustom data (key-value pairs)
methodsarrayOptionnelFilter accepted payment methods
operatorstringOptionnelOperator code (e.g. mtn_bj). If specified, the payment is processed immediately.

Examples

bash
curl -X POST https://backend.zayono.com/api/v1/payments/initialize \
  -H "Authorization: Bearer zyn_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "amount": 5000,
    "currency": "XOF",
    "description": "Premium subscription - March 2025",
    "return_url": "https://your-site.com/payment/return",
    "customer": {
      "email": "jean.dupont@example.com",
      "first_name": "Jean",
      "last_name": "Dupont",
      "phone": "+22990123456"
    },
    "operator": "mtn_bj",
    "metadata": {
      "order_id": "ORD-2025-001",
      "plan": "premium"
    }
  }'
javascript
const response = await fetch('https://backend.zayono.com/api/v1/payments/initialize', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer zyn_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    'Content-Type': 'application/json',
    'X-Idempotency-Key': '550e8400-e29b-41d4-a716-446655440000',
  },
  body: JSON.stringify({
    amount: 5000,
    currency: 'XOF',
    description: 'Premium subscription - March 2025',
    return_url: 'https://your-site.com/payment/return',
    customer: {
      email: 'jean.dupont@example.com',
      first_name: 'Jean',
      last_name: 'Dupont',
      phone: '+22990123456',
    },
    operator: 'mtn_bj',
    metadata: {
      order_id: 'ORD-2025-001',
      plan: 'premium',
    },
  }),
})

const data = await response.json()
php
$response = Http::withToken('zyn_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
    ->withHeaders(['X-Idempotency-Key' => '550e8400-e29b-41d4-a716-446655440000'])
    ->post('https://backend.zayono.com/api/v1/payments/initialize', [
        'amount' => 5000,
        'currency' => 'XOF',
        'description' => 'Premium subscription - March 2025',
        'return_url' => 'https://your-site.com/payment/return',
        'customer' => [
            'email' => 'jean.dupont@example.com',
            'first_name' => 'Jean',
            'last_name' => 'Dupont',
            'phone' => '+22990123456',
        ],
        'operator' => 'mtn_bj',
        'metadata' => [
            'order_id' => 'ORD-2025-001',
            'plan' => 'premium',
        ],
    ]);

Responses

201 — Payment initialized

json
{
  "message": "Payment initialized successfully.",
  "data": {
    "id": "9e5f6a7b-8c9d-4e3f-a1b2-c3d4e5f6a7b8",
    "status": "initiated",
    "amount": 5000,
    "currency": "XOF",
    "checkout_url": null,
    "return_url": "https://your-site.com/payment/return",
    "created_at": "2025-05-15T10:30:00+00:00"
  },
  "errors": null
}

Fees passed on to the customer

If the selected method has a fee_percent configured on your account, the amount charged to the customer is automatically increased. You can fetch the breakdown (amount, amount_charged, fee_percent) by calling GET /v1/payments/{id} after initialization or by listening to the payment.successful webhook which includes these fields.

About checkout_url

For Mobile Money payments, checkout_url is always null — the flow runs through an OTP on the customer's phone, with no web redirect. For card payments or for the few operators that require an intermediate page (rare), checkout_url contains the URL to redirect the customer to.

If you want a hosted payment page in every case (with operator selection on the customer side), use the dedicated POST /v1/checkout/initialize endpoint instead — its response always populates checkout_url.

202 — Accepted but processing failed

The payment was created but the aggregator could not process it. A retry will be attempted via fallback or webhook.

json
{
  "message": "Payment initialized but processing failed. Will retry via fallback or webhook.",
  "data": {
    "transaction": {
      "id": "9e5f6a7b-8c9d-4e3f-a1b2-c3d4e5f6a7b8",
      "status": "initiated",
      "amount": 5000,
      "currency": "XOF",
      "checkout_url": null,
      "return_url": "https://your-site.com/payment/return",
      "created_at": "2025-05-15T10:30:00+00:00"
    },
    "aggregator_error": "Timeout connecting to aggregator API"
  },
  "errors": null
}

422 — Validation error

json
{
  "message": "Validation failed.",
  "data": null,
  "errors": {
    "amount": ["The amount field is required."],
    "customer.email": ["The customer.email field is required."]
  }
}

401 — Not authenticated

json
{
  "message": "Invalid or missing API key.",
  "data": null,
  "errors": null
}

Official Zayono API documentation