Provider · Ethiopia (ETB)

SantimPay direct integration

The Ethiopia corridor. Accept ETB from Telebirr, CBE, and more — either by redirecting the customer to SantimPay's hosted page (default) or by charging a specific channel directly. Amounts are in ETB. Payments settle via the signed notify webhook.

C2BB2CETB

Currency

SantimPay charges in ETB — create the PaymentIntent with currency: "ETB". On the MerasPay hosted checkout / QR, the SantimPay tile only appears on ETB sessions.

1 · Hosted redirect (default)

Create the intent with provider: "santimpay". You get back a next_action.type = "redirect"; send the customer to the redirect_url, where they pick their channel (Telebirr, CBE, …) and pay. No phone or channel is collected on your side.

POST /v1/payment_intentsbash
curl -X POST https://api.merashub.com/v1/payment_intents \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: order_42" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100,
    "currency": "ETB",
    "provider": "santimpay",
    "return_url": "https://yoursite.example/orders/42/return",
    "description": "Order #42"
  }'
Response — redirectjson
{
  "id": "pi_01H...",
  "status": "requires_action",
  "next_action": {
    "type": "redirect",
    "redirect_url": "https://checkout.santimpay.com/..."
  }
}
Redirect, then verify on returnjavascript
// Send the customer to SantimPay's hosted page.
if (intent.next_action?.type === 'redirect') {
  res.redirect(303, intent.next_action.redirect_url);
}

// SantimPay returns them to return_url and fires the notify webhook.
// Confirm the real status server-side — don't trust the return alone:
app.get('/orders/42/return', async (req, res) => {
  const r = await fetch(
    'https://api.merashub.com/v1/payment_intents/' + intentId,
    { headers: { 'Authorization': 'Bearer ' + process.env.MERAS_SECRET_KEY } },
  );
  const fresh = await r.json();
  res.render(fresh.status === 'succeeded' ? 'thank-you' : 'try-again');
});

2 · Direct channel charge (optional)

To skip the hosted page and charge a specific channel, pass metadata.santim_mode: "direct"with the channel and the customer's phone. The customer approves the debit in their wallet app; the payment settles via the notify webhook.

Direct chargebash
curl -X POST https://api.merashub.com/v1/payment_intents \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100,
    "currency": "ETB",
    "provider": "santimpay",
    "customer_msisdn": "251901020309",
    "metadata": { "santim_mode": "direct", "santim_payment_method": "Telebirr" }
  }'
NameTypeDescription
provider
required
stringAlways "santimpay".
amount
required
integerETB, major units (as-is — no minor conversion).
currency
required
stringAlways "ETB".
return_urlstringWhere the customer returns after the hosted page (hosted flow).
customer_msisdnstringRequired for the direct-charge flow; omitted for hosted redirect.
metadata.santim_modestring"direct" for a channel charge; omit (or "redirect") for the hosted page.
metadata.santim_payment_methodstringChannel for the direct charge, e.g. "Telebirr", "CBE".

3 · Payout (B2C)

SantimPay is also the Ethiopia-bound payout rail. Disburse with provider: "santimpay" + metadata.santim_payment_method; the beneficiary phone/account is the receiver.

Webhooks

SantimPay posts a signed notification to your notify URL and MerasPay emits payment_intent.succeeded / payment_intent.payment_failedto your registered webhook endpoint. The notify is verified with SantimPay's public key; treat the webhook (or a fresh GET /v1/payment_intents/:id) as the source of truth — never finalise the order on the return redirect alone.

Amounts are ETB

SantimPay's API has no currency field — the amount is always ETB. Don't route a non-ETB session to SantimPay (a 10 DJF session would be charged as 10 ETB).