1
Get your credentials
Ask C2C for a merchant API key (Optionally, set a default callback URL for webhooks in Merchant Portal → Settings.
mk_live_...) and signing secret (sksec_...) for the development environment. Both are shown only once. Store them as environment variables:2
Add the API helper
Every request carries your API key in the
C2C-API-Key header. Deposit and withdrawal requests also carry a signature field in the body; C2C rejects them without one. Status and balance requests aren’t signed.c2c.js
3
Test your credentials
Read your wallet balance. It’s a safe call with no side effects:A
401 here means the API key is wrong. Check your signing code separately against the worked examples: on order creation, a 401 with a code means the signature is wrong. See troubleshooting.4
Create a deposit order
Response (200)
orderId. If the call times out, retry with the same Idempotency-Key and the same body. You will get the same order back, never a duplicate. You can also look the order up by its merchantOrderRef.If no member is available right now, the order is still accepted with status Awaiting. Redirect the customer as usual: a member is assigned when they open the payment page.5
Redirect the customer
Send the customer to
paymentPageUrl within 15 minutes. The page opens on the walletType you requested. With JazzCash, as here, they pay the displayed account number and enter the last digits of their transaction ID. Other payment methods ask for something else: on the QR methods the customer gives the account they pay from instead of a transaction ID. See Hosted payment page.6
Get the outcome
Handle the Poll until the status is final if you don’t use webhooks. Every final outcome sends a webhook, but an order in
order.completed / order.failed webhook, and confirm with a status query:ManualReview doesn’t until C2C resolves it. See Order status.Withdrawals
Paying a customer out uses the same endpoint, with the customer’s account in the request. No redirect is needed:422 Insufficient merchant balance. Once accepted, its amount + fee is reserved (taken out of your available balance) until the member confirms the payout, when it is debited. If no member is available, the withdrawal is accepted as Awaiting and assigned automatically once one is; its amount + fee stays reserved meanwhile. See the Withdrawal flow.
Go-live checklist
Security
Security
- API key and signing secret stored in a secret manager, never in client code or logs
- Every deposit and withdrawal request signed. Your code reproduces the worked examples.
- Webhook signatures verified with a constant-time comparison
Reliability
Reliability
Idempotency-Keypersisted before the first attempt and reused on every retry5xxand network errors retried with backoff, resending the same body with the sameIdempotency-Key- Reconciliation job polls orders that haven’t reached a final status
Business logic
Business logic
- Fulfil and mark payouts paid only on
Completed AwaitingandManualReviewtreated as pending, never as failed409handled: one live order permerchantOrderRef- Wallet balance monitored before submitting withdrawals;
422 Insufficient merchant balancehandled - Customers returned to your site through
successUrl/failureUrl, with the outcome confirmed server-side
Production
Production
- Production base URL, API key and signing secret obtained from C2C
- Production callback URL configured (HTTPS)