1. Kushki One
Español
  • English
  • Español
  • Docs de API 🇵🇪
  • Online Payments
    • Errores ISO
    • Errores del API de Kushki
    • Notas de versión
    • Card Payments
      • Solicitar un token de tarjeta
      • Hacer un cargo o cargo diferido
      • Preautorización (sin token)
      • Crear pago (sin token)
      • Anular una transacción
      • Reembolsar una transacción
      • Verificar cuenta
      • Solicitar opciones de diferido
      • Autorizar pagos
      • Reautorizar pagos
      • Capturar un pago autorizado
      • Validar OTP
      • Información de BIN
      • Información de BIN V2
    • One-Click & Scheduled Payments
      • Solicitar un token de cargo recurrente
      • Crear un cargo recurrente
      • Actualizar los datos de la tarjeta del cargo recurrente
      • Hacer un pago One-click
      • Cancelar un cargo recurrente
      • Actualizar un cargo recurrente
      • Agregar un cargo o descuento temporal
      • Autorizar pagos
      • Capturar un pago autorizado
      • Consultar información del cargo recurrente
    • Card Out
      • Obtener token de Card Payout
      • Obtener token de suscripción
      • Push funds
      • Push Funds en suscripciones
      • Consultar estado de la transacción
      • Eliminar suscripción
    • Transfer In
      • Consultar lista de bancos
      • Solicitar un token de Transfer In
      • Iniciar transacción
      • Consultar estado
    • Transfer Out
      • Consultar lista de bancos
      • Consultar lista de bancos V2
      • Solicitar un token de Transfer Out
      • Iniciar transacción
      • Consultar estado
      • Saldo para payouts
    • Cash In
      • Solicitar un token de Cash In
      • Iniciar transacción
      • Estado de la transacción
    • Smartlinks V2
      • Crear un Smartlink
      • Actualizar un Smartlink
      • Consultar un Smartlink
      • Eliminar un Smartlink
    • Analytics
      • Consultar listado de transacciones v2
    • Chargebacks
      • Consultar chargebacks
      • Solicitar exportación de chargebacks
    • Gateway Status
      • Consultar estado del gateway
    • Payment Credentials
      • Crear una credencial
      • Buscar credenciales
      • Búsqueda avanzada
      • Activar o desactivar
      • Eliminar credencial
      • Actualizar credencial
      • Regenerar una credencial
    • Payment Button
      • Crear un Payment Button
    • Platform Status
      • Consultar estado de la plataforma
    • Subscription Transactions
      • Consultar transacciones de suscripción
    • Settlement
      • Consultar liquidación
    • Fraud Report
      • Consultar alertas de fraude
  • Card Present Payments (API Raw)
    • Notas de versión
    • Proceso de intercambio de llaves
    • Datos de prueba
    • Catálogo de errores de Kushki para transacciones POS
    • El objeto Amount
    • One-time Payments
      • Pago único
    • Two-step Payments
      • Autorización y captura
    • Voids & Refunds
      • Reembolsar una transacción
      • Anular y reversar
    • Card information
      • Consultar información de BIN
      • Información de BIN V2
      • Solicitar opciones de diferido
    • Query Transactions
      • Búsqueda de transacciones
    • Webhooks
      • Introducción
      • Buenas prácticas
      • Reembolsos
      • Pagos con tarjeta
      • Revisa tus webhooks
    • Chargebacks
      • Consultar chargebacks
      • Solicitar exportación de chargebacks
    • Fraud Report
      • Consultar alertas de fraude
  • Kushki One
    • Error Catalog
    • Release notes
    • Transaction Examples
    • Webhooks
    • Cloud Services
      • Payment Cloud
        • Sync
          • Charge
          • Authorization (Pre-auth)
          • Capture
          • Re-authorization
          • Post-tip
          • Refund
          • Abort
          • Void
        • Async
          • Charge (Async)
          • Authorization — Pre-auth (Async)
          • Capture (Async)
          • Re-authorization (Async)
          • Post-tip (Async)
          • Void (Async)
        • Search
          • Transaction Search
      • Print Cloud
        • Create Print Job
        • Get Print Job Status
    • Local Services
      • Payment Local
        • Sync
          • Charge
          • Authorization (Pre-auth)
          • Capture
          • Re-authorization
          • Post-tip
          • Void
          • Refund
          • Abort
        • Async
          • Charge (Async)
          • Authorization — Pre-auth (Async)
          • Capture (Async)
          • Re-authorization (Async)
          • Post-tip (Async)
          • Void (Async)
          • Abort (Async)
        • Search
          • Transaction Search — Online
          • Transaction Search — Local
      • Print Local
        • Create Print Job
        • Get Print Job Status
        • Print Job Webhook (inbound — implemented by your POS)
  • Appian - Submerchant Register
    • Release Notes
    • Submerchant Validation in Batch
    • Query submerchant status by requestId/submerchantId
    • Submerchant Document Upload
    • Get submerchantIds
    • Get credentials for submerchants
  • Schemas
    • Shared
      • ErrorResponse
      • BadRequestResponse
      • InvalidBinResponse
      • payment_method
      • payment_submethod
      • messageFields
      • Channel
    • Amount & Taxes
      • Amount-cash-in
      • GetConfigurationRequest
    • Identity & Contact
      • Shipping Address
    • Card & Payments
      • ChargesVoidCardResponse
      • Promotions
      • Submerchant
    • Subscriptions
      • SubscriptionUpdate
      • SubscriptionAdjustmentRequest
      • SubscriptionTransactionsResponse
    • Webhooks
    • Analytics
      • AnalyticsTransactionItem
      • AnalyticsListResponse
    • Settlement
      • SettlementDateRangeRequest
      • SettlementTicketRequest
      • SettlementResponse
    • Chargebacks
      • ChargebackListResponse
      • ChargebackSearchRequest
    • Cash
      • CashChargeInitRequest
      • CashStatusResponse
    • Transfer
      • TransferTokenRequest
      • TransferInitRequest
      • TransferStatusResponse
    • Payouts
      • PayoutsWebhooksItem
    • Smart Link
      • SmartLinkAmount
    • Terminal
      • TerminalContactDetails
      • TerminalCardDetails
      • TerminalPosDetails
      • TransactionSearchRequest
      • TerminalCardData
    • RequestBodies
      • one-and-two-step-payment
    • card-old
    • AmountWithTaxes-old
    • TransactionResponse
    • PrintJobRequest
    • one-and-two-step-payment
    • Card Present (CP)
    • one-and-two-step-payment1
    • Card
    • amount
    • FraudAlertRequest
    • SettlementDateRangeRequest
    • SubscriptionTransactionsResponse
    • Shipping Address
    • transactionType
    • ChargebackItem-old
    • SubscriptionTransaction
    • amount
    • AmountCore-old
    • CommandText-old
    • Language
    • extra_taxes
    • CommandText
    • RawResponse
    • Card Not Present (CNP)
    • Deferred
    • networkToken
    • FraudAlertResponse
    • ErrorResponse400-old
    • Deferred-old
    • SettlementResponse
    • extra_taxes-old
    • ExtraTaxes-old
    • CommandColumns-old
    • card
    • CommandColumns
    • CardData
    • FraudAlertRecord
    • currency
    • currency
    • ErrorResponse
    • webhooksItem
    • orderDetails-old
    • Country
    • ErrorResponse401-old
    • SettlementRecord
    • pos_details-old
    • ColumnItem-old
    • LinkFailure
    • ColumnItem
    • Amount
    • card_details
    • ValidationError
    • documentType
    • ErrorResponse403-old
    • card_details-old
    • TransactionResponse-old
    • CommandDivider-old
    • enc_tlv
    • CommandDivider
    • TransactionEvent
    • extraTaxes
    • extraTaxes-old
    • payment_method
    • ErrorResponse500-old
    • threeDomainSecure
    • enc_tlv
    • RawResponse-old
    • CommandFeed-old
    • CommandFeed
    • TransactionStatus
    • deferred
    • binInfo
    • contact_details-old
    • CardData-old
    • CommandSpace-old
    • CommandSpace
    • ReadingType
    • pos_details
    • Billing-Address-old
    • deferred-old
    • sub_merchant
    • AmountWithTip-old
    • CommandCut-old
    • metadata
    • sub_merchant
    • CommandCut
    • FailureReason
    • contact_details
    • headers
    • metadata
    • LinkFailure-old
    • CommandImage-old
    • CommandImage
    • EventTerminal
    • Amount-old
    • ContactDetails-old
    • SubscriptionUpdate
    • TransactionSearchRequest-old
    • CommandQR-old
    • orderDetails
    • CommandQR
    • EventOperation
    • Subscription
    • payment_submethod
    • citMit
    • SubscriptionAdjustmentRequest
    • CommandBarcode-old
    • Shipping Address
    • CommandBarcode
    • EventAmount
    • messageFields
    • PrinterError-old
    • Billing Address
    • EventExtraTaxes
    • PrintJobAccepted
    • webhooksChargeback
    • Language
    • PrintJobStatus-old
    • PrinterError
    • EventMetadata
    • networkToken-old
    • PrintWebhookPayload-old
    • AmountWithTaxes
    • PrintJobStatus
    • PrintJobStatusRequest
    • threeDomainSecure
    • webhooks
    • AmountCore
    • webhooks
    • product-old
    • headers
    • PrintWebhookPayload
    • ExtraTaxes
    • Metadata
    • webhooksChargeback
    • UnexpectedErrorResponse-old
    • AmountWithTip
    • citMit
    • TransactionSearchBody
    • TransactionSearchOnlineBody
    • network
    • Card-old-old
    • binInfo
    • AmountWithOptionalTip
    • TransactionSearchLocalBody
    • TransactionEvent_2
    • messageFields
    • Promotions-old
    • UnexpectedErrorResponse
    • FailureReason_2
    • transactionType
    • EventTerminal_2
    • EventOperation_2
    • InvalidBinResponse-old
    • EventAmount_2
    • EventExtraTaxes_2
    • EventMetadata_2
    • currency
    • Amount-CL-old
    • SettlementTicketRequest
    • metadata
    • payment_method
    • currency
    • currency
    • Submerchant
    • Shipping Address
    • GetConfigurationRequest-old
    • BadRequestResponse
    • ContactDetails
    • product
    • TransactionEvent_21
    • TransactionStatus2
    • ReadingType3
    • FailureReason_24
    • EventTerminal_25
    • EventOperation_26
    • EventAmount_27
    • EventMetadata_28
    • EventExtraTaxes_29
    • PrintWebhookPayload10
    • TransactionEvent11
    • FailureReason12
    • EventTerminal13
    • EventOperation14
    • EventAmount15
    • EventMetadata16
    • EventExtraTaxes17
HomePerú 🇵🇪
México 🇲🇽Ecuador 🇪🇨Colombia 🇨🇴Chile 🇨🇱
HomePerú 🇵🇪
México 🇲🇽Ecuador 🇪🇨Colombia 🇨🇴Chile 🇨🇱
  1. Kushki One

Webhooks

Beta — Early Access
Kushki ONE is currently in Beta for Peru 🇵🇪. Endpoints, parameters and response structures may change without prior notice. Do not deploy to production without coordinating with the Kushki integration team.
Kushki ONE pushes real-time notifications from the terminal to your backend over two independent webhook channels. They do not share a payload structure, an enabling parameter, or a delivery policy — read the section for the channel you are integrating.
ChannelEnabled byFires onDelivery
Transaction Webhookevents_webhook_url in the request bodyEvery payment lifecycle state changeRetried with backoff
Print WebhookwebhookUrl in the print job bodyPrint job reaching COMPLETED or FAILEDFire-and-forget
Both channels use POST with Content-Type: application/json, and both require HTTPS in production.

Delivers a notification on every state change of a terminal-mediated payment.

Enabling#

Supply events_webhook_url in the request body of an async payment operation:
POST /terminal/v1/async/charge                          ← Local Network
POST /terminal/v1/{terminalSerial}/async/charge         ← Cloud
{
  "events_webhook_url": "https://api.negocio.pe/webhook/terminal-events",
  "amount": { "iva": 0, "subtotal_iva": 0, "subtotal_iva0": 12000 },
  "client_transaction_id": "c5a3f3be-9d6f-4d39-8af5-58dbb589af79"
}
INFO
Webhooks are emitted by async operations only. Sync operations block until the acquirer answers and return the result directly in the HTTP response, so they have nothing to notify. Omitting events_webhook_url on an async call is valid — the transaction still runs, but you receive no state notifications and no final outcome.

