Webhooks & Callbacks
Korba Xchange notifies your server the moment a transaction changes state — no polling required. Configure a callback URL in your dashboard and we will deliver a signed GET request with the transaction outcome directly to your endpoint.
Overview
When a transaction is initiated you supply a callback_url. Once the transaction
reaches a terminal state — either SUCCESS or FAILED — Korba
Xchange fires a GET request to that URL, appending the outcome as query
parameters.
Callbacks are delivered at least once. If your endpoint returns a non-2xx response we will retry with exponential back-off. Design your handler to be idempotent — processing the same callback twice should have no adverse side-effect.
Callback Format
Korba Xchange appends three query parameters to your callback_url. The base URL you
provide is left intact; parameters are joined with ? (or & if your
URL already contains query parameters).
{callback_url}?transaction_id={UNIQUE_ID}&status={SUCCESS|FAILED}&message={DETAILS}
Callback Parameters
Example Callback
Below is what a successful callback looks like when delivered to your endpoint:
GET https://webhook.site/1c4d4a5d ?transaction_id=UNIQUE_ID &status=SUCCESS &message=Transaction+processed+successfully
Webhook Security
Webhooks include an additional security
layer: the callback carries an X-Callback-Token HTTP header containing a
pre-shared secret that you configure in your XCheckout settings on the dashboard.
Always validate this header before processing the callback. Reject any request where the token is absent or does not match your configured value — this prevents replay attacks from third parties who might discover your callback URL.
X-Callback-Token: your-configured-secret-token Content-Type: application/x-www-form-urlencoded
Example Handler
The snippets below show minimal production-ready callback handlers that verify the callback token (for XCheckout), look up the transaction, and update its status idempotently.
# Django view — GET /callbacks/korba/ import logging from django.conf import settings from django.http import HttpResponse, HttpResponseForbidden from django.views import View logger = logging.getLogger(__name__) class KorbaCallbackView(View): def get(self, request): # 1. Verify XCheckout callback token (XCheckout integrations only) token = request.headers.get("X-Callback-Token") if token != settings.KORBA_CALLBACK_TOKEN: logger.warning("Rejected callback — invalid token") return HttpResponseForbidden() # 2. Extract parameters transaction_id = request.GET.get("transaction_id") status = request.GET.get("status") message = request.GET.get("message", "") logger.info(f"Callback: txn={transaction_id} status={status}") # 3. Idempotently update your record Order.objects.filter( transaction_id=transaction_id, payment_status="pending", ).update(payment_status=status.lower()) # 4. Respond quickly — do heavy work in a background task return HttpResponse("OK", status=200)
Best Practices
-
Verify the callback token. For XCheckout integrations, always check the
X-Callback-Tokenheader before processing. Return403 Forbiddenimmediately if the value is absent or wrong. -
Respond quickly. Your endpoint should return an HTTP
200within a few seconds. Offload any heavy processing — sending emails, generating receipts — to a background queue after responding. -
Make your handler idempotent. Callbacks may be delivered more than once.
Use the
transaction_idas a natural idempotency key: only act when the record is in apendingstate, and ignore subsequent callbacks for the same reference. - Log every callback. Store the raw query parameters and timestamp for each incoming callback. This is invaluable during incident investigation and reconciliation.
-
Use HTTPS. Your callback URL must use
https://. Korba Xchange will not deliver callbacks to plain HTTP endpoints in production. - Cross-check with the Transaction Status API. For high-value transactions, confirm the callback by calling the Transaction Status endpoint independently before fulfilling an order.