Base URLs
Sandbox: https://sandbox-api.slexpay.pk/v1
Production: https://api.slexpay.pk/v1
Checkout host: https://checkout.slexpay.pk
Everything needed to integrate Slex Pay APIs in one place: authentication, endpoints, required parameters, request/response examples, webhook verification, retries, and production readiness controls.
Sandbox: https://sandbox-api.slexpay.pk/v1
Production: https://api.slexpay.pk/v1
Checkout host: https://checkout.slexpay.pk
Header: Authorization: Bearer <SECRET_KEY>
Optional: X-Client-Id: <PUBLIC_ID>
Content-Type: application/json
Authorization (required) - your API secret key.Content-Type (required) - must be application/json.X-Idempotency-Key (recommended for write operations) - unique UUID per create/refund request.X-Request-Id (optional) - your own trace ID for support and debugging.User-Agent (recommended) - app name and version for easier diagnostics.Authorization: Bearer sk_live_xxxxxxxxx
Content-Type: application/json
X-Idempotency-Key: 6a39f276-13d0-4f5a-8cd2-7c9a43f85739
X-Request-Id: order_9483_create_payment
Create an order first. This gives a stable commerce reference before payment initiation.
Endpoint: POST /orders
merchant_order_id - unique order ID from your system.amount - decimal amount in PKR (e.g., 2500.00).currency - currently PKR.customer.name - payer full name.customer.email or customer.phone - at least one contact field required.return_url - where the customer is redirected after checkout.description - order description for statement/reference.metadata - JSON object for your internal tags (max 20 keys).expires_at - ISO timestamp to auto-expire unpaid order.curl --request POST "https://sandbox-api.slexpay.pk/v1/orders" \
--header "Authorization: Bearer sk_test_xxx" \
--header "Content-Type: application/json" \
--header "X-Idempotency-Key: 3f9398f4-55dd-4fd1-a33b-17ee3157b2cf" \
--data '{
"merchant_order_id": "ORD-100245",
"amount": "2500.00",
"currency": "PKR",
"description": "Premium subscription - April",
"customer": {
"name": "Jhon",
"email": "Jhon@example.com",
"phone": "+923001112233"
},
"return_url": "https://merchant-site.com/payment/return",
"metadata": {
"plan": "premium",
"source": "web_checkout"
}
}'
{
"id": "ord_6f4b770f95b84d99",
"merchant_order_id": "ORD-100245",
"status": "created",
"amount": "2500.00",
"currency": "PKR",
"created_at": "2026-05-05T16:19:31Z"
}
Use the order ID to create a customer checkout session.
Endpoint: POST /payments/sessions
order_id - value returned from /orders.channel - requested payment route (e.g., card, wallet, raast).callback_url - backend endpoint for asynchronous callback (recommended with webhooks).allowed_methods - restrict methods list shown on checkout.customer_ip - risk telemetry hint.language - checkout language preference, e.g. en.POST /v1/payments/sessions
{
"order_id": "ord_6f4b770f95b84d99",
"channel": "card",
"callback_url": "https://merchant-site.com/api/slexpay/callback",
"allowed_methods": ["card", "wallet"],
"language": "en"
}
{
"payment_session_id": "ps_31b8f15b84384f88",
"checkout_url": "https://checkout.slexpay.pk/session/ps_31b8f15b84384f88",
"expires_at": "2026-05-05T17:19:31Z"
}
Endpoint: GET /payments/{payment_id}
Always verify status server-to-server before final order fulfillment.
created - payment record initialized.processing - authorization in progress.succeeded - confirmed successful payment.failed - unsuccessful attempt.cancelled - customer aborted checkout.expired - session expired before payment.refunded - payment refunded in full.partially_refunded - payment partially refunded.Endpoint: POST /payments/{payment_id}/refunds
amount - refund amount (must be less than or equal to captured amount).reason - merchant-defined reason string.metadata - additional internal fields.{
"amount": "500.00",
"reason": "Customer requested partial return",
"metadata": {
"ticket_id": "SUP-8285"
}
}
Webhooks send real-time event notifications to your backend endpoint.
Configure URL: merchant dashboard -> Developers -> Webhooks
Method: POST with JSON body
Signature header: X-Slexpay-Signature
payment.succeededpayment.failedpayment.expiredrefund.processeddispute.opened{
"id": "evt_9b0f2ec6545b4e8a",
"type": "payment.succeeded",
"created_at": "2026-05-05T16:22:11Z",
"data": {
"payment_id": "pay_8ea9da7a0f5f4d57",
"order_id": "ord_6f4b770f95b84d99",
"merchant_order_id": "ORD-100245",
"amount": "2500.00",
"currency": "PKR",
"status": "succeeded"
}
}
Always verify webhook signatures before accepting event payloads.
// Pseudocode
raw_body = request.rawBody
signature = request.headers["x-slexpay-signature"]
expected = HMAC_SHA256(raw_body, WEBHOOK_SECRET)
if !constant_time_equals(signature, expected):
return 401
process_event(raw_body)
event_id to avoid duplicate processing.200 then process asynchronously.All API errors return consistent JSON with machine-readable error codes.
{
"error": {
"code": "invalid_request",
"message": "amount must be greater than 0",
"field": "amount",
"request_id": "req_7d65fd1fdfe047ee"
}
}
authentication_failed - invalid or missing API key.invalid_request - malformed payload or missing required field.resource_not_found - ID does not exist.conflict - duplicate action or idempotency collision.rate_limited - too many requests.internal_error - temporary server-side failure; retry with backoff.429 and 5xx responses.Retry-After when present.const res = await fetch("https://sandbox-api.slexpay.pk/v1/orders", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.SLEXPAY_SECRET,
"Content-Type": "application/json",
"X-Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
merchant_order_id: "ORD-100245",
amount: "2500.00",
currency: "PKR",
customer: { name: "Jhon", email: "Jhon@example.com" },
return_url: "https://merchant-site.com/payment/return"
})
});
$payload = [
"merchant_order_id" => "ORD-100245",
"amount" => "2500.00",
"currency" => "PKR",
"customer" => ["name" => "Jhon", "email" => "Jhon@example.com"],
"return_url" => "https://merchant-site.com/payment/return"
];
$ch = curl_init("https://sandbox-api.slexpay.pk/v1/orders");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("SLEXPAY_SECRET"),
"Content-Type: application/json",
"X-Idempotency-Key: " . uniqid("idem_", true)
],
CURLOPT_POSTFIELDS => json_encode($payload)
]);
merchant_order_id (string, required) - merchant-side unique key; max 64 chars.amount (string decimal, required) - two-decimal currency amount in PKR.currency (string, required) - must be PKR.description (string, optional) - internal/business description shown in logs.customer.name (string, required) - payer display name.customer.email (string, optional) - RFC-valid email for receipts.customer.phone (string, optional) - E.164 preferred, e.g. +923001112233.return_url (url, required) - post-checkout redirection endpoint.metadata (object, optional) - max 20 keys, string values recommended.order_id (string, required) - order token returned by create order API.channel (string, required) - selected channel intent for checkout routing.callback_url (url, required) - server URL for async callback handshake.allowed_methods (array, optional) - method allowlist in checkout UI.language (string, optional) - locale hint for checkout rendering.id - unique event ID, use for idempotent event processing.type - event type key (e.g., payment.succeeded).created_at - event time in UTC ISO timestamp.data.payment_id - transaction ID for verification API.data.order_id - internal order token mapped to your merchant order.Use deterministic test amounts in sandbox to validate your handling logic:
100.00 - force payment.succeeded scenario.101.00 - force payment.failed scenario.102.00 - force payment.expired scenario.103.00 - delayed confirmation; verify polling and webhook reconciliation.104.00 - duplicate webhook replay; confirm dedupe by event ID.These controlled cases help ensure your fulfillment logic and retry system are safe before production launch.
5xx, 429, and webhook signature failures.If you are migrating from another gateway, use this phased rollout model to avoid disruption:
Keep rollback toggles ready during migration so you can route traffic safely if any dependency degrades.
No. Always confirm using webhook + status API verification before fulfillment.
No. Generate a unique key per logical write operation and reuse only for retries of the same payload.
This is normal. Webhook is your source of truth for backend payment state.
Yes, until cumulative refunded amount reaches captured total amount.
Before going live, our team can review your request flow, webhook handling, retry logic, and error states.
Create keys, rotate secrets, register webhook URLs, and monitor API activity from your merchant panel.
Tip: keep API secrets server-side only. Never expose secret keys in frontend JavaScript, mobile apps, or public repositories.