NNarya Developers
API referenceTransactions

Report a transaction

POST
/device/v1/transactions

Reports one card or QR transaction. Call it after each transaction, approved or declined.

A 202 means Narya has accepted the transaction; it is stored shortly afterwards.

Resubmitting an id is always safe: it never creates a second transaction. After a 500 or 503, or if the connection drops, resend the same body with the same id.

Authorization

DeviceAuth
headerAuthorizationBearer <dvc_<prefix>_<secret>>

The terminal's device token, returned once by POST /device/v1/activations. Send it as Authorization: Bearer <token> on every request except activation.

Request Body

application/json
  1. body

One transaction. channel selects the variant, card or qr. Each variant accepts only its own fields, so a card field on a QR transaction is refused with 400 rather than ignored.

Whether original_transaction_id is required depends on type. A missing or forbidden one is reported in invalid_params.

id*string

A UUIDv7 your terminal generates. Submitting the same id again updates that transaction instead of creating another.

Formatuuid
device_assignment_id?string

Optional. The assignment the transaction was made under. Omit it on a terminal that runs one product: Narya finds the assignment from the terminal and captured_at. Send it on a terminal that runs several products at once. Without it Narya cannot tell which product a transaction belongs to, and the transaction is accepted with 202 but not recorded.

Formatuuid
channel*"card"
Value in"card"
type*string
Value in"sale""refund""void_sale""void_refund""pre_auth""completion"
status*string
Value in"approved""declined"
captured_at*string

The terminal's clock when the transaction started.

Formatdate-time
currency*string

The cardholder's currency (ISO 4217). Anything other than MYR means the cardholder accepted a dynamic currency conversion (DCC) offer.

Match^[A-Z]{3}$
amount_total*integer

In minor units: 1250 is MYR 12.50. With DCC, the amount in the cardholder's currency.

Formatint64
Range0 <= value
amount_local*integer

Always MYR, in minor units. Equal to amount_total without DCC.

Formatint64
Range0 <= value
tid?string

Terminal ID (ISO 8583 field 41), as sent to the host.

Lengthlength <= 16
mid?string

Merchant ID (field 42), as sent to the host.

Lengthlength <= 32
acquirer_ref?string

Retrieval reference number (field 37). A void has its own. Absent on offline sales.

Lengthlength <= 32
response_code?string

Host response code (field 39).

Lengthlength <= 8
invoice_no?string

The terminal's invoice number (field 62).

Lengthlength <= 32
batch_no?string

The settlement batch number. Batch numbers repeat across settlement cycles.

Lengthlength <= 16
dcc_offered?boolean

Whether DCC was offered, including when the cardholder chose MYR.

dcc_conversion_rate?string

Decimal string, for example "4.4213", so the quoted rate stays exact. Up to 10 digits before the point and 8 after.

Match^-?[0-9]{1,10}(\.[0-9]{1,8})?$
dcc_margin_pct?string

Decimal string, like dcc_conversion_rate. 3.15 means 3.15 per cent. Up to 3 digits before the point and 3 after.

Match^-?[0-9]{1,3}(\.[0-9]{1,3})?$
dcc_reference?string
Lengthlength <= 32
card_scheme?string
Value in"visa""mastercard""mydebit""jcb""upi""amex"
card_pan_first6?string

The first six digits of the card number.

Match^[0-9]{6}$
card_pan_last4?string

The last four digits of the card number.

Match^[0-9]{4}$
card_entry_mode?string
Value in"chip""contactless""magstripe""manual""fallback""card_not_present"
card_cvm?string

The cardholder verification method used. none means no verification was required; omit the field when the terminal cannot report one.

Value in"pin""offline_pin""signature""cdcvm""none"
card_approved_offline?boolean

Approved offline: voice-approved or below the floor limit. Independent of type completion.

card_approval_code?string

Authorisation code (field 38).

Lengthlength <= 12
card_stan?string

System trace audit number (field 11). A reversal reuses the original value.

Lengthlength <= 12
original_transaction_id?string

The id of the transaction this one refers to. Required for void_sale, void_refund and completion; optional for refund; not allowed for sale and pre_auth.

Formatuuid

Response Body

Accepted. The transaction is stored shortly afterwards.

application/json
  1. response

Returned with 202. The transaction is accepted and is stored shortly afterwards.

event_id*string

Narya's reference for this submission. Record it, and quote it if an accepted transaction later appears to be missing.

Formatuuid
id*string

The id you submitted, returned unchanged.

Formatuuid
received_at*string

When Narya accepted the submission. A large gap from the captured_at you sent suggests the terminal's clock has drifted. Reports group transactions by captured_at, so a wrong clock files them under the wrong day.

Formatdate-time
curl -X POST 'https://device-narya-staging.pmadvisors.my/device/v1/transactions' \  -H 'Content-Type: application/json' \  -d '{  "id": "01a01e96-4153-7925-997c-38e69a23650c",  "device_assignment_id": "01a01e96-4153-7974-ad6f-ad9c974010d6",  "channel": "card",  "type": "sale",  "status": "approved",  "captured_at": "2026-08-20T09:15:04Z",  "currency": "MYR",  "amount_total": 1250,  "amount_local": 1250,  "tid": "70012345",  "mid": "000000012345678",  "acquirer_ref": "422612345678",  "response_code": "00",  "invoice_no": "000137",  "batch_no": "000012",  "card_scheme": "visa",  "card_pan_first6": "411111",  "card_pan_last4": "1111",  "card_entry_mode": "contactless",  "card_approval_code": "T12345",  "card_stan": "001374"}'
Example Response
{  "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "received_at": "2019-08-24T14:15:22Z"}