Accept payments with Kushki One

The Payment API lets you process card-present payments from your POS system to a Kushki ONE terminal running in semi-integrated mode. The terminal handles the entire cardholder interaction and the EMV chip: your system sends the amount and receives the result.

Requirements

How it works

The payloads and the headers are identical between topologies. The routes are not β€” four things change, and they are listed under the base URLs.

TopologyBase URL
Local Network (LAN / Wi-Fi)http://{TERMINAL_IP}:6868/terminal/v1 or https://{TERMINAL_IP}:6869/terminal/v1
Cloud (Internet) β€” UAThttps://uat-cloudt.kushkipagos.com/terminal/v1/{terminalSerial}
Cloud (Internet) β€” Productionhttps://cloudt.kushkipagos.com/terminal/v1/{terminalSerial}

What changes between Cloud and the local network, beyond the base URL:

DifferenceLocal NetworkCloud
Online search route/transaction_search_online/sync/transaction_search_online
/abort methodGET, in both modesPOST, sync only
Async abortAvailableDoes not exist
Print routes/terminal/v1/print/{terminalSerial}/sync/print

Sync and async modes

Every operation that requires terminal interaction exists in two variants, under separate path prefixes.

ModePrefixBehaviorWhere the result arrives
Sync/sync/Holds the connection open until the acquirer answersIn the HTTP response
Async/async/Returns immediately with a TERMINAL_ACKNOWLEDGED acknowledgement. Never blocksWebhook only

Available operations

OperationPathSyncAsyncWhat it does
Sale/chargeβœ…βœ…Immediate charge: authorizes and captures in a single step
Authorization/authorizationβœ…βœ…Reserves funds without capturing them
Capture/captureβœ…βœ…Charges the funds from an approved authorization
Re-authorization/re_authorizationβœ…βœ…Extends the amount or the validity of an active authorization
Post-tip/pos_tipβœ…βœ…Adds a tip to an already-authorized transaction
Reversal/voidβœ…βœ…Reverses a transaction: cancellation within the calendar day, refund after the cut-off
Abort/abortβœ…βœ…Cancels an operation in progress on the terminal
Online search/transaction_search_onlineβœ…β€”Queries transaction history at the acquirer
Local search/transaction_search_localβœ…β€”Queries the history stored on the terminal

Key concepts

client_transaction_id

A UUID v4 identifier that your POS system generates. It works as an idempotency key: if the terminal already processed that identifier, it detects the duplicate and prevents a double charge.

Generate a new one for every sale. Reuse it only when you are retrying the exact same operation after a network failure.

transaction_reference

An identifier that Kushki generates and returns in the response of every approved transaction, inside rawResponse. It is the link between operations in the same lifecycle.

Amount structure

The amount object is sent in the currency’s minor units, as an integer. The number of decimals depends on the country.

Optional fields, by operation

These are the only optional fields, and each one belongs to specific operations. They behave the same in sync and async.

FieldTypeApplies toWhat it does
amount.tipinteger/charge and /authorizationAdds a tip. The tip can be set at pre-authorization time, not only when charging
cashback_amountinteger/chargeCash withdrawal on top of the purchase. Send 0 if it does not apply
deferred / query_deferredobject / boolean/chargeInstallments. The field and its shape change by country β€” see below
omit_cardboolean/capture, /re_authorization and /voidWith true the operation runs without asking for the card
metadataobject/charge, /authorization and /pos_tipFree-form traceability: reference, customer_email, device

On /pos_tip, amount.tip is not an optional field β€” it is the amount of the operation.

omit_card is what makes the hotel case work: extending or capturing a pre-authorization after the guest has left the desk.

Installments change by country

The two fields are mutually exclusive and never travel together:

CountryFieldShapeMaximum
Mexicoquery_deferredBoolean. The terminal offers Meses Sin Intereses to the cardholder after reading the card; your POS does not choose the monthsβ€”
Chiledeferredmonths, plus credit_type: "03" for cuotas comercio β€” a string, not a number12 with credit_type, 48 without it
Colombiadeferredmonths only. credit_type does not apply48
Perudeferredmonths only. credit_type does not apply2–48, every network

If a capability is not enabled for your terminal, the terminal ignores the field instead of rejecting the request β€” so a 200 does not prove the tip was applied. To have it enabled, write to soporte@kushkipagos.com.

Reading the HTTP status

Payment flows

Direct sale

The most common retail flow. The terminal activates the reader when it receives the request and waits for the cardholder to complete the interaction.

POST /sync/charge β†’ 200 OK (approved: true)

Pre-authorization and capture

Use this when the final amount is unknown at the time of the interaction: hotels, fuel stations, open-tab restaurants.

POST /sync/authorization β†’ store transaction_reference
↓ (hours or days later)
POST /sync/capture β†’ with the stored transaction_reference

You can insert /re_authorization to raise the reserved amount or extend the window before capturing. Send subtotal_iva0: 0 to extend the validity only.

Authorization validity

Card typeValidity from authorization
Debit (Visa / Mastercard)7 days
Credit (Visa / Mastercard)28 days

The capture can reach up to 110% of the total authorized, adding the authorization and every non-canceled re-authorization. Only one capture is allowed per cycle.

Post-tip

Adds a tip to an already-authorized transaction. Use it when the cardholder decides the amount after the initial charge. Send the value in amount.tip alongside the original transaction_reference.

Reversal

There is a single reversal endpoint, /void, and the system decides what the operation becomes based on when you call it. The cut-off is 23:59 local time in every country: within the same calendar day the reversal is a cancellation; from midnight onwards it enters the refund cycle and takes business days.

Wait at least 1 minute after the original transaction before reversing it, or it fails for no apparent reason.

The type returned by transaction search tells you what actually happened:

TypeWhat it means
VOIDYou called /void on the same calendar day. Cancellation β€” the cardholder never sees the charge
REFUNDYou called /void after the cut-off. It entered the refund cycle and takes business days
REVERSEYou did not ask for it. The platform generates it on its own when communication with the terminal fails

Authentication

Kushki ONE uses one mechanism β€” hash + encryption β€” and it is the same in Cloud, on the local network and on localhost: Authorization: Basic <SHA512>, timestamp in seconds, and the body as the encrypted envelope {"data":"<iv_hex>:<cipher_hex>"}.

Every payload shown on this page is the plaintext you encrypt, not what travels on the wire. The full flow, the key derivation chain and the diagnostic tree are on Authentication and request encryption.

Direct sale example

A charge of 12000 minor units with no tax breakdown. What that represents depends on the country’s decimals β€” check Amount format in Kushki ONE before your first integration.

  • Javascript
  • Python
const payload = {
amount: {
iva: 0, subtotal_iva: 0, subtotal_iva0: 12000,
extra_taxes: { airport_tax: 0, iac: 0, ice: 0, travel_agency: 0 },
},
client_transaction_id: crypto.randomUUID(),
};
const res = await fetch(`${BASE_URL}/sync/charge`, {
method: "POST",
headers: buildHeaders(payload),
body: JSON.stringify(payload),
});
const data = await res.json();
console.log(data.approved, data.rawResponse.transaction_reference);
import uuid, requests
payload = {
"amount": {
"iva": 0, "subtotal_iva": 0, "subtotal_iva0": 12000,
"extra_taxes": {"airport_tax": 0, "iac": 0, "ice": 0, "travel_agency": 0},
},
"client_transaction_id": str(uuid.uuid4()),
}
res = requests.post(f"{BASE_URL}/sync/charge",
headers=build_headers(payload), json=payload)
data = res.json()
print(data["approved"], data["rawResponse"]["transaction_reference"])

Best practices

  • Generate a unique client_transaction_id per sale and reuse it only when retrying the same operation.
  • Persist the transaction_reference as soon as you receive the authorization or charge response.
  • Check that the amount fields add up to the expected total before you send the request.
  • Log the client_transaction_id and the HTTP code of every operation to make reconciliation and support easier.
  • Call /abort only while a transaction is active on the terminal. Calling it afterwards returns 409 Conflict.
  • Sign exactly the same bytes you send: serialize once, sign that string and send that same string.
Async services and webhooks

Integrate async mode: lifecycle states, event structure and the delivery retry policy.

Error catalog

Look up the error models, the codes by category and the corrective actions for every endpoint.