Supercommerce API Docs
Webhooks

Webhook — CCAvenue (Payments)

The three public CCAvenue ingest surfaces: the browser return and cancel handlers that 302 the shopper onward, and the server-to-server dynamic event notification. None is trusted for money.

Three public surfaces. Two are browser-driven form POSTs that redirect the shopper onward; one is a genuine server-to-server notification. All three decrypt CCAvenue's encResp only to identify the order, then settle by re-reading the Status API.

Source: api-modules/payment-ccavenue/src/controllers/ccavenue-response.controller.ts and ccavenue-notify.controller.ts


Authentication

CCAvenue signs nothing. There is no header MAC, no shared webhook secret and no per-request signature on any of these endpoints. Two things stand in for one:

  1. Only CCAvenue holds the working key needed to produce a body that decrypts.
  2. Decisively — settlement re-reads the Status API regardless of what the body says.

The second is what actually makes this safe. The body cannot move money in any direction; at most a forged one causes a redundant status lookup for an order the attacker already knows the internal UUID of. Do not "harden" these endpoints by trusting order_status or amount from the payload.

Because there is no signature header, nothing is added to WEBHOOK_SIGNATURE_HEADERS. The archived delivery body holds only ciphertext.


POST /webhooks/payments/ccavenue/response

CCAvenue's redirect_url. The shopper's browser posts here when the billing page finishes, on success and failure alike.

  • Request: application/x-www-form-urlencoded with a single encResp field.
  • Response: always a 302, never JSON.

The handler decrypts encResp, resolves the order from merchant_param1, reconciles through the shared funnel, then redirects to the storefront:

The payment attempt is read off the echoed order_id (a -R<n> suffix, or attempt 1 when absent), so a late callback for an earlier attempt reconciles against that attempt. Order resolution still goes through merchant_param1 alone — the echoed order_id names the attempt, never the order.

{store_url}{storefront_return_path}?order=ORD-2026-00000123&status=paid
statusMeaning
paidSettled.
failedCCAvenue reported a terminal failure; the order is cancelled.
pendingCCAvenue has not finished. The order self-heals via the notification or the sweep.
unknownThe callback could not be decrypted or attributed, or reconcile errored. Logged server-side.

Every failure path still redirects. A shopper mid-payment must land somewhere sensible rather than on an error page, and the order recovers by other means.

POST /webhooks/payments/ccavenue/cancel

CCAvenue's cancel_url — where the shopper is sent if they abandon the billing page. Identical handling and identical redirect contract.


POST /webhooks/payments/ccavenue/notify

CCAvenue's dynamic event notification, configured in the MARS panel. This one is server-to-server, so a shopper who closes the browser after paying still gets their order settled in seconds rather than waiting for the stale-pending sweep.

  • Request: same encResp form field.
  • Response: 200 with the standard envelope.
{
  "data": { "accepted": true, "orderStatus": "Successful", "handled": true },
  "message": "Success",
  "statusCode": 200
}
FieldMeaning
acceptedThe delivery was well-formed.
orderStatusCCAvenue's order_status, echoed for the operator's benefit.
handledWhether this delivery caused a transition. false for duplicates, unattributable callbacks and non-terminal states.

Deduplication

CCAvenue ships no event id, so one is composed as `${tracking_id ?? order_id}-${order_status}` and claimed through the shared webhook inbox. Retries of the same event collide; a later state change on the same transaction stays distinct.

A delivery that ended failed is the exception: the next retry re-admits it and settlement runs again. That is what makes a Status API outage self-healing — the deliveries that 5xx'd during it settle on CCAvenue's own retry rather than needing an operator replay.

Outcomes

SituationInbox outcomeHTTP
Settled or cancelled the orderprocessed200
Duplicate delivery (processed / skipped)not re-claimed200
Order not attributablenot claimed200
CCAvenue reports a non-terminal stateskipped200
Reconcile threwfailed5xx — CCAvenue retries, and the retry re-runs settlement

A non-terminal state is not a delivery failure, so it acks 200 and is recorded as skipped rather than triggering a retry storm.

Missing encResp

Returns 400. On this endpoint that indicates a misconfiguration on our side — the api's raw-body capture is scoped to /webhooks, so a missing body means the route moved out from under it — and is logged at error level.


Setup

Register all three URLs in the MARS panel. They must be publicly reachable over HTTPS. The admin configuration page renders them with copy buttons.

{api_base}/webhooks/payments/ccavenue/response
{api_base}/webhooks/payments/ccavenue/cancel
{api_base}/webhooks/payments/ccavenue/notify

The first two are also sent as redirect_url and cancel_url on every transaction, built from response_base_url, so a per-transaction value always overrides whatever is configured in MARS.


On this page