API endpoints for managing terminal devices. Same authentication as the rest of the Service API — see the Overview for what's new in this version.
A device is created against a merchant, not against a specific acquirer profile. On creation, the underlying Enabler activation profile is pushed with one acceptance block per acquirer already bound to that merchant via Merchant payment config — so bind the merchant's payment config first, then create devices for it.
Terminal List
GET /api/openapi/v1/device
Authorization: Bearer {jwt}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| mchId | query | string | true | Merchant ID |
| deviceId | query | string | false | Filter by device/activation-code ID (exact match) |
| deviceType | query | string | false | Filter by device type |
| pageNumber | query | number | false | Default 1 |
| pageSize | query | number | false | Default 20; use -1 to return all on one page |
Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response List<T> Data: Device (see example below) |
Example Response (200)
{
"msg": "SUCCESS",
"code": 0,
"data": {
"total": 1,
"current": 1,
"hasNext": false,
"records": [
{
"deviceId": "9F3A7B21C450",
"deviceType": "COTS",
"deviceStatus": 1,
"deviceUpdate": 0,
"uuid": "abcd-1234-efgh-5678",
"deviceAlias": "Terminal-01",
"deviceName": "Store-Terminal-01",
"deviceAdmin": "admin",
"appVersion": "1.2.3",
"deviceToken": "{\"code\":\"87654321\"}",
"methodList": "{\"all\":{}}",
"groupId": "G-12345678",
"profileId": "5201",
"emvParams": "{\"amexFloorLimit\":\"00000100\",\"terminalCountryCode\":\"0840\",\"txnCurrencyCode\":\"0840\",\"terminalType\":\"21\",\"terminalCapability\":\"0068C8\",\"emvFlags\":\"VMAUJDP\"}",
"extParams": "{\"acquirers\":{\"316\":{\"acqMid\":\"1234567850001\",\"acqTid\":\"0001252001\"}}}",
"operatingMode": "STANDALONE",
"activesAt": "2026-05-05T10:00:00+0000",
"createdAt": "2026-05-01T08:00:00+0000",
"updatedAt": "2026-05-05T10:00:00+0000",
"isDevice": true
}
]
}
}isDevice is only present (true) once the record is an activated device — for a still-pending
activation code (deviceId with the CD- prefix) the field is omitted entirely rather than false.
Terminal Detail
Retrieves a single terminal device or activation code by ID.
GET /api/openapi/v1/device/{deviceId}
Authorization: Bearer {jwt}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| deviceId | path | string | true | Device / activation-code ID. A bare 12-digit activation code is also accepted without the CD- prefix |
Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response<T> Data: Device (see example below), or null |
If deviceId doesn't exist, data is null (still a 200, code: 0). If it exists but belongs
to a different merchant/PBO, the call fails instead of returning it — code: 13000 ("Owner info
invalid") — so existence can't be probed across tenants.
Example Response (200)
{
"msg": "SUCCESS",
"code": 0,
"data": {
"deviceId": "9F3A7B21C450",
"deviceType": "COTS",
"deviceStatus": 1,
"deviceUpdate": 0,
"uuid": "abcd-1234-efgh-5678",
"deviceAlias": "Terminal-01",
"deviceName": "Store-Terminal-01",
"deviceAdmin": "admin",
"appVersion": "1.2.3",
"deviceToken": "{\"code\":\"87654321\"}",
"methodList": "{\"all\":{}}",
"groupId": "G-12345678",
"profileId": "5201",
"emvParams": "{\"amexFloorLimit\":\"00000100\",\"terminalCountryCode\":\"0840\",\"txnCurrencyCode\":\"0840\",\"terminalType\":\"21\",\"terminalCapability\":\"0068C8\",\"emvFlags\":\"VMAUJDP\"}",
"extParams": "{\"acquirers\":{\"316\":{\"acqMid\":\"1234567850001\",\"acqTid\":\"0001252001\"}}}",
"operatingMode": "STANDALONE",
"activesAt": "2026-05-05T10:00:00+0000",
"createdAt": "2026-05-01T08:00:00+0000",
"updatedAt": "2026-05-05T10:00:00+0000",
"isDevice": true
}
}Generate Activation Code
POST /api/openapi/v1/device
Content-Type: application/json
Authorization: Bearer {jwt}Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| mchId | String | Yes | Merchant ID this device belongs to |
| deviceAlias | String | No | A friendly name for the activation code |
| deviceName | String | No | Device name |
| deviceType | String | No | Device type (e.g. "COTS") |
| operatingMode | String | No | Device operating mode |
| methodList | String | No | Comma-separated list of payment methods this device supports |
| deviceAdmin | String | No | Admin password for the device |
| extParams | Object | No | Per-acquirer parameters, keyed as extParams.acquirers.{acquirerProfileId} — each entry carries the fields that profile's enablerParams declared (e.g. acqMid/acqTid); see Acquirer |
| emvParams | Object | No | EMV configuration parameters for the device |
Request Body Example
{
"mchId": "M-12345678",
"deviceAlias": "Store-Terminal-01",
"deviceType": "COTS",
"methodList": "01,02,03",
"emvParams": {
"amexFloorLimit": "00000100",
"terminalCountryCode": "0840",
"txnCurrencyCode": "0840",
"terminalType": "21",
"terminalCapability": "0068C8",
"emvFlags": "VMAUJDP"
},
"extParams": {
"acquirers": {
"316": { "acqMid": "1234567850001", "acqTid": "0001252001" }
}
}
}Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response<T> Data: { id, activationCode, profileId } |
profileId is null when the merchant has no acquirer bound yet for a matching payment method —
the device row and activation code are still created, but the Enabler push is skipped until a
Merchant payment config exists.
Example Response (200)
{
"msg": "SUCCESS",
"code": 0,
"data": {
"id": "CD-87654321",
"activationCode": "87654321",
"profileId": "5201"
}
}Update Terminal
Explicit-write semantics: only fields you include in the request body are changed. Omit a field
entirely to leave it untouched — this is different from sending null, which clears it.
PUT /api/openapi/v1/device/{deviceId}
Content-Type: application/json
Authorization: Bearer {jwt}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| deviceId | path | string | true | Device ID |
| deviceAlias | body | string | false | A friendly name for the terminal; omit to leave unchanged, send null to clear |
| deviceName | body | string | false | Device name; omit to leave unchanged, send null to clear |
| deviceType | body | string | false | Device type; omit to leave unchanged, send null to clear |
| operatingMode | body | string | false | Device operating mode; omit to leave unchanged, send null to clear |
| methodList | body | string | false | Comma-separated list of payment methods; omit to leave unchanged, send null to clear |
| deviceAdmin | body | string | false | Admin password; omit to leave unchanged, send null to clear |
| extParams | body | string | false | JSON-encoded per-acquirer parameters, keyed as extParams.acquirers.{acquirerProfileId}; omit to leave unchanged, send null to clear |
| emvParams | body | string | false | JSON-encoded EMV configuration parameters; omit to leave unchanged, send null to clear |
Request Body Example
{
"deviceAlias": "Store-Terminal-02",
"methodList": "01,02",
"extParams": "{\"acquirers\":{\"316\":{\"acqMid\":\"1234567850001\",\"acqTid\":\"0001252001\"}}}"
}Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response<T> |
Terminal Logout & Suspend
DELETE /api/openapi/v1/device/{deviceId}
Authorization: Bearer {jwt}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| deviceId | path | string | true | An unactivated code (CD- prefix) unbinds and deletes the code; an activated device ID logs it out |
| deviceStatus | query | integer | false | For an activated device: 2 = Logout, 3 = Decommission |
Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response<T> |
Idle Terminal
Marks an activation code as idle without deleting it, freeing it for re-activation.
DELETE /api/openapi/v1/device/{code}/idle
Authorization: Bearer {jwt}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| code | path | string | true | Activation code ID |
Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response<T> |
Send Activation Code
Emails an existing activation code to the given address.
POST /api/openapi/v1/device/code
Content-Type: application/json
Authorization: Bearer {jwt}Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| deviceId | String | Yes | Activation code / device ID |
String | Yes | Destination email address |
Request Body Example
{
"deviceId": "CD-87654321",
"email": "[email protected]"
}Response
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK (opens in a new tab) | OK | Wrapper: Response<T> |
Get Device EMV Params
Returns the resolved EMV parameters and AID list currently pushed to a device.
GET /api/openapi/v1/device/emv/{deviceId}
Authorization: Bearer {jwt}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| deviceId | path | string | true | Device ID |
Example Response (200)
{
"msg": "SUCCESS",
"code": 0,
"data": {
"emvParams": {
"amexFloorLimit": "00000100",
"terminalCountryCode": "0840",
"txnCurrencyCode": "0840",
"terminalType": "21",
"terminalCapability": "0068C8",
"emvFlags": "VMAUJDP"
},
"emvAID": [
{ "aid": "A0000000031010", "paymentMethod": "01" },
{ "aid": "A0000000041010", "paymentMethod": "02" }
]
}
}