Wallet payments
Start a wallet payment and reconcile its status
Charge a customer's mobile wallet in two calls: initiate the wallet payment, then reconcile its status.
Initiate wallet payment
| Endpoint | Value |
|---|---|
| TEST | https://test-fep.kashier.io/v3/orders/ |
| Method | POST |
| LIVE | https://fep.kashier.io/v3/orders/ |
| Method | POST |
Headers
| Key | Value |
|---|---|
| Kashier-Hash | Hash generated as explained in Request hashing |
| Content-Type | application/json |
Request body
{
"apiOperation": "INITIATE_R2P",
"paymentMethod": {
"type": "wallet"
},
"order": {
"reference": "PM-{timestamp}",
"amount": 100,
"currency": "EGP"
},
"customer": {
"mobilePhone": "01001001001"
},
"interactionSource": "ECOMMERCE",
"reconciliation": {
"webhookUrl": "http://your-webhook-url"
},
"merchantId": "{your_merchant_id}"
}Body description
| Key | Type | Description | Required |
|---|---|---|---|
| apiOperation | String | Must be "INITIATE_R2P" | true |
| order.reference | String | Unique order reference (prefixed with 'PM-' and timestamp) | true |
| order.amount | Number | Payment amount | true |
| order.currency | String | Currency code (e.g., "EGP") | true |
| customer.mobilePhone | String | Customer's wallet mobile number | true |
| webhookUrl | String | URL to receive payment notifications | true |
| merchantId | String | Your merchant identifier | true |
Success response
{
"response": {
"apiOperation": "INITIATE_R2P",
"operation": "initiate_r2p",
"result": "SUCCESS",
"status": "SUCCESS",
"order": {
"systemOrderId": "19b76ede-8236-4dec-a2d5-80a373508188",
"reference": "PM-1711283427747"
},
"transactionId": "TX-21232888547",
"transactionResponseMessage": {
"en": "Request to pay message send successfully.",
"ar": ""
}
},
"status": "SUCCESS"
}Response description
| Key | Type | Description |
|---|---|---|
| systemOrderId | String | Unique identifier for the order, used for reconciliation |
| reference | String | Your original order reference |
| transactionId | String | Unique transaction identifier |
| status | String | Transaction status ("SUCCESS", "FAILED", etc.) |
Code k_5 is terminal
If the response code is k_5 — "the mobile number is not registered on any provider" — the number cannot be charged. Treat k_5 as terminal, not transient. Kashier also skips scheduling its automatic reconciliation for that order, so it never self-resolves: do not keep polling it, and ask the customer for a wallet number registered with a provider.
Payment reconciliation
| Endpoint | Value |
|---|---|
| TEST | https://test-fep.kashier.io/v3/orders/:merchantOrderId or :systemOrderId |
| LIVE | https://fep.kashier.io/v3/orders/:merchantOrderId or :systemOrderId |
| Method | PUT |
Headers
| Key | Value |
|---|---|
| Accept | application/json |
| Content-Type | application/json |
Auth on the reconcile call is unconfirmed
The initiate call above is gated by Kashier-Hash, but we have not been able to confirm
from Kashier's own references what the PUT reconcile leg expects — the published header
list for it has only Accept and Content-Type, and we would rather say so than invent a
header. If your reconcile is rejected as unauthorized, send the same Kashier-Hash you
generated for the initiate call and contact Kashier support to confirm the expected
auth for this leg.
Request body
{
"apiOperation": "RECONCILE_WALLET",
"paymentMethod": {
"type": "wallet"
},
"merchantId": "{your_merchant_id}"
}Body description
| Key | Type | Description |
|---|---|---|
| apiOperation | String | Must be "RECONCILE_WALLET" |
| paymentMethod.type | String | Must be "wallet" |
| merchantId | String | Your merchant identifier |
The order to reconcile is identified by the path, not the body: put the
systemOrderId returned by the initiate request (or your own merchantOrderId) in
place of :merchantOrderId or :systemOrderId in the URL above.
Success response
{
"response": {
"apiOperation": "RECONCILE_WALLET",
"result": "SUCCESS",
"status": "SUCCESS",
"paymentMethod": {
"wallet": {
"paidThrough": "Tahweel",
"payScheme": "TestSchema",
"payerName": "Test Account",
"payerAccount": "01001001001"
}
},
"amount": 100,
"totalCapturedAmount": 100,
"totalAuthorizedAmount": 100,
"transactionResponseMessage": {
"en": "Approved",
"ar": " "
}
},
"status": "SUCCESS"
}Response description
| Key | Type | Description |
|---|---|---|
| status | String | Payment status |
| paidThrough | String | Wallet provider name |
| payerName | String | Customer name |
| payerAccount | String | Customer wallet number |
| totalCapturedAmount | Number | Total amount captured |
| totalAuthorizedAmount | Number | Total amount authorized |
Reconcile outcomes
A reconcile does not always come back SUCCESS. Branch on the returned status.
| Status | HTTP | What to do |
|---|---|---|
SUCCESS | 200 | The customer approved. The order moves to CAPTURED, settlement runs and the webhook fires. Stop polling. |
PENDING | 200 | The customer has not acted on the request yet. This is normal, not an error — keep polling. |
FAILURE | 400 | Declined or timed out. Stop polling and start a new payment if the customer wants to retry. |
Note
If a pay transaction already exists for the order, reconcile returns the stored result instead of calling the provider again.
Error handling
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 500 | Internal Server Error |
Webhook notification
When a payment is completed, a webhook notification is sent to the specified webhookUrl with the payment status and details. Ensure your webhook endpoint is configured to handle these notifications securely.
Best practices
-
Always store the systemOrderId returned from the initiate request
-
Implement proper error handling and retries
-
Validate webhook notifications using signature verification
-
Use appropriate timeouts for reconciliation requests
-
Implement idempotency for payment requests
Security considerations
-
Never expose your API key in client-side code
-
Always validate webhook signatures
-
Use HTTPS for all API calls
-
Implement request timeout handling
-
Store sensitive payment data securely