KashierDevelopersKashier Developers
Direct API integration

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

EndpointValue
TESThttps://test-fep.kashier.io/v3/orders/
MethodPOST
LIVEhttps://fep.kashier.io/v3/orders/
MethodPOST

Headers

KeyValue
Kashier-HashHash generated as explained in Request hashing
Content-Typeapplication/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

KeyTypeDescriptionRequired
apiOperationStringMust be "INITIATE_R2P"true
order.referenceStringUnique order reference (prefixed with 'PM-' and timestamp)true
order.amountNumberPayment amounttrue
order.currencyStringCurrency code (e.g., "EGP")true
customer.mobilePhoneStringCustomer's wallet mobile numbertrue
webhookUrlStringURL to receive payment notificationstrue
merchantIdStringYour merchant identifiertrue

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

KeyTypeDescription
systemOrderIdStringUnique identifier for the order, used for reconciliation
referenceStringYour original order reference
transactionIdStringUnique transaction identifier
statusStringTransaction 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

EndpointValue
TESThttps://test-fep.kashier.io/v3/orders/:merchantOrderId or :systemOrderId
LIVEhttps://fep.kashier.io/v3/orders/:merchantOrderId or :systemOrderId
MethodPUT

Headers

KeyValue
Acceptapplication/json
Content-Typeapplication/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

KeyTypeDescription
apiOperationStringMust be "RECONCILE_WALLET"
paymentMethod.typeStringMust be "wallet"
merchantIdStringYour 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

KeyTypeDescription
statusStringPayment status
paidThroughStringWallet provider name
payerNameStringCustomer name
payerAccountStringCustomer wallet number
totalCapturedAmountNumberTotal amount captured
totalAuthorizedAmountNumberTotal amount authorized

Reconcile outcomes

A reconcile does not always come back SUCCESS. Branch on the returned status.

StatusHTTPWhat to do
SUCCESS200The customer approved. The order moves to CAPTURED, settlement runs and the webhook fires. Stop polling.
PENDING200The customer has not acted on the request yet. This is normal, not an error — keep polling.
FAILURE400Declined 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

CodeDescription
200Success
400Bad Request
401Unauthorized
403Forbidden
404Not Found
500Internal 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

  1. Always store the systemOrderId returned from the initiate request

  2. Implement proper error handling and retries

  3. Validate webhook notifications using signature verification

  4. Use appropriate timeouts for reconciliation requests

  5. Implement idempotency for payment requests

Security considerations

  1. Never expose your API key in client-side code

  2. Always validate webhook signatures

  3. Use HTTPS for all API calls

  4. Implement request timeout handling

  5. Store sensitive payment data securely

On this page