API reference
The endpoints an in-store integration uses. All requests are authenticated with your
API key and made against https://api-live.kcpboundless.com.
This reference is maintained by hand for now. It will be generated directly from the API's OpenAPI specification, so the published reference always matches the running service.
Payments
Take a payment
POST /api/in-store/payments
Sends a bill to a terminal and returns the payment in AWAITING_TERMINAL. See
Accept a payment for the request body and response.
Check a payment's status
POST /api/in-store/payments/{id}/sync-status
Returns the current state of the payment, advancing it if the customer has finished at the device. Safe to call repeatedly.
Cancel a payment
POST /api/in-store/payments/{id}/cancel
Withdraws a bill that is still waiting at the terminal. If the customer completed the payment first, their payment stands and the response reports that instead — always read the returned status. See Cancel — before the customer pays.
Void a payment
POST /api/in-store/payments/{id}/void
Reverses a captured payment at the acquirer, same day, where the acquirer supports it. A confirmed
void leaves the payment CANCELLED; a 200 with the payment still CAPTURED means the reversal
is not yet confirmed. See Void — after the customer paid
for the window, the preconditions, and the cases your till must handle.
Read a payment
GET /api/transactions/{id}
The payment's current state, without contacting the terminal — the cheap call for routine polling.
sync-status above is the one that refreshes from the device first.
Payment status history
GET /api/transactions/by-payment/{paymentId}
The append-only status history for a payment, newest first — one element per status event. See Trace a payment.
List payments
GET /api/transactions?merchantExternalId={merchantExternalId}
&from=&to=&status=&acquirerName=&q=&page=&size=
Paged, newest first. Filter by date range, status, or free text; page is 0-indexed and the
response carries content plus totalElements / totalPages.
Stores
GET /api/merchants/{merchantExternalId}/stores
GET /api/merchants/{merchantExternalId}/stores/search?q=&status=&country=&hasTerminals=&sort=&page=&size=
POST /api/merchants/{merchantExternalId}/stores
GET /api/merchants/{merchantExternalId}/stores/{storeExternalId}
PUT /api/merchants/{merchantExternalId}/stores/{storeExternalId}
DELETE /api/merchants/{merchantExternalId}/stores/{storeExternalId}[?force=true]
Create, read, update, and remove the stores under your business. The plain list is alphabetical;
search adds free text, filters, sorting, and paging. Deletes cascade to the store's terminals
and are guarded when the store took payments in the last 24 hours — see
Removing safely.
Terminals
GET /api/merchants/{merchantExternalId}/stores/{storeExternalId}/terminals
POST /api/merchants/{merchantExternalId}/stores/{storeExternalId}/terminals
GET /api/merchants/{merchantExternalId}/stores/{storeExternalId}/terminals/{terminalExternalId}
PUT /api/merchants/{merchantExternalId}/stores/{storeExternalId}/terminals/{terminalExternalId}
DELETE /api/merchants/{merchantExternalId}/stores/{storeExternalId}/terminals/{terminalExternalId}[?force=true]
Create, read, update, and remove the terminals under a store. The same delete guard applies.
Webhook configuration
POST /api/webhooks/configs create a destination
GET /api/webhooks/configs list yours
GET /api/webhooks/configs/{id} read one
PUT /api/webhooks/configs/{id} update url or event selection
DELETE /api/webhooks/configs/{id} remove
POST /api/webhooks/configs/{id}/regenerate-key rotate the signing secret
POST /api/webhooks/configs/{id}/test send a TEST event now
GET /api/webhooks/configs/{id}/events delivery history
GET /api/webhooks/events/{eventId}/attempts per-delivery attempts
Create body: { "url": "https://...", "description": "...", "eventTypes": ["PAYMENT_CAPTURED"] } —
omit eventTypes to receive every event. The response includes the signing secret. See
Webhooks.
Errors
Every error uses one shape:
{
"timestamp": "2026-09-08T06:20:11Z",
"status": 409,
"error": "Conflict",
"message": "Payment 01997b3e… is already CAPTURED"
}
Treat message as human-readable diagnostics, not a machine contract. Branch on the HTTP status
and your own request context — never on message text, which may be reworded.
| Code | When | Your response |
|---|---|---|
200 OK | The request succeeded. | Read the returned status — success of the request is not the same as the outcome you asked for. |
201 Created | The payment was accepted. | Read the returned status — a 201 can carry a REFUSED payment on a busy terminal. |
400 Bad Request | Validation failed — message names the field and the reason. | Fix the request. Do not retry unchanged. |
401 Unauthorized | Missing or invalid credentials. | Check the key, and the bearer prefix rule. Do not retry. |
403 Forbidden | Valid credentials, but outside your permissions. | Do not retry. |
404 Not Found | The resource does not exist — including anything that exists but belongs to another business. | Do not retry. |
409 Conflict | The request conflicts with the current state — the payment is already decided, a reversal is not permitted in its current state, or the terminal is not configured. | Read the message; the state must change first. |
429 Too Many Requests | Rate limit exceeded. | Honour Retry-After, then retry. |
5xx | A temporary problem on our side. | Retry with backoff. A create is protected by reference idempotency. |