---
schema_version: "1"
id: 13664ed78d6f51c208e222aa0c8b1dbbff9135975176dd3fe77a85f9cbab4c23
title: Payment Gateway SPI
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/retail-cloud/reference/generated-api-specs/payment-spi.md
canonical_url: https://developer.salesforce.com/docs/commerce/retail-cloud/references/payment-spi
source_site: developer.salesforce.com
content_type: documentation
content_hash: b8c0afa56485b330d68cbae7a6b81bc5daef4b9163ef8be1a89418036db0aeeb
products:
  - Point of Sale for Developers
  - Salesforce APIs
---
Payment Gateway SPI

# Payment Gateway SPI

Integrate third-party payment gateway terminals (for example, Worldpay or Stripe Terminal) with Point of Sale (POS) through a store-local proxy server. The proxy translates gateway protocols and streams real-time terminal events over WebSockets, so new gateway integrations can be added without modifying the POS iOS application.

For architecture, security modes, date-format requirements, and client-side timeouts, see [Integrate Payment Gateways Using the Payment Gateway SPI](https://developer.salesforce.com/docs/commerce/retail-cloud/guide/payment-gateway-spi.html).

**Version:** 1.3.0

## Security

*   `hmacAuth` (apiKey)
    
    HMAC-SHA256 request signing. Required for all POST endpoints.
    
    ### HMAC Message Format
    
    The HMAC signature is computed over a pipe-delimited message string using a pre-shared secret stored in the device Keychain.
    
    **For requests WITH an amount** (payment, capture, refund):
    
    ```
    {storeId}|{registerId}|{transactionId}|{amount}|{ISO8601-timestamp}|{nonce}
    ```
    
    Example:
    
    ```
    STORE-001|REG-01|550e8400-e29b-41d4-a716-446655440000|49.99|2026-03-12T14:04:06Z|abc123-nonce
    ```
    
    **For requests WITHOUT an amount** (cancel, void):
    
    ```
    {storeId}|{registerId}|{transactionId}|{ISO8601-timestamp}|{nonce}
    ```
    
    Example:
    
    ```
    STORE-001|REG-01|550e8400-e29b-41d4-a716-446655440000|2026-03-12T14:05:00Z|def456-nonce
    ```
    
    ### Required Headers
    
    All HMAC-signed requests MUST include these four headers:
    
    | Header | Description |
    | --- | --- |
    | `X-HMAC` | HMAC-SHA256 hex digest of the message |
    | `X-Nonce` | Unique nonce for replay protection |
    | `X-Store-ID` | Store identifier |
    | `X-Register-ID` | Register/terminal identifier |
    
    ### Response Signing
    
    The proxy MUST include an `X-HMAC` response header on all **2xx POST responses**. The client validates this signature against the raw response body to ensure response integrity. The signing key is the same pre-shared HMAC secret.
    
    ### Nonce Requirements
    
    *   Each nonce MUST be unique per request
    *   The server SHOULD reject requests with previously seen nonces (replay protection)
    *   Nonce format: UUID string or equivalent unique token
    
    *   API key in header: X-HMAC
*   `mtls` (mutualTLS)
    
    Mutual TLS (mTLS) transport security. The SPI server verifies the client certificate presented by the iOS device, and the client pins the server certificate by SHA256 hash.
    
    **Client certificate**: Installed in the iOS Keychain during device provisioning. **Server certificate pinning**: The client validates the server cert's SHA256 hash against a pinned value from the store configuration.
    

## Tags

### Payments

Initiate a sale or pre-authorization, capture a pre-authorized payment, void an authorized payment, cancel an in-progress transaction, and query transaction status. This is the core cardholder-present payment flow. When the client uses the WebSocket channel, it opens a WebSocket to receive real-time terminal events, then calls `POST /payment` to start the transaction. The proxy forwards the request to the terminal, waits for cardholder interaction, and returns the authorization result.

### Refund

Process referenced refunds (against a prior transaction) and unreferenced refunds (standalone, without an original transaction to reference). The proxy translates the refund request into the gateway's native protocol and returns the settlement result. Unreferenced refunds typically require elevated cashier permissions in the POS.

### Terminal

Discover terminals registered with the SPI server, retrieve the status of a specific terminal, and check the health of the SPI server itself. Use these endpoints at POS startup to enumerate available terminals, before a transaction to verify a terminal is online, and periodically to detect connectivity or configuration problems.

### Gift Cards

Perform gift card lifecycle operations (activate, load, unload, balance, cashout, reversal, refund, verify) through a single dispatch endpoint, and process gift card payments through a dedicated endpoint that mirrors the standard payment flow with WebSocket event streaming. Gift card payment operations behave like card-present payments and support the same partial-authorization and split-tender scenarios.

### Card Acquisition

Tokenize a customer's payment card without capturing funds. Use for card-on-file enrollment, saved-payment-method setup, and any workflow that needs a reusable token without a live transaction. Returns a gateway-issued token, masked PAN, and card brand.

### Terminal Display

Push content to the terminal's customer-facing screen (for example, a virtual receipt, an order summary, or a signature-capture prompt) and clear the display when the interaction is complete. Use to keep the customer informed during multi-step transactions and to display order details for confirmation.

### Terminal Input

Prompt the terminal to collect customer input — free-text (for example, email for a digital receipt), numeric digits (for example, a loyalty number), or a yes/no confirmation — and cancel any pending input prompt when the workflow changes. Input responses are returned to the POS through the same request/response cycle.

### Pay By Link

Create Pay By Link (PBL) payment links to send to customers via email, SMS, or QR code; expire an unused link; query link status; and process a refund or void against a completed PBL payment. Use for remote payment, deposit collection, and in-store scenarios where the customer prefers to pay from their own device.

### Health

Verify that the SPI server is reachable and healthy. The POS client calls the health endpoint on startup and at configurable intervals to detect proxy outages, network partitions, or configuration drift before they surface as failed transactions.

### Offline

Retrieve store-and-forward (SAF) transactions from a terminal's offline queue, validate and complete offline payment payloads captured by partial-offline gateways (for example, Elavon) once connectivity returns, and query a terminal's offline status. Use during and after network outages to reconcile transactions that were captured while the terminal was disconnected from the gateway.

## Operations

### POST Initiate a sale or pre-authorization payment

`POST /api/v1/payment`

Operation ID: `initiatePayment`. Tags: Payment. Security: hmacAuth.

Sends a payment request to the specified terminal via the configured gateway. The proxy forwards the request to the terminal, waits for the cardholder interaction, and returns the authorization result.

When the client uses the WebSocket channel, it opens a connection to `WSS /events?transactionId={transactionId}` before calling this endpoint to receive real-time terminal events (card inserted, PIN entry, authorization progress). The WebSocket channel is optional — support clients that skip it and rely on the REST response alone.

**HMAC signed**: Yes (with amount)

#### Parameters

*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `PaymentRequest`.

_Example_

```
{
  "transactionId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 49.99,
  "currency": "USD",
  "gateway": "worldpay",
  "terminalId": "T-001",
  "paymentType": "sale",
  "metadata": {
    "orderId": "ORD-12345",
    "cashierId": "C-42"
  },
  "timestamp": "2026-03-12T14:04:06.000Z"
}
```

#### Responses

*   **200** Payment processed successfully
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body for integrity verification
    
    Media type: `application/json`. Schema: `PaymentResponse`.
    
    _Example_
    
    ```
    {
      "transactionId": "550e8400-e29b-41d4-a716-446655440000",
      "status": "APPROVED",
      "authCode": "AUTH123456",
      "requestId": "PSP-REF-789",
      "alternateRequestId": "TX-REF-456",
      "gatewayContext": {
        "pspReference": "8535516979155668",
        "merchantAccount": "PSRetailUS"
      },
      "receiptData": {
        "merchantCopy": [
          {
            "key": "pan",
            "display": "Card Number",
            "value": "****1234"
          },
          {
            "key": "authCode",
            "display": "Auth Code",
            "value": "AUTH123456"
          }
        ],
        "customerCopy": [
          {
            "key": "pan",
            "display": "Card Number",
            "value": "****1234"
          }
        ]
      },
      "cardDetails": {
        "maskedPan": "****1234",
        "cardBrand": "VISA",
        "entryMethod": "CHIP",
        "fundingSource": "CREDIT"
      },
      "timestamp": "2026-03-12T14:04:12.206Z"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### GET Query the current status of a payment transaction

`GET /api/v1/payment/{transactionId}`

Operation ID: `queryTransactionStatus`. Tags: Payment.

Returns the current state of a previously initiated payment transaction. Useful for recovery scenarios where the client lost connectivity during the original payment flow.

**HMAC signed**: No

#### Parameters

*   `transactionId` (path, string (uuid), required) UUID v4 of the payment transaction. Must match a transaction previously submitted via POST /api/v1/payment.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.

#### Responses

*   **200** Transaction status retrieved
    
    Media type: `application/json`. Schema: `PaymentResponse`.
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### POST Cancel an in-progress payment transaction

`POST /api/v1/payment/{transactionId}/cancel`

Operation ID: `cancelPayment`. Tags: Payment. Security: hmacAuth.

Cancels a payment that is currently being processed on the terminal. This is used when the operator or customer wants to abort before the transaction is authorized.

**HMAC signed**: Yes (without amount)

#### Parameters

*   `transactionId` (path, string (uuid), required) UUID v4 of the payment transaction. Must match a transaction previously submitted via POST /api/v1/payment.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `CancellationRequest`.

_Example_

```
{
  "transactionId": "550e8400-e29b-41d4-a716-446655440000",
  "reason": "customer_requested",
  "timestamp": "2026-03-12T14:05:00.000Z"
}
```

#### Responses

*   **200** Cancellation result
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `CancellationResponse`.
    
    _Example_
    
    ```
    {
      "transactionId": "550e8400-e29b-41d4-a716-446655440000",
      "cancelled": true,
      "message": "Transaction cancelled successfully"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### POST Void a previously authorized payment

`POST /api/v1/payment/{transactionId}/void`

Operation ID: `voidPayment`. Tags: Payment. Security: hmacAuth.

Voids a payment that has been authorized but not yet settled. Must be called before the settlement batch is processed.

**HMAC signed**: Yes (without amount)

#### Parameters

*   `transactionId` (path, string (uuid), required) UUID v4 of the payment transaction. Must match a transaction previously submitted via POST /api/v1/payment.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `VoidRequest`.

_Example_

```
{
  "transactionId": "550e8400-e29b-41d4-a716-446655440000",
  "reason": "operator_void",
  "timestamp": "2026-03-12T14:06:00.000Z",
  "gatewayContext": {
    "pspReference": "8535516979155668",
    "merchantAccount": "PSRetailUS"
  }
}
```

#### Responses

*   **200** Void result
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `VoidResponse`.
    
    _Example_
    
    ```
    {
      "transactionId": "550e8400-e29b-41d4-a716-446655440000",
      "voided": true,
      "message": "Transaction voided successfully"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### POST Capture a previously pre-authorized payment

`POST /api/v1/payment/{transactionId}/capture`

Operation ID: `capturePayment`. Tags: Payment. Security: hmacAuth.

Captures (settles) a payment that was initiated with `paymentType: "pre_authorization"`. The capture amount may be less than or equal to the original authorization amount.

**HMAC signed**: Yes (with amount)

#### Parameters

*   `transactionId` (path, string (uuid), required) UUID v4 of the payment transaction. Must match a transaction previously submitted via POST /api/v1/payment.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `CaptureRequest`.

_Example_

```
{
  "transactionId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 45,
  "currency": "USD"
}
```

#### Responses

*   **200** Capture result
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `CaptureResponse`.
    
    _Example_
    
    ```
    {
      "transactionId": "550e8400-e29b-41d4-a716-446655440000",
      "status": "APPROVED",
      "authCode": "CAP789012",
      "timestamp": "2026-03-12T14:07:00.206Z"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### POST Process a referenced or unreferenced refund

`POST /api/v1/refund`

Operation ID: `processRefund`. Tags: Refund. Security: hmacAuth.

Sends a refund request to the terminal via the proxy.

*   **Referenced refund**: Include `originalTransactionId` and set `refundType: "referenced"`. The gateway links the refund to the original payment for reconciliation.
*   **Unreferenced refund**: Omit `originalTransactionId` and set `refundType: "unreferenced"`. The refund is processed as a standalone credit to the card presented at the terminal.

**HMAC signed**: Yes (with amount)

#### Parameters

*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `RefundRequest`.

_Example: referenced_ Referenced refund

```
{
  "transactionId": "660e8400-e29b-41d4-a716-446655440001",
  "originalTransactionId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 10,
  "currency": "USD",
  "gateway": "worldpay",
  "terminalId": "T-001",
  "refundType": "referenced",
  "timestamp": "2026-03-12T15:00:00.000Z",
  "gatewayContext": {
    "pspReference": "8535516979155668",
    "merchantAccount": "PSRetailUS"
  }
}
```

_Example: unreferenced_ Unreferenced refund

```
{
  "transactionId": "770e8400-e29b-41d4-a716-446655440002",
  "amount": 25,
  "currency": "USD",
  "gateway": "worldpay",
  "terminalId": "T-001",
  "refundType": "unreferenced",
  "timestamp": "2026-03-12T15:01:00.000Z"
}
```

#### Responses

*   **200** Refund processed
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `RefundResponse`.
    
    _Example_
    
    ```
    {
      "transactionId": "660e8400-e29b-41d4-a716-446655440001",
      "status": "APPROVED",
      "authCode": "REF456789",
      "timestamp": "2026-03-12T15:00:05.206Z"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### GET Check SPI server health

`GET /api/v1/health`

Operation ID: `checkHealth`. Tags: Health.

Returns the SPI server's health status, including connectivity to downstream gateways and certificate expiry information.

**HMAC signed**: No

#### Responses

*   **200** Proxy is healthy
    
    Media type: `application/json`. Schema: `HealthResponse`.
    
    _Example_
    
    ```
    {
      "status": "ok",
      "version": "1.2.0",
      "uptime": 86400.5,
      "timestamp": "2026-03-12T14:04:06.206Z",
      "checks": {
        "database": "ok",
        "gateway": "ok",
        "terminal_connectivity": "ok"
      },
      "certificateExpiry": "2027-03-12T00:00:00Z"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### GET Get the status of a specific terminal

`GET /api/v1/terminal/{terminalId}/status`

Operation ID: `getTerminalStatus`. Tags: Terminal.

Returns the online/offline status and last heartbeat time for a terminal registered with the proxy.

**HMAC signed**: No

#### Parameters

*   `terminalId` (path, string, required) Device ID of the terminal as registered with the SPI server. Must exactly match the terminalId used during terminal registration/discovery.  
    Example: `T-001`.

#### Responses

*   **200** Terminal status retrieved
    
    Media type: `application/json`. Schema: `TerminalStatus`.
    
    _Example_
    
    ```
    {
      "terminalId": "T-001",
      "online": true,
      "lastSeen": "2026-03-12T14:03:55.000Z",
      "gateway": "worldpay"
    }
    ```
    
*   **404** Terminal not found
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### GET List all terminals registered with the proxy

`GET /api/v1/terminals`

Operation ID: `listTerminals`. Tags: Terminal.

Returns an array of all terminal devices registered with the SPI server. Used by the POS client for terminal discovery during setup and for displaying available terminals in the UI.

**HMAC signed**: No

#### Responses

*   **200** Terminal list retrieved
    
    Media type: `application/json`. Schema: `array of TerminalInfo`.
    
    Array of `TerminalInfo`.
    
    _Example_
    
    ```
    [
      {
        "terminalId": "T-001",
        "name": "Register 1 Terminal",
        "ipAddress": "192.168.1.100",
        "online": true,
        "gateway": "worldpay",
        "modelNumber": "VX820",
        "serialNumber": "SN-123456"
      },
      {
        "terminalId": "T-002",
        "name": "Register 2 Terminal",
        "online": false,
        "gateway": "worldpay"
      }
    ]
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### POST Perform a gift card operation

`POST /api/v1/giftcard/{operation}`

Operation ID: `giftCardOperation`. Tags: Gift Cards.

Performs a gift card operation (activate, load, unload, balance, cashout, reversal, refund, verify). Gift card payment uses a separate endpoint with WebSocket streaming.

HMAC signing: Operations with amounts include amount in HMAC message. Operations without amounts (activate, balance, verify) use signWithoutAmount.

#### Parameters

*   `operation` (path, string, required)  
    Allowed values: `activate`, `load`, `unload`, `balance`, `cashout`, `reversal`, `refund`, `verify`.

#### Request body (required)

Media type: `application/json`. Schema: `ProxyGiftCardRequest`.

#### Responses

*   **200** Gift card operation completed
    
    Media type: `application/json`. Schema: `ProxyGiftCardResponse`.
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### POST Process gift card payment with WebSocket events

`POST /api/v1/giftcard/payment`

Operation ID: `giftCardPayment`. Tags: Gift Cards.

Processes a gift card payment. When the client uses the WebSocket channel, it opens the connection first, then calls this endpoint — mirroring the standard payment flow. The WebSocket channel is optional; when the client skips it, the payment completes via the REST response alone.

#### Request body (required)

Media type: `application/json`. Schema: `ProxyGiftCardRequest`.

#### Responses

*   **200** Gift card payment completed
    
    Media type: `application/json`. Schema: `ProxyGiftCardResponse`.
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### POST Tokenize card without payment

`POST /api/v1/card/acquire`

Operation ID: `acquireCard`. Tags: Card Acquisition.

Acquires card details (token, masked PAN, brand) without processing a payment. When the client uses the WebSocket channel, it receives real-time terminal feedback over that connection. The WebSocket channel is optional; when the client skips it, the operation completes via the REST response alone. Use cases: save card on file, loyalty enrollment, pre-authorization.

#### Request body (required)

Media type: `application/json`. Schema: `ProxyCardAcquisitionRequest`.

#### Responses

*   **200** Card acquired successfully
    
    Media type: `application/json`. Schema: `ProxyCardAcquisitionResponse`.
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### POST Display content on terminal screen

`POST /api/v1/terminal/{terminalId}/display`

Operation ID: `displayOnTerminal`. Tags: Terminal Display.

Sends virtual receipt or other display content to the terminal screen. This is an unsigned POST (no HMAC headers) as display operations are low-risk.

#### Parameters

*   `terminalId` (path, string, required)

#### Request body (required)

Media type: `application/json`. Schema: `ProxyDisplayRequest`.

#### Responses

*   **200** Display updated successfully
    
    Media type: `application/json`. Schema: `ProxyDisplayResponse`.
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    

### POST Clear terminal display

`POST /api/v1/terminal/{terminalId}/display/clear`

Operation ID: `clearDisplay`. Tags: Terminal Display.

Resets the terminal screen to idle state. Unsigned POST (no HMAC headers).

#### Parameters

*   `terminalId` (path, string, required)

#### Responses

*   **200** Display cleared
    
    Media type: `application/json`. Schema: `ProxyDisplayResponse`.
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    

### POST Collect input from terminal

`POST /api/v1/terminal/{terminalId}/input`

Operation ID: `collectInput`. Tags: Terminal Input.

Prompts the terminal to collect customer input (text, digit string, or confirmation). Unsigned POST. Timeout is 120s to allow for customer interaction.

#### Parameters

*   `terminalId` (path, string, required)

#### Request body (required)

Media type: `application/json`. Schema: `ProxyInputRequest`.

#### Responses

*   **200** Input collected
    
    Media type: `application/json`. Schema: `ProxyInputResponse`.
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    

### POST Cancel pending terminal input

`POST /api/v1/terminal/{terminalId}/input/cancel`

Operation ID: `cancelTerminalInput`. Tags: Terminal Input.

Cancels any pending input collection on the terminal. Unsigned POST.

#### Parameters

*   `terminalId` (path, string, required)

#### Responses

*   **200** Input cancelled
    
    Media type: `application/json`. Schema: `ProxyInputResponse`.
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    

### POST Create a Pay By Link payment link

`POST /api/v1/paybylink`

Operation ID: `createPaymentLink`. Tags: Pay By Link. Security: hmacAuth.

Creates a payment link that can be sent to a customer via email, SMS, or QR code. The customer opens the link in a browser to complete payment without a physical terminal.

After creating the link, the client may subscribe to WebSocket events for real-time status updates (PBL\_LINK\_CREATED, PBL\_PAYMENT\_STARTED, PBL\_PAYMENT\_APPROVED, etc.).

**HMAC signed**: Yes (with amount)

#### Parameters

*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `PBLCreateRequest`.

_Example_

```
{
  "transactionId": "pbl-550e8400-e29b-41d4-a716-446655440000",
  "amount": 49.99,
  "currency": "USD",
  "gateway": "worldpay",
  "shopperEmail": "shopper@example.com",
  "merchantReference": "PS-ORDER-001",
  "tokenize": true,
  "captureNow": false,
  "timestamp": "2026-03-23T10:00:00.000Z"
}
```

#### Responses

*   **201** Payment link created
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `PBLCreateResponse`.
    
    _Example_
    
    ```
    {
      "paymentLinkId": "PL-12345",
      "url": "https://pay.example.com/link/PL-12345",
      "expiresAt": "2026-03-24T10:00:00Z",
      "status": "ACTIVE",
      "gatewayContext": {
        "checkoutSessionId": "CS-789"
      }
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### POST Expire an active payment link

`POST /api/v1/paybylink/{paymentLinkId}/expire`

Operation ID: `expirePaymentLink`. Tags: Pay By Link. Security: hmacAuth.

Expires a payment link that has not yet been used. After expiration, the link URL returns an error page and no payment can be made.

**HMAC signed**: Yes (without amount)

#### Parameters

*   `paymentLinkId` (path, string, required) Unique identifier of the payment link, as returned by the createPaymentLink endpoint.  
    Example: `PL-12345`.
*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `object`.

*   `transactionId` (_string_, required) Unique ID for this expire request
*   `originalTransactionId` (_string_) The payment link ID being expired
*   `currency` (_string_)
*   `timestamp` (_string (date-time)_, required)
*   `gatewayContext` (_GatewayContext_)

#### Responses

*   **200** Payment link expired
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `PBLExpireResponse`.
    
    _Example_
    
    ```
    {
      "paymentLinkId": "PL-12345",
      "status": "EXPIRED"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### GET Check the status of a payment link

`GET /api/v1/paybylink/{paymentLinkId}/status`

Operation ID: `checkPaymentLinkStatus`. Tags: Pay By Link.

Returns the current status of a payment link including payment details if the link has been used. No HMAC signing required for GET requests.

**HMAC signed**: No

#### Parameters

*   `paymentLinkId` (path, string, required) Unique identifier of the payment link, as returned by the createPaymentLink endpoint.  
    Example: `PL-12345`.

#### Responses

*   **200** Payment link status retrieved
    
    Media type: `application/json`. Schema: `PBLStatusResponse`.
    
    _Example_
    
    ```
    {
      "paymentLinkId": "PL-12345",
      "status": "APPROVED",
      "amount": 49.99,
      "cardDetails": {
        "maskedPan": "****1234",
        "cardBrand": "VISA",
        "entryMethod": "ECOMMERCE",
        "fundingSource": "CREDIT"
      }
    }
    ```
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    

### POST Refund or void a PBL payment

`POST /api/v1/paybylink/{paymentLinkId}/refund`

Operation ID: `refundPaymentLink`. Tags: Pay By Link. Security: hmacAuth.

Processes a refund or void for a payment made via a payment link. The SPI server decides whether to perform a refund or void based on the settlement state of the original transaction.

*   **Refund** (amount present): Refunds the specified amount. May be a partial refund (amount less than original) or full refund.
*   **Void** (amount absent/null): Voids the pre-settlement authorization. The server determines internally whether a void is possible.

**HMAC signed**: Yes (with amount when present, without amount when absent)

#### Parameters

*   `paymentLinkId` (path, string, required) Unique identifier of the payment link, as returned by the createPaymentLink endpoint.  
    Example: `PL-12345`.
*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `PBLRefundRequest`.

_Example: refund_ Refund with amount (partial or full refund)

```
{
  "transactionId": "rfnd-001",
  "originalTransactionId": "txn-001",
  "amount": 10.5,
  "currency": "USD",
  "timestamp": "2026-03-23T12:00:00.000Z"
}
```

_Example: void_ Void (no amount — server performs void)

```
{
  "transactionId": "void-001",
  "originalTransactionId": "txn-001",
  "currency": "USD",
  "timestamp": "2026-03-23T12:00:00.000Z"
}
```

#### Responses

*   **200** Refund/void processed
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `PBLRefundResponse`.
    
    _Example: refunded_ Successful refund
    
    ```
    {
      "transactionId": "rfnd-001",
      "status": "REFUNDED",
      "refundId": "ref-gateway-001",
      "amount": 10.5
    }
    ```
    
    _Example: voided_ Successful void
    
    ```
    {
      "transactionId": "void-001",
      "status": "VOIDED",
      "message": "Authorization voided successfully"
    }
    ```
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **503**
    
    **503 Proxy Unavailable**
    
    The SPI server itself is not available (e.g., starting up, shutting down, or experiencing an internal error).
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "SPI_UNAVAILABLE",
      "message": "Payment SPI server is unavailable"
    }
    ```
    
*   **504**
    
    **504 Gateway Timeout**
    
    The SPI server did not receive a response from the payment gateway or terminal within the expected time window.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "GATEWAY_TIMEOUT",
      "message": "Payment gateway did not respond in time"
    }
    ```
    

### GET Query offline (SAF) transactions from the terminal

`GET /api/v1/offline/transactions`

Operation ID: `queryOfflineTransactions`. Tags: Offline.

Retrieves stored-and-forwarded transactions from the terminal's SAF queue. The SPI server proxies this request to the terminal hardware — it does not independently track SAF state. Not all terminals support SAF query; gated by `DeviceCapabilities.supportsOfflineSAFQuery`.

**HMAC signed**: No

#### Parameters

*   `terminalId` (query, string, required) Terminal to query SAF queue for  
    Example: `T-001`.
*   `gateway` (query, string, required) Gateway identifier  
    Example: `worldpay`.
*   `startTime` (query, number (double)) Unix timestamp (seconds since epoch). Only return transactions after this time.  
    Example: `1774537200`.

#### Responses

*   **200** SAF transactions retrieved
    
    Media type: `application/json`. Schema: `SAFQueryResponse`.
    
    _Example: withTransactions_ Queue with transactions
    
    ```
    {
      "transactions": [
        {
          "transactionId": "txn-001",
          "status": "APPROVED",
          "amount": 49.99,
          "currency": "USD",
          "maskedPan": "****1234",
          "cardBrand": "VISA",
          "entryMethod": "CHIP",
          "timestamp": "2026-03-23T10:00:00Z",
          "gatewayContext": {}
        }
      ],
      "terminalId": "T-001",
      "queryTimestamp": "2026-03-23T11:00:00Z"
    }
    ```
    
    _Example: empty_ Empty queue
    
    ```
    {
      "transactions": [],
      "terminalId": "T-001",
      "queryTimestamp": "2026-03-23T11:00:00Z"
    }
    ```
    
*   **400** Missing required parameters
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
*   **404**
    
    **404 Transaction Not Found**
    
    The specified transaction ID does not exist on the proxy. The response body SHOULD include the transaction ID in `details.transactionId`.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TRANSACTION_NOT_FOUND",
      "message": "Transaction not found",
      "details": {
        "transactionId": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    

### POST Validate and complete a partial offline payment payload

`POST /api/v1/payment/validate-offline`

Operation ID: `validateOfflinePayment`. Tags: Offline. Security: hmacAuth.

Accepts an incomplete payment payload captured offline by a partial-offline gateway (e.g., Elavon) and sends it to the gateway for server-side completion. Used when `DeviceCapabilities.offlinePaymentMode == .partialOffline` and `DeviceCapabilities.requiresOfflinePayloadValidation == true`.

**HMAC signed**: Yes (with amount)

#### Parameters

*   `X-HMAC` (header, string, required) HMAC-SHA256 hex digest computed over the pipe-delimited message string using the pre-shared secret. See the Security section for the exact message format.
*   `X-Nonce` (header, string, required) Unique single-use token for replay protection. The server SHOULD reject requests with previously seen nonces. Format: UUID string or equivalent unique token.
*   `X-Store-ID` (header, string, required) Identifier of the store making the request. Included as a component of the HMAC message to scope signatures to a specific store.
*   `X-Register-ID` (header, string, required) Identifier of the POS register/device making the request. Included as a component of the HMAC message to scope signatures to a specific register within the store.

#### Request body (required)

Media type: `application/json`. Schema: `ValidateOfflineRequest`.

_Example_

```
{
  "transactionId": "txn-offline-001",
  "amount": 49.99,
  "currency": "USD",
  "gateway": "elavon",
  "terminalId": "T-001",
  "offlinePayload": {
    "cardData": "<encrypted-partial-payload>",
    "captureTimestamp": "2026-03-23T09:30:00Z",
    "terminalSequenceNumber": 42
  },
  "timestamp": "2026-03-23T11:00:00Z"
}
```

#### Responses

*   **200** Offline payment validated
    
    Headers:
    
    *   `X-HMAC` (string) HMAC-SHA256 signature of the response body
    
    Media type: `application/json`. Schema: `ValidateOfflineResponse`.
    
    _Example: approved_ Validation approved
    
    ```
    {
      "transactionId": "txn-offline-001",
      "status": "APPROVED",
      "authCode": "AUTH123",
      "receiptData": {
        "merchantCopy": [
          {
            "key": "authCode",
            "display": "Auth Code",
            "value": "AUTH123"
          }
        ],
        "customerCopy": [
          {
            "key": "authCode",
            "display": "Auth Code",
            "value": "AUTH123"
          }
        ]
      },
      "timestamp": "2026-03-23T11:00:05Z",
      "gatewayContext": {}
    }
    ```
    
    _Example: declined_ Validation declined
    
    ```
    {
      "transactionId": "txn-offline-001",
      "status": "DECLINED",
      "timestamp": "2026-03-23T11:00:05Z",
      "gatewayContext": {}
    }
    ```
    
*   **400** Missing or malformed offline payload
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
*   **401**
    
    **401 Authentication Failed**
    
    The client certificate was rejected or missing (mTLS failure), or HMAC credentials are invalid.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "AUTHENTICATION_FAILED",
      "message": "Client certificate rejected or missing"
    }
    ```
    
*   **409**
    
    **409 HMAC Validation Failed**
    
    The HMAC signature in the `X-HMAC` header does not match the expected value computed from the request body and headers. This may indicate a replay attack, clock skew, or misconfigured shared secret.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "HMAC_VALIDATION_FAILED",
      "message": "Request signature validation failed"
    }
    ```
    
*   **502** Gateway unreachable (retry later)
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    

### GET Query terminal offline status (optional — Nice to Have)

`GET /api/v1/terminal/{terminalId}/offline-status`

Operation ID: `getTerminalOfflineStatus`. Tags: Offline.

Returns whether the terminal is currently operating in offline mode. The SPI server proxies this query to the terminal hardware — it does not independently track terminal state. Not all terminals expose their offline status; gated by `DeviceCapabilities.supportsTerminalOfflineStatus`.

**HMAC signed**: No

#### Parameters

*   `terminalId` (path, string, required) Device ID of the terminal as registered with the SPI server. Must exactly match the terminalId used during terminal registration/discovery.  
    Example: `T-001`.
*   `gateway` (query, string, required) Gateway identifier  
    Example: `worldpay`.

#### Responses

*   **200** Terminal offline status retrieved
    
    Media type: `application/json`. Schema: `TerminalOfflineStatus`.
    
    _Example_
    
    ```
    {
      "terminalId": "T-001",
      "isOffline": true,
      "safQueueDepth": 5,
      "lastOnlineTimestamp": "2026-03-23T09:00:00Z",
      "timestamp": "2026-03-23T11:00:00Z"
    }
    ```
    
*   **404** Terminal not found
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
*   **501** Terminal/gateway does not support offline status query
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
*   **502**
    
    **502 Terminal Offline**
    
    The proxy cannot reach the payment terminal. The terminal may be powered off, disconnected from the network, or unresponsive.
    
    Media type: `application/json`. Schema: `ErrorResponse`.
    
    _Example_
    
    ```
    {
      "error": "TERMINAL_OFFLINE",
      "message": "Payment terminal is offline or unreachable"
    }
    ```
    

## Schemas

### PaymentRequest

*   `transactionId` (_string (uuid)_, required) Unique identifier for this transaction, generated by the client. Used as the correlation ID across WebSocket events, logs, status queries, and subsequent operations (cancel, void, capture). Must be a valid UUID v4 string.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `amount` (_number (decimal)_, required) Payment amount with decimal precision (e.g., 49.99). Represents the total charge to the cardholder. For pre-authorizations, this is the hold amount. Implementations MUST preserve at least 2 decimal places.  
    Example: `49.99`.
*   `currency` (_string_, required) ISO 4217 three-letter currency code (e.g., "USD", "EUR", "GBP"). Must be exactly 3 characters.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `gateway` (_string_, required) Identifier of the payment gateway configured on the SPI server (e.g., "worldpay", "stripe\_terminal", "adyen"). The proxy uses this to route the request to the correct gateway SDK.  
    Example: `worldpay`.
*   `terminalId` (_string_, required) Device ID of the payment terminal registered with the proxy server (e.g., "T-001"). Identifies which physical terminal should process the transaction.  
    Example: `T-001`.
*   `paymentType` (_PaymentType_, required)
*   `metadata` (_object_, nullable) Optional key-value pairs (string keys, string values) forwarded to the gateway. Use for passing order IDs, cashier IDs, or other context the gateway may need for reconciliation or reporting.
    
    Additional properties: `string`.
    
    _Example_
    
    ```
    {
      "orderId": "ORD-12345",
      "cashierId": "C-42"
    }
    ```
    
*   `timestamp` (_string (date-time)_, required) Creation timestamp of the request in ISO 8601 format. Included in the HMAC signature so the server can detect stale or replayed requests.  
    Example: `2026-03-12T14:04:06.000Z`.

### PaymentResponse

*   `transactionId` (_string (uuid)_, required) Echo of the transaction ID from the request. Confirms which transaction this response belongs to.
*   `status` (_PaymentStatus_, required)
*   `authCode` (_string_, nullable) Authorization code issued by the payment processor when the transaction is approved. Null/absent when status is not "APPROVED".  
    Example: `AUTH123456`.
*   `requestId` (_string_, nullable) The acquirer's transaction identifier (e.g., Adyen pspReference, Worldpay transaction reference). This is the primary reference used for reconciliation with the payment processor. The POS maps this to its internal TenderData.requestId.  
    Example: `PSP-REF-789`.
*   `alternateRequestId` (_string_, nullable) A secondary transaction reference from the gateway (e.g., Adyen txRef from receipt data). Provides an additional reconciliation point. The POS maps this to its internal TenderData.alternateRequestId.  
    Example: `TX-REF-456`.
*   `receiptData` (_ReceiptData_)
*   `cardDetails` (_CardDetails_)
*   `timestamp` (_string (date-time)_, required) Timestamp when the proxy generated this response. ISO 8601 format.
*   `gatewayContext` (_GatewayContext_)

### ErrorResponse

Standard error response body returned for all non-2xx HTTP responses. Provides both a machine-readable error code for programmatic handling and a human-readable message for logging.

*   `error` (_string_) Machine-readable error code. Use this for programmatic error handling. Values: "AUTHENTICATION\_FAILED", "TRANSACTION\_NOT\_FOUND", "HMAC\_VALIDATION\_FAILED", "TERMINAL\_OFFLINE", "SPI\_UNAVAILABLE", "GATEWAY\_TIMEOUT".  
    Example: `TRANSACTION_NOT_FOUND`.
*   `message` (_string_) Human-readable error description for logging and debugging. Not intended for display to end users.  
    Example: `Transaction 550e8400-... not found`.
*   `details` (_object_) Additional context about the error. Currently supports transactionId to identify which transaction triggered the error.
    *   `transactionId` (_string_) The transaction ID related to the error, when applicable. Included in 404 responses to confirm which transaction was not found.

### CancellationRequest

*   `transactionId` (_string (uuid)_, required) The transaction ID of the in-progress payment to cancel. Must match the path parameter.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `reason` (_string_, nullable) Human-readable reason for the cancellation. Forwarded to the gateway for logging/reconciliation. Suggested values: "customer\_requested", "timeout", "operator\_cancelled".  
    Example: `customer_requested`.
*   `timestamp` (_string (date-time)_, required) Request creation timestamp in ISO 8601 format. Included in the HMAC signature (without-amount format for cancel operations).  
    Example: `2026-03-12T14:05:00.000Z`.
*   `gatewayContext` (_GatewayContext_)

### CancellationResponse

*   `transactionId` (_string (uuid)_, required) The transaction ID of the payment that was the target of the cancellation request.
*   `cancelled` (_boolean_, required) true if the cancellation was successfully processed by the terminal/gateway; false if the cancellation could not be applied (e.g., transaction already authorized).
*   `message` (_string_, nullable) Human-readable message providing additional context from the proxy or gateway. Example: "Transaction cancelled successfully" or "Cannot cancel - transaction already authorized".

### VoidRequest

*   `transactionId` (_string (uuid)_, required) The transaction ID of the authorized payment to void. Must match the path parameter. The transaction must not yet be settled.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `reason` (_string_, nullable) Human-readable reason for the void. Forwarded to the gateway for logging/reconciliation. Suggested values: "operator\_void", "duplicate", "customer\_requested".  
    Example: `operator_void`.
*   `timestamp` (_string (date-time)_, required) Request creation timestamp in ISO 8601 format. Included in the HMAC signature (without-amount format for void operations).  
    Example: `2026-03-12T14:06:00.000Z`.
*   `gatewayContext` (_GatewayContext_)

### VoidResponse

*   `transactionId` (_string (uuid)_, required) The transaction ID of the payment that was the target of the void request.
*   `voided` (_boolean_, required) true if the void was successfully processed by the gateway; false if the void could not be applied (e.g., transaction already settled in the gateway batch).
*   `message` (_string_, nullable) Human-readable message from the proxy or gateway providing additional context about the void result.
*   `gatewayContext` (_GatewayContext_)

### CaptureRequest

*   `transactionId` (_string (uuid)_, required) The transaction ID of the pre-authorized payment to capture. Must match the path parameter and reference a transaction that was initiated with paymentType "pre\_authorization".  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `amount` (_number (decimal)_, required) Capture amount with decimal precision. Must be less than or equal to the original pre-authorization amount. For a full capture, use the same amount. For a partial capture, use a smaller amount.  
    Example: `45`.
*   `currency` (_string_, required) ISO 4217 three-letter currency code. Must match the currency of the original pre-authorization.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `gatewayContext` (_GatewayContext_)

### CaptureResponse

*   `transactionId` (_string (uuid)_, required) The transaction ID of the pre-authorized payment that was captured.
*   `status` (_PaymentStatus_, required)
*   `authCode` (_string_, nullable) Authorization code from the payment processor for the capture operation. Null when the capture was not approved.
*   `timestamp` (_string (date-time)_, required) Timestamp when the proxy generated this response. ISO 8601 format.
*   `gatewayContext` (_GatewayContext_)

### RefundRequest

*   `transactionId` (_string (uuid)_, required) Unique identifier for this refund transaction, generated by the client. Distinct from any original payment transaction ID.  
    Example: `660e8400-e29b-41d4-a716-446655440001`.
*   `originalTransactionId` (_string (uuid)_, nullable) The transaction ID of the original payment being refunded. Required when refundType is "referenced" -- the gateway uses this to link the refund to the original charge for reconciliation. Omit or set to null for unreferenced refunds.  
    Example: `550e8400-e29b-41d4-a716-446655440000`.
*   `amount` (_number (decimal)_, required) Refund amount with decimal precision. For referenced refunds, may be less than or equal to the original payment amount (partial refund). For unreferenced refunds, this is the credit amount.  
    Example: `10`.
*   `currency` (_string_, required) ISO 4217 three-letter currency code. For referenced refunds, must match the original payment's currency.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `gateway` (_string_, required) Gateway identifier configured on the proxy. Must match the gateway used for the original payment (referenced) or the desired gateway (unreferenced).  
    Example: `worldpay`.
*   `terminalId` (_string_, nullable) Terminal device ID. The refund is processed at this terminal, which prompts the cardholder to present their card. Nullable for PBL refunds routed through the standard refund endpoint (no terminal involved).  
    Example: `T-001`.
*   `refundType` (_RefundType_, required)
*   `metadata` (_object_, nullable) Optional key-value pairs (string keys, string values) forwarded to the gateway for reconciliation or reporting.
    
    Additional properties: `string`.
    
*   `timestamp` (_string (date-time)_, required) Request creation timestamp in ISO 8601 format. Included in the HMAC signature so the server can detect stale requests.  
    Example: `2026-03-12T15:00:00.000Z`.
*   `gatewayContext` (_GatewayContext_)

### RefundResponse

*   `transactionId` (_string (uuid)_, required) The refund transaction ID matching the original request. Confirms which refund this response belongs to.
*   `status` (_PaymentStatus_, required)
*   `authCode` (_string_, nullable) Authorization code from the payment processor for the refund, if approved. Null when status is not "APPROVED".
*   `timestamp` (_string (date-time)_, required) Timestamp when the proxy generated this response. ISO 8601 format.
*   `gatewayContext` (_GatewayContext_)

### HealthResponse

*   `status` (_string_, required) Overall server health status. Expected values: "ok" (all systems operational) or "degraded" (some checks failing but server is responding).  
    Example: `ok`.
*   `version` (_string_, nullable) Proxy server software version string. Useful for diagnostics and support.  
    Example: `1.2.0`.
*   `uptime` (_number_, nullable) Server uptime in seconds since the proxy process started. Decimal value for sub-second precision.  
    Example: `86400.5`.
*   `timestamp` (_string (date-time)_, nullable) Server response timestamp in ISO 8601 format.
*   `checks` (_object_, nullable) Named health check results as key-value pairs. Each key is a subsystem name, each value is its status string. Used to identify which specific component is unhealthy.
    
    Additional properties: `string`.
    
    _Example_
    
    ```
    {
      "database": "ok",
      "gateway": "ok"
    }
    ```
    
*   `certificateExpiry` (_string (date-time)_, nullable) Expiry date of the SPI server's TLS certificate in ISO 8601 format. The POS client uses this for proactive alerting before certificate expiration causes outages.  
    Example: `2027-03-12T00:00:00Z`.

### TerminalStatus

*   `terminalId` (_string_, required) The terminal device ID, echoed back for confirmation.  
    Example: `T-001`.
*   `online` (_boolean_, required) true if the proxy can reach the terminal and it is responding to heartbeats; false if the terminal is unreachable, powered off, or has not sent a heartbeat within the expected window.
*   `lastSeen` (_string (date-time)_, nullable) Timestamp of the last successful heartbeat or communication from this terminal. Null if the terminal has never been seen by the proxy.
*   `gateway` (_string_, nullable) The payment gateway this terminal is configured for (e.g., "worldpay", "stripe\_terminal").  
    Example: `worldpay`.

### TerminalInfo

*   `terminalId` (_string_, required) Unique device ID of the terminal as registered with the proxy.  
    Example: `T-001`.
*   `name` (_string_, required) Human-readable display name for the terminal. Shown in the POS terminal selection UI.  
    Example: `Register 1 Terminal`.
*   `ipAddress` (_string_, nullable) IP address of the terminal on the store LAN. Null if the terminal communicates via a non-IP protocol.  
    Example: `192.168.1.100`.
*   `online` (_boolean_, required) Whether the terminal is currently online and reachable by the proxy.
*   `gateway` (_string_, required) The payment gateway this terminal is configured for (e.g., "worldpay", "stripe\_terminal").  
    Example: `worldpay`.
*   `modelNumber` (_string_, nullable) Terminal hardware model number (e.g., "VX820", "Lane/3000"). Useful for support and diagnostics.  
    Example: `VX820`.
*   `serialNumber` (_string_, nullable) Terminal serial number. Useful for support and asset tracking.  
    Example: `SN-123456`.

### ProxyGiftCardRequest

*   `transactionId` (_string (uuid)_, required) Unique transaction identifier
*   `operationType` (_string_, required) The gift card operation to perform  
    Allowed values: `activate`, `load`, `unload`, `balance`, `cashout`, `payment`, `reversal`, `refund`, `verify`.
*   `cardNumber` (_string_, nullable) Gift card number (null if terminal reads it)
*   `amount` (_number_, nullable) Amount in minor units. Required for load, unload, cashout, payment, reversal, refund
*   `currency` (_string_, required) ISO 4217 currency code  
    Example: `USD`.
*   `gateway` (_string_, required) Gateway identifier from proxy configuration
*   `terminalId` (_string_, required) Terminal identifier
*   `originalTransactionId` (_string_, nullable) Required for reversal and verify operations
*   `metadata` (_object_, nullable)
    
    Additional properties: `string`.
    
*   `timestamp` (_string (date-time)_)
*   `gatewayContext` (_GatewayContext_)

### ProxyGiftCardResponse

*   `transactionId` (_string_, required)
*   `status` (_PaymentStatus_, required)
*   `balance` (_number_, nullable) Current card balance
*   `authCode` (_string_, nullable) Authorization code from gateway
*   `cardNumber` (_string_, nullable) Card number (may differ from request if terminal read card)
*   `timestamp` (_string (date-time)_, required)
*   `gatewayContext` (_GatewayContext_)

### ProxyCardAcquisitionRequest

*   `transactionId` (_string (uuid)_, required)
*   `terminalId` (_string_, required)
*   `gateway` (_string_, required)
*   `paymentAmount` (_number_, nullable) Optional amount for $0 auth verification
*   `metadata` (_object_, nullable)
    
    Additional properties: `string`.
    
*   `timestamp` (_string (date-time)_, required)

### ProxyCardAcquisitionResponse

*   `transactionId` (_string_, required)
*   `status` (_PaymentStatus_, required)
*   `paymentToken` (_string_, nullable) Tokenized card reference for future use
*   `paymentBrand` (_string_, nullable) Card brand (e.g., visa, mastercard)
*   `maskedPan` (_string_, nullable) Masked card number (e.g., \*\*\*\*1234)
*   `first6` (_string_, nullable) First 6 digits (BIN)
*   `last4` (_string_, nullable) Last 4 digits
*   `entryMethod` (_string_, nullable)  
    Allowed values: `chip`, `contactless`, `swipe`, `manual`.
*   `timestamp` (_string (date-time)_, required)

### ProxyDisplayRequest

*   `lines` (_array of ProxyDisplayLine_, required)
*   `terminalId` (_string_, required)

### ProxyDisplayResponse

*   `success` (_boolean_, required)
*   `message` (_string_, nullable)

### ProxyInputRequest

*   `inputType` (_string_, required)  
    Allowed values: `text`, `digitString`, `getConfirmation`.
*   `promptLines` (_array of string_, required)
*   `terminalId` (_string_, required)

### ProxyInputResponse

*   `success` (_boolean_, required)
*   `value` (_string_, nullable) Text/digit value (for text and digitString types)
*   `confirmed` (_boolean_, nullable) Confirmation result (for getConfirmation type)
*   `message` (_string_, nullable)

### PBLCreateRequest

*   `transactionId` (_string_, required) Unique identifier for this PBL transaction, generated by the client.  
    Example: `pbl-550e8400-e29b-41d4-a716-446655440000`.
*   `amount` (_number (decimal)_, required) Payment amount with decimal precision.  
    Example: `49.99`.
*   `currency` (_string_, required) ISO 4217 three-letter currency code.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `gateway` (_string_, required) Gateway identifier configured on the proxy (e.g., "worldpay").  
    Example: `worldpay`.
*   `shopperEmail` (_string_, nullable) Email address of the shopper. Used by some gateways to send the payment link directly to the customer.  
    Example: `shopper@example.com`.
*   `merchantReference` (_string_, nullable) Merchant-defined reference for the payment (e.g., order ID).  
    Example: `PS-ORDER-001`.
*   `tokenize` (_boolean_, nullable) Whether to tokenize the card used for payment. Default: false.
*   `captureNow` (_boolean_, nullable) If true, capture immediately on authorization. If false, authorize only (requires separate capture). Default determined by gateway config.
*   `timestamp` (_string (date-time)_, required) Request creation timestamp in ISO 8601 format. Included in the HMAC signature.  
    Example: `2026-03-23T10:00:00.000Z`.

### PBLCreateResponse

*   `paymentLinkId` (_string_, required) Unique identifier for the created payment link. Used in subsequent expire, status, and refund calls.  
    Example: `PL-12345`.
*   `url` (_string (uri)_, required) The payment link URL to send to the customer. Can be rendered as a QR code or sent via email/SMS.  
    Example: `https://pay.example.com/link/PL-12345`.
*   `expiresAt` (_string (date-time)_, nullable) When the payment link expires in ISO 8601 format. After this time the link is no longer usable.  
    Example: `2026-03-24T10:00:00Z`.
*   `status` (_string_, required) Initial status of the link. Should be "ACTIVE" on successful creation.  
    Example: `ACTIVE`.
*   `gatewayContext` (_GatewayContext_)

### GatewayContext

Opaque gateway-specific context for transaction round-tripping. Returned by the SPI server in responses that create or modify transactions. The client stores this verbatim and passes it back in subsequent operations (void, capture, refund). The client MUST NOT parse or modify this object. When absent in a request, the server falls back to stateful lookup by transactionId. Size SHOULD be kept under 4KB.

_Example_

```
{
  "pspReference": "8535516979155668",
  "merchantReference": "ORD-12345"
}
```

### PBLExpireResponse

*   `paymentLinkId` (_string_, required) The payment link ID that was expired.  
    Example: `PL-12345`.
*   `status` (_string_, required) Status after expiration. Should be "EXPIRED".  
    Example: `EXPIRED`.

### PBLStatusResponse

*   `paymentLinkId` (_string_, required) The payment link ID.  
    Example: `PL-12345`.
*   `status` (_PBLStatus_, required)
*   `amount` (_number (decimal)_, nullable) Payment amount, present when a payment has been attempted.  
    Example: `49.99`.
*   `cardDetails` (_CardDetails_)
*   `additionalData` (_object_, nullable) Gateway-specific additional data returned with the status.
*   `gatewayContext` (_GatewayContext_)

### PBLRefundRequest

*   `transactionId` (_string_, required) Unique identifier for this refund/void transaction.  
    Example: `rfnd-001`.
*   `originalTransactionId` (_string_, required) The original payment transaction ID being refunded/voided.  
    Example: `txn-001`.
*   `amount` (_number (decimal)_, nullable) Refund amount. When present, a refund is performed for the specified amount (may be partial). When absent or null, the server performs a void of the pre-settlement authorization.  
    Example: `10.5`.
*   `currency` (_string_, required) ISO 4217 three-letter currency code.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `timestamp` (_string (date-time)_, required) Request creation timestamp in ISO 8601 format. Included in HMAC.  
    Example: `2026-03-23T12:00:00.000Z`.
*   `gatewayContext` (_GatewayContext_)

### PBLRefundResponse

*   `transactionId` (_string_, required) Echo of the refund/void transaction ID from the request.  
    Example: `rfnd-001`.
*   `status` (_string_, required) Result status. "REFUNDED" for successful refunds, "VOIDED" for successful voids, "DECLINED" or "ERROR" for failures.  
    Allowed values: `REFUNDED`, `VOIDED`, `DECLINED`, `ERROR`. Example: `REFUNDED`.
*   `refundId` (_string_, nullable) Gateway-assigned refund reference ID. Present for successful refunds.  
    Example: `ref-gateway-001`.
*   `amount` (_number (decimal)_, nullable) The refunded amount. Present for refunds, absent for voids.  
    Example: `10.5`.
*   `message` (_string_, nullable) Human-readable message providing additional context, especially for void responses or error details.  
    Example: `Authorization voided successfully`.
*   `gatewayContext` (_GatewayContext_)

### SAFQueryResponse

*   `transactions` (_array of SAFTransaction_, required) List of offline transactions from the terminal's SAF queue. Empty array if no transactions are queued.
*   `terminalId` (_string_, required) The terminal that was queried.  
    Example: `T-001`.
*   `queryTimestamp` (_string (date-time)_, required) When the query was executed (ISO 8601).

### ValidateOfflineRequest

*   `transactionId` (_string_, required) Unique identifier for this offline transaction.  
    Example: `txn-offline-001`.
*   `amount` (_number (decimal)_, required) Payment amount with decimal precision.  
    Example: `49.99`.
*   `currency` (_string_, required) ISO 4217 currency code.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `gateway` (_string_, required) Gateway identifier.  
    Example: `elavon`.
*   `terminalId` (_string_, required) Terminal that captured the offline payment.  
    Example: `T-001`.
*   `offlinePayload` (_object_, required) Gateway-specific partial payment payload captured offline by the terminal. Opaque to the iOS client — passed through to the SPI server which forwards it to the gateway for completion.
*   `timestamp` (_string (date-time)_, required) Request creation timestamp (ISO 8601). Included in HMAC.

### ValidateOfflineResponse

*   `transactionId` (_string_, required) Echo of the transaction ID from the request.  
    Example: `txn-offline-001`.
*   `status` (_PaymentStatus_, required)
*   `authCode` (_string_, nullable) Authorization code from the gateway, if approved.  
    Example: `AUTH123`.
*   `receiptData` (_ReceiptData_)
*   `timestamp` (_string (date-time)_, required) When the server generated this response (ISO 8601).
*   `gatewayContext` (_GatewayContext_)

### TerminalOfflineStatus

Terminal offline status. Only available when the terminal/gateway supports reporting this information. The SPI server proxies to the terminal.

*   `terminalId` (_string_, required) The terminal device ID.  
    Example: `T-001`.
*   `isOffline` (_boolean_, required) true if the terminal is currently operating in offline mode; false if operating normally with gateway connectivity.
*   `safQueueDepth` (_integer_, nullable) Number of transactions in the terminal's SAF queue. Null if the terminal does not report queue depth.  
    Example: `5`.
*   `lastOnlineTimestamp` (_string (date-time)_, nullable) When the terminal was last online (ISO 8601). Null if not reported.
*   `timestamp` (_string (date-time)_, required) When the server generated this response (ISO 8601).

### PaymentType

The type of payment transaction:

*   "sale": Standard transaction that settles immediately in the gateway's next batch.
*   "pre\_authorization": Hold placed on the cardholder's account. Requires a separate capture call before settlement. The hold amount may be partially or fully captured.

Type: `string`.

Allowed values: `sale`, `pre_authorization`. Example: `sale`.

### PaymentStatus

Terminal payment authorization result:

*   "APPROVED": Payment authorized by the card issuer.
*   "DECLINED": Payment declined by the card issuer.
*   "CANCELLED": Payment cancelled by operator or customer before authorization completed.
*   "ERROR": An error occurred during processing on the terminal or gateway.
*   "TIMEOUT": The terminal or card issuer did not respond within the expected time window.
*   "PENDING": Partial authorization received (split-tender scenario where the issuer approved less than requested).

Type: `string`.

Allowed values: `APPROVED`, `DECLINED`, `CANCELLED`, `ERROR`, `TIMEOUT`, `PENDING`. Example: `APPROVED`.

### ReceiptData

Structured receipt data returned after a successful payment. Contains separate arrays for merchant and customer receipt copies. Null when the terminal does not return receipt data (e.g., declined transactions).

*   `merchantCopy` (_array of ReceiptLine_, nullable) Structured line items for the merchant's receipt copy. May contain additional fields not present in the customer copy (e.g., cardholder verification method). Null when the gateway does not provide structured receipt data.
*   `customerCopy` (_array of ReceiptLine_, nullable) Structured line items for the customer's receipt copy. Typically a subset of the merchant copy.

### CardDetails

Masked card information returned by the terminal after a payment. Null when no card was presented (e.g., transaction cancelled before card insert).

*   `maskedPan` (_string_, required) Masked Primary Account Number. Only the last 4 digits are visible (e.g., "\*\*\*\*1234"). The terminal/gateway handles masking; the proxy passes it through.  
    Example: `****1234`.
*   `cardBrand` (_string_, required) Card network brand. Common values: "VISA", "MASTERCARD", "AMEX", "DISCOVER", "JCB", "UNIONPAY", "DINERS".  
    Example: `VISA`.
*   `entryMethod` (_string_, required) How the card was presented at the terminal: "CHIP" (EMV chip inserted), "CONTACTLESS" (NFC tap -- card or mobile wallet), "SWIPE" (magnetic stripe), "MANUAL" (manually keyed).  
    Allowed values: `CHIP`, `CONTACTLESS`, `SWIPE`, `MANUAL`. Example: `CHIP`.
*   `cardTypeVariant` (_string_, nullable) Card type variant as reported by the gateway. Common values: "CREDIT", "DEBIT". Null if the gateway does not distinguish card types.  
    Example: `CREDIT`.
*   `fundingSource` (_string_, nullable) Funding source of the card. Common values: "CREDIT", "DEBIT", "PREPAID". Null if not reported by the gateway.  
    Example: `CREDIT`.
*   `cardBin` (_string_, nullable) Bank Identification Number -- the first 6-8 digits of the PAN. Used for card identification and routing rules. Null if not reported by the gateway.  
    Example: `411111`.
*   `accountType` (_string_, nullable) Account type selected by the cardholder (for debit cards). Common values: "CHECKING", "SAVINGS". Null for credit cards or if not reported by the gateway.
*   `cardAlias` (_string_, nullable) Shopper reference or tokenized card alias from the gateway. Used for card-on-file or recurring payment scenarios. Null if the gateway does not provide a token.
*   `cardExpirationMonth` (_string_, nullable) Card expiration month as a two-digit string ("01" through "12"). Null if not reported by the gateway.  
    Example: `12`.
*   `cardExpirationYear` (_string_, nullable) Card expiration year. May be two-digit ("27") or four-digit ("2027") depending on the gateway. Null if not reported.  
    Example: `2027`.

### RefundType

Whether the refund is linked to an original transaction:

*   "referenced": Linked to an original payment via originalTransactionId. The gateway matches the refund to the original charge for reconciliation and reporting.
*   "unreferenced": Standalone credit to the card presented at the terminal, not linked to any prior transaction.

Type: `string`.

Allowed values: `referenced`, `unreferenced`. Example: `referenced`.

### ProxyDisplayLine

*   `type` (_string_, required)  
    Allowed values: `title`, `product`, `summary`, `total`, `taxItem`, `taxTotal`.
*   `content` (_string_, required)
*   `quantity` (_number_, nullable)
*   `amount` (_number_, nullable)

### PBLStatus

Status of a Pay By Link payment link:

*   "ACTIVE": Link created and awaiting payment.
*   "APPROVED": Payment completed successfully via the link.
*   "DECLINED": Payment attempted but declined by the issuer.
*   "EXPIRED": Link expired without payment.
*   "REFUNDED": Completed payment was refunded.
*   "VOIDED": Pre-settlement authorization was voided.
*   "ERROR": An error occurred during processing.

Type: `string`.

Allowed values: `ACTIVE`, `APPROVED`, `DECLINED`, `EXPIRED`, `REFUNDED`, `VOIDED`, `ERROR`. Example: `ACTIVE`.

### SAFTransaction

A single offline transaction from the terminal's Store and Forward queue. Contains only masked card data — no PAN, CVV, or PCI-scoped fields.

*   `transactionId` (_string_, required) Unique transaction identifier.
*   `status` (_PaymentStatus_, required)
*   `amount` (_number (decimal)_, required) Transaction amount with decimal precision.  
    Example: `49.99`.
*   `currency` (_string_, required) ISO 4217 currency code.  
    Minimum length: 3. Maximum length: 3. Example: `USD`.
*   `maskedPan` (_string_, nullable) Masked card number (e.g., "\*\*\*\*1234").  
    Example: `****1234`.
*   `cardBrand` (_string_, nullable) Card network brand (e.g., "VISA", "MASTERCARD").  
    Example: `VISA`.
*   `entryMethod` (_string_, nullable) How the card was presented (CHIP, CONTACTLESS, SWIPE, MANUAL).  
    Example: `CHIP`.
*   `timestamp` (_string (date-time)_, required) When the transaction was captured on the terminal.
*   `gatewayContext` (_GatewayContext_)

### ReceiptLine

A single line item in a structured receipt. Maps 1:1 to the POS CardReaderReceiptLine model used by existing payment integrations.

*   `key` (_string_, required) Machine-readable identifier for this receipt field. Used programmatically to extract specific values (e.g., for mapping to POS tender data). Common keys: "pan", "aid", "authCode", "cardholderName", "transactionType".  
    Example: `pan`.
*   `display` (_string_, required) Human-readable label suitable for printing on a receipt. This is what appears to the left of the value on the printed receipt (e.g., "Card Number", "Auth Code", "AID").  
    Example: `Card Number`.
*   `value` (_string_, required) The data value for this receipt line. Always a string, even for numeric values. Sensitive data should already be masked by the terminal/gateway (e.g., PAN shown as "\*\*\*\*1234").  
    Example: `****1234`.

### PaymentEventType

Types of real-time payment events streamed via WebSocket. Maps to terminal state transitions during a payment flow:

*   "CONNECTED": WebSocket handshake complete, proxy ready.
*   "CARD\_INSERTED": Card inserted or tapped on terminal.
*   "PIN\_ENTRY\_STARTED": Terminal prompting for PIN entry.
*   "PIN\_ENTRY\_COMPLETED": Customer finished entering PIN.
*   "AUTHORIZATION\_STARTED": Terminal sending auth request to issuer.
*   "AUTHORIZATION\_APPROVED": Issuer approved the authorization.
*   "AUTHORIZATION\_DECLINED": Issuer declined the authorization.
*   "ERROR": An error occurred on the terminal.
*   "CANCELLED": Payment was cancelled.
*   "PBL\_LINK\_CREATED": Pay By Link URL generated and ready.
*   "PBL\_PAYMENT\_STARTED": Customer opened the payment link.
*   "PBL\_PAYMENT\_APPROVED": Payment completed via the link.
*   "PBL\_PAYMENT\_DECLINED": Payment attempted via link but declined.
*   "PBL\_LINK\_EXPIRED": Payment link expired without payment.

Type: `string`.

Allowed values: `CONNECTED`, `CARD_INSERTED`, `PIN_ENTRY_STARTED`, `PIN_ENTRY_COMPLETED`, `AUTHORIZATION_STARTED`, `AUTHORIZATION_APPROVED`, `AUTHORIZATION_DECLINED`, `ERROR`, `CANCELLED`, `PBL_LINK_CREATED`, `PBL_PAYMENT_STARTED`, `PBL_PAYMENT_APPROVED`, `PBL_PAYMENT_DECLINED`, `PBL_LINK_EXPIRED`.

### PaymentEvent

A real-time event received via the WebSocket connection during a payment flow. Events provide terminal status updates as the cardholder interacts with the terminal (card insert, PIN entry, authorization progress).

*   `eventType` (_PaymentEventType_, required)
*   `transactionId` (_string (uuid)_, required) The transaction this event belongs to. Matches the transactionId query parameter used to open the WebSocket connection.
*   `timestamp` (_string (date-time)_, required) When the event occurred on the proxy/terminal side, in ISO 8601 format.
*   `data` (_object_, nullable) Optional event-specific key-value data. Keys and structure vary by event type. Values may be strings, numbers, or booleans -- the iOS client coerces all values to strings internally. Common keys by event type: CARD\_INSERTED -> "terminalMessage"; ERROR -> "errorCode", "errorMessage"; AUTHORIZATION\_APPROVED -> "authCode"; CANCELLED -> "reason".
    
    _Example_
    
    ```
    {
      "terminalMessage": "Please insert card",
      "remainingRetries": 3
    }
    ```