Kushki ONE is currently in Beta for Colombia 🇨🇴. Endpoints, parameters and response structures may change without prior notice. Do not deploy to production without coordinating with the Kushki integration team.
Kushki ONE Connect simplifies error handling with a single structured JSON model that standardizes every failure response — regardless of whether the problem originated in the terminal, a validation, authentication, or the acquirer. This lets you build more robust integrations, automate recovery flows, and stop relying solely on HTTP status codes.This catalog is your primary diagnostic tool. It covers the error model structure, per-category code catalogs, how we map third-party rejections, and a quick-reference troubleshooting guide.All errors share the same response structure. Always evaluate type first to classify the failure source, then look up the corresponding code.
Field
Type
Always present
Description
type
String
✅
Error category. Identifies the failure source. See Section 2.
code
String
✅
Unique error code. Prefix + number for Kushki ONE's own families (PAR-003, TER-004, AUTH-001, NF-001, CONF-4007, MAN-30005). Acquirer codes are the processor's own, unprefixed.
param
String
❌
The exact request field that caused the error. Present only when the failure is attributable to a field — see below.
message
String
✅
Human-readable description of the failure reason.
object
Object
❌
Traceability data: client_transaction_id, terminal_id and serial_number.
Canonical example:
{"type":"PARAMETER","code":"PAR-003","param":"amount.iva","message":"Field amount.iva must satisfy: value >= 0","object":{"client_transaction_id":"c5a3f3be-9d6f-4d39-8af5-58dbb589af69","terminal_id":"172653","serial_number":"TJ54241R20931"}}
The response is flat — there is no wrapper
The five fields above sit at the root of the body. The two envelopes that older builds returned, {"success": false, "data": {…}} and {"failure": {…}}, no longer exist. If your POS parses either of them it will stop finding the error. Read type and code from the root.
INFO
object.terminal_id may arrive empty on TER-003. It is a known gap; do not make your error handling depend on it being populated.
param is not an optional field that happens to be missing sometimes. It is omitted deliberately whenever the error was not caused by a field of your request. The rule in one line: param appears only when the error is attributable to a request field.
Comes with param
Why
PAR-003, TER-003, AUTH-001
Data validation errors — there is a field at fault
NF-001
Carries the identifier that was not found
Comes without param
Why
TER-004
Printer busy, or the cardholder cancelled. The request was valid; the hardware or the person was not
MAN-30005
Card or PIN timeout. Same reason
ACQUIRER
The transaction was valid and the bank declined it
CONF-4007
Terminal provisioning, not the call
PAR-002 with unreadable JSON
The parser fails before deserializing, so there is no field to point at
Without this rule an integrator reads the catalog, sees param among the fields, and codes assuming it always arrives.
On payment endpoints the HTTP status is always 200, whatever happened. It confirms that the terminal processed your request — not that the operation succeeded. Always evaluate the response body.
A POS that branches on response.ok treats a busy terminal, an expired PIN and a cardholder cancellation as successes. Verified in testing, all with 200: a negative parameter, a busy terminal and a PIN timeout on /sync/charge; an offline decline and a user cancellation on /async/authorization; an operation not allowed and an invalid parameter on /async/capture; and an amount larger than the sale on /async/void.The print endpoints are the exception and do return real HTTP codes: 404 when the job does not exist, 409 while the queue is busy.
Generated when the request contains fields with incorrect format, out-of-range values, or missing required fields. The param field identifies the specific field that caused the error. All PARAMETER errors are 100% preventable by validating the payload before calling the API.
code
Description
Message template
Example
PAR-001
Required field not sent.
Field {{field}} is required.
Field amount.subtotal_iva0 is required.
PAR-002
Field of incorrect type, or body that is not valid JSON.
JSON/JVM parse error. The request body is not valid JSON, or contains an incorrect data type in a field.
INFO
There is no BUSY code. A busy terminal is TER-003 when it is running a transaction and TER-004 when it is printing — both with type: TERMINAL. See Section 4.
param uses the same snake_case and the same full path as your request, so the value you read is the exact name to search for in your own payload.
Code
param
Error message
Applies to
2002
amount.iva
amount.iva cannot be negative
All
2003
amount.subtotal_iva
amount.subtotal_iva cannot be negative
All
2004
amount.subtotal_iva0
amount.subtotal_iva0 cannot be negative
All
2005
amount.tip
amount.tip cannot be negative
/charge and /authorization
2006
amount.extra_taxes.airport_tax
amount.extra_taxes.airport_tax cannot be negative
All
2007
amount.extra_taxes.iac
amount.extra_taxes.iac cannot be negative
All
2008
amount.extra_taxes.ice
amount.extra_taxes.ice cannot be negative
All
2009
amount.extra_taxes.travel_agency
amount.extra_taxes.travel_agency cannot be negative
All
INFO
On /pos_tip, amount.tip is not an optional field — it is the amount of the operation, so 2005 applies there too. The full map of which optional field belongs to which operation is in Cloud Services.
Date filters in transaction search are Unix timestamps in milliseconds, interpreted in the terminal's local time — America/Bogota for Colombia. A 10-digit value in seconds is not rejected: it lands in 1970 and the search silently returns your whole history. See Transaction Search.
Generated when the physical terminal cannot accept the requested operation. Unlike hardware errors, these indicate a state or connectivity problem with the terminal, not a component failure.
code
Description
Message template
Example
TER-001
Terminal not linked to the merchant.
Terminal {{serial_number}} does not exist, or is not linked to your account.
Terminal SN816265 does not exist, or is not linked to your account.
TER-002
Terminal not responding (offline or off-network).
Terminal {{serial_number}} is not responding. It may be offline or not connected to the local network.
Terminal PB651542 is not responding. It may be offline or not connected to the local network.
TER-003
Terminal busy processing a transaction.
Terminal {{serial_number}} is busy processing transaction (client_transaction_id: {{id}}).
Terminal SN71652 is busy processing transaction (client_transaction_id: c5a3f3be-9d6f-4d39-8af5-58dbb589af69).
TER-004
Printer busy, or cardholder cancellation. See below.
Terminal {{serial_number}} is busy executing action {{action}}.
Terminal JH152353 is busy executing action PRINT.
TER-005
Terminal in a mode incompatible with the operation.
The terminal is in {{mode}} mode and does not allow the requested action.
The terminal is in STANDALONE mode and does not allow the requested action.
The endpoint you called tells you which one, so you never have to disambiguate at runtime:
Where you got it
What it means
What to do
/print or /print_job
The printer is busy; the message names the action in progress
Retry in a few seconds
Any payment endpoint
The cardholder cancelled on the terminal screen
Do not retry — it is an expected cancellation
INFO
The terminal handles one transaction at a time. TER-003 and TER-004 are the expected answer when your POS sends a second command before the first completes — wait, or call abort.
Generated when credentials are invalid or lack sufficient permissions to execute the requested action.
code
Description
Message
AUTH-001
Credentials cannot be authenticated.
Invalid or expired credentials
AUTH-002
Credentials are valid but lack permission for the action.
Your credentials are valid but do not grant access to this resource.
{"type":"AUTH","code":"AUTH-001","message":"Invalid or expired credentials"}
The four common causes of AUTH-001:
1.
The body was re-serialized after signing, so the hash no longer matches the bytes sent.
2.
The timestamp falls outside the ±5 minute window around server time.
3.
Signing with the private_credential_id instead of the Business-Code. private_credential_id is a terminal configuration value and is never used to sign requests.
4.
On an operation with no payload — /abort — signing an empty string instead of the literal {}. Two bytes of difference, and no hint in the response.
Security
Never log the full value of the Authorization header in production. Only log its presence or absence for diagnostic purposes.
code: the acquirer's native code, unchanged and unprefixed. E020 is returned as E020.
message: same message originally returned by Kushki.
object: includes client_transaction_id, terminal_id and serial_number when applicable.
Why there is no prefix
Authorization codes are native to the processing network and are left intact on purpose, to preserve the ISO 8583 traceability the card brands require. Do not expect an ACQ- prefix — it never arrives.
{"code":"E020","message":"Either Invalid amount or Currency conversion field overflow"}
Mapped response from Kushki ONE Connect:
{"type":"ACQUIRER","code":"E020","message":"Either Invalid amount or Currency conversion field overflow","object":{"client_transaction_id":"c5a3f3be-9d6f-4d39-8af5-58dbb589af69","terminal_id":"172653","serial_number":"PJ715652"}}
INFO
An amount rejection in a COP market is very often a minor-unit mistake rather than a real acquirer problem — check the amount against Building the amount before escalating.
Manufacturer SDK codes are read-only and intended for diagnostics and logging. For the complete Sunmi code catalog by functional range (card reading, cryptography, EMV, PIN, Android permissions), ask your Kushki integration team.
Generated when the requested operation is not enabled for this terminal, or when the amount sent exceeds a configured limit. Unlike PARAMETER errors these are not fixed by modifying the payload — they need a capability or a limit changed for your terminal.
{"type":"CONFIGURATION","code":"CONF-4001","message":"Tip is not enabled","object":{"client_transaction_id":"c5a3f3be-9d6f-4d39-8af5-58dbb589af69","terminal_id":"172653","serial_number":"SN816265"}}
INFO
These errors are not resolved in code. A CONFIGURATION error means the feature exists but is not active for this terminal. Note that when a capability is simply absent the terminal may instead ignore the field rather than reject the call, so do not rely on a tip being applied without checking the response.
Errors generated by the integrated thermal printer hardware. These codes are standardized regardless of the terminal manufacturer, and they also arrive on the print webhook as errorCode.
code
Cause
Recommended action for the operator
OUT_OF_PAPER
No paper roll loaded.
Insert a new roll and retry.
COVER_OPEN
Paper compartment cover is open.
Close the cover firmly.
COVER_INCOMPLETE
Cover improperly closed, or roller not applying pressure.
Open and close again, ensuring the roller latches correctly.
PAPER_JAM
Paper jammed in the mechanism.
Remove the jammed paper and close. Insert a new roll.
PRINTER_HOT
Thermal printhead overheated.
Wait 2–3 minutes and retry.
MOTOR_HOT
Feed motor overheated.
Wait for cool-down.
CUTTER_ERROR
Auto-cutter blade jammed.
Requires technical service intervention.
OFFLINE
Module not responding to the Android system.
Restart the terminal.
INFO
A busy print queue is not in this table: it arrives as TER-004 with type: TERMINAL, and over HTTP as a 409.
When you receive an error, follow these recommendations:
On a payment endpoint, did you get 200? → That means nothing about the outcome. Read the body before deciding.
type is AUTH? → Verify credentials (AUTH-001) or permissions (AUTH-002). Check the four causes in Section 5: re-serialized body, clock outside ±5 min, signing with the wrong key, or an empty string instead of {}.
type is PARAMETER? → Review the field indicated in param. Add validation in the POS before calling the API. If param is absent, the body was not readable as JSON.
type is TERMINAL, code is TER-002? → Terminal is offline. Check network connectivity.
type is TERMINAL, code is TER-003? → Terminal is busy with a transaction. Wait, or use abort.
type is TERMINAL, code is TER-004? → On a print endpoint, the printer is busy: retry. On a payment endpoint, the cardholder cancelled: do not retry.
type is TERMINAL, code is TER-006? → Capability not enabled for this terminal. Write to soporte@kushkipagos.com.
type is TERMINAL-PRINTER? → Physical hardware condition. Show the message to the operator with resolution instructions.
type is TERMINAL-SUNMI, code is MAN-30005? → Card or PIN timeout. Treat as an expected cancellation.
type is ACQUIRER? → Processor rejection. Show the message to the customer. Log the native code with the client_transaction_id for support.
type is INTERNAL, code is MQTT_REQUEST_FAILED? → The Cloud relay could not reach the terminal. Check the terminal is online and retry; if it persists, escalate.
type is INTERNAL or NOT_FOUND? → Log the full payload and escalate to Kushki technical support.
type is CONFIGURATION? → Capability not enabled, or amount over a configured limit. Do not retry with the same payload. Write to soporte@kushkipagos.com.
INFO
Best practice: always log type + code + message + object.client_transaction_id + timestamp in your logging system. This information is essential for fast diagnosis.
On an async operation, a failure does not arrive as an HTTP error — it arrives as an event. TERMINAL_REJECTED and DECLINED carry a failure_reason object with the same type, code and message documented above: