1. Kushki One
  • API Docs Colombia 🇨🇴
  • Online Payments
    • Release Notes
    • Card Payments
      • Request a card token
      • Make a charge or deferred charge
      • Create payment (tokenless)
      • Void a transaction
      • Refund a transaction
      • Request deferred options
      • Authorize payments
      • Preauthorization (tokenless)
      • Reauthorize payments
      • Capture an authorized payment
      • Verify Account
      • Validate OTP
      • Bin Info
      • BIN info V2
    • One-Click & Scheduled Payments
      • Request a recurring charge token
      • Create a recurring charge
      • Make an One-click payment
      • Update recurring charge card data
      • Cancel a recurring charge
      • Update a recurring charge
      • Add a temporary charge or discount
      • Authorize payments
      • Capture an authorized payment
      • Get recurring charge Info
    • Chargebacks
      • Query Chargebacks
      • Request Chargeback Export
    • Transfer in
      • Get Bank List
      • Request a Transfer In token
      • Init Transaction
      • Get Status
      • Cancel Transaction
    • Transfer out
      • Get Bank List
      • Get Bank List V2
      • Request a Transfer Out token
      • Init Transaction
      • Get Status
      • Balance for Payouts
    • Cash in
      • Request a cash in token
      • Init Transaction
      • Transaction Status
      • Delete a cash in transaction
      • Update a cash in transaction
    • Cash-out
      • Request a cash out token
      • Init Transaction
      • Transaction Status
      • Update a cash out transaction
      • Delete a cash out transaction
    • Smartlinks-v2
      • Create a Smartlink
      • Get a Smartlink
      • Update a Smartlink
      • Delete a smartlink
    • Analytics
      • Get transactions list v1
      • Get transactions list v2
    • Gateway-status
      • Get gateway status
      • Get platform status
    • Payment Credentials
      • Create a credential
      • Search credentials
      • Advanced search
      • Delete credential
      • Regenerate a credential
      • Activate or deactivate
      • Update credential
    • Payment Button
      • Create a payment button
    • Settlement
      • Query settlement
    • Subscription Transactions
      • Get subscription transactions
  • Kushki One
    • Error Catalog
    • Release notes
    • Transaction Examples
    • Webhooks
    • Cloud Services
      • Payment
        • 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)
        • Search
          • Transaction Search
      • Print
        • Create Print Job
        • Get Print Job Status
    • Local Services
      • Payment
        • 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
        • Create Print Job
        • Get Print Job Status
        • Print Job Webhook (inbound — implemented by your POS)
  • API RAW CARD PRESENT PAYMENTS
    • Release Notes
    • Error Catalog
    • The Amount Object
    • Key Exchange Process
    • Test data
    • Card Information
      • Get BIN Info
      • BIN info V2
      • Request deferred options
    • One-time Payments
      • Void & Reverse
    • Two-step Payments
      • Authorization and capture
    • Voids & Refunds
      • Void & Reverse
      • Refund a transaction
    • Query Transactions
      • Transaction Search
    • Webhooks
      • Introduction
      • Good Practices
      • Webhooks-Card Payments
      • Webhooks-Refunds
      • Check your webhooks
    • Chargebacks
      • Query Chargebacks
      • Request Chargeback Export
  • Appian - Submerchant Register
    • Submerchant Validation in Batch
    • Query submerchant status by requestId/submerchantId
    • Get submerchantIds
    • Get credentials for submerchants
  • Schemas
    • RequestBodies
      • one-and-two-step-payment
    • SubscriptionTransactionsResponse
    • Card
    • Channel
    • Amount-cash-in
    • ChargebackListResponse
    • SettlementDateRangeRequest
    • TransactionResponse
    • PrintJobRequest
    • card
    • one-and-two-step-payment-3
    • SubscriptionTransaction
    • networkToken
    • ChargebackItem
    • SettlementRecord
    • RawResponse
    • CommandText
    • amount
    • ErrorResponse
    • currency
    • webhooksItem
    • ErrorResponse400
    • SettlementResponse
    • CardData
    • CommandColumns
    • extra_taxes
    • Amount
    • ErrorResponse401
    • LinkFailure
    • ColumnItem
    • pos_details
    • extraTaxes
    • ErrorResponse403
    • CommandDivider
    • card_details
    • TransactionEvent
    • Deferred
    • Country
    • payment_method
    • ErrorResponse500
    • CommandFeed
    • enc_tlv
    • TransactionStatus
    • CommandSpace
    • contact_details
    • ReadingType
    • ContactDetails
    • CommandCut
    • deferred
    • sub_merchant
    • FailureReason
    • documentType
    • Subscription
    • CommandImage
    • metadata
    • EventTerminal
    • orderDetails
    • Language
    • TransactionSearchRequest
    • CommandQR
    • EventOperation
    • Shipping Address
    • payment_submethod
    • CommandBarcode
    • EventAmount
    • Billing-Address
    • EventExtraTaxes
    • PrintJobAccepted
    • SubscriptionUpdate
    • PrinterError
    • EventMetadata
    • threeDomainSecure
    • SubscriptionAdjustmentRequest
    • AmountWithTaxes
    • PrintJobStatus
    • PrintJobStatusRequest
    • product
    • webhooks
    • AmountCore
    • headers
    • ExtraTaxes
    • PrintWebhookPayload
    • Metadata
    • webhooksChargeback
    • citMit
    • AmountWithTip
    • network
    • TransactionSearchBody
    • TransactionSearchOnlineBody
    • binInfo
    • AmountWithOptionalTip
    • TransactionSearchLocalBody
    • messageFields
    • TransactionEvent_2
    • UnexpectedErrorResponse
    • FailureReason_2
    • transactionType
    • ExternalReferenceId
    • EventTerminal_2
    • ExternalSubscriptionId
    • EventOperation_2
    • EventAmount_2
    • EventExtraTaxes_2
    • EventMetadata_2
    • SettlementTicketRequest
    • Amount-old
    • currency
    • extraTaxes2
    • currency
    • ErrorResponse
    • TransactionEvent_23
    • TransactionStatus4
    • ReadingType5
    • FailureReason_26
    • EventTerminal_27
    • EventOperation_28
    • EventAmount_29
    • EventMetadata_210
    • EventExtraTaxes_211
    • PrintWebhookPayload12
    • TransactionEvent13
    • FailureReason14
    • EventTerminal15
    • EventOperation16
    • EventAmount17
    • EventMetadata18
    • EventExtraTaxes19
BienvenidaPerú 🇵🇪México 🇲🇽Ecuador 🇪🇨Colombia 🇨🇴
Chile 🇨🇱
BienvenidaPerú 🇵🇪México 🇲🇽Ecuador 🇪🇨Colombia 🇨🇴
Chile 🇨🇱
  1. Kushki One

Webhooks

Beta — Early Access
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 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.co/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 23:59 local time in Colombia) 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": "20000000106033700000",
  "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.co/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 COP, 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 COP.
Error Catalog
Every error code, grouped by category, with the recommended action.

Got a suggestion on this documentation? Contact us.
Modified at 2026-08-24 16:32:09
Previous
Transaction Examples
Next
Cloud Services
Built with