Hosted Checkout
There are currently two ways to implement the hosted checkout solution:
- Using an iframe
- Redirection to payment page
Both approaches follow similar steps:
Step 1: Create Checkout Session
Merchants must first create a session for the payment to take place.
- API: Private
- Authentication: Live or Test Public Keys
- Endpoint:
/v1/hosted-checkout - Method: POST
Example Request
{
"requestId": "order2-1277",
"currency": "USD",
"amount": 151,
"webhookUrl": "https://your-merchant-domain.com/webhook",
"successRedirectUrl": "https://your-merchant-domain.com/success",
"errorRedirectUrl": "https://your-merchant-domain.com/error",
"orderDetails": [
{
"name": "Shoes",
"currency": "string",
"quantity": 1,
"description": "string",
"price": 0
}
],
"deliveryDetails": {
"currency": "USD",
"fee": 0
}
}Example Response
{
"sessionId": "0193cebd-772f-713a-af5f-cf4f2c8591bf",
"url": "https://staging.cashia.com/link/YourMerchantName/0193cebd-772f-713a-af5f-cf4f2c8591bf",
"amount": 10,
"currency": "KES",
"requestId": "order-1234"
}Authentication with HMAC
The hosted checkout endpoint requires HMAC (Hash-based Message Authentication Code) authentication. You need to include specific headers in your request:
Required Headers
X-Cashia-Key-ID: Your API Key IDX-Cashia-Timestamp: Current Unix timestamp (seconds since epoch)X-Cashia-Nonce: A unique random string for each requestX-Cashia-Signature: HMAC SHA256 signature of the signing stringX-Cashia-Hash: HMAC SHA256 hash of the request body (for POST/PUT/PATCH requests)Content-Type:application/json
Generating the Signature
The signature is computed using HMAC SHA256 with your secret key. The signing string format is:
host example:
https://host + method + timestamp + nonce + keyIdImportant: Do not include any separators or additional characters between the components.
Example Request Body
{
"requestId": "test-14-68a2ff317f34abc3a8a9a9",
"amount": 200,
"currency": "KES",
"successRedirectUrl": "https://your-merchant-domain.com/success",
"errorRedirectUrl": "https://your-merchant-domain.com/error",
"webhookUrl": "https://your-merchant-domain.com/webhook",
"orderDetails": [
{
"name": "soda",
"currency": "KES",
"quantity": 1,
"description": "soda",
"price": 100
}
],
"deliveryDetails": {
"currency": "KES",
"fee": 0
}
}Postman Pre-request Script
Here’s a Postman pre-request script to automatically generate the required headers:
// Import CryptoJS library for hashing
const CryptoJS = require('crypto-js');
// Retrieve the source environment from the collection variable
const sourceEnv = pm.variables.get("source_env");
if (!sourceEnv) {
throw new Error("The 'source_env' variable is not set in the collection. Please define it as 'staging' or 'local'.");
}
// Configuration - Generate dynamic values for the headers
const secret = pm.environment.get("secret"); // Retrieve the shared secret from environment
const keyID = pm.environment.get("key_id"); // Retrieve the Key ID from environment
const nonce = Math.random().toString(36).substring(2, 15); // Generate a unique nonce
const timestamp = Math.floor(Date.now() / 1000); // Current Unix time in seconds
const method = pm.request.method.toUpperCase();
const host = pm.environment.get("host"); // Retrieve the API host from environment
// Retrieve and hash the request body if it exists (for POST/PUT/PATCH methods)
let requestBody = '';
let bodyHash;
if (method === "POST" || method === "PUT" || method === "PATCH") {
if (pm.request.body && pm.request.body.mode === 'raw') {
requestBody = pm.request.body.raw || '';
}
// Hash the request body string
bodyHash = CryptoJS.HmacSHA256(requestBody, secret).toString(CryptoJS.enc.Hex);
} else {
// For GET and other methods with no body, hash an empty string
bodyHash = CryptoJS.HmacSHA256('', secret).toString(CryptoJS.enc.Hex);
}
// Create signing string - must match format exactly: host + method + timestamp + nonce + keyId
const signingString = `${host}${method}${timestamp}${nonce}${keyID}`;
// Compute HMAC SHA256 Signature
const signature = CryptoJS.HmacSHA256(signingString, secret).toString(CryptoJS.enc.Hex);
// Set environment variables for use in headers
pm.environment.set('timestamp', timestamp);
pm.environment.set('nonce', nonce);
pm.environment.set('signature', signature);
pm.environment.set('body_hash', bodyHash);
pm.environment.set('Content-Type', 'application/json');Postman Headers Configuration
In your Postman request, add these headers:
X-Cashia-Key-ID:{{key_id}}X-Cashia-Timestamp:{{timestamp}}X-Cashia-Nonce:{{nonce}}X-Cashia-Signature:{{signature}}X-Cashia-Hash:{{body_hash}}Content-Type:{{Content-Type}}
Implementation Notes
-
Body Hash: For POST/PUT/PATCH requests, the body must be hashed exactly as it appears in the request (including any whitespace or formatting). Ensure the body string matches exactly between generation and sending.
-
Nonce: Each request must have a unique nonce. Do not reuse nonces across requests.
-
Timestamp: The timestamp should be the current Unix time in seconds. The server may reject requests with timestamps that are too old (typically more than 5 minutes).
-
Host: The host value should match the API host you’re calling (e.g.,
api.example.comfor staging).
Step 2: Use the URL in Your Code
Iframe Approach
With the URL from the above response, render an iframe:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Merchant Checkout Page</title>
</head>
<body>
<div>Merchant Checkout Page</div>
<iframe
name="cashia"
width="400"
height="600"
src="https://staging.cashia.com/link/YourMerchantName/0193cee1-3206-7e18-b981-37e036b4545f">
</iframe>
</body>
</html>Hosted Page Redirect Approach
With the URL from the response, redirect the user to the payment page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Merchant Checkout Page</title>
</head>
<body>
<div>Merchant Checkout Page</div>
<div style="margin-bottom: 20px"></div>
<a href="https://staging.cashia.com/link/YourMerchantName/0193cee1-3206-7e18-b981-37e036b4545f"
target="_blank">
<div>Click to Pay</div>
</a>
</body>
</html>Step 3: Redirection to Success/Error Page
Payment processing results in either success or failure/cancellation. The end user must be notified of the payment outcome via successCallbackURL or errorCallbackURL.
During session creation, provide callback URLs for both scenarios. Based on the payment result, the payment gateway will trigger the corresponding callback URL.
Example success callback URL with parameters:
https://your-merchant-domain.com/success?validTimeStamp=1708118400&requestId=order2-1237&status=CThe payment gateway adds requestId and status at the end of the request.