Payment Gateway Service
Collect payments from your users — mobile money (Orange Money, MTN MoMo, KULU, …) and card — directly from the apps you deploy on kuploy-cloud. Pick "Payment Gateway" from the + Create Service menu and your project gets a hosted checkout endpoint plus APIs your apps can call.
The Payment Gateway service is available only when your kuploy-cloud host has enabled it. If you don't see Payment Gateway in the service-type picker, ask your platform admin — they may be on a plan that doesn't include it, or they may not have finished configuring it yet.
The complete merchant integration reference — POST /api/pay, webhook payloads, field mapping, payment links, subscriptions, sandbox testing — lives at docs.epay-gateway.com/merchant. That site is gated; ask your platform admin for an invite once your Payment Gateway service is live.
What you get
When you add a Payment Gateway to a project, the service settings panel shows:
| Item | Purpose |
|---|---|
| Merchant code | Unique identifier for your org inside the gateway. Pass it on every API call. Copy-to-clipboard in the panel. Shows Provisioning… for a moment right after you create the service — refresh shortly. |
| Webhook signing key | The HMAC-SHA256 secret used to sign the x-epay-signature header on every payment event delivered to your webhook. Reveal/copy it from the panel and use it to verify incoming events. Keep it secret. |
| Checkout URL | Canonical POST /api/pay endpoint on your platform's gateway. Your backend redirects customers here to complete payment. |
| Payment methods | Toggle which methods are enabled for your merchant (Orange Money, MoMo, Card, KULU, …). The list is driven by whatever your platform admin has configured on the gateway — so new methods appear automatically as your platform adds them. |
| Webhook URL | Where payment events for your app are delivered. Editable any time. |
You configure the details inside the service settings panel — no platform-admin help required once the service is created.
Your organization has a single merchant identity. If you add the Payment Gateway service to more than one project, they all share the same merchant code and signing key — payment events for the org are delivered to every webhook URL you've configured across those services.
Create a Payment Gateway service
- Open your project in the kuploy-cloud dashboard.
- Click + Create Service and choose Payment Gateway.
- Give the service a descriptive name (shown in dashboards; usually the name of the app it will serve).
- Pick the payment methods you want to enable. You can change this later.
- Optionally set a webhook URL — an endpoint on one of your deployed apps that the gateway can POST to when something happens (payment succeeded, subscription renewed, etc.).
- Click Create. Your platform provisions a merchant identity for your org and wires everything up. The merchant code may show Provisioning… for a few moments on first creation — refresh the panel and it appears.
Accepting a one-off payment
From your app's backend, redirect the customer to the hosted checkout:
POST https://<gateway-host>/api/pay?merchantCode=<your-merchant-code>
amount=1000
currency=XOF
reference=order-12345
returnUrl=https://yourapp.example/thanks
The gateway shows a counter, the customer picks a method (Orange Money, MoMo, Card, …), and on success your app is notified through the webhook you configured above. Full field reference in the epay-gateway payment integration docs.
Always pass your own reference (an order ID, invoice ID, whatever anchors the payment in your own system). It comes back on every webhook and lets your app match payments to records without parsing anything brittle.
Recurring subscriptions
The service also supports recurring billing — useful if your app has paid tiers of its own. From your backend:
- Create a plan with a price and a billing interval via the service's API.
- On sign-up, call the subscription API with the customer's identifier and your plan ID.
- React to
customer.subscription.*andinvoice.*events at your webhook endpoint.
The management API shape — including the full subscription-lifecycle events — is documented at docs.epay-gateway.com/merchant/subscriptions. Access is invite-only; ask your platform admin if you need credentials.
Reacting to webhook events
The gateway emits Stripe-shaped events so the same handling code works for both native card subscriptions and mobile-money subscriptions. The events you'll usually care about:
| Event | Meaning for your app |
|---|---|
customer.subscription.created | New subscription is live; unlock the paid features. |
customer.subscription.updated | Plan change, renewal, or status flip — re-check what the customer can access. |
customer.subscription.deleted | Subscription was canceled; revoke paid features at end of period. |
invoice.payment_succeeded | Money landed; clear any past-due state on your side. |
invoice.payment_failed | Payment failed; decide whether to dunning/email the customer. |
Every event carries metadata.externalReference — set that to your own customer or subscription ID when you create the subscription, then you can ignore the rest of the payload if you want.
Verifying event signatures
Every event delivered to your webhook carries an x-epay-signature header: a lowercase-hex HMAC-SHA256 of the exact raw request body, keyed with your Webhook signing key (the secret shown in the service panel). There is no timestamp envelope.
Verify it before trusting any payload — compute the HMAC over the raw body and compare in constant time:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, signatureHeader, signingKey) {
const expected = createHmac("sha256", signingKey).update(rawBody).digest("hex");
if (!signatureHeader || expected.length !== signatureHeader.length) return false;
return timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}
Compute the HMAC over the unparsed request body — re-serializing parsed JSON can change bytes (key order, spacing) and break the check. Read the raw body first, verify, then parse. Reject any request whose signature doesn't match.
kuploy-cloud receives each event from the gateway, verifies it, and relays it verbatim (same body, same x-epay-signature) to the webhook URL(s) you configured. Because the signature is keyed with your signing key, you verify it directly — exactly as if the gateway delivered to you. Your webhook must be publicly reachable.
Managing payment methods
In the service settings, the Payment Methods section lists every method your platform supports. Toggle individual methods on or off per merchant — useful when you want to, say, launch with Orange Money and MoMo first, then enable cards later.
Changes take effect on the next payment: already-initiated checkouts keep their original method list.
Tearing down
To remove the Payment Gateway service from a project, open its settings and click Delete Service. The local binding is cleared immediately. Because your org has a single shared merchant, it is only released once you remove your last Payment Gateway service — until then, your other services keep using the same merchant code and signing key. Any in-flight payments or active subscriptions tied to the merchant stop when it's released — migrate customers first if you have active recurring billing.
Known limitations
These pieces exist conceptually but aren't fully surfaced in the UI yet. The integration paths above all work around them today.
- Invoice PDFs — payment history renders as a transaction list. Downloadable PDF invoices (with line items, tax breakdown, hosted receipt URL) land when your payment gateway's invoice engine ships — at that point they appear automatically in the service settings without any code change on your side.
- Self-serve customer portal for your end-users — today, your app is responsible for its own "update card" / "cancel subscription" UI by calling the gateway's management API. A hosted portal page your customers can visit directly is being built on the payment gateway; when live, it'll be available per merchant at a URL the service panel surfaces.
- Refunds, disputes, tax — not yet exposed through the gateway's management API. If you need one of these before it ships, contact your platform admin — they can act on your behalf from the gateway admin console.
For the full, current state of what the payment gateway itself supports, see the canonical reference at docs.epay-gateway.com/merchant. Access is invite-only; ask your platform admin.
Common pitfalls
- "Payment Gateway" doesn't appear in + Create Service — your host either doesn't offer the feature on their plan yet, or the platform admin hasn't finished configuring it. Ask them.
- Checkout URL returns an error — double-check the
merchantCodequery parameter matches exactly what the service settings panel shows; codes are case-sensitive. - No webhook hits — set a Webhook URL in the service settings (events are only relayed once it's configured), and make sure it's publicly reachable. Test it with
curlfrom outside your network. Note that internal/loopback/private-network URLs (localhost,10.x,192.168.x,*.internal, …) are refused for safety. - Signature check fails — verify against the raw request body using the Webhook signing key from the panel (not the merchant code), as shown in Verifying event signatures.