Products · QR

QR Payments

EMVCo MPM static and dynamic QR codes. Every Djiboutian mobile wallet scans — Waafi, D-Money, CAC, SabaPay, and EAB.

3 endpointsqr_

Two modes

Static QR

Printed, reusable

Generated once per outlet and printed at the point of sale. The customer scans and manually enters the transaction amount in their wallet app. Best for small merchants, market stalls, and low-volume counters.

  • + No API call per transaction
  • + Works offline (QR never expires)
  • Amount not embedded; customer inputs manually
Dynamic QR

Per-transaction, amount embedded

Generated fresh for each transaction with the amount pre-encoded in the EMVCo payload. The customer scans and confirms — no manual entry. Sessions expire after a configurable window (default 5 minutes).

  • + Amount pre-filled — no customer input errors
  • + Idempotent per transaction; no double-pay risk
  • Requires an API call per transaction

How it works — dynamic QR

  1. 1

    Create a QR session

    Call POST /v1/qr/sessions with amount, currency, and provider. Use provider=any for a universal QR that the wallet app resolves automatically.
  2. 2

    Display the QR to the customer

    The response includes qr_data (base64 PNG, ready to render in an <img> tag) and qr_string (the raw EMVCo MPM payload for custom rendering or printing). Show either on screen or on a receipt printer.
  3. 3

    Customer scans with wallet app

    The customer opens their Waafi, D-Money, CAC, SabaPay, or EAB wallet app and scans the QR code. The wallet resolves the EMVCo payload, displays the amount and merchant name for confirmation, then the customer approves.
  4. 4

    Provider confirms payment

    The wallet app sends the payment instruction to the provider. The provider settles the transaction and notifies MerasPay via the provider callback.
  5. 5

    Webhook fires

    MerasPay books the ledger and dispatches a payment_intent.succeeded webhook. The QR session transitions to completed. Poll GET /v1/qr/sessions/{id} or subscribe to the webhook — whichever fits your architecture.

Endpoints

POST/v1/qr/sessions

Create a dynamic QR session with an embedded amount. Returns a PNG and EMVCo payload.

GET/v1/qr/sessions/{id}

Retrieve a session's current status and payment details.

POST/v1/qr/static

Generate a static QR code for a merchant outlet. No expiry — suitable for printing.

Dynamic session — parameters

NameTypeDescription
amount
required
integerMinor units. DJF is zero-decimal; pass integer DJF.
currency
required
ISO 4217"DJF" for domestic. "USD" accepted on international-enabled accounts.
provider
required
enumOne of waafi · dmoney · cac · sabapay · eab · any. Use any to generate a universal QR.
expiry_secondsintegerSession TTL in seconds. Default 300 (5 min). Maximum 3600 (1 hour).
descriptionstring≤140 chars. Appears as the payment reference in the customer's wallet history.
metadatamapFree-form string-string map; round-trips on every response and webhook.
Setting provider=anygenerates a universal QR that the customer's wallet resolves automatically — supported by Waafi and D-Money as of 2026-Q1. Additional wallets are being onboarded; check the changelog for updates.

Static QR — parameters

NameTypeDescription
provider
required
enumOne of waafi · dmoney · cac · sabapay · eab · any.
outlet_labelstringDisplay name embedded in the QR (e.g. "Café Djibouti — Table 4"). ≤60 chars.
merchant_category_codestringISO 18245 MCC (4 digits). Defaults to the merchant account's registered MCC.

Sample — create dynamic session

POST /v1/qr/sessionsbash
curl -X POST https://api.merashub.com/v1/qr/sessions \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: order_99" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 35000,
    "currency": "DJF",
    "provider": "any",
    "expiry_seconds": 300,
    "description": "Order #99 — table service"
  }'
201 Createdjson
{
  "id": "qr_01HZK5GYJX9J4T3WR6K1C0DP7S",
  "status": "pending",
  "amount_minor": 35000,
  "currency": "DJF",
  "provider": "any",
  "qr_string": "00020101021226430014DJ.MERASPAY.COM...",
  "qr_data": "data:image/png;base64,iVBORw0KGgo...",
  "expires_at": "2026-05-25T10:20:30Z",
  "created_at": "2026-05-25T10:15:30Z"
}

Session status states

  • pending

    Session created — QR displayed, awaiting customer scan.

  • scanned

    Customer has scanned the QR; wallet is processing.

  • completed

    Payment confirmed. Ledger booked, webhook fired.

  • expired

    Session TTL elapsed before the customer paid.

  • cancelled

    Merchant cancelled the session before expiry.

Dynamic QR session expiry

Dynamic QR sessions expire after expiry_seconds (default 5 minutes). Once expired, the QR code becomes invalid and the customer cannot pay. Poll GET /v1/qr/sessions/{id} to check status, or subscribe to the qr_session.expired webhook to trigger a UI refresh or new session creation automatically.