POS Terminal Integration
This guide walks through integrating Stable Genius payments into a physical point-of-sale terminal. By the end, your terminal will display a QR code, detect payment, and confirm the sale — all through two API calls.Overview
The integration pattern for POS terminals is:- Your terminal creates a payment intent when the cashier finalizes an order
- The terminal displays the QR code on screen
- The customer scans and pays from their wallet
- Your terminal receives a webhook and shows a success screen
Prerequisites
- Stable Genius API key (
sk_test_*for development) - A merchant onboarded via the dashboard
- A terminal with a screen capable of displaying QR codes
- Network connectivity (WiFi or cellular) for API calls and webhooks
Step 1: Create Payment Intent at Checkout
When the cashier presses “Pay” or “Charge,” your terminal calls the API:Step 2: Display QR Code
Render the QR code on the terminal screen. You have two options: Option A: Render from payload (recommended for terminals with QR libraries)Step 3: Wait for Payment Confirmation
Your backend receives the webhook when the customer pays. Push the confirmation to the terminal:Step 4: Show Success on Terminal
When the terminal receives the confirmation push:Terminal-to-Server Communication
The webhook fires to your backend, not directly to the terminal. You need a way to push updates from your backend to the terminal. Common patterns:| Method | Best For | Latency |
|---|---|---|
| WebSocket | Always-connected terminals | Under 100ms |
| MQTT | IoT/embedded terminals | Under 200ms |
| Server-Sent Events (SSE) | Web-based POS | Under 500ms |
| Polling | Simple integrations | 1-3s |
Handling Edge Cases
Customer sends wrong amount: The payment intent tracks the expected amount. If the customer sends more or less, thetransaction.created webhook fires with the actual amount. Your system should reconcile and handle over/underpayments per your business logic.
Network disconnection: If the terminal loses connectivity after displaying the QR code, the payment still works — the customer’s on-chain transaction is independent of your terminal’s connection. When connectivity resumes, the webhook will be retried and delivered.
Terminal reboot mid-payment: Store the active payment_intent_id locally. On reboot, call GET /v1/payment-intents/{id} to check if payment was received while offline.
Full Example
See our example POS integration on GitHub for a complete working implementation.Building on Android? Our first-party POS terminal (Genie) runs on Android with Kotlin/Jetpack Compose. Contact us about licensing the terminal software or building on our hardware platform.