POS
Overview
The Amwal POS component enables merchants to accept digital payments through their Point of Sale systems with a built-in numeric keypad interface and real-time payment processing.
Screenshots
1. Amount Entry Screen
Users enter payment amounts using the built-in numeric keypad_
2. QR Code Display
QR code is automatically generated for customers to scan_
3. Payment Processing
Real-time payment status monitoring with loading indicator
4. Payment Success
Success confirmation with transaction details_
5. Error Handling
Clear error messages with retry options_
Quick Start
Installation
<script type="module" src="https://cdn.jsdelivr.net/npm/amwal-checkout-button@latest/dist/checkout/checkout.esm.js"></script>
Basic Setup
<!-- Add the component to your HTML -->
<amwal-pos
auth-token="your-auth-token-here"
store-id="your-store-id-here"
api-base-url="https://backend.sa.amwal.tech"
currency="SAR"
locale="en"
min-amount="1"
max-amount="999999"
customer-first-name="Ahmed"
customer-last-name="Al-Rashid"
customer-email="[email protected]"
customer-phone="+966501234567"
metadata='{"store_location": "Riyadh Main Branch", "cashier_id": "EMP001", "terminal": "POS-001"}'
callback-url="https://your-pos-system.com/webhook/payment-complete"
debug="true"
></amwal-pos>
Or programmatically:
// Create element
const amwalPos = document.createElement('amwal-pos');
// Set properties
amwalPos.authToken = 'your-auth-token-here';
amwalPos.storeId = 'your-store-id-here';
amwalPos.apiBaseUrl = 'https://backend.sa.amwal.tech';
amwalPos.currency = 'SAR';
amwalPos.locale = 'en'; // 'en' or 'ar'
amwalPos.minAmount = 1;
amwalPos.maxAmount = 999999;
// Customer info
amwalPos.customerFirstName = 'Ahmed';
amwalPos.customerLastName = 'Al-Rashid';
amwalPos.customerEmail = '[email protected]';
amwalPos.customerPhone = '+966501234567';
// POS metadata (JSON string)
amwalPos.metadata = JSON.stringify({
store_location: 'Riyadh Main Branch',
cashier_id: 'EMP001',
terminal: 'POS-001'
});
amwalPos.callbackUrl = 'https://your-pos-system.com/webhook/payment-complete';
amwalPos.debug = true;
// Add to DOM
document.getElementById('pos-container').appendChild(amwalPos);
Payment Status Flow
The component transitions through these screens:
Screen | Description |
---|---|
amount-entry | User enters payment amount using keypad |
qr-code | QR code displayed for customer to scan |
processing | Checking payment status automatically |
success | Payment completed successfully |
error | Payment failed or error occurred |
API Status Responses
The component monitors these status values:
Payment Link Status:
Paid
- Payment completed successfullyFailed
- Payment failedCancelled
- Payment was cancelled
Transaction Status:
success
- Transaction completedfailed
- Transaction failederror
- Transaction error occurred
Configuration Options
All configuration is done via HTML attributes or JavaScript properties:
<!-- HTML Attributes (kebab-case) -->
<amwal-pos
auth-token="string" <!-- Required: API authorization token -->
store-id="string" <!-- Required: Store identifier -->
api-base-url="string" <!-- Required: API endpoint -->
currency="SAR" <!-- Payment currency (default: SAR) -->
locale="en" <!-- Interface language: 'en' or 'ar' (default: 'en') -->
min-amount="1" <!-- Minimum transaction amount (default: 1) -->
max-amount="999999" <!-- Maximum transaction amount (default: 999999) -->
payment-title="string" <!-- Custom payment title -->
payment-description="string" <!-- Custom payment description -->
customer-first-name="string" <!-- Customer first name -->
customer-last-name="string" <!-- Customer last name -->
customer-email="string" <!-- Customer email -->
customer-phone="string" <!-- Customer phone (+966XXXXXXXXX) -->
customer-street1="string" <!-- Address line 1 -->
customer-street2="string" <!-- Address line 2 -->
customer-city="string" <!-- Customer city -->
customer-state="string" <!-- Customer state/province -->
customer-country="string" <!-- Customer country (ISO code) -->
customer-postcode="string" <!-- Customer postal code -->
address-required="false" <!-- Require address input (default: false) -->
sms-language="ar" <!-- SMS language: 'ar' or 'en' -->
send-sms="false" <!-- Send SMS notifications (default: false) -->
passkey-enabled="false" <!-- Enable passkey authentication (default: false) -->
only-show-bank-installments="false" <!-- Show only bank installments (default: false) -->
only-show-pay-in-full="false" <!-- Show only full payment (default: false) -->
callback-url="string" <!-- Webhook URL for notifications -->
metadata="string" <!-- JSON string with custom data -->
debug="false" <!-- Enable debug logging (default: false) -->
></amwal-pos>
JavaScript Properties
const amwalPos = document.querySelector('amwal-pos');
// Required properties
amwalPos.authToken = 'string';
amwalPos.storeId = 'string';
amwalPos.apiBaseUrl = 'string';
// Payment configuration
amwalPos.currency = 'SAR'; // Currently only SAR supported
amwalPos.locale = 'en'; // 'en' or 'ar'
amwalPos.minAmount = 1;
amwalPos.maxAmount = 999999;
// Transaction details
amwalPos.paymentTitle = 'Custom Title';
amwalPos.paymentDescription = 'Custom Description';
// Customer information
amwalPos.customerFirstName = 'Ahmed';
amwalPos.customerLastName = 'Al-Rashid';
amwalPos.customerEmail = '[email protected]';
amwalPos.customerPhone = '+966501234567';
amwalPos.customerStreet1 = '123 Main St';
amwalPos.customerCity = 'Riyadh';
amwalPos.customerCountry = 'SA';
// Payment options
amwalPos.addressRequired = false;
amwalPos.smsLanguage = 'ar';
amwalPos.sendSms = true;
amwalPos.passkeyEnabled = false;
amwalPos.onlyShowBankInstallments = false;
amwalPos.onlyShowPayInFull = false;
// Integration
amwalPos.callbackUrl = 'https://yoursite.com/webhook';
amwalPos.metadata = JSON.stringify({
store_location: 'Main Branch',
cashier_id: 'EMP001',
terminal: 'POS-001'
});
// Development
amwalPos.debug = true;
Webhook Integration
Set up your webhook endpoint to receive payment notifications:
// Your webhook endpoint
app.post('/webhook/payment-complete', (req, res) => {
const payment = req.body;
switch (payment.status) {
case 'success':
console.log('Payment completed:', payment.transactionId);
printReceipt(payment);
break;
case 'fail':
console.log('Payment failed:', payment.errorMessage);
notifyFailure(payment);
break;
case 'refunded':
console.log('Payment refunded:', payment.refundAmount);
printRefundReceipt(payment);
break;
}
res.status(200).send('OK');
});
Webhook Payload Example
{
"transactionId": "txn_1234567890",
"status": "success",
"amount": "125.50",
"currency": "SAR",
"timestamp": "2025-08-12T10:30:00Z",
"customer": {
"firstName": "Ahmed",
"lastName": "Al-Rashid",
"phone": "+966501234567"
},
"metadata": {
"store_location": "Riyadh Main Branch",
"cashier_id": "EMP001",
"terminal": "POS-001"
}
}
Component Lifecycle
The component automatically:
- Amount Entry: Shows numeric keypad for amount input
- QR Generation: Creates payment link and generates QR code
- Status Monitoring: Automatically checks payment status every 10 seconds (max 5 attempts)
- Result Display: Shows success or error screen based on payment outcome
- Reset: Allows starting a new transaction
Receipt Generation
The component provides transaction details that can be used for receipt generation:
// Listen for payment completion via webhook
app.post('/webhook/payment-complete', (req, res) => {
const paymentData = req.body;
if (paymentData.status === 'success') {
generateReceipt({
storeName: 'Your Store Name',
transactionId: paymentData.transactionId,
amount: paymentData.amount,
currency: paymentData.currency,
timestamp: new Date().toLocaleString('ar-SA'),
paymentMethod: 'Amwal Digital Payment',
terminal: JSON.parse(paymentData.metadata || '{}').terminal
});
}
res.status(200).send('OK');
});
function generateReceipt(data) {
const receiptText = `
================================
${data.storeName}
================================
Transaction ID: ${data.transactionId}
Amount: ${data.amount} ${data.currency}
Payment Method: ${data.paymentMethod}
Terminal: ${data.terminal}
Date: ${data.timestamp}
================================
Thank you for your business!
================================
`;
// Send to your POS printer
sendToPrinter(receiptText);
}
Programmatic Control
// Get component reference
const amwalPos = document.querySelector('amwal-pos');
// Set amount programmatically (before user input)
amwalPos.amount = '25.50';
// Get current state
console.log('Current screen:', amwalPos.currentScreen);
console.log('Current amount:', amwalPos.amount);
console.log('Transaction ID:', amwalPos.transactionId);
// Reset component for new transaction
amwalPos.amount = '';
amwalPos.currentScreen = 'amount-entry';
Testing
Test Scenarios
- Successful Payment: Enter amount → Process → Receive success
- Payment Failure: Enter amount → Process → Handle failure
- Network Issues: Start payment → Disconnect → Reconnect
- Refund Processing: Complete payment → Process refund
- Invalid Amount: Enter invalid amount → Show validation error
Test Configuration
<amwal-pos
auth-token="d9ccf8bc-ed63-44ad-a54c-9d8fee63df6b"
store-id="f24267bd-79f4-433f-a9f2-485c171301e4"
api-base-url="https://backend.sa.amwal.tech"
debug="true"
min-amount="1"
max-amount="1000"
locale="en"
customer-first-name="Test"
customer-last-name="User"
customer-email="[email protected]"
customer-phone="+966501234567"
metadata='{"test_mode": true}'
></amwal-pos>
Internal API Calls
The component makes these API calls automatically:
Create Payment Link
POST /payment_links/{storeId}/create
Authorization: {authToken}
Content-Type: application/json
{
"amount": 125.50,
"title": "POS Payment - SAR 125.50",
"singleUse": true,
"description": "Payment for SAR 125.50",
"selectedDate": "2025-08-13T10:30:00.000Z",
"client_first_name": "Ahmed",
"client_last_name": "Al-Rashid",
"client_email": "[email protected]",
"client_phone_number": "+966501234567",
// ... other customer fields
"language": "en",
"sms_language": "ar",
"send_sms": true,
"callback_url": "https://yoursite.com/webhook",
"metadata": {
"pos_transaction": true,
"timestamp": "2025-08-12T10:30:00.000Z",
"store_location": "Main Branch",
"cashier_id": "EMP001"
}
}
Check Payment Status
POST /payment_links/{paymentLinkId}/details
Authorization: {authToken}
Content-Type: application/json
{}
Response:
{
"payment_link": {
"id": "link_123",
"status": "Paid"
},
"transactions": [
{
"id": "txn_456",
"status": "success"
}
]
}
Support
- Technical Support: [email protected]
- Merchant Portal: merchant.amwal.tech
Troubleshooting
Common Issues:
- Component not loading: Check internet connection and script tag is correct
- Authentication error: Verify
auth-token
andstore-id
are correct - QR code not showing: Check API credentials and network connectivity
- Amount validation error: Ensure amount is within
min-amount
andmax-amount
range - Payment stuck in processing: Component automatically retries status checks 5 times
Debug Mode:
<amwal-pos debug="true"></amwal-pos>
This shows detailed console logs for troubleshooting.
Console Logs (when debug=true):
[AmwalPos] Debug Mode Enabled
[AmwalPos] Current Screen: amount-entry
[AmwalPos] Creating payment link with payload: {...}
[AmwalPos] Payment link created: {...}
[AmwalPos] Payment check attempt 1/5
[AmwalPos] Payment status response: {...}
Updated 11 days ago