OPI Proxy

This page is currently only available in English.

Latest Release GitHub Repo

The Nexi OPI Proxy gives integrators a much cleaner way to work with Nexi terminals in Switzerland.

Instead of building a direct TCP and XML integration against OPI, you run one local Docker service and call a smaller HTTP and JSON API. The proxy keeps the OPI transport, XML message handling, terminal callbacks, receipts, and transaction follow-up logic inside the service.

The idea is simple: your application talks HTTP and JSON, the proxy talks OPI to the terminal.

Nexi OPI Proxy JSON payment request and response example

Start using the Nexi OPI Proxy today!

Check out the Nexi OPI Proxy on GitHub, built to make terminal integrations over the OPI protocol much simpler and save unnecessary integration work.

richiehug/nexi-opi-proxy

What a First Payment Looks Like

One of the nicest things about the proxy is that payments can be initiated by simple requests. To start a payment, just call /terminals/:terminalAlias/payment.

{
  "reference": "ORDER-1001",
  "amount": 49.90,
  "currency": "CHF"
}

With the recommended asynchronous mode, the proxy accepts the request after it has reached the terminal and returns a stored transactionId with HTTP 202 Accepted:

{
  "transactionId": "33866707-9cd9-45fd-bd71-e743c879691c",
  "status": "pending",
  "terminalAlias": "my-terminal"
}

Poll GET /transactions/:transactionId until the stored transaction reaches a final state. A 202 means accepted for processing, not paid successfully.

That is the main benefit of the OPI Proxy: your application stays close to a modern API model while the proxy handles the OPI conversation with the terminal. No custom TCP framing, manual XML request building, or terminal callback handling is needed in the checkout application.

Official Terminal Scope

The public release line supports:

  • Ingenico RX5000, DX8000, and EX8000
  • PAX Q30 and A77
  • PAX IM15 and IM30 for validated unattended proxy-mode flows

Other models may exist in development, but they are not part of the official public support statement.

Why Integrators Use the Proxy

Direct OPI is proven and powerful, but it pushes a lot of low-level responsibility into the POS.

A direct OPI integration usually needs to handle:

  • framed TCP messaging
  • XML request construction
  • XML response parsing
  • DeviceRequest and DeviceResponse handling
  • receipt and journal handling
  • terminal-specific operational behaviour
  • transaction reference storage for later capture, cancel, refund, and reprint

The proxy keeps that complexity out of the POS codebase and lets modern applications integrate over HTTP instead. For many integrators, this means a smaller integration surface, faster testing, and less terminal-specific code in the main checkout application.

What the Proxy Abstracts

The proxy hides:

  • TCP socket handling to the terminal
  • OPI XML request generation
  • OPI XML response parsing
  • terminal callback handling during live flows
  • receipt storage and transaction-linked receipt lookup
  • selectable JSON or SQLite runtime persistence
  • stored transaction follow-up for capture, cancel, refund, and receipt retrieval

From the POS side, the model becomes:

  • HTTP requests
  • JSON payloads
  • bearer tokens
  • stable terminalAlias values
  • stored transactionId based follow-up actions

The POS no longer needs to understand every OPI detail directly. It only needs to call the proxy API and handle the resulting transaction state.

What You Can Do Today

The current public proxy covers:

Route What you can do
GET /health Confirm that the proxy is running and read its release version.
GET /terminals/:terminalAlias/info Read terminal identity, software, acquirer, and supported-brand information.
GET /terminals/:terminalAlias/status Request the live OPI terminal status.
GET /terminals/:terminalAlias/ping Check network reachability without opening an OPI session.
POST /terminals/:terminalAlias/payment Start a sale, preauthorisation, cashback, or approved Forced Acceptance payment.
POST /terminals/:terminalAlias/refund Start a standalone terminal-side refund.
POST /terminals/:terminalAlias/reversal Reverse the terminal's last payment.
POST /transactions/:transactionId/capture Capture a stored preauthorisation.
POST /transactions/:transactionId/cancel Cancel a stored preauthorisation.
POST /transactions/:transactionId/refund Refund a specific stored sale or capture.
GET /transactions/:transactionId Read the persisted source-of-truth transaction state, including DCC results when available.
GET /transactions/:transactionId/receipts Retrieve receipts linked to a known transaction.
GET /terminals/:terminalAlias/receipts/latest Retrieve the latest transaction or terminal-service receipt bundle.
GET /terminals/:terminalAlias/receipts?limit=5 List recent receipt bundles for a terminal.
POST /terminals/:terminalAlias/reprint Request the last receipt again and support receipt-based recovery.
POST /terminals/:terminalAlias/activate Activate or log in the terminal.
POST /terminals/:terminalAlias/deactivate Deactivate or log out the terminal.
POST /terminals/:terminalAlias/abort Abort the active pending card flow.
POST /terminals/:terminalAlias/transmit Submit terminal-side transactions.
POST /terminals/:terminalAlias/close Perform final balance and logoff.
POST /terminals/:terminalAlias/config Refresh terminal configuration through TMS.
POST /terminals/:terminalAlias/init Refresh merchant and acquirer initialisation.
POST /terminals/:terminalAlias/reset Restart the terminal application.

Long-running routes support synchronous or asynchronous handling. Mutating routes also support Idempotency-Key for safe retries.

Runtime and Security Model

The public distribution is Docker-first. That means:

  • clone the public repo and run with Docker
  • keep merchant-owned state in config/, data/, logs/, and certs/
  • generate config/auth.json during initialization
  • use host networking on the supplied Linux Docker deployment so both OPI directions use the host network stack
  • use HTTP only for initial testing on a trusted network; use HTTPS for shared or remotely reachable deployments

The proxy supports bearer-token authentication with route-level scopes such as:

  • terminals:read
  • terminals:write
  • transactions:read
  • transactions:write
  • receipts:read
  • admin:manage

GET /health stays public for health checks.

Continue with Getting Started, Configuration, API, and Operations and Upgrades. The GitHub repository remains the full release reference, including the OpenAPI description and detailed release notes.

When the Proxy Is a Good Fit

The proxy is a strong fit when:

  • your team prefers HTTP and JSON over raw TCP and XML
  • you want OPI complexity out of the POS codebase
  • you want transaction-based follow-up actions such as capture, cancel, refund, or receipt lookup
  • you want a local integration surface that is easier to support operationally
  • you want terminal aliases instead of hard-coding terminal IPs and ports throughout your POS
  • you want a cleaner separation between checkout logic and terminal protocol handling

When Direct OPI May Still Be the Better Fit

A direct OPI integration may still be the better fit when:

  • your system already has a mature OPI stack
  • you need full control over every OPI message
  • you want to implement terminal-specific behaviour directly in the POS
  • your architecture does not allow a local proxy service
  • your unattended flow needs direct custom control over terminal-side delivery confirmation

The proxy is not meant to remove OPI as an option. It gives integrators a simpler path when they do not want to own the low-level protocol integration themselves.