Teya Pay at Table API

The Pay at Table API from Teya — 9 operation(s) for pay at table.

OpenAPI Specification

teya-pay-at-table-api-openapi.yml Raw ↑
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