Teya Pay at Table API
The Pay at Table API from Teya — 9 operation(s) for pay at table.
The Pay at Table API from Teya — 9 operation(s) for pay at table.
openapi: 3.1.0
info:
title: Teya FX Captures Pay at Table API
version: 1.0.0
description: The Teya FX API allows you to fetch the latest exchange rates for currency pairs and perform Dynamic Currency Conversion (DCC). Use this API to verify card eligibility, retrieve real-time exchange rates, and create DCC offers with persisted quotes.
servers:
- url: https://api.teya.com
description: Production Server
- url: https://api.teya.xyz
description: Development Server
tags:
- name: Pay at Table
paths:
/poslink/v1/tabs:
get:
tags:
- Pay at Table
summary: List tabs for a store
description: "Returns tabs for the specified store, cursor-paginated.\n\nSupports optional filters:\n- `status`: repeatable. When omitted, defaults to active tabs only\n (`OPEN`, `PAYING`, `PAUSED`). To include archived tabs, pass\n `status=COMPLETED` and/or `status=CLOSED` explicitly.\n- `merchant_reference`: merchant-assigned reference. Unique per store, so the\n filtered response will contain at most one tab.\n"
operationId: listTabs
parameters:
- name: store_id
in: query
description: The store identifier
required: true
schema:
type: string
format: uuid
- name: status
in: query
description: 'Tab statuses to include. Repeatable (e.g., `status=OPEN&status=PAUSED`).
When omitted, returns only active tabs (`OPEN`, `PAYING`, `PAUSED`).
To include archived tabs, pass `status=COMPLETED` and/or `status=CLOSED` explicitly.
'
required: false
schema:
type: array
items:
type: string
enum:
- OPEN
- PAYING
- PAUSED
- COMPLETED
- CLOSED
- name: merchant_reference
in: query
description: Merchant-assigned reference to filter by. When provided, returns the single tab matching (store_id, merchant_reference) or an empty list.
required: false
schema:
type: string
- name: after
in: query
description: Opaque cursor pointing to the last item of the current page. Use to fetch the next page. Mutually exclusive with `before`.
required: false
schema:
type: string
- name: before
in: query
description: Opaque cursor pointing to the first item of the current page. Use to fetch the previous page. Mutually exclusive with `after`.
required: false
schema:
type: string
- name: limit
in: query
description: Maximum number of results to return. Defaults to 50, capped at 300.
required: false
schema:
type: integer
format: int32
default: 50
maximum: 300
minimum: 1
example: 50
responses:
'200':
description: Tabs retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/TabListResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
post:
tags:
- Pay at Table
summary: Create a new tab
description: Creates a new tab for a store. The tab starts in OPEN status.
operationId: createTab
parameters:
- name: Idempotency-Key
in: header
description: 'Unique key used to safely retry the request. Repeating the request with the same key
and body returns the same tab. Reusing the same key with a different body returns
HTTP 409. Keys are scoped to the store and retained for at least 24h.
'
required: true
schema:
type: string
maxLength: 64
minLength: 1
requestBody:
description: Tab creation payload
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTabRequest'
examples:
restaurant_table:
summary: Restaurant table with order reference
description: restaurant_table
value:
store_id: eac4d470-4731-45b2-af6b-c828f03c1f9d
tab_name: Table 5
merchant_reference: ORDER-2026-001
epos_instance_id: epos-register-1
currency_code: GBP
bar_guest_tab:
summary: Bar tab named after a guest
description: bar_guest_tab
value:
store_id: eac4d470-4731-45b2-af6b-c828f03c1f9d
tab_name: Jane D. — bar
merchant_reference: BAR-2026-117
currency_code: EUR
retail_counter:
summary: Retail counter open tab
description: retail_counter
value:
store_id: eac4d470-4731-45b2-af6b-c828f03c1f9d
tab_name: 'Counter #2'
merchant_reference: CTR-2026-2031
epos_instance_id: epos-register-2
currency_code: USD
required: true
responses:
'201':
description: Tab created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/TabResponse'
examples:
new_tab_created:
summary: Freshly created tab (OPEN, zero amounts)
description: new_tab_created
value:
tab_id: 3f2b6a2e-9d3e-4a1f-8f1e-6b2e5a8c9d01
store_id: eac4d470-4731-45b2-af6b-c828f03c1f9d
tab_name: Table 5
status: OPEN
total_amount:
amount: 0
currency: GBP
total_paid: 0
remaining: 0
merchant_reference: ORDER-2026-001
epos_instance_id: epos-register-1
payment_requests: []
created_at: '2026-04-21T10:00:00Z'
updated_at: '2026-04-21T10:00:00Z'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'409':
description: Conflict — a tab with the same merchant reference already exists for this store
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
examples:
conflict_duplicate_merchant_reference:
summary: Tab already exists for this (store_id, merchant_reference)
description: conflict_duplicate_merchant_reference
value:
code: CONFLICT
description: Tab with merchant_reference already exists
'415':
description: Unsupported media type
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNSUPPORTED_MEDIA_TYPE
description: Unsupported Media Type
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
/poslink/v1/tabs/{tab_id}/show-bill-intents:
post:
tags:
- Pay at Table
summary: Create a show-bill intent
description: 'Terminal signals intent to display the bill for a tab. The server accepts
the intent and notifies the ePOS via a `SHOW_BILL_REQUEST` SSE event, which
in turn posts bill content back to the server. At most one terminal can hold
an active show-bill intent per tab at a time.
'
operationId: createShowBillIntent
parameters:
- name: tab_id
in: path
description: The tab identifier
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TerminalIdRequest'
required: true
responses:
'202':
description: Show-bill intent accepted and forwarded to the ePOS
content:
application/json:
schema:
$ref: '#/components/schemas/ShowBillIntentResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'404':
description: Tab not found
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'409':
description: Conflict — a bill is already being displayed, or tab state does not allow display
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'415':
description: Unsupported media type
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
/poslink/v1/tabs/{tab_id}/payment-intents:
post:
tags:
- Pay at Table
summary: Create a payment intent
description: 'Terminal initiates a payment intent for a tab. The tab transitions to
`PAYING` if it is in `OPEN` or `PAUSED`; PAYING tabs are no-op idempotent.
On a `PAUSED → PAYING` transition POSLink auto-emits a `TAB_RESUMED` SSE
event before the `PAY_REQUEST`. The ePOS then calls POST /v3/payment-requests
(with tab_id and payment_type) to materialise the payment. Supports FULL and
SPLIT payment types with CARD or CASH methods.
'
operationId: createPaymentIntent
parameters:
- name: tab_id
in: path
description: The tab identifier
required: true
schema:
type: string
format: uuid
requestBody:
description: Payment intent payload
content:
application/json:
schema:
$ref: '#/components/schemas/PayIntentRequest'
examples:
card_full:
summary: Terminal intends to charge the full remaining balance on card
description: card_full
value:
terminal_id: term-001
amount:
amount: 5000
currency: GBP
method: CARD
type: FULL
card_split:
summary: Terminal intends to take a partial (split) card payment
description: card_split
value:
terminal_id: term-002
amount:
amount: 2500
currency: GBP
method: CARD
type: SPLIT
cash_full:
summary: Terminal signals a full cash settlement (recorded for reconciliation)
description: cash_full
value:
terminal_id: term-003
amount:
amount: 5000
currency: GBP
method: CASH
type: FULL
required: true
responses:
'202':
description: Payment intent accepted and forwarded to ePOS
content:
application/json:
schema:
$ref: '#/components/schemas/PayIntentResponse'
examples:
intent_accepted:
summary: Payment intent forwarded to the ePOS
description: intent_accepted
value:
tab_id: 3f2b6a2e-9d3e-4a1f-8f1e-6b2e5a8c9d01
terminal_id: term-001
amount:
amount: 5000
currency: GBP
method: CARD
type: FULL
status: FORWARDED
show_bill_expires_at: '2026-05-26T15:30:00Z'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'404':
description: Tab not found
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'409':
description: Conflict — tab is not in a payable state (TAB_NOT_PAYABLE), or requested amount exceeds remaining balance
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'415':
description: Unsupported media type
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
/poslink/v1/tabs/{tab_id}/pauses:
post:
tags:
- Pay at Table
summary: Pause a tab
description: 'Records a pause event on the tab. Strict semantics: only a tab in
`PAYING` status can be paused — pause is a mid-split-payment
operation. On success the tab moves to `PAUSED` and the ePOS
receives a `TAB_PAUSED` SSE event.
'
operationId: pauseTab
parameters:
- name: tab_id
in: path
description: The tab identifier
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TerminalIdRequest'
required: true
responses:
'201':
description: Tab paused; pause event recorded
content:
application/json:
schema:
$ref: '#/components/schemas/PauseTabResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'404':
description: Tab not found
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'409':
description: Conflict — tab is not in a state that allows pausing (TAB_NOT_PAUSEABLE)
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'415':
description: Unsupported media type
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
/poslink/v1/tabs/{tab_id}/hide-bill-intents:
post:
tags:
- Pay at Table
summary: Create a hide-bill intent
description: 'Terminal signals intent to stop displaying the bill for a tab. Strict
semantics: the lock must currently be held by the calling terminal —
a hide racing the credit-completed path or the TTL sweeper is rejected
with `409 TAB_NO_ACTIVE_SHOW_BILL`. On success the server clears the
show-bill state on the tab and notifies the ePOS via a
`TAB_BILL_HIDDEN` SSE event.
'
operationId: createHideBillIntent
parameters:
- name: tab_id
in: path
description: The tab identifier
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TerminalIdRequest'
required: true
responses:
'202':
description: Hide-bill intent accepted and forwarded to the ePOS
content:
application/json:
schema:
$ref: '#/components/schemas/HideBillIntentResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'404':
description: Tab not found
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'409':
description: Conflict — no active show-bill lock on the tab, or lock is held by a different terminal
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'415':
description: Unsupported media type
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
/poslink/v1/tabs/{tab_id}/errors:
post:
tags:
- Pay at Table
summary: Report a tab error
description: 'Reports an error from the ePOS for a specific tab (e.g., table not found, bill already settled).
The server accepts the rejection and notifies the affected terminal so it can surface
the error to the operator.
'
operationId: reportError
parameters:
- name: tab_id
in: path
description: The tab identifier
required: true
schema:
type: string
format: uuid
requestBody:
description: Error report payload
content:
application/json:
schema:
$ref: '#/components/schemas/TabErrorRequest'
examples:
table_not_found:
summary: ePOS rejects the tab because the requested table does not exist
description: table_not_found
value:
terminal_id: term-001
error_code: TABLE_NOT_FOUND
message: Table 5 was not found in the ePOS system
bill_already_settled:
summary: ePOS rejects the tab because the bill has already been paid
description: bill_already_settled
value:
terminal_id: term-001
error_code: BILL_ALREADY_SETTLED
message: Bill has already been paid in full
epos_error:
summary: Generic ePOS-side error surfaced to the operator
description: epos_error
value:
terminal_id: term-001
error_code: EPOS_ERROR
message: ePOS returned an unexpected error while processing the tab
required: true
responses:
'202':
description: Rejection accepted and forwarded to the terminal
content:
application/json:
schema:
$ref: '#/components/schemas/TabErrorResponse'
examples:
error_forwarded:
summary: Error accepted and forwarded to the reporting terminal
description: error_forwarded
value:
tab_id: 3f2b6a2e-9d3e-4a1f-8f1e-6b2e5a8c9d01
status: OPEN
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: BAD_REQUEST
description: Bad Request
'401':
description: Lacks valid authentication credentials for the requested resource
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: UNAUTHORIZED
description: Unauthorized
'403':
description: The server understands the request but refuses to authorize it
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: FORBIDDEN
description: Forbidden
'404':
description: Tab not found
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'408':
description: Request timeout
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: REQUEST_TIMEOUT
description: Request timeout
'415':
description: Unsupported media type
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
'429':
description: Too many requests in a given amount of time
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: TOO_MANY_REQUESTS
description: Too Many Requests
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionResponse'
example:
code: INTERNAL_SERVER_ERROR
description: Internal Server Error
/poslink/v1/tabs/{tab_id}/bill:
get:
tags:
- Pay at Table
summary: Retrieve the current bill for a tab
description: Returns the current bill for a tab, including items, amounts, and bill image URL (if any). If the ePOS has reported a rejection via POST /v1/tabs/{tab_id}/errors before any bill content was posted, the response still returns 200 with the bill fields empty/zero and last_error_* populated so the terminal can surface the error to the user.
operationId: getBill
parameters:
- name: tab_id
in: path
description: The tab identifier
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Bill retrieved. `bill_file_url` is null when the ePOS POSTed the bill without a `print_model` (no print-receipt round-trip occurred), or when the ePOS rep
# --- truncated at 32 KB (111 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/teya/refs/heads/main/openapi/teya-pay-at-table-api-openapi.yml