Bank Rows
- Base path
/api/v1/physical-pos- Identity
- Ed25519 request signature on every request —
X-Key-Id,X-Date,X-Nonce,X-Signature, plusDigeston requests with a body. ±5 min clock window, single-use nonce. A Bearer token or a panel session is not accepted here. - Authorization
- The key must carry the Physical POS product (
PHYSICAL_POS) and the scope for the endpoints on this page:physical_pos:view·physical_pos:manage. Without the product the call gets403 PRODUCT_NOT_ENABLED; without the scope403 API_INSUFFICIENT_SCOPE. See Authentication and Scopes. - Cross-surface
- These endpoints are the s2s surface — call them from your own server with a signed request. The same records have screens in the panel, but panel endpoints cannot be called with an API key, and these endpoints cannot be called with a panel session.
A logical terminal can work with several banks. For each bank the terminal has a bank row: the merchant number (MID) and terminal number (TID) the bank gave you, and the currencies accepted with this row. Bank rows live in the terminal's environment; a test key can only read bank rows, and write requests get 403 physical_pos.environment.test_key_read_only.
| Method | Path | Scope |
|---|---|---|
GET | /api/v1/physical-pos/terminals/{terminalId}/acquirers | physical_pos:view |
POST | /api/v1/physical-pos/terminals/{terminalId}/acquirers | physical_pos:manage |
PATCH | /api/v1/physical-pos/terminal-acquirers/{terminalAcquirerId} | physical_pos:manage |
The cURL examples compute the signature with lunixi-sign.sh: Authentication › Signing helper.
Bank row object
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Row ID; used as terminalAcquirerId on update. |
terminalId | string (UUID) | The row's terminal. |
environment | string | TEST or LIVE; the terminal's environment. |
vendorAcquirerRef | string | The code the POS vendor gives this bank, as you sent it. |
acquirerCode | string | null | The four-digit code of the mapped bank (acquirerCode in the catalog). null if not mapped. |
acquirerDisplayName | string | null | Name of the mapped bank. null if not mapped. |
mappingStatus | string | MAPPED: vendorAcquirerRef was mapped to a bank in the catalog. UNMAPPED: no mapping. |
merchantNumber | string | The merchant number (MID) from the bank. |
terminalNumber | string | The terminal number (TID) from the bank. |
label | string | null | Your own label for the row. |
currencies | string[] | Currencies accepted with this row (ISO 4217), in alphabetical order. |
verificationStatus | string | UNVERIFIED: entered manually, not confirmed by the vendor. VENDOR_CONFIRMED: confirmed by the vendor. |
source | string | Where the row came from: MANUAL (added in the panel or via the API), VENDOR_ACCOUNT or DEVICE_REPORTED. |
acquirerStatus | string | ACTIVE or DISABLED. |
lastSyncedAt | string | null | When the row was last updated from the vendor; null for manually added rows. |
rowVersion | integer | The row's concurrency version. → rowVersion |
createdAt | string | Creation time. |
updatedAt | string | Last change time. |
List bank rows
GET /api/v1/physical-pos/terminals/{terminalId}/acquirers
| Query parameter | Type | Description |
|---|---|---|
limit | integer | Rows per page, 1–100. Default 25. |
cursor | string | pageInfo.nextCursor from the previous response. |
includeTotal | boolean | When true, pageInfo.totalCount is filled. |
The terminal detail already includes the first 100 rows: Retrieve a terminal.
source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminals/00000000-0000-0000-0000-000000000301/acquirers"
lunixi_sign GET "$REQ_PATH"
curl "https://api-gateway.lunixi.com$REQ_PATH" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGNATURE"{
"status": "success",
"code": "SUCCESS",
"data": {
"items": [
{
"id": "00000000-0000-0000-0000-000000000601",
"terminalId": "00000000-0000-0000-0000-000000000301",
"environment": "LIVE",
"vendorAcquirerRef": "B01",
"acquirerCode": "0000",
"acquirerDisplayName": "Example Bank",
"mappingStatus": "MAPPED",
"merchantNumber": "000000000000001",
"terminalNumber": "PS000001",
"label": "Example Bank TRY",
"currencies": ["TRY"],
"verificationStatus": "UNVERIFIED",
"source": "MANUAL",
"acquirerStatus": "ACTIVE",
"lastSyncedAt": null,
"rowVersion": 1,
"createdAt": "2026-01-01T07:30:00.000Z",
"updatedAt": "2026-01-01T07:30:00.000Z"
}
],
"pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null }
},
"pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null },
"statusCode": 200,
"requestId": "00000000-0000-0000-0000-000000000000"
}Add a bank row
POST /api/v1/physical-pos/terminals/{terminalId}/acquirers · Idempotency-Key required
| Field | Type | Required | Description |
|---|---|---|---|
vendorAcquirerRef | string | Yes | The code the POS vendor gives the bank: A-Z, a-z, 0-9; at most 16 characters. Case is kept. |
merchantNumber | string | Yes | Merchant number (MID): A-Z, 0-9; at most 32 characters. Upper-cased. |
terminalNumber | string | Yes | Terminal number (TID): A-Z, 0-9; at most 32 characters. Upper-cased. |
label | string | No | Your own label, at most 64 characters. Follows the text rules. |
currencies | string[] | Yes | ISO 4217 currency codes (e.g. ["TRY"]); no duplicates, at most 16. Upper-cased and stored in alphabetical order. |
Conditions:
- The terminal must have a vendor; a row cannot be added to a vendor-less terminal:
400 physical_pos.terminal.vendor_required. Assign the vendor with a terminal update. - A row cannot be added to a closed terminal:
409 physical_pos.terminal.closed. - If the same terminal already has a row with the same
vendorAcquirerRefandterminalNumber, or one of your terminals in this environment has an active row with that pair:409 physical_pos.acquirer.duplicate.
Lunixi maps vendorAcquirerRef to a bank in the catalog using the vendor's bank code mapping. With a mapping you get mappingStatus: "MAPPED" and acquirerCode set; without one, mappingStatus: "UNMAPPED" and acquirerCode: null. A manually added row starts with source: "MANUAL" and verificationStatus: "UNVERIFIED".
source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminals/00000000-0000-0000-0000-000000000301/acquirers"
BODY='{"vendorAcquirerRef":"B01","merchantNumber":"000000000000001","terminalNumber":"ps000001","label":"Example Bank TRY","currencies":["try"]}'
lunixi_sign POST "$REQ_PATH" "$BODY"
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
-H "Content-Type: application/json" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "Digest: $DIGEST" \
-H "X-Signature: $SIGNATURE" \
-H "Idempotency-Key: 4f9b2c1e-0000-4000-8000-000000000004" \
--data-raw "$BODY"A new row returns 201; a repeat with the same key and the same body returns 200. data: { "acquirer": { … }, "replayed": false }; the acquirer fields are as in the list.
The MID, TID and bank code do not change after a row is created. If your bank gave you a new terminal number, add a new row and set the old row to DISABLED.
Update a bank row
PATCH /api/v1/physical-pos/terminal-acquirers/{terminalAcquirerId}
| Field | Type | Required | Description |
|---|---|---|---|
rowVersion | integer | Yes | The row's rowVersion you last read (not the terminal's). |
label | string | null | No | New label; null removes it. |
currencies | string[] | No | New currency list; replaces the old one. |
status | string | No | ACTIVE or DISABLED. Any other value gets 400 physical_pos.input.code_invalid. |
- Send at least one of
label,currenciesandstatus; with none the request gets400 physical_pos.input.empty_patch. If the values you send equal the current ones, the row does not change,rowVersiondoes not increase and200is returned. - A row of a closed terminal cannot be updated:
409 physical_pos.terminal.closed. - Setting a
DISABLEDrow back toACTIVEgets409 physical_pos.acquirer.duplicateif another active row with the same bank code and TID exists in the same environment.
source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminal-acquirers/00000000-0000-0000-0000-000000000601"
BODY='{"rowVersion":1,"currencies":["EUR","TRY","USD"]}'
lunixi_sign PATCH "$REQ_PATH" "$BODY"
curl -X PATCH "https://api-gateway.lunixi.com$REQ_PATH" \
-H "Content-Type: application/json" \
-H "X-Key-Id: $LUNIXI_KEY_ID" \
-H "X-Date: $DATE" \
-H "X-Nonce: $NONCE" \
-H "Digest: $DIGEST" \
-H "X-Signature: $SIGNATURE" \
--data-raw "$BODY"Response: { "acquirer": { … } } with the new rowVersion.
Errors
| HTTP | code | When |
|---|---|---|
400 | physical_pos.idempotency.key_required / physical_pos.idempotency.key_invalid | Idempotency-Key missing or malformed on add. |
400 | physical_pos.input.ref_invalid | vendorAcquirerRef is malformed. |
400 | physical_pos.input.bank_terminal_number_invalid | merchantNumber or terminalNumber is malformed. |
400 | physical_pos.input.text_invalid | label breaks the rules. |
400 | physical_pos.acquirer.currency_invalid | Invalid currency list: unknown code, duplicate or more than 16. |
400 | physical_pos.input.code_invalid | Invalid status. |
400 | physical_pos.terminal.vendor_required | The terminal has no vendor. |
400 | physical_pos.input.empty_patch | Empty update. |
400 | physical_pos.cursor.invalid | Broken cursor. |
403 | physical_pos.environment.test_key_read_only | Write request made with a test key. |
404 | physical_pos.terminal.not_found | The terminal does not exist, is not yours or is in the other environment. |
404 | physical_pos.acquirer.not_found | The row does not exist, is not yours or is in the other environment. |
409 | physical_pos.terminal.closed | The terminal is closed. |
409 | physical_pos.acquirer.duplicate | A row with the same bank code and TID exists. |
409 | physical_pos.version_conflict | rowVersion is not current. |
409 | physical_pos.idempotency_mismatch | The same Idempotency-Key was used with a different request. |
429 | RATE_LIMITED | Terminal family write limit exceeded. → Rate limits |
All codes: Error Codes.