1. Webhook
Casharc
Merchant
  • Merchant
  • Getting Started
    • Introduction
    • Authentication
    • Quickstart
  • Core Concepts
    • Statuses
    • Status Codes
  • Guides
    • Idempotency
    • Metadata
  • Payments
    • Create Payment
      POST
    • List Payments
      GET
    • Retrieve Payment
      GET
    • Confirm Payment
      POST
    • Cancel Payment
      POST
    • Refund Payment
      POST
  • Payouts
    • Create Payout
      POST
    • List Payouts
      GET
    • Retrieve Payout
      GET
    • Cancel Payout
      POST
  • Appeals
    • Create Appeal
      POST
    • List Appeals
      GET
    • Retrieve Appeal
      GET
    • Cancel Appeal
      POST
  • Balance
    • Retrieve Balance
  • Files
    • Upload File
  • Webhook
    • Overview
    • Event Types
    • Verifying
    • Payment Event
    • Payout Event
    • Appeal Event
  1. Webhook

Overview

Webhooks notify your server when something happens to your payments, payouts, and appeals. Instead of polling the API, you register an endpoint and Casharc sends an HTTP POST to it every time an object changes state.

Setting up an endpoint#

Add a webhook endpoint in your project settings. For each endpoint you choose which event types it receives. A project can have several endpoints — for example, one per environment or one per service. Events are delivered to endpoints that are active at the moment the event occurs.
On creation, each endpoint gets its own signing secret. Use it to verify that a request genuinely came from Casharc. If a secret leaks, rotate it in your project settings. Rotation takes effect immediately: the next delivery is signed with the new secret.
An endpoint must be a publicly reachable https URL. Addresses in private, loopback and link-local networks are refused.

The event object#

Every delivery carries a single event in its body:
{
  "id": "evt_2n1TKXh5tX7P1Rfr",
  "type": "payment.completed",
  "created_at": "2026-01-01T00:34:12Z",
  "data": { ... }
}
FieldDescription
idUnique identifier of the event. Stays the same across all delivery attempts.
typeEvent type, in the form {object}.{state}. See Event Types.
created_atWhen the change occurred, in UTC, with second precision.
dataA full snapshot of the object — the same shape the API returns for it.
data is a snapshot, not a diff: it holds the complete object, so you can update your records without calling the API. The snapshot is taken when the event is processed, usually within seconds of created_at. If the object changed again in that time, data already shows the newer state, and a separate event for that newer change follows.

Headers#

HeaderDescription
X-TimestampUnix timestamp, in seconds, at which this delivery attempt was signed. Changes on every retry.
X-SignatureHex-encoded HMAC-SHA256 of {X-Timestamp}.{raw_body}. See Verifying.
User-AgentCasharc-Webhooks/1.0
Content-Typeapplication/json
Headers describe the delivery; the body describes the event. Everything you need to act on is in the signed body — read id and type from there, after verifying the signature.

Responding to a webhook#

Return any 2xx status within 10 seconds to acknowledge the delivery. The response body is ignored.
Any other outcome counts as a failed attempt:
SituationResult
2xxDelivered.
3xxFailed. Redirects are not followed.
4xx, 5xxFailed.
The full response takes longer than 10 sFailed.
Connection or TLS errorFailed.
Acknowledge first, then process. Verify the signature, store the event, return 200, and handle the business logic asynchronously — slow processing inside the request leads to timeouts and unnecessary retries.

Retries#

A failed delivery is retried with exponential backoff:
AttemptDelay after previous attempt
1— (sent immediately)
2~1 minute
3~5 minutes
4~30 minutes
5~2 hours
6~6 hours
7~12 hours
8~24 hours
Every retry carries the same body and is signed with a fresh X-Timestamp. After the last attempt fails, the event is no longer delivered automatically; retrieve the object from the API to catch up on its state.

Handling duplicates#

Delivery is at-least-once: the same event may arrive more than once — for example, when your server processed it but the acknowledgement was lost. Deduplicate by the event id: if you have already processed an event with this id, return 200 and do nothing.

Ordering#

Events are not guaranteed to arrive in the order they occurred. A retried event may arrive after a newer one for the same object.
For each object, keep the created_at of the last event you processed and ignore any event with an earlier created_at. If you need to be certain of the current state, retrieve the object from the API.

Repeated event types#

An event is sent on every status change of an object, and its type names the outcome. One type covers several statuses, so the same type can arrive more than once for one object. For example:
payment.completed is the general success event. It is sent when a payment becomes partially_paid, paid or overpaid, and again if the paid amount is later corrected (for example, from partially_paid to paid).
payment.refunded is sent for both partially_refunded and refunded.
Appeal events are sent once per appeal, when it reaches approved, rejected or canceled.
Always read status, status_code and the amounts from data; do not infer them from the event type.

Compatibility#

We may add new event types and new fields to existing objects. Ignore event types you do not recognize — return 2xx so they are not retried — and do not fail on unknown fields.
Previous
Upload File
Next
Event Types
Built with