POS Payments (Physical Terminal)
POS payments let you send a charge directly to a connected physical terminal (POS). The flow is synchronous: the response arrives when the terminal processes the payment (or times out).
List terminals
Before sending a POS payment, you need to know the terminal identifier (poiId).
Live: GET https://aviratopayments.com/external/v1/pos/terminals?webcode={webcode}
Test: GET https://aviratopayments.com/external/v1/test/pos/terminals?webcode={webcode}Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webcode | string | Yes | Your business identifier |
syncFromProvider | boolean | No | true to force sync with the provider. Default: false |
Example
curl -X GET "https://aviratopayments.com/external/v1/pos/terminals?webcode=SHOP01" \
-H "X-API-KEY: your_live_api_key"Response (200)
{
"success": true,
"data": [
{
"poiId": "V400m-123456789",
"status": "boarded",
"name": "Mostrador Principal",
"model": "V400m",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-06-20T08:30:00Z"
}
]
}Only terminals with boarded status (active and operational) are returned.
- With
syncFromProvider=false(default): returns all terminals registered asboarded. - With
syncFromProvider=true: only returns terminals that are also currently connected (online). Useful to know which terminals are operational in real time.
Test environment: 3 simulated terminals are returned, all with
boardedstatus: | poiId | Name | Model | Connectivity | |-------|--------|--------|-------------| |V400m-TEST-000001| Terminal Test 1 - Mostrador | V400m | Online | |S1F2-TEST-000002| Terminal Test 2 - Terraza | S1F2 | Online | |P400Plus-TEST-000003| Terminal Test 3 - Almacen | P400Plus | Offline | WithsyncFromProvider=true, only the 2 online terminals are returned. WithsyncFromProvider=false, all 3 are returned. The offline terminal (P400Plus-TEST-000003) lets you test handling of theDeviceErrorerror (502, code 13004) when trying to charge on a disconnected terminal. OnlypoiIdvalues from this list are accepted for sending POS payments in Test. Using an unlistedpoiIdwill return a 400 error.
---
Create POS payment
Sends a charge to a physical terminal. The request waits until the terminal processes the payment.
Live: POST https://aviratopayments.com/external/v1/pos/payment
Test: POST https://aviratopayments.com/external/v1/test/pos/paymentBody parameters
| Field | Type | Required | Description |
|---|---|---|---|
webcode | string | Yes | Your business identifier |
poiId | string | Yes | Terminal identifier (from /pos/terminals) |
amount.value | integer | Yes | Amount in cents |
amount.currency | string | Yes | ISO 4217 code. Accepted values: EUR, GBP, USD |
description | string | No | Charge description. Max 255 characters |
customReference | string | No | Your internal reference. Max 100 characters |
isPreAuth | boolean | No | true for pre-authorization. Default: false |
Example (Live)
curl -X POST https://aviratopayments.com/external/v1/pos/payment \
-H "X-API-KEY: your_live_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pos-sale-67890" \
-d '{
"webcode": "SHOP01",
"poiId": "V400m-123456789",
"amount": {
"value": 5000,
"currency": "EUR"
},
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628"
}'Successful response (200)
{
"success": true,
"data": {
"posPaymentId": "SHOP01-POSX-1719500000",
"paymentReference": "SHOP01-POSX-1719500000",
"poiId": "V400m-123456789",
"amount": {
"value": 5000,
"currency": "EUR"
},
"status": "success",
"isPreAuth": false,
"pspReference": "KVGQSN3K2SKFNVNS",
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628",
"createdAt": "2026-06-28 14:15:00"
}
}
posPaymentIdformat: In Live the format is{webcode}-POSX-{timestamp}. In Test the format is{webcode}-POSXT-{timestamp}.
Recommended timeout: Configure a timeout of at least 240 seconds on both your HTTP client and your server (for example,
max_execution_timein PHP,proxy_read_timeoutin Nginx, or the equivalent in your stack). The request waits for the customer to interact with the terminal (insert card, enter PIN, etc.), which can take time. If your server closes the connection before receiving the response, you will not get the direct result — although the payment may still complete in the background.
POS payment statuses
| Status | Description |
|---|---|
pending | Payment sent to terminal, waiting for result |
success | Payment completed successfully |
failed | Payment failed (declined, terminal error) |
timeout | Terminal did not respond in time |
Handling timeouts
If the terminal does not respond within the time limit, the response will have status: "timeout". In this case:
- Do not retry immediately: the payment may still be in progress
- Use
Idempotency-Key: if you resend the request with the same key, you will receive the stored response - Query status: use
GET /pos/paymentsto verify whether the payment completed - The webhook still arrives: If the payment completes after the timeout, you will receive a confirmation webhook (
AUTHORISATION) with the final result. Implement webhooks as a safety net so you do not lose completed payments you could not capture in the synchronous response.
POS-specific errors
| Code | HTTP | Cause |
|---|---|---|
| 13005 | 409 | Terminal busy (DeviceBusy): another payment is in progress |
| 13004 | 502 | Terminal error (DeviceError): communication problem |
| 12001 | 400 | Invalid parameters (missing poiId, incorrect amount, etc.) |
All POS errors follow the standard error format:
{
"success": false,
"error": {
"message": "Terminal is busy processing another payment",
"code": 13005,
"statusCode": 409,
"traceId": "abc123def456..."
}
}---
POS simulation in the Test environment
In the Test environment, POS payments are not sent to a real terminal. The system validates poiId against the list of simulated terminals and determines the result:
Simulated terminals
Only poiId values returned by GET /test/pos/terminals are accepted. If you send a poiId not on the list, you will receive a 400 error.
If you send a payment to the offline terminal (P400Plus-TEST-000003), the real error returned by the processor when a terminal is not connected is simulated:
{
"success": false,
"error": {
"message": "Error in POS payment response: Reject",
"code": 13004,
"statusCode": 502,
"traceId": "..."
}
}For online terminals (V400m-TEST-000001, S1F2-TEST-000002), the result is determined by the last two digits of the amount (amount.value):
Magic amounts (last 2 digits of the amount)
| Ending | Result | Description |
|---|---|---|
77 | failed | Payment declined (card declined) |
99 | timeout | Terminal timeout |
55 | Error 409 | Terminal busy |
| Any other | success | Successful payment |
Examples
Amount (amount.value) | Last 2 digits | Result |
|---|---|---|
5000 (50.00 EUR) | 00 | Success |
10077 (100.77 EUR) | 77 | Declined |
2599 (25.99 EUR) | 99 | Timeout |
1055 (10.55 EUR) | 55 | Terminal busy (409 error) |
15001 (150.01 EUR) | 01 | Success |
Important: In Test, the response includes a small simulated delay (2-3 seconds) to emulate terminal communication time.
Webhooks in Test: When a POS payment completes (success or failure) in the Test environment, a simulated webhook is automatically generated and sent to your webhook URL, just as in Live when the processor confirms the operation.
---
List POS payments
Query POS payment history with filters and cursor-based pagination.
Live: GET https://aviratopayments.com/external/v1/pos/payments?webcode={webcode}
Test: GET https://aviratopayments.com/external/v1/test/pos/payments?webcode={webcode}Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webcode | string | Yes | Your business identifier |
status | string | No | Filter by status: pending, success, failed, timeout |
created_at_start | string | No | Start date (filter) |
created_at_end | string | No | End date (filter) |
cursor | string | No | Pagination cursor (from previous response) |
take | integer | No | Results per page (1-100, default: 20) |
order | string | No | Result order: asc or desc (default: asc) |
Example
curl -X GET "https://aviratopayments.com/external/v1/pos/payments?webcode=SHOP01&status=success&take=10" \
-H "X-API-KEY: your_live_api_key"Response (200)
{
"success": true,
"data": {
"posPayments": [
{
"posPaymentId": "SHOP01-POSX-1719500000",
"paymentReference": "SHOP01-POSX-1719500000",
"poiId": "V400m-123456789",
"amount": { "value": 5000, "currency": "EUR" },
"status": "success",
"isPreAuth": false,
"pspReference": "KVGQSN3K2SKFNVNS",
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628",
"createdAt": "2026-06-28 14:15:00"
}
],
"meta": {
"cursor": "eyJpZCI6NDJ9",
"hasMore": true,
"total": 156
}
}
}Pagination
Pagination uses cursors instead of page numbers:
- The first request is made without
cursor - If
meta.hasMoreistrue, use the value ofmeta.cursoras thecursorparameter on the next request - Repeat until
meta.hasMoreisfalse
# Page 1
curl ".../pos/payments?webcode=SHOP01&take=20"
# Page 2 (using cursor from previous response)
curl ".../pos/payments?webcode=SHOP01&take=20&cursor=eyJpZCI6NDJ9"---
Differences between online and POS payments
| Aspect | Online | POS |
|---|---|---|
| Flow | Asynchronous (create session + redirect customer) | Synchronous (immediate terminal response) |
| Who pays | Customer in their browser | Customer at physical terminal |
| Reference | sessionId (format {webcode}-EXT-{ts}) | posPaymentId (format {webcode}-POSX-{ts}) |
| Redirect | Yes (urlOk / urlKo) | No |
| Timeout | Session expires on payment page | Terminal does not respond (status timeout) |
| Modifications | Refund, capture, cancel, extend | Refund, capture, cancel, extend (same endpoints) |
| Test | Fictitious cards (holderName) | Magic amounts (last 2 digits) |