One envelope, two uses#

There is a single event schema. It arrives in two places:
1.
The HTTP response to your async call — always status: TERMINAL_ACKNOWLEDGED with previous_status: "". This is an acknowledgement, not a result.
2.
Each webhook delivery — every subsequent state change, through the acquirer's final APPROVAL or DECLINED.
That symmetry is deliberate: write one deserializer and use it for both.

Lifecycle states#

Seven states in total. Five originate in the terminal; only APPROVAL and DECLINED come from the acquirer.
statusOriginMeaning
TERMINAL_ACKNOWLEDGEDTerminalPayment intent received. Processing started. Always the first state.
TERMINAL_CANCELEDTerminalCanceled on the terminal by the cardholder, or aborted by the POS.
CARD_PRESENTEDTerminalThe cardholder presented the card. See reading_type.
TERMINAL_REJECTEDTerminalRejected locally before reaching the acquirer — timeout, max retries, or validation.
APPROVAL_REQUESTEDTerminalSent to the acquirer for authorization.
DECLINEDAcquirerThe acquirer declined.
APPROVALAcquirerThe acquirer approved.

Transitions#

TERMINAL_ACKNOWLEDGED ─┬─→ CARD_PRESENTED ──┬─→ APPROVAL_REQUESTED ─┬─→ APPROVAL
                       │         │      ▲   │                       └─→ DECLINED
                       │         │      └───┘  card re-presented after rejection
                       │         └─→ TERMINAL_CANCELED
                       ├─→ TERMINAL_CANCELED
                       └─→ TERMINAL_REJECTED
