Somali

Developers

Pay with EXELO, on your own site

Your checkout button sends the cart to EXELO. Your customer pays with Zaad or eDahab on the EXELO page, comes back to your site, and your server is told the order is paid. The sale, GST, receipt and your payout are handled by EXELO, like any sale at your till.

  • ~45 min to go live
  • 1 file on your server
  • 1 line on your page

1 Get your keys 5 min

In the EXELO app: Profile → Integrations → Create API key. Copy theexk_live_… key and the whsec_… webhook secret. They are shown once; keep them on your server only, never in your page.

Only the wallets your shop has verified in EXELO are offered to customers.

2 Put one file on your server 20 min

PHP: download exelo-checkout.php, paste your two keys at the top, and fill exelo_cart() from your order andexelo_paid() to mark it paid. Upload it next to your shop.

Any other language: create a session from your server (Node example):

// POST /exelo-checkout?order=1042  (your server)
app.post("/exelo-checkout", async (req, res) => {
  const order = await db.orders.find(req.query.order);
  const r = await fetch("https://exelo-api-5xhuqz5x7q-bq.a.run.app/api/v1/checkout/sessions", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + process.env.EXELO_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      reference: order.id,
      currency: "SLSH",                       // or "USD"
      items: order.lines.map(l => ({ name: l.name, quantity: l.qty, price: l.price })),
      success_url: "https://your-shop.so/thanks",
      cancel_url:  "https://your-shop.so/cart",
      webhook_url: "https://your-shop.so/exelo-webhook",
    }),
  });
  const { data } = await r.json();
  res.json({ url: data.url });            // the button takes the customer there
});

3 Add the button 5 min

<script src="https://exelo.app/js/exelo-pay.js" defer></script>

<button data-exelo-checkout="/exelo-checkout.php?order=1042">
  Pay with EXELO
</button>

The script styles the button, asks your server for a session and takes the customer to the EXELO pay page. Add data-exelo-style="none" to keep your own button style.

4 Mark the order paid 10 min

When the customer has paid, EXELO sends checkout.session.paid to yourwebhook_url (HTTPS) and the customer returns to success_url with?exelo_session=cs_…. Trust the webhook, not the return: it is signed.

Exelo-Signature: t=1792300000,v1=5f2c…

valid = hmac_sha256(webhook_secret, t + "." + raw_body) == v1   // and t within 10 minutes
{
  "id": "evt_…",
  "type": "checkout.session.paid",
  "data": {
    "session_id": "cs_…",
    "reference": "1042",
    "status": "paid",
    "paid_at": "2026-10-18T09:41:00+00:00",
    "receipt_no": "INV-381",
    "currency": "SLSH",
    "subtotal": { "amount": 59000, "display": "59,000 SLSH" },
    "gst":      { "amount": 1475,  "display": "1,475 SLSH" },
    "total":    { "amount": 60475, "display": "60,475 SLSH" },
    "items": [ { "name": "Rice 5kg", "quantity": 2, "price": 25000 } ]
  }
}

Answer 2xx to accept it. Otherwise EXELO retries after 1, 5 and 30 minutes, then 2, 6 and 24 hours. The same event may arrive twice: mark the order paid once.

API reference

POST /checkout/sessions

Authorization: Bearer exk_live_… · base URL https://exelo-api-5xhuqz5x7q-bq.a.run.app/api/v1

FieldType
items[]name, quantity, priceRequired, 1–100 lines. Price before GST, per unit.
currencySLSH · USDSLSH in whole shillings; USD in dollars with cents (e.g. 12.50).
referencestringYour order number, sent back in the webhook.
success_urlURLWhere the customer goes after paying.
cancel_urlURL“Back to the shop” on the pay page.
webhook_urlHTTPS URLReceives checkout.session.paid.
expires_in_minutes5–1440Default 60.

Returns 201 with id, url, status(open, paid, expired), subtotal,gst and total. GST is added on top of your prices.

GET /checkout/sessions/{id}

The same object, to check a payment from your server.

Go-live checklist

  • Your keys are on the server only, not in the page or a public repository.
  • Your webhook URL is HTTPS and checks the signature.
  • You made one small real payment and saw the order turn paid.
  • Lost a key? Revoke it in Integrations and create a new one.