NeroPay Docs
API & Integrations

Terminal API

Terminal

Terminal API

Connect in-person devices to NeroPay and build POS payment flows.

Locations Readers Terminal payments

Terminal API map

Method Endpoint Purpose
GET /locations List merchant terminal locations.
POST /locations Create a terminal location.
PATCH /locations/{id} Update a terminal location where enabled.
GET /readers List merchant readers.
POST /readers Register a reader.
DELETE /readers/{id} Remove a reader.
POST /terminal/readers/{id}/cancel-action Cancel the current action on a reader.
POST /terminal/payments Send a terminal payment request.

Terminal resources are returned only for the authenticated merchant or selected connected account. Developers should store returned neropay_location_id and neropay_reader_id for future payments and support workflows.

Authentication

All Terminal API requests use your NeroPay API secret key. For write requests, include a timestamp, signature and idempotency key to prevent duplicate device or payment actions.

Header Required Description
Authorization Yes Bearer secret API key.
Accept Yes Use application/json.
Content-Type For POST/PATCH Use application/json when sending JSON body data.
X-NeroPay-Timestamp For write requests Unix timestamp used when creating the request signature.
X-NeroPay-Signature For write requests HMAC signature for the request body.
Idempotency-Key For write requests A unique key for each create, update, delete or payment request.
NeroPay-Account Optional Connected account ID, for example NP6454f52b_6165.

Create a location

Create a location before registering a reader. A location should represent a real store, branch, counter or payment area. The returned id is the local NeroPay API resource ID, while neropay_location_id is the terminal location reference used for reader registration and terminal payments.

Endpoint

POST https://eu.neropay.app/v2/locations

Request parameters

Parameter Type Required Description
display_name string Yes Location name shown in the dashboard, for example Main Store.
line1 string Yes First address line.
city string Yes City or town.
postal_code string Yes Postal code.
country string Yes Two-letter country code, for example GB.
is_default boolean Optional Set to true when this should be the default terminal location.

Example PHP request

 'Main Store',
'line1' => '1 Demo Street',
'city' => 'London',
'postal_code' => 'SW1A 1AA',
'country' => 'GB',
'is_default' => true,
];

$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = time();
$signature = hash_hmac('sha256', $timestamp . '.' . $body, $secretKey);

$ch = curl_init($baseUrl . '/locations');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $secretKey,
'Accept: application/json',
'Content-Type: application/json',
'X-NeroPay-Timestamp: ' . $timestamp,
'X-NeroPay-Signature: ' . $signature,
'Idempotency-Key: loc_' . bin2hex(random_bytes(12)),
// Optional for NeroConnect platforms:
// 'NeroPay-Account: NP6454f52b_6165',
],
CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;

Example response

{
  "success": true,
  "data": {
    "id": 14059,
    "display_name": "Main Store",
    "line1": "1 Demo Street",
    "city": "London",
    "postal_code": "SW1A 1AA",
    "country": "GB",
    "is_default": true,
    "account_id": "NPEE4E742AB2_6165",
    "neropay_location_id": "tml_Gex0cASDFxDhTL",
    "created_at": "2026-04-27T19:54:44+01:00",
    "updated_at": "2026-04-27T19:54:44+01:00"
  }
}

Register a reader

Register a physical reader using its registration code. The reader must be registered against an existing NeroPay terminal location. Store the returned id and neropay_reader_id; the id can be used for resource operations, while neropay_reader_id is used when sending terminal actions.

Endpoint

POST https://eu.neropay.app/v2/readers

Request parameters

Parameter Type Required Description
label string Yes A friendly reader name, for example Front counter.
location_id integer or string Yes The local location id or the neropay_location_id returned from the location API.
registration_code string Yes The registration code displayed on the physical reader.

Example PHP request

 'Front counter',
'location_id' => 14059,
'registration_code' => 'simulated-wpe',
];

$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = time();
$signature = hash_hmac('sha256', $timestamp . '.' . $body, $secretKey);

$ch = curl_init($baseUrl . '/readers');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $secretKey,
'Accept: application/json',
'Content-Type: application/json',
'X-NeroPay-Timestamp: ' . $timestamp,
'X-NeroPay-Signature: ' . $signature,
'Idempotency-Key: rdr_' . bin2hex(random_bytes(12)),
],
CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;

Example response

