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.
- Log in to your DMS account.
- Create an OAuth Client Application (see Getting Started for the step-by-step walkthrough).
- Use that client's credentials to obtain an access token via the
client_credentialsgrant. - Send that token as a bearer token on every call to
<linq-application-host>.
Obtaining a token
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:
Using the 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
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, andparams) 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-Keyas consumed. A request that comes backNOT_DISPATCHED, or that fails before a request status is even determined (e.g. a disabled device, rejected with403before 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 newIdempotency-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:
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 100–499 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'sclient_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.
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.