DANGER
APPROVAL_REQUESTED is the point of no return. Once the transaction reaches the acquirer it can no longer be aborted — you must wait for APPROVAL or DECLINED. If it is approved, reverse it with void (same day, before roughly 20:59 local time in Peru) or refund.
A card rejected at the terminal can be presented again, producing another CARD_PRESENTED with an incremented interaction_attempt. This is why the lifecycle is a graph, not a straight line: do not assume a fixed number of events per transaction.

Payload#

{
  "event_id": "c08211a1-344c-4f1c-850b-41e33fb08cca",
  "previous_status": "TERMINAL_ACKNOWLEDGED",
  "occurred_at": "2026-08-03T20:53:34.859Z",
  "status": "CARD_PRESENTED",
  "merchant_id": "20000000103802320000",
  "client_transaction_id": "c5a3f3be-9d6f-4d39-8af5-58dbb589af79",
  "interaction_attempt": 1,
  "reading_type": "CHIP",
  "terminal": {
    "serialNumber": "TJ54241P20911",
    "model": "P2SE-BPKT",
    "wifiMac": "",
    "room": "3.0.10"
  },
  "operation": {
    "type": "charge",
    "amount": {
      "iva": 0.0,
      "subtotalIva": 0.0,
      "subtotalIva0": 12000.0,
      "extraTaxes": { "airportTax": 0.0, "iac": 0.0, "ice": 0.0, "travelAgency": 0.0 }
    },
    "clientTransactionId": "c5a3f3be-9d6f-4d39-8af5-58dbb589af79",
    "eventsWebHook": "https://api.negocio.pe/webhook/terminal-events",
    "metadata": {
      "customerEmail": "user@example.com",
      "device": "SUNMI-P3",
      "reference": "ORD-20240317-001"
    }
  }
}
FieldTypePresentDescription
event_idstring (UUID)✅Unique per event. Use this to deduplicate.
previous_statusstring✅State before this event. Empty string ("") on the first event.
occurred_atstring✅ISO-8601 UTC with milliseconds.
statusstring✅Current lifecycle state. One of the seven above.
merchant_idstring✅Kushki merchant identifier.
client_transaction_idstring (UUID)✅From your request. Use this to correlate events.
interaction_attemptinteger⬦Card-interaction counter. From CARD_PRESENTED onward.
reading_typestring⬦CHIP | CONTACTLESS | MAGNETIC_STRIPE. From CARD_PRESENTED onward; refreshed on each new read.
failure_reasonobject⬦{ type, code, message }. Only on TERMINAL_REJECTED and DECLINED.
terminalobject✅{ serialNumber, model, wifiMac, room }.
operationobject✅Snapshot of the originating operation.
operation.transactionReferencestring (UUID)⬦On capture, re_authorization, pos_tip and void.
✅ always present · ⬦ conditional
The Payment API reference is the authoritative contract for this payload — see the TransactionEvent schema on each async operation under Cloud Services or Local Network Services. The table above is a reading aid.
Mixed casing is intentional
Top-level fields use snake_case. Everything inside terminal and operation uses camelCase — serialNumber, subtotalIva0, eventsWebHook. This mirrors the terminal's internal representation. Deserialize it as-is; do not normalize.
Amounts are echoed as decimals
Requests take integers in the smallest unit of PEN, but events echo them back as decimals (12000.0). Never reuse an amount taken from an event to build a new request — see Building the amount.
INFO
No cardholder data is delivered. The transaction webhook carries no PAN, no cardholder name, and no card network. If you need card details, read them from the sync response or from Transaction Search.