{
  "success": true,
  "data": {
    "id": 884,
    "label": "Front counter",
    "location_id": 14059,
    "account_id": "NPEE4E742AB2_6165",
    "neropay_location_id": "tml_Gex0cASDFxDhTL",
    "neropay_reader_id": "tmr_Y8mVq9K2pR4x",
    "status": "online",
    "created_at": "2026-04-27T20:02:10+01:00"
  }
}

Create a terminal payment

Use a terminal payment when you want to send an amount to a registered reader. The transaction is created as pending first. When the customer completes or cancels the reader action, the transaction status updates accordingly and webhook events can be delivered to your application.

Endpoint

POST https://eu.neropay.app/v2/terminal/payments

Request parameters

Parameter Type Required Description
amount decimal Yes Amount in major currency units, for example 12.50.
currency string Yes Three-letter currency code, for example GBP.
reader_id integer or string Yes Local reader id or neropay_reader_id.
location_id integer or string Optional Local location id or neropay_location_id.
description string Optional Short description shown in transaction reporting.
reference string Optional Your internal order, sale or receipt reference.
connect_application_fee decimal Optional NeroConnect platform fee amount. Only available when acting for a connected account.

Example PHP request

 12.50,
'currency' => 'GBP',
'reader_id' => 'tmr_Y8mVq9K2pR4x',
'location_id' => 'tml_Gex0cASDFxDhTL',
'description' => 'In-store card payment',
'reference' => 'POS-1001',
];

$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = time();
$signature = hash_hmac('sha256', $timestamp . '.' . $body, $secretKey);

$ch = curl_init($baseUrl . '/terminal/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $secretKey,
'Accept: application/json',
'Content-Type: application/json',
'X-NeroPay-Timestamp: ' . $timestamp,
'X-NeroPay-Signature: ' . $signature,
'Idempotency-Key: termpay_' . bin2hex(random_bytes(12)),
],
CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;

Example response

{
  "success": true,
  "data": {
    "id": 6636598,
    "trx": "NP-TERM-8f39d21",
    "status": "pending",
    "amount": "12.50",
    "currency": "GBP",
    "reader_id": "tmr_Y8mVq9K2pR4x",
    "location_id": "tml_Gex0cASDFxDhTL",
    "reference": "POS-1001",
    "description": "In-store card payment",
    "account_id": "NPEE4E742AB2_6165",
    "created_at": "2026-04-27T20:10:31+01:00"
  }
}

Cancel a reader action

Cancel the current action on a reader, such as a payment that is waiting for customer interaction. Use this when a customer changes their mind, the sale is abandoned, or the POS needs to reset the reader.

Endpoint

POST https://eu.neropay.app/v2/terminal/readers/{id}/cancel-action

Example PHP request

 true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $secretKey,
'Accept: application/json',
'Content-Type: application/json',
'X-NeroPay-Timestamp: ' . $timestamp,
'X-NeroPay-Signature: ' . $signature,
'Idempotency-Key: cancel_' . bin2hex(random_bytes(12)),
],
CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;

Example response

{
  "success": true,
  "data": {
    "reader_id": "tmr_Y8mVq9K2pR4x",
    "status": "cancelled",
    "message": "Reader action cancelled."
  }
}

Example error responses

Errors use a consistent JSON structure. Do not parse error messages for business logic; use the error.code value.

Missing authentication

{
  "success": false,
  "error": {
    "code": "unauthenticated",
    "message": "A valid API key is required."
  }
}

Invalid connected account

{
  "success": false,
  "error": {
    "code": "account_not_found",
    "message": "Connected account was not found."
  }
}

Invalid reader registration code

{
  "success": false,
  "error": {
    "code": "reader_registration_failed",
    "message": "The reader could not be registered. Check the registration code and try again."
  }
}

Reader not found

{
  "success": false,
  "error": {
    "code": "reader_not_found",
    "message": "Reader was not found for this merchant."
  }
}

Validation error

{
  "success": false,
  "error": {
    "code": "validation_error",
    "message": "The given data was invalid.",
    "fields": {
      "amount": [
        "The amount field is required."
      ],
      "reader_id": [
        "The reader_id field is required."
      ]
    }
  }
}

Implementation notes

  • Use GET /locations and GET /readers before creating duplicates.
  • Use one unique Idempotency-Key per write request.
  • Store both local IDs and NeroPay IDs in your POS system.
  • For connected account integrations, send NeroPay-Account with every request that should act on a connected merchant.
  • Never send raw card data to the Terminal API. Terminal payments are completed on the reader.