Skip to content

Linq

Linq is Synqpay's cloud gateway for real-time communication with the device — a single HTTPS call that executes your JSON-RPC request on the real device and hands back its actual response, as if you were calling it directly.

Overview

Every other transport in this section (HTTP, TCP, WebSocket, Serial) requires your client to be on the same local network as the device, or physically connected to it. Linq removes that requirement: your integration calls Linq from anywhere, Linq relays the request to the device over its own persistent connection, waits for the device to actually process it, and hands back the device's real JSON-RPC response synchronously — as if you'd called the device directly.

The JSON-RPC request/response contract itself is unchanged — same method/params/id, same error object shape. What Linq adds is the transport (cloud-reachable HTTPS instead of LAN), OAuth2-based authentication in place of a device-paired api-key, and a small set of its own headers to support that (idempotent retries, an operation id to reference later, and a status describing how the relay itself went).

Endpoints

Linq uses two separate hosts:

Host Purpose
<linq-auth-host> Issues OAuth2 access tokens.
<linq-application-host> Serves the actual JSON-RPC API (/synqpay/rpc).

Hosts aren't published here

Both hosts are provided to you independently as part of onboarding — they aren't public and won't appear in this documentation. Everywhere below, <linq-auth-host>/<linq-application-host> are placeholders for the values you were given.

Authorization

Unlike the local transports' device-paired api-key, Linq doesn't use an api-key at all. Authentication is OAuth2, and it authenticates the caller (your integration), not a specific device.

  1. Log in to your DMS account.
  2. Create an OAuth Client Application (see Getting Started for the step-by-step walkthrough).
  3. Use that client's credentials to obtain an access token via the client_credentials grant.
  4. Send that token as a bearer token on every call to <linq-application-host>.

Obtaining a token

POST https://<linq-auth-host>/oauth2/token
Content-Type: application/x-www-form-urlencoded

Body parameters:

Parameter Required Description
grant_type Yes Must be client_credentials.
client_id Yes Your OAuth Client Application's id.
client_secret Yes Your OAuth Client Application's secret.
scope Yes linq/rpc

Response:

1
2
3
4
5
{
    "access_token": "eyJra...",
    "token_type": "Bearer",
    "expires_in": 3600
}

Using the token

Authorization: Bearer <access_token>

against <linq-application-host>. With that token, you can reach every device registered in DMS to the account your OAuth Client Application belongs to — access isn't scoped per-device or per-request, it's inherited entirely from the account.

Making a Request

POST https://<linq-application-host>/synqpay/rpc

Request Headers

Header Required Description
Authorization Yes Bearer <access_token>
X-Device-ID Yes Target device identifier. Case-insensitive.
X-Idempotency-Key Yes See Idempotency below. Max 128 characters.
Content-Type Yes application/json

Device ID format

A device id is <brand>_<serial-number>, all lowercase — for example, ingenico_244rkr528387. Supported brands: ingenico, castles, verifone.

Response Headers

Header Description
X-Idempotency-Key Echoes back the key sent in the request.
X-Operation-Id Server-generated id for this operation. Stable across idempotent retries of the same key.
X-Request-Status Where this specific request got to — see table below.

X-Request-Status values

Important

X-Request-Status describes what happened to the request itself, not whether the operation succeeded. COMPLETED means a response was received from the device — a device-level failure (e.g. MissingParam) still comes back as X-Request-Status: COMPLETED, with the actual error object inside the JSON-RPC response body, exactly as the device produced it.

Value Meaning
NOT_DISPATCHED The request never reached the device — it failed on Linq's side before it could be sent. If you see this, nothing was attempted against the device at all.
UNREACHABLE The device never acknowledged the request — it's likely offline.
TIMED_OUT The device acknowledged the request but never sent a final response within the timeout.
COMPLETED A final response was received from the device and is returned in the body — check the body's own result/error for the actual outcome.
ERROR The request was dispatched, but Linq failed to relay the outcome (e.g. a malformed response from the device, or an internal relay error) — not a device-level JSON-RPC error.

Note

If X-Request-Status is missing entirely (e.g. an authentication failure, a 413/429 rejection, or Linq shutting down for a deploy), treat it the same as NOT_DISPATCHED — the request never reached this stage at all, so nothing was ever attempted against the device.

Idempotency

X-Idempotency-Key scopes to your account, not to a specific device — the same value must not be reused for two different logical operations.

  • Reusing a key with an identical request (same method, id, and params) is safe: Linq returns the original result without re-executing anything against the device.
  • Reusing a key with a different request is rejected as a conflict (see 409 Conflict, IdempotencyConflictError).
  • Only a dispatched request registers its Idempotency-Key as consumed. A request that comes back NOT_DISPATCHED, or that fails before a request status is even determined (e.g. a disabled device, rejected with 403 before dispatch is ever considered), never registers the key at all — it stays reusable once you retry.
  • If the device did acknowledge the request but no final response ever arrived (TIMED_OUT), that outcome is permanent for this key — retrying needs a new Idempotency-Key, since the device may still be processing the original one.

Timing

A call to /synqpay/rpc blocks synchronously until one of the following happens:

  • The device acknowledges the request within 2 seconds — otherwise the call returns immediately with X-Request-Status: UNREACHABLE.
  • The device sends its final response within 4 minutes of acknowledging — otherwise the call returns with X-Request-Status: TIMED_OUT.

There is no separate polling step — the single HTTP request is held open for the full round trip.

Hebrew / Arabic support

The Synqpay API supports UTF-8 encoding for all characters, including Hebrew and Arabic. It is highly recommended that each request include the header Content-Type: application/json; charset=utf-8.

CORS

Linq is a server-to-server integration, and CORS is not enabled. A browser calling <linq-application-host> directly will be blocked by the browser's same-origin policy. This is deliberate — your OAuth client credentials should never be exposed to a browser context.


Status Codes and Errors

Unlike the local transports (which always return HTTP 200 for any JSON-RPC call, success or device-level error), Linq uses real HTTP status codes for problems at the relay layer — authentication, validation, rate limiting, and so on. A device-level JSON-RPC error still comes back as HTTP 200, with the error inside the response body.

Status Body Description
200 Relay succeeded — body is the device's own JSON-RPC response (result or error).
400 Bad request — malformed JSON-RPC envelope, missing/invalid headers, unknown device, or the device was unreachable/timed out.
401 Authentication failed.
403 Access denied — you're not authorized for this device, or it's disabled.
409 Idempotency key conflict.
413 Request body too large.
429 Too many requests from this client.
500 Internal error.
503 Service Unavailable. Retry after a short backoff.

Statuses with a body return the same JSON-RPC error object shape as device errors:

1
2
3
4
5
6
7
8
{
    "jsonrpc": "2.0",
    "id": "1234",
    "error": {
        "code": 1102,
        "message": "device not found"
    }
}

The code's numeric range tells you the source: Linq's own codes are always 4 digits (1000+) or a negative JSON-RPC reserved code; device application errors are always in the 100499 range.

400 Bad Request

Code Name Description
-32700 ParseError The request body isn't valid JSON, or the JSON-RPC envelope is structurally invalid (a required field like jsonrpc, method, or id is missing or malformed).
1001 InvalidInputError A request header or field failed validation (e.g. a missing or oversized X-Device-ID/X-Idempotency-Key).
1102 DeviceNotFoundError The X-Device-ID header doesn't match a device known to your account.
1201 DeviceUnreachableError The device never acknowledged the request within 2 seconds — it's likely offline.
1202 DeviceTimeoutError The device acknowledged the request but didn't send a final response within 4 minutes.

401 Unauthorized

No error body is returned for authentication failures. Every cause — missing/malformed Authorization header, expired or invalid token, a disabled or unknown account — produces an identical, bodyless 401, deliberately, so a caller can't distinguish "wrong token" from "unknown account." Confirm your bearer token is present and unexpired, and re-authenticate against <linq-auth-host> if needed.

403 Forbidden

Code Name Description
1101 AccessDeniedError Either your credentials aren't authorized for this device, or the device is disabled.

409 Conflict

Code Name Description
1300 IdempotencyConflictError The X-Idempotency-Key was reused with a different request (different method, id, or params) — see Idempotency.

500 Internal Server Error

Code Name Description
1000 InternalError An unexpected internal error occurred on Linq's side. Retry; if it persists, contact support with the request's approximate time and X-Operation-Id (if one was returned).

Postman

Test /synqpay/rpc calls against your device without writing any code.

Before you start

You'll need:

  • Your two Linq hosts (<linq-auth-host>/<linq-application-host>) and your OAuth Client Application's client_id/client_secret — see Getting Started if you don't have these yet.
  • A device id registered to your account.
  • Postman installed, or the web version.

Get the collection

Click Run in Postman to fork the collection into your own workspace.

Run In Postman

Forking also prompts you to create a Postman Environment — this is where the collection's variables live.

Warning

Creating the environment doesn't select it. Use the environment dropdown in Postman's top-right corner to make it active — otherwise {{variables}} won't resolve and every request will fail.

Set up your environment

Fill in the following variables in your environment:

Variable Value
linq-auth-host Your auth host
linq-application-host Your application host
linq-client-id Your OAuth Client Application's id
linq-client-secret Your OAuth Client Application's secret
device-id The device you want to call

Leave bearer-token empty — it's filled in automatically in the next step.

Get a bearer token

Open the Linq Authorization folder and run the token request. On a successful response, a script automatically saves the returned access_token into your bearer-token variable. Every request in the Synqpay API folder inherits the collection's Bearer auth from that same variable, so this is the only manual step — repeat it whenever your token expires.

Make your first call

Open the Synqpay API folder and send any request — for example, getDeviceInfo. X-Device-ID is filled from your device-id variable, and a fresh X-Idempotency-Key is generated automatically on every send — there's nothing else to configure per request.