Transaction Updates

Real-time payment status updates via Server-Sent Events | Teya Developer Documentation

Scope

Transaction Updates are emitted only while a payment is in progress.
They occur during status = IN_PROGRESS and not once a payment reaches final states like SUCCESSFUL, FAILED, or CANCELLED.
The stream ends with a final snapshot when the payment leaves IN_PROGRESS.

How it works (SSE)

Transaction Updates are delivered over Server-Sent Events (SSE) from the Payment Requests endpoint. If the payment is active, the connection upgrades to a live stream; when the payment reaches a final state, you receive a final snapshot and the stream closes.

Endpoint

GET /poslink/v3/payment-requests/{payment-request-id}

Headers:
Authorization: Bearer <access_token>
Accept: text/event-stream

Event Types

  • full - Complete snapshot of the payment request (initial and final)
  • diff - Incremental updates while IN_PROGRESS, including progress_status

Stream Behavior

  • If already final → server sends one full and closes
  • If NEW/IN_PROGRESS → server streams diff updates until final, then sends final full and closes

Implementation Guide

1️⃣ Subscribe to SSE

curl -N \
  -H "Authorization: Bearer <access_token>" \
  -H "Accept: text/event-stream" \
  "https://<host>/poslink/v3/payment-requests/<payment-request-id>"

2️⃣ Handle Events and Update UI

Use the initial full event to render the starting state. On diff events, read progress_status and show friendly, staff-facing messages. When you receive a final full (SUCCESSFUL, FAILED, or CANCELLED), stop listening and finalize the UI.

const es = new EventSource(`/poslink/v3/payment-requests/${paymentRequestId}`);

es.addEventListener("full", (e) => {
  const data = JSON.parse(e.data);
  renderSnapshot(data);
  if (["SUCCESSFUL","FAILED","CANCELLED"].includes(data.status)) {
    finalizePayment(data);
    es.close();
  }
});

es.addEventListener("diff", (e) => {
  const data = JSON.parse(e.data);
  updateProgressUI(data.progress_status, data.updated_at);
});

es.onerror = () => {
  // Let the browser retry; optionally surface a subtle reconnecting indicator
};

3️⃣ Map Progress Status to UI Copy

Progress Status Suggested UI Copy
SENT_TO_PAYMENT_APP Sending to card machine…
RECEIVED Request received
WAITING_FOR_CARD_ENTRY Waiting for card…
INSERT_CARD Insert card
CARD_PRESENTED Processing card…
PIN_ENTRY Enter PIN on card machine
TIP_SELECTION Choose tip on card machine
APP_SELECTION Select application
DCC_SELECTION Choose currency on card machine
REMOVE_CARD Remove card
UNKNOWN Continuing…

4️⃣ Implement Robust Reconnection

  • Use exponential backoff (1s → up to 15s) with jitter
  • Prevent UI regression using timestamps (updated_at)

5️⃣ Avoid Legacy Polling

The final full SSE event is authoritative; avoid duplicate calls to any v1 status endpoint for confirmation.

Using the Teya SDK

Pre-built Integratio

If you integrate via the official Teya SDK, Transaction Updates are already built in:

  • Pre-built design screens and state mapping for in-progress steps
  • Standard callbacks for full and diff events
  • Stream lifecycle management (connect, retry, finalize)

You don't need to implement your own status mapping or UI from scratch - ensure you're on a recent SDK version that supports SSE-based updates.

Example Sequences

Successful Sale

1. full: NEW
2. diff: IN_PROGRESS + WAITING_FOR_CARD_ENTRY
3. diff: IN_PROGRESS + CARD_PRESENTED
4. diff: IN_PROGRESS + PIN_ENTRY (if applicable)
5. full: SUCCESSFUL → stream closes

Best Practices

  • Reflect every in-progress state in your POS design when integrating directly with the API
  • Future-proofing: Tolerate unknown progress_status values without breaking (show generic message and keep listening). We may add more statuses over time
  • Single source of truth: Treat the final full event as the authoritative end of the flow; do not call v1 to confirm final outcomes
  • UX clarity: Keep messages short and actionable; use an inline stepper or status panel so staff always know "what's next"
  • Resilience: Implement reconnection with backoff; on resume, rely on updated_at to avoid UI going backwards
  • Accessibility & locales: Provide accessible labels and ensure copy is localizable
  • Observability: Log transitions (status, progress_status, timestamps) for support and analytics

Reference (Event Schema)

{
  "payment_request_id": "uuid",
  "requested_amount": { "currency": "string", "amount": 0, "tip": 0 },
  "status": "NEW | IN_PROGRESS | SUCCESSFUL | CANCELLING | CANCELLED | FAILED",
  "transaction_type": "SALE | ...",
  "created_at": "ISO 8601 timestamp",
  "updated_at": "ISO 8601 timestamp", 
  "merchant_reference": "string",
  "status_reason": "string (optional)",
  "epos_instance_id": "string",
  "gateway_payment_id": "string (on SUCCESSFUL)",
  "store_id": "uuid",
  "terminal_id": "string",
  "progress_status": "enum (present when IN_PROGRESS)",
  "metadata": {}
}