Page cover
For the complete documentation index, see llms.txt. This page is also available as Markdown.

Webhooks

Lyzi webhooks let you be notified in real time, on your own server, whenever an event happens on a transaction (payment, refund, KYC status change, etc.). Instead of polling the API in a loop, you receive an HTTP POST on the URL of your choice for each event.

A webhook is a plain HTTP POST that the Lyzi server sends to your URL. The request body is a signed JSON payload, and every delivery is retried automatically if it fails.

Configuration

There are two things to set up:

  1. The destination URL (webhookUrl): provided when you create the transaction or the payment link. This URL receives the notifications related to that transaction.

  2. The signing secret (webhookSigningSecret): used to verify the authenticity of every webhook you receive. It is specific to your merchant account.

Retrieve your signing secret

The secret is available from your developer space / back office, or via the API:

Retrieve the secret
GET https://api.lyzi.fr/api/users/webhook-secret
Authorization: Bearer <your_token>

Response:

{
  "success": true,
  "data": { "webhookSigningSecret": "whsec_2b7f...e91a" },
  "status": 200
}

The secret always starts with the whsec_ prefix. Store it securely: it must never be exposed on the client side (browser, mobile app).

Available events

Every webhook carries an event field in the resource.event format.

Order events (order.*)

Event
Description

order.initial

The order has just been created.

order.pending

The order has been accepted.

order.awaiting

Awaiting payment (forwarded to the exchange).

order.waiting_chain_confirmation

Awaiting on-chain confirmation.

order.paid

The order has been paid.

order.cancelled

The order has been cancelled.

order.error

An error occurred on the order.

order.expired

The payment window expired.

order.kyt_failed

The KYT check failed.

order.refunding

A refund is in progress.

order.refunded

Partial refund completed.

order.full_refunded

Full refund completed.

KYC events (kyc.*)

Event
Description

kyc.pending

The payer's identity verification is in progress.

kyc.approved

The identity verification was approved.

kyc.refused

The identity verification was refused.

kyc.edd_completed

The enhanced due diligence (EDD) review reached a decision.

No webhook is emitted for AI compliance reports, detailed KYT, or KYA.

Default behavior

By default, your account receives payment and refund events:

  • order.paid

  • order.refunding

  • order.refunded

  • order.full_refunded

The other events (intermediate statuses, order.cancelled, order.error, order.expired, kyc.* events, etc.) are optional: they must be enabled for your account. Contact your Lyzi representative to subscribe to the additional events you need.

Request structure

Each delivery is a POST with a JSON body. The following headers are present:

Header
Description

Content-Type

Always application/json.

Lyzi-Event

The event type, e.g. order.paid.

Lyzi-Webhook-Id

Unique delivery identifier (32 characters). Use it for idempotency.

Lyzi-Signature

HMAC signature of the payload (see below).

Example payload (order.paid)

The body reuses the same fields as the order status response, plus the added event field.

Example payload (kyc.approved)

kyc.* events send a compact payload, tied to the related order.

For kyc.edd_completed, the payload additionally contains eddStatus, eddOutcome (approved or refused) and spendingLimit.

Verify the signature

Every webhook is signed so you can guarantee it comes from Lyzi and has not been tampered with.

The Lyzi-Signature header has the following format:

  • t: the Unix timestamp (in seconds) at signing time.

  • v1: the HMAC-SHA256 signature, in hexadecimal.

The signature is computed over the string ${t}.${raw_body}, using your webhookSigningSecret as the key. The raw_body is the request body exactly as received, without re-serializing it.

Verification steps

  1. Read the raw request body (before any JSON parsing).

  2. Extract t and v1 from the Lyzi-Signature header.

  3. Recompute HMAC-SHA256("${t}.${raw_body}", webhookSigningSecret).

  4. Compare the result to v1 using a constant-time comparison.

  5. Reject the request if the timestamp t differs from the current time by more than 5 minutes (replay protection).

Example (Node.js)

Idempotency

Lyzi guarantees a single delivery per (order, event) pair. However, because of retries, your server may receive the same delivery more than once if your response is slow or fails.

Use the Lyzi-Webhook-Id header as an idempotency key: store the identifiers you have already processed and ignore duplicates. Your handlers must be idempotent.

Retries

If your server does not respond with a 2xx status, Lyzi automatically retries the delivery.

Parameter
Default value

Total number of attempts

5 (1 initial + 4 retries)

Retry strategy

Exponential backoff

Initial delay between retries

2 seconds (then 4 s, 8 s, 16 s)

Response timeout

10 seconds

A 2xx response marks the delivery as successful. Any other response (or a timeout) triggers a retry, until the attempts are exhausted, after which the delivery is considered permanently failed.

Rotate the secret

You can regenerate your signing secret at any time. The previous secret is immediately invalidated.

Response:

Best practices

  • Always verify the signature before processing a webhook.

  • Respond 2xx quickly, then process asynchronously.

  • Deduplicate using Lyzi-Webhook-Id.

  • Tolerate replays by rejecting timestamps that are too old (5-minute window).

  • Never expose your webhookSigningSecret on the client side.

  • Do not assume delivery order of events: rely on the status field and on updatedAt.