1. Quickstart: your first payment (Local API)

This guide takes you from zero to a first approved payment over the Local API (HTTP) in about ten minutes. It uses curl so you can verify the flow before writing any code.

Prerequisites

  • A provisioned terminal on your local network (see Connect your terminal to POS) and its IP address.
  • The terminal in integrated mode, reachable on port 8080.

Step 1 — Open a session

Every Local API integration starts with a Login. Send it once when your POS starts, not per transaction.

curl -X POST http://TERMINAL_IP:8080/login \
  -H "Content-Type: application/json" \
  -d '{
    "MessageHeader": {"ProtocolVersion":"3.1","MessageClass":"Service","MessageCategory":"Login","MessageType":"Request","ServiceID":"1","SaleID":"POS_01","POIID":"POI_01"},
    "LoginRequest": {"DateTime":"2026-07-06T10:00:00.0+02:00","OperatorID":"Cashier_01","OperatorLanguage":"EN","SaleSoftware":[{"ApplicationName":"MyPOS","ProviderIdentification":"POS_ID","SoftwareVersion":"1.0.0"}]}
  }'

A successful response contains LoginResponse.Response.Result = "Success". Store the POISerialNumber it returns — see Session and login lifecycle for why.

Step 2 — Send a payment

curl -X POST http://TERMINAL_IP:8080/payment \
  -H "Content-Type: application/json" \
  -d '{
    "MessageHeader": {"ProtocolVersion":"3.1","MessageClass":"Service","MessageCategory":"Payment","MessageType":"Request","ServiceID":"2","SaleID":"POS_01","POIID":"POI_01"},
    "PaymentRequest": {
      "PaymentData": {"PaymentType":"Normal"},
      "PaymentTransaction": {"AmountsReq":{"Currency":"EUR","RequestedAmount":"11.99"}},
      "SaleData": {"OperatorID":"Cashier_01","SaleTransactionID":{"TimeStamp":"2026-07-06T10:01:00.0+02:00","TransactionID":"1001"}}
    }
  }'

The terminal replies 202 Accepted immediately — the payment has started, not finished. The ServiceID changed (2): the terminal does not require or check this, but varying it per request makes logs far easier to correlate.

Step 3 — Poll for the result

curl http://TERMINAL_IP:8080/payment

While the cardholder is presenting their card you receive 206 — keep polling (once per second is fine). When the transaction completes you receive 200 with the PaymentResponse. Check:

  • Response.ResultSuccess or Failure
  • PaymentResult.AmountsResp.AuthorizedAmount — may be lower than requested (partial authorisation)
  • POIData.POITransactionIDstore this; you need it for reversals and refunds

Warning

Never treat 206 as a failure and never re-send the payment while polling. Set your HTTP client timeout above 90 seconds — see Transport bindings for the full rules.

Step 4 — Close the session

curl -X POST http://TERMINAL_IP:8080/logout \
  -H "Content-Type: application/json" \
  -d '{"MessageHeader":{"ProtocolVersion":"3.1","MessageClass":"Service","MessageCategory":"Logout","MessageType":"Request","ServiceID":"3","SaleID":"POS_01","POIID":"POI_01"},"LogoutRequest":{}}'

Where to go next

  • How the message model works — the rules behind ServiceID, transaction IDs and error conditions.
  • Transport bindings — HTTP & TCP/IP — the polling contract in full, plus the socket transport.
  • Taking a payment — the complete payment guide: partial authorisation, signature, receipts.
  • Testing & certification — validate against the Dummy Server before go-live.