Integrate with the Paymob (Accept) payment API for Egyptian payments. Use this skill whenever the user wants to accept payments in Egypt, integrate Paymob into their app, handle EGP transactions, create payment orders, generate payment keys, process card and wallet payments, manage refunds, or work with Paymob's API in any way. Also trigger when the user mentions 'Paymob', 'Accept Egypt', 'Egyptian payments', 'EGP checkout', 'mobile wallet payments', 'kiosk payments', 'cash collection', or needs payment solutions for Egypt.
Paymob, operating as Accept, is Egypt's leading payment gateway, processing payments in EGP (Egyptian Pound) and supporting debit/credit cards, mobile wallets (Vodafone, Etisalat, Orange), bank transfers, kiosk payments, and various BNPL providers. It powers online and offline payments for businesses across Egypt with a comprehensive REST API.
You're building something that needs to accept payments in Egypt — an e-commerce checkout, a subscription service, a marketplace, digital services, invoicing platforms, or anything that touches money movement in Egypt. Paymob handles card payments, mobile wallet integration, bank transfers, kiosk payments, cash collection, and provides powerful order management capabilities.
Paymob uses a two-step authentication flow. First, you authenticate with your API key to get an auth token (valid for 1 hour), then use that token for subsequent API calls.
Base URL: https://accept.paymob.com/api
Store your API key securely in environment variables like PAYMOB_API_KEY. Never hardcode API keys in your source code.
Exchange your API key for an auth token that's valid for one hour. This is the first step in every payment flow.
Endpoint:
POST /auth/tokens
Request:
{
"api_key": "your_api_key_here"
}
Response:
{
"profile": {
"id": 12345,
"created_at": "2023-01-01T00:00:00Z",
"coins": 0,
"staging": false
},
"token": "nJWzxxxxxxxxxxxxxxxxxxxxxxxx"
}
Store the token value for use in subsequent requests. Implement caching to avoid requesting new tokens unnecessarily.
Initialize an order for payment processing. This order holds transaction details until payment is processed.
Endpoint:
POST /ecommerce/orders
Headers:
Authorization: Bearer {token}
Content-Type: application/json
Request:
{
"auth_token": "{token}",
"delivery_needed": false,
"currency": "EGP",
"amount_cents": 500000,
"merchant_order_id": "ORD-2025-12345",
"items": [
{
"name": "Premium Subscription",
"amount_cents": 500000,
"description": "1 month access",
"quantity": "1"
}
]
}
Important: All amounts in the API are in cents, not pounds. For example, 5000 EGP = 500,000 cents.
Response:
{
"id": 987654321,
"merchant_order_id": "ORD-2025-12345",
"amount_cents": 500000,
"currency": "EGP",
"paid": false,
"pending": false,
"delivery_status": null,
"created_at": "2025-02-23T10:00:00Z"
}
Save the id from the response — you'll need it to generate a payment key.
Create a secure payment key that customers use to access the checkout. The payment key is valid for 30 minutes.
Endpoint:
POST /acceptance/payment_keys
Headers:
Authorization: Bearer {token}
Content-Type: application/json
Request:
{
"auth_token": "{token}",
"order_id": 987654321,
"billing_data": {
"apartment": "Apt 5",
"email": "[email protected]",
"floor": "2",
"first_name": "Ahmed",
"street": "123 Main St",
"building": "20",
"phone_number": "+201234567890",
"postal_code": "11111",
"city": "Cairo",
"country": "EG",
"last_name": "Hassan",
"state": "Cairo"
},
"currency": "EGP",
"integration_id": 123456,
"amount_cents": 500000
}
Key fields:
integration_id: The ID for your payment method (cards, wallet, etc.). Found in Paymob dashboard under Developers > Payment Integrations.billing_data: Customer information for the paymentamount_cents: Must match the order amount exactlyResponse:
{
"profile": {
"id": 12345
},
"redirect_url": "https://accept.paymob.com/api/acceptance/iframes/...",
"token": "ZXhhbXBsZV9wYXltZW50X2tleQ=="
}
Options for using the payment key:
redirect_url where they enter payment detailsGet the current state of an order and all associated payments.
Endpoint:
GET /ecommerce/orders/{order_id}
Headers:
Authorization: Bearer {token}
Response:
{
"id": 987654321,
"merchant_order_id": "ORD-2025-12345",
"amount_cents": 500000,
"currency": "EGP",
"paid": true,
"pending": false,
"payments": [
{
"id": 1234567890,
"amount_cents": 500000,
"currency": "EGP",
"is_auth": true,
"pending": false,
"paid": true,
"created_at": "2025-02-23T10:05:00Z"
}
],
"created_at": "2025-02-23T10:00:00Z"
}
Issue a refund for a completed payment.
Endpoint:
POST /acceptance/payments/{payment_id}/refund
Headers:
Authorization: Bearer {token}
Content-Type: application/json
Request:
{
"auth_token": "{token}"
}
Response:
{
"id": 1234567890,
"order": {
"id": 987654321,
"merchant_order_id": "ORD-2025-12345"
},
"amount_cents": 500000,
"currency": "EGP",
"is_refund": true,
"pending": false,
"created_at": "2025-02-23T10:10:00Z"
}
Paymob sends webhooks to your endpoint whenever payment events occur. Configure your webhook URL in the Paymob dashboard (Settings > Webhook) and verify incoming requests with HMAC-SHA512 signature verification.
Paymob sends webhooks for various transaction events:
charge.success — Payment completed successfullycharge.failed — Payment attempt failedcharge.refunded — Refund processedpayment.approved — Payment approved by bankpayment.denied — Payment denied by bankAlways verify the webhook signature to ensure the request came from Paymob. Use HMAC-SHA512 with your webhook secret key.
Paymob's HMAC is computed over concatenated specific fields from obj (not JSON.stringify of the whole object). The fields are concatenated in alphabetical order according to the Paymob webhook spec. Confirm the exact list on the Paymob dashboard → Settings → Webhook.
Node.js Example:
const crypto = require('crypto');
// Paymob HMAC is SHA-512 over specific concatenated fields from obj
// Field list (alphabetical): amount_cents, created_at, currency, error_occured,
// has_parent_transaction, id, integration_id, is_3d_secure, is_auth, is_capture,
// is_refunded, is_standalone_payment, is_voided, order.id, owner, pending,
// source_data.pan, source_data.sub_type, source_data.type, success
function paymobWebhookHmac(obj, secret) {
const fields = [
obj.amount_cents,
obj.created_at,
obj.currency,
obj.error_occured,
obj.has_parent_transaction,
obj.id,
obj.integration_id,
obj.is_3d_secure,
obj.is_auth,
obj.is_capture,
obj.is_refunded,
obj.is_standalone_payment,
obj.is_voided,
obj.order.id,
obj.owner,
obj.pending,
obj.source_data?.pan,
obj.source_data?.sub_type,
obj.source_data?.type,
obj.success
].join('');
return crypto.createHmac('sha512', secret).update(fields).digest('hex');
}
const hmacObject = req.body.obj;
const expectedHmac = paymobWebhookHmac(hmacObject, process.env.PAYMOB_WEBHOOK_SECRET);
if (expectedHmac === req.body.hmac) {
// Valid webhook
console.log('Transaction ID:', hmacObject.id);
console.log('Order ID:', hmacObject.order.id);
console.log('Amount:', hmacObject.amount_cents);
console.log('Paid:', hmacObject.paid);
} else {
console.error('Invalid webhook signature');
return res.status(401).send('Unauthorized');
}
Python Example:
import hmac
import hashlib
def paymob_webhook_hmac(obj, secret):
# Concatenate specific fields in alphabetical order
fields = [
str(obj.get('amount_cents', '')),
str(obj.get('created_at', '')),
str(obj.get('currency', '')),
str(obj.get('error_occured', '')),
str(obj.get('has_parent_transaction', '')),
str(obj.get('id', '')),
str(obj.get('integration_id', '')),
str(obj.get('is_3d_secure', '')),
str(obj.get('is_auth', '')),
str(obj.get('is_capture', '')),
str(obj.get('is_refunded', '')),
str(obj.get('is_standalone_payment', '')),
str(obj.get('is_voided', '')),
str(obj.get('order', {}).get('id', '')),
str(obj.get('owner', '')),
str(obj.get('pending', '')),
str(obj.get('source_data', {}).get('pan', '')),
str(obj.get('source_data', {}).get('sub_type', '')),
str(obj.get('source_data', {}).get('type', '')),
str(obj.get('success', ''))
]
data = ''.join(fields)
return hmac.new(secret.encode(), data.encode(), hashlib.sha512).hexdigest()
hmac_obj = request.json['obj']
expected = paymob_webhook_hmac(hmac_obj, os.getenv('PAYMOB_WEBHOOK_SECRET'))
if expected == request.json['hmac']:
# Valid webhook
pass