Skip to main content

Overview

The Terminal Gateway implements four key concepts that apply to both HTTP and WebSocket protocols:
  • Terminal ID Resolution - How the system identifies terminals using deviceId or connectionId
  • Single Device Enforcement - One active connection per API key
  • Terminal Reconnection Resilience - 60-second grace period for terminal reconnections during payments
  • Desktop POS Recovery - Automatic and manual recovery mechanisms for missed payment results

Terminal ID Resolution

When sending commands to terminals (payments, status checks, etc.), the terminalId parameter is resolved in the following order:
  1. Device ID (Recommended) - The system first attempts to resolve terminalId as a deviceId from the terminal registry. This is the preferred approach as deviceId remains constant even when a terminal reconnects and receives a new connectionId.
  2. Connection ID (Legacy Fallback) - If no matching deviceId is found, the system treats terminalId as a raw connectionId for backward compatibility with older integrations.
Always use deviceId when available. It provides a stable reference that doesn’t change when terminals reconnect, and enables Terminal Reconnection Resilience for handling mid-payment disconnections.

Single Device Enforcement

The Terminal Gateway enforces single device connection per API key. Only one active connection is allowed at any time.

How It Works

1

First connection established

Your POS client connects with an API key and becomes the active connection.
2

Second connection attempts

If another device connects with the same API key, the existing connection is forcibly disconnected.
3

Displacement notification

The displaced connection receives a forceDisconnect message (WebSocket) or loses session state (HTTP).
4

New connection active

The new connection becomes the active connection for that API key.

Why Single Device Enforcement?

Security

Prevents unauthorized access from multiple locations simultaneously.

Consistency

Ensures terminal state and payment flows are managed by a single source.

Auditability

Clear connection tracking for compliance and debugging.

Resource Management

Prevents resource exhaustion from duplicate connections.

forceDisconnect Message (WebSocket)

When your WebSocket connection is displaced, you receive:
{
  "action": "forceDisconnect",
  "reason": "api_key_used_elsewhere",
  "message": "Connection displaced by new connection with same API key",
  "reconnectAllowed": true
}

Disconnect Reasons

ReasonDescription
api_key_used_elsewhereAnother device connected with the same API key
stale_connection_timeoutConnection was inactive for too long
admin_actionConnection terminated by administrator
otherOther system-initiated disconnect

Handling forceDisconnect

function handleMessage(message) {
  if (message.action === 'forceDisconnect') {
    console.log('Connection displaced:', message.reason);

    // Notify user that connection was lost
    showAlert('Connection lost - another device connected with your credentials');

    // Optionally attempt reconnection if allowed
    if (message.reconnectAllowed) {
      console.log('Reconnection allowed, will attempt to reconnect...');
      setTimeout(() => connect(), 5000);
    }
  }
}

Best Practices

  • Use separate API keys for each POS terminal or workstation
  • Do not run multiple instances of your application with the same API key
  • Implement graceful handling of forceDisconnect with user notification
  • Log displacement events for debugging connection issues

Terminal Reconnection Resilience

Terminals with a stable device identifier (deviceId) benefit from reconnection resilience during payment processing. If a terminal disconnects mid-payment, there’s a 60-second grace period for it to reconnect.

How It Works

1

Terminal connects with deviceId

Terminal connects with the X-Device-Id header and is registered in the terminal registry.
2

Payment initiated

Your POS sends a payment request to the terminal.
3

Terminal disconnects

If the terminal loses connection during payment processing, the transaction status changes to AWAITING_RECONNECT.
4

60-second grace period

The terminal has 60 seconds to reconnect and deliver the payment result.
5

Terminal reconnects (within grace period)

Cached payment results are processed and delivered to your POS.
6

Grace period expires

If the terminal reconnects after 60 seconds with a successful payment, the payment is automatically voided.

Status Flow Diagram

Payment Initiated


   PENDING ───────────────────────────────┐
       │                                  │
       │ Terminal disconnects             │ Terminal responds
       ▼                                  ▼
AWAITING_RECONNECT                   COMPLETED / FAILED

       ├─── Terminal reconnects within 60s ───▶ COMPLETED / FAILED

       └─── Grace period expires + successful payment ───▶ VOIDED

Terminal Status Values

Your POS receives terminalStatusUpdate notifications (WebSocket) or can poll the terminals endpoint (HTTP):
StatusDescription
connected / onlineTerminal is online and ready
reconnectingTerminal disconnected, may reconnect within 60 seconds
disconnected / offlineTerminal is fully offline

Voided Payments

If a terminal reconnects after the 60-second grace period with a successful payment result:
  1. The payment is automatically voided to prevent charging the customer without your knowledge
  2. Your POS receives a paymentVoided notification (WebSocket)
  3. Transaction status is set to VOIDED

paymentVoided Notification

{
  "action": "paymentVoided",
  "terminalId": "TERM-001",
  "transactionId": "TXN-20240115-001",
  "reason": "Terminal reconnected after grace period expired",
  "originalPaymentResponse": {
    "transactionId": "TXN-20240115-001",
    "status": "SUCCESS",
    "amount": "99.99",
    "currency": "USD"
  },
  "timestamp": "2024-01-15T10:38:30.000Z"
}

Handling Voided Payments

Always handle paymentVoided notifications to inform staff that a late payment was automatically reversed. This prevents confusion when the terminal shows “approved” but no payment was collected.
function handlePaymentVoided(message) {
  const { transactionId, reason, originalPaymentResponse } = message;

  console.log(`Payment ${transactionId} was automatically voided`);
  console.log(`Reason: ${reason}`);
  console.log(`Original amount: ${originalPaymentResponse.amount}`);

  // Update order to require new payment
  updateOrderStatus(transactionId, 'VOIDED');

  // Alert staff with clear messaging
  showAlert(
    `Payment for ${originalPaymentResponse.amount} ${originalPaymentResponse.currency} ` +
    `was voided: Terminal reconnected too late. Please retry the payment.`
  );

  // Log for audit trail
  logVoidedPayment({
    transactionId,
    reason,
    originalAmount: originalPaymentResponse.amount,
    voidedAt: message.timestamp
  });
}

Best Practices

Use deviceId

Always configure terminals with a stable deviceId via the X-Device-Id header to benefit from reconnection resilience.

Handle All Statuses

Implement handlers for AWAITING_RECONNECT and VOIDED statuses in your payment flow.

Monitor Connectivity

Display terminal connection status in your POS UI to help staff identify issues.

Audit Voided Payments

Log all voided payments for reconciliation and customer service purposes.

Desktop POS Recovery

When a desktop POS disconnects after initiating a payment and misses the successful result, the Terminal Gateway provides two complementary recovery mechanisms to ensure payment results are never lost.

Recovery Mechanisms

Undelivered Message Queue

Automatic recovery for brief network interruptions. Payment results are stored and pushed automatically upon reconnection.

Transaction Status Query API

Manual fallback for longer disconnections. Query transaction status at any time after reconnection.

Undelivered Message Queue

When a payment completes but the desktop POS cannot receive the result (due to disconnection or network issues), the Terminal Gateway automatically queues the message for later delivery.
1

Payment completes

The terminal processes the payment and sends the result.
2

Delivery fails

The gateway detects that the desktop POS is disconnected or unreachable.
3

Message queued

The payment result is stored in the undelivered message queue.
4

Desktop reconnects

Upon reconnection, queued messages are automatically pushed to the desktop POS.
The message queue handles automatic recovery for common network blips without requiring any action from the desktop POS. Your application receives the paymentComplete notification as if the connection had never been interrupted.

Transaction Status Query API

For longer disconnections or edge cases where the message queue may not apply, use the Transaction Status Query API to manually check payment status. HTTP API:
GET /v1/transactions/{transactionId}
WebSocket API:
{
  "action": "getTransactionStatus",
  "transactionId": "TXN-20240115-001"
}
const BASE_URL = 'https://{your-api-endpoint}';

// Query transaction status after reconnection
// See Authentication docs for generateAuthHeaders implementation
async function checkTransactionStatus(transactionId) {
  const path = `/v1/transactions/${transactionId}`;
  const headers = generateAuthHeaders('GET', path);

  const response = await fetch(`${BASE_URL}${path}`, {
    method: 'GET',
    headers
  });

  const transaction = await response.json();

  if (transaction.status === 'COMPLETED') {
    console.log(`Payment was successful: ${transactionId}`);
    console.log(`Amount: ${transaction.amount} ${transaction.currency}`);
    // Update your order accordingly
    updateOrderStatus(transactionId, 'PAID');
  } else if (transaction.status === 'FAILED') {
    console.log(`Payment failed: ${transaction.errorMessage}`);
    // Prompt for retry
    promptPaymentRetry(transactionId);
  } else if (transaction.status === 'PENDING') {
    console.log('Payment still processing...');
    // Check again later
  }

  return transaction;
}

// On reconnection, check any pending transactions
async function onReconnect(pendingTransactionIds) {
  for (const txnId of pendingTransactionIds) {
    await checkTransactionStatus(txnId);
  }
}

When to Use Each Mechanism

ScenarioRecommended Approach
Brief network interruption (seconds)Automatic - Message queue handles delivery
Desktop restart during paymentQuery API on startup with pending transaction IDs
Extended offline period (minutes/hours)Query API for all transactions initiated during downtime
Uncertain if result was receivedQuery API to verify transaction status

Best Practices

Track Pending Transactions

Maintain a local list of initiated transaction IDs until you receive confirmation. Check these on reconnection.

Implement Idempotent Handlers

Your payment handlers should safely handle receiving the same result twice (from queue and query).

Use Transaction IDs

Always use unique, meaningful transaction IDs that you can query later if needed.

Log Recovery Events

Log when payments are recovered via queue or query for debugging and audit purposes.
Together, these mechanisms ensure complete coverage: the message queue handles automatic recovery for common network blips, while the query API serves as a manual fallback for longer disconnections or edge cases.

Next Steps