Kiosk & cash payments
Basata kiosk codes, Aman installment-at-kiosk, and the generic Cash mark-as-paid operation
Overview
Kashier has three payment methods in this family, each with a different completion mechanism:
| Method | paymentMethod.type | How it completes |
|---|---|---|
| Basata | basata | You generate a payment reference code; the customer pays it at a Basata outlet, and Basata notifies Kashier. |
| Aman | aman | The customer completes an OTP-verified installment purchase through Aman. |
| Cash | cash | Internal "mark-as-paid" bookkeeping operation — no external provider call, no real-time authorization. |
Looking for Contact, valU, Octo, Souhoola, Mogo, Tru, or Forsa?
Those are BNPL/installment providers, not cash or kiosk methods, even though Contact's name suggests otherwise. See Installment plans → BNPL providers.
Basata: generate payment code
Generates a payment code for the Basata payment method.
| Endpoint | Value |
|---|---|
| TEST-URL | https://test-fep.kashier.io/v3/orders |
| LIVE-URL | https://fep.kashier.io/v3/orders |
| Method | POST |
Headers
| Endpoint | Required | Value |
|---|---|---|
| Kashier-Hash | Yes | HMAC-SHA256 hash calculated based on the path and API key |
| Content-Type | Yes | application/json |
curl --location 'https://test-fep.kashier.io/v3/orders' \
--header 'Kashier-Hash: your_generated_hash' \
--header 'Content-Type: application/json' \
--data '{
"apiOperation": "GENERATE_CODE",
"paymentMethod": {
"type": "BASATA",
"basata": {
"mobileNumber": "01001001001"
}
},
"order": {
"reference": "PM-89451648984",
"amount": 10.00,
"currency": "EGP"
},
"interactionSource": "ECOMMERCE",
"reconciliation": {
"webhookUrl": "https://your-call-back-url.com",
"merchantRedirect": "https://your-call-back-url.com"
},
"merchantId": "MID-XXXXX-XXXX"
}'Body description
| Parameter | Type | Required | Description |
|---|---|---|---|
| apiOperation | String | Yes | Must be set to 'GENERATE_CODE' |
| paymentMethod.type | String | Yes | Must be set to 'BASATA' |
| paymentMethod.basata.mobileNumber | String | Yes | Customer's mobile number |
| order.reference | String | Yes | Unique order reference ID (can be generated using a timestamp) |
| order.amount | Number | Yes | Transaction amount |
| order.currency | String | Yes | Currency code (e.g., 'EGP') |
| interactionSource | String | Yes | Source of interaction (typically 'ECOMMERCE') |
| reconciliation.webhookUrl | String | Yes | URL for webhook notifications |
| reconciliation.merchantRedirect | String | Yes | URL to redirect the customer after the transaction |
| merchantId | String | Yes | Your merchant ID provided by Kashier |
Response structure
This 00 / SUCCESS means the code was generated, not that the customer paid
GENERATE_CODE does not call Basata at all — Kashier generates the reference code and
its expireAt itself on this leg, and the transactionResponseCode: "00" / "Approved"
below is produced locally by that generator. The order is created with status
INITIATED, not paid. The customer still has to take the reference code to a Basata
outlet. Treat the completion webhook (event: pay, status: SUCCESS) as the
authoritative "customer has paid" signal — never this response.
{
"response": {
"apiOperation": "GENERATE_CODE",
"operation": "generate_code",
"currency": "EGP",
"result": "SUCCESS",
"status": "SUCCESS",
"authorizationNumber": "",
"authentication": {},
"paymentMethod": {
"type": "BASATA",
"basata": {
"mobileNumber": "01001001001",
"referenceCode": "21496319",
"expireAt": "2025-04-06T13:05:45.007Z"
}
},
"metaData": {
"termsAndConditions": {
"ip": "156.210.51.26"
},
"merchantWebhook": "https://your-website.com/paymentWebhook"
},
"reconciliation": {
"webhookUrl": "https://your-call-back-url.com",
"merchantRedirect": "https://your-call-back-url.com?&signature=",
"redirect": false
},
"merchantId": "MID-21232-888",
"order": {
"amount": 10,
"currency": "EGP",
"callbackURL": "https://your-call-back-url.com",
"systemOrderId": "e5f15beb-c922-42a2-b6ba-015f5a435a20",
"reference": "test12d34"
},
"amount": 10,
"totalRefundedAmount": 0,
"totalCapturedAmount": 0,
"totalAuthorizedAmount": 0,
"merchantRedirectUrl": "https://your-call-back-url.com?&signature=",
"apiKeyId": "64e630f515427000134fd486",
"method": "basata",
"creationDate": "2025-04-06T14:05:44.981Z",
"orderId": "e5f15beb-c922-42a2-b6ba-015f5a435a20",
"provider": "basata",
"merchantOrderId": "test12d34",
"orderReference": "TEST-ORD-193390011",
"interactionSource": "ECOMMERCE",
"device": {
"ipAddress": "156.210.51.26"
},
"transactionId": "TX-212328882424",
"transactionResponseCode": "00",
"transactionResponseMessage": {
"en": "Approved"
}
},
"messages": {
"en": "Approved"
},
"status": "SUCCESS",
"showCaptcha": false
}Key response fields
| Parameter | Description |
|---|---|
| response.result | Result of the operation ('SUCCESS' or error) |
| response.paymentMethod.basata.referenceCode | The generated Basata reference code |
| response.paymentMethod.basata.expireAt | Expiration time for the reference code |
| response.transactionId | Unique transaction ID |
| response.order.systemOrderId | System-generated order ID |
Authentication is done via the Kashier-Hash header. The hash is calculated using HMAC-SHA256 with your API key and a specific path format.
Hash calculation
const path = `/?payment=${merchantId}.${order.reference}.${order.amount}.${order.currency}`;
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, apikey).update(path);
const hash = hmac.finalize().toString(CryptoJS.enc.hex);This is the standard payment hash — see Request hashing for the full recipe and the other signed-string forms.
Using the Postman collection
Prerequisites
-
Postman application installed
-
Your Kashier merchant ID
-
Your Kashier API key
Setup
-
Import the provided Postman collection JSON file
-
Update the collection variables:
-
merchantId: your merchant ID
-
apikey: your API key
-
The collection already includes pre-defined values for test-fep and live-fep
Execution
-
Select the "Generate Basata Code" request
-
The pre-request script will automatically:
-
Generate a unique order reference
-
Create the request body
-
Calculate the authentication hash
- Send the request to generate a Basata code
Variables
| Variable | Description |
|---|---|
| test-fep | Test environment base URL |
| live-fep | Production environment base URL |
| merchantId | Your merchant ID |
| apikey | Your API key |
| hash | Calculated authentication hash (auto-generated) |
| paymentRequest | JSON request body (auto-generated) |
Error handling
The API may return error responses with appropriate HTTP status codes and error messages. Common error scenarios include:
-
Invalid authentication (incorrect hash)
-
Missing required parameters
-
Invalid parameter values
-
System errors
Error responses will include a status field with a value other than "SUCCESS" and detailed error messages.
Aman: installment at kiosk
Aman is an installment-at-kiosk method: instead of a static reference code, the customer completes an OTP-verified installment purchase through Aman. Use paymentMethod.type: "aman" for the order's payment method, the same way you'd use basata or cash.
An Aman payment progresses through five steps, each a separate apiOperation against the order:
| Step | apiOperation | What happens |
|---|---|---|
| Initiate purchase | initiate_purchase | Starts the Aman flow for the order. |
| Send OTP | send_otp | Aman sends a one-time password to the customer. |
| Pay | pay | The customer's OTP is submitted and the purchase completes. |
| Reconcile | reconcile | Kashier confirms the transaction status with Aman. |
| Refund | refund | Reverses a completed Aman transaction. |
Aman's purchase result is keyed on Aman's own numeric result code: ResultID === 0 means success, and any other value is a failure. The transactionResponseCode returned to you mirrors that ResultID (or a fallback default code) rather than the standard 00/k_* dictionary used by card and Basata payments.
After a successful pay or reconcile, the order's payment-method data is enriched with the installment details Aman returns:
| Field | Meaning |
|---|---|
transactionId | Aman's transaction reference |
cardNumber | Card used for the installment |
firstInstallmentDate | Date of the first installment |
lastInstallmentDate | Date of the last installment |
adminFees | Administrative fee charged by Aman |
As with Basata, treat the completion webhook (event: pay, status: SUCCESS) as the authoritative "customer has paid" signal, not any intermediate response.
Cash: mark-as-paid (synthetic)
paymentMethod.type: "cash" — generic Cash — is not a reference-code rail like Basata, and it makes no external call to any provider. It's an internal bookkeeping operation: submitting a pay request with paymentMethod.type: "cash" debits your merchant balance and immediately writes a transaction with a hard-coded transactionResponseCode: "00" / "Approved" response.
Not a real-time authorization
Cash's SUCCESS response is synthetic — Kashier does not contact any external processor to authorize it. Unlike Basata, Aman, or a card payment, there is no real settlement-risk signal here: a Cash payment request always returns success. Use it only to record a payment you already collected through some other channel — not as a way to accept a real-time cash payment.
Contact and other BNPL providers
Contact (paymentMethod.type: "contact") is not a cash/kiosk method despite the superficial similarity — in Kashier it's a BNPL/installment provider with its own multi-step flow (categories, balance validation, tenure selection, OTP, pay, refund). See Installment plans → BNPL providers for Contact alongside Octo, Souhoola, Mogo, Tru, and Forsa.