1Create integration keys
Sign in and open API & integrations. Enter the public HTTPS URL of your store server's webhook route, then keep the API key and webhook secret as server-only secrets.
Open integration settings →MUAKKAD_API_KEY=mk_live_...MUAKKAD_WEBHOOK_SECRET=whsec_...
2Enable payment methods
Create and enable payment methods in Muakkad's Store settings. Every active method appears in checkout so the customer can choose.
Open Store settings →3Create a checkout, then redirect
Your website creates a unique order reference, sends it as order_reference, and sends the correct amount from the customer's cart. Muakkad does not generate the order reference or amount, and the customer chooses from all active payment methods. Repeating the same request with identical details safely returns the existing checkout.
curl -X POST https://api.muakkad.com/v1/checkouts \
-H "X-API-Key: mk_live_..." \
-H "Content-Type: application/json" \
-d '{"amount":"250.00",
"order_reference":"ORDER-1042",
"return_url":"https://store.example.com/thanks"}'
Successful response · 201
{
"id": "CHECKOUT_UUID",
"order_reference": "ORDER-1042",
"amount": "250.00",
"currency": "EGP",
"status": "pending",
"checkout_url": "https://www.muakkad.com/checkout/CHECKOUT_UUID",
"created_at": "2026-09-25T10:00:00Z",
"expires_at": "2026-09-26T10:00:00Z",
"confirmed_at": null
}
Redirect the customer to checkout_url. Do not treat the browser return as proof of payment; use the webhook or retrieve the status.
4Verify the result
Muakkad sends X-Muakkad-Signature as t=timestamp,v1=digest. Compute HMAC-SHA256 over timestamp + a dot + the raw request body and compare in constant time.
import crypto from "node:crypto";
// Configure this route to receive the unparsed request body.
const signature = request.headers["x-muakkad-signature"];
const [timestampPart, digestPart] = signature.split(",");
const timestamp = timestampPart.slice(2);
const received = digestPart.slice(3);
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (age > 300) throw new Error("Stale webhook");
const expected = crypto
.createHmac("sha256", process.env.MUAKKAD_WEBHOOK_SECRET)
.update(timestamp + "." + rawBody)
.digest("hex");
if (received.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected)))
throw new Error("Invalid webhook signature");
Return HTTP 2xx after persisting the event. On a timeout or non-2xx response, Muakkad retries by default after roughly 30 seconds with jittered exponential backoff up to one hour, for at most 12 attempts. Use X-Muakkad-Delivery to deduplicate retries and X-Muakkad-Event for the event type.
Fallback status lookup
curl https://api.muakkad.com/v1/checkouts/ORDER-1042 \
-H "X-API-Key: mk_live_..."
5How to test the integration
- Create and enable payment methods in Store settings, then create integration keys with a public HTTPS test webhook URL.
- Create a checkout from your website server using a unique order reference and the amount calculated by your website.
- Open checkout_url, let the customer choose a payment method, and submit the transfer details.
- Verify that the webhook arrives and its signature is valid.
- Run the status lookup and confirm status matches confirmed or rejected.
Quick reference
POST /v1/checkoutsCreate checkoutGET /v1/checkouts/{order_reference}Retrieve checkout status
Every route requires X-API-Key. Terminal statuses are confirmed, rejected, and expired; pending or manual_review may appear while processing.