POS Billing Application Integration
Integrate your merchant billing application with Zoho Payments POS to initiate payment sessions, send them to the terminal for customer authentication, and poll for the final transaction status, all through simple REST APIs.
All requests use HTTPS. Pass the organisation ID as the account_id query parameter and your OAuth scope token in the Authorization header.
| Environment | Base URL |
|---|---|
| Production | https://payments.zoho.in |
Query Parameters (common for all APIs):
| Parameter | Type | Required | Description |
|---|---|---|---|
account_id |
string | Yes | Zoho Payments organisation ID. |
Headers (common for all APIs):
| Header Key | Value |
|---|---|
Authorization |
Zoho-oauthtoken 1000.41d9xxxxxxxxxxxxxxxxxc2d1.8fccxxxxxxxxxxxxxx125f |
Content-Type |
application/json |
1. Create a Payment Session
Call the Create Payment Session API with the amount, currency, terminal ID, and payment method. The API returns a unique payments_session_id that tracks this transaction through its full lifecycle.
OAuth Scope: ZohoPay.payments.CREATE
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/terminal/paymentsessions |
Create a new POS payment session for a specific terminal and amount. |
{
"amount": 100.50,
"currency": "INR",
"type": "pos_payment",
"terminal_id": "1234r5tr",
"invoice_number": "INV-12345",
"description": "Payment for Order #12345",
"meta_data": [
{ "key": "Key1", "value": "Value1" }
],
"payment_method_details": {
"type": "card"
}
}
{
"code": 0,
"message": "success",
"payments_session": {
"payments_session_id": "2000000012001",
"currency": "INR",
"amount": "100.50",
"terminal_id": "1234r5tr",
"created_time": 1708950672,
"payment_session_type": "pos_payment",
"session_status": "in_progress",
"invoice_number": "INV-12345",
"description": "Payment for Order #12345",
"meta_data": [
{ "key": "Key1", "value": "Value1" }
]
}
}
2. Persist the Reference ID
Store the payments_session_id against the corresponding invoice or order in your billing system. This ID is required for all subsequent API calls, including status polling, settlement reconciliation, and dispute handling.
3. Cashier Pulls the Payment on the POS
The cashier taps Fetch Payments on the POS terminal. The terminal pulls the active payment session assigned to it over a secure connection, based on the terminal_id specified during session creation.
Note: Only one active session is supported per terminal at a time. Ensure the previous session has reached a final status (succeeded or failed) before creating a new one for the same terminal.
Multi-counter setup
If your business operates multiple counters, assign a unique terminal_id to each counter in your billing system. When creating a payment session, always pass the terminal_id of the counter where the customer is currently checking out. This ensures the session appears only on that counter’s terminal and not on others.
Scenario: A retail store with three counters (Counter A → terminal_id: TRM001, Counter B → terminal_id: TRM002, Counter C → terminal_id: TRM003) should map each billing station to its corresponding terminal ID. When a customer checks out at Counter B, the billing system must create the session with "terminal_id": "TRM002". The session will appear only on that terminal’s queue.
4. Terminal Processes the Payment
The POS displays the payment details, the customer completes the payment, and the terminal prints a receipt on success. For a detailed breakdown, refer to What Happens at the Terminal.
5. Poll for Payment Status
Poll the Retrieve Payment Session API every 5 seconds until session_status reaches a final state (succeeded or failed).
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/terminal/paymentsessions/{payments_session_id}?account_id=ORG_ID |
Retrieve the latest status and payment details. |
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
payments_session_id |
string | Yes | The payments_session_id returned during session creation. |
{
"code": 0,
"message": "success",
"payments_session": {
"payments_session_id": "2000000012001",
"currency": "INR",
"amount": "100.50",
"session_status": "in_progress",
"payment_session_type": "pos_payment",
"created_time": 1708950672,
"invoice_number": "INV-12345",
"description": "Payment for Order #12345"
}
}
{
"code": 0,
"message": "success",
"payments_session": {
"payments_session_id": "2000000012001",
"currency": "INR",
"amount": "100.50",
"session_status": "succeeded",
"payment_session_type": "pos_payment",
"created_time": 1708950672,
"invoice_number": "INV-12345",
"description": "Payment for Order #12345",
"payments": [
{
"payment_id": "173000002314886",
"status": "succeeded",
"date": 1758174448,
"date_formatted": "Sep 18, 2025, 11:17 am",
"payment_method": {
"type": "card",
"type_formatted": "Card"
}
}
]
}
}
{
"code": 0,
"message": "success",
"payments_session": {
"payments_session_id": "2000000012001",
"currency": "INR",
"amount": "100.50",
"session_status": "failed",
"payment_session_type": "pos_payment",
"created_time": 1708950672,
"invoice_number": "INV-12345",
"description": "Payment for Order #12345",
"payments": [
{
"payment_id": "173000002314886",
"status": "failed",
"date": 1758174448,
"date_formatted": "Sep 18, 2025, 11:17 am",
"failure_code": "insufficient_funds",
"payment_method": {
"type": "card",
"type_formatted": "Card"
}
}
]
}
}
6. Update the Invoice
Once the Retrieve Payment Session API returns a final status (succeeded or failed), use the invoice_number from the response to locate and update the corresponding record in your billing system. This step does not involve any Zoho Payments API call; the action is performed entirely within your own application.
| Payment Status | Merchant Action |
|---|---|
succeeded |
Mark invoice or order as paid. Trigger downstream fulfilment. |
failed |
Mark payment as failed. Surface the failure code to the cashier. |
in_progress |
Continue polling. Do not assume failure on a slow response. |
Important: Always trust the retrieve API as the source of truth. Do not mark a payment as failed only because the POS device timed out locally.
Session Status Reference
| Status | Final | Description |
|---|---|---|
in_progress |
No | Session is created or the customer is paying. Continue polling. |
succeeded |
Yes | Payment was authorised and captured. Update invoice as paid. |
failed |
Yes | Payment failed. Inspect payments[].failure_code for the reason. |