Delivery and retries#

Acknowledge with any 2xx. Anything else is evaluated against this policy:
OutcomeBehavior
2xxSuccess. Delivery complete.
Timeout, connection reset, DNS failureRetry
408, 429, 500, 502, 503, 504Retry
400, 401, 403, 404, 409, 422No retry — treated as permanent rejection
Backoff is exponential with jitter, base = 2s:
delay = min(60s, base * 2^attempt) + random(0..base)
Delivery stops after 10 attempts or 15 minutes, whichever comes first.
INFO
Offline resilience. If the terminal loses connectivity it holds events in a persistent local queue and replays them once the network returns, preserving per-transaction ordering. A burst of delayed events after an outage is normal behavior, not a fault.

Building a consumer#

Because events are retried and replayed, your endpoint must be idempotent.
Deduplicate by event_id. Retries and queue replays repeat the same event_id. Persist the ones you have processed and discard repeats.
Correlate by client_transaction_id. All events of one transaction share it. terminal.serialNumber tells you which device, but is not a correlation key on its own.
Detect gaps with previous_status. If it does not match the last state you recorded for that transaction, an event is missing or arrived out of order. Reconcile via Transaction Search.
Respond fast, process later. Return 2xx immediately and hand the payload to an internal queue. Slow endpoints trigger retries, which cost you duplicates.
Treat APPROVAL / DECLINED as final. No further events follow. For TERMINAL_REJECTED, read failure_reason.code against the Error Catalog.

Print Webhook#

Delivers the final status of a print job when it reaches COMPLETED or FAILED.

Enabling#

Supply webhookUrl when creating the print job. The URL must be reachable from the internet (Cloud) or from the terminal's local network (Local).
WARNING
The field is webhookUrl — not events_webhook_url. The two channels use different parameter names.
In Local Network mode the terminal delivers this callback to your POS. Its contract is documented as an inbound endpoint under Print Job Webhook.

Payload#

FieldTypePresentDescription
printJobIdstring✅ID of the finished job.
statusstring✅COMPLETED | FAILED.
externalReferencestring✅Reference supplied when enqueuing. Empty string if none.
errorCodestring⬦Only when status is FAILED. See printer error codes.
errorMessagestring⬦Only when status is FAILED. Human-readable description.
Successful job
{
  "printJobId": "RECEIPT-20240317-001",
  "status": "COMPLETED",
  "externalReference": "POS-ORDER-7788"
}
Failed job — hardware error
{
  "printJobId": "RECEIPT-20240317-001",
  "status": "FAILED",
  "externalReference": "POS-ORDER-7788",
  "errorCode": "COVER_OPEN",
  "errorMessage": "The thermal printer cover was opened abruptly."
}

Delivery#

Fire-and-forget with a 15-second timeout. If your endpoint does not answer in time or returns a non-2xx status, the terminal does not retry — it continues its flow rather than blocking the printer.
INFO
Only terminal states fire the webhook. Intermediate PENDING and IN_PROGRESS transitions are never delivered. Poll Get Print Job Status if you need them.
Because there are no retries on this channel, build a polling fallback for flows where a lost print confirmation matters.

Implementation checklist#

TransactionPrint
Respond 2xx immediately, queue the work✅✅
Serve the endpoint over HTTPS✅✅
Deduplicate by event_id✅—
Deduplicate by printJobId—✅
Correlate by client_transaction_id✅—
Validate terminal.serialNumber against your fleet✅—
Detect gaps via previous_status✅—
Expect retries and replays — be idempotent✅—
Build a polling fallbackrecommendedrequired

Related#

Transaction Examples
Copy-ready requests for every operation, and how to build amounts in PEN.
Error Catalog
Every error code, grouped by category, with the recommended action.

Got a suggestion on this documentation? Contact us.
Modified at 2026-08-31 15:15:55
Previous
Transaction Examples
Next
Cloud Services
Built with