LirPay
OpenAPI

Configure and verify webhooks

Saved webhook addresses are deprecated. Pass webhook_url directly in each POST /payment-links, POST /withdrawals, POST /conversions, or POST /fulfillments request. The request destination overrides the saved URL and receives signed events, retries, and redeliveries.

{
  "display_name": "Order 1042",
  "amount": "25.00",
  "currency": "USD",
  "project_id": "6d14a419-a00b-4fc0-9613-9c8959ed20c2",
  "webhook_url": "https://merchant.example/webhooks/lirpay"
}

During the transition, saved URLs remain a fallback only while NOTIFY_DEPRECATED_WH=true on the server. When the flag is removed, saved URL updates return 410 deprecated_webhook_removed, GET /webhook returns null, and requests without webhook_url receive no webhooks. Existing secrets and event history are retained.

If a webhook configuration exists for the key environment, keep using its signing secret. Otherwise, open merchant Settings, click Generate secret, then Copy secret, configure your receiver, and Save to activate the new value. Use POST /webhook/test with a JSON body containing url to test a request destination.

GEThttps://lirpay.org/api/v2/integration/webhook

Read the deprecated saved webhook during the transition; returns null after compatibility ends.

API key or OAuth tokenwebhooks:read
PUThttps://lirpay.org/api/v2/integration/webhook

Deprecated: create or update a saved URL during the transition. Returns HTTP 410 after compatibility ends.

API key or OAuth tokenwebhooks:write
ParameterTypeInRequiredDescription
urlURLbodyyesHTTPS endpoint in live mode. Test mode also accepts HTTP.
event_typesstring[]bodyyesNon-empty list of supported events.
enabledbooleanbodynoDelivery state. Defaults to true.

Request

{
  "url": "https://merchant.example/webhooks/lirpay",
  "event_types": [
    "payment.succeeded",
    "balance.updated",
    "withdrawal.completed"
  ],
  "enabled": true
}

The first PUT response includes a new secret. Store it because later GET responses expose only has_secret.

DELETEhttps://lirpay.org/api/v2/integration/webhook

Disable webhook delivery for the current environment.

API key or OAuth tokenwebhooks:write
POSThttps://lirpay.org/api/v2/integration/webhook/test

Send and record a signed test event.

API key or OAuth tokenwebhooks:write
POSThttps://lirpay.org/api/v2/integration/webhook/rotate-secret

Replace the signing secret and return the new value once.

API key or OAuth tokenwebhooks:write
GEThttps://lirpay.org/api/v2/integration/webhook-events

List event payloads and delivery state.

API key or OAuth tokenwebhooks:read
ParameterTypeInRequiredDescription
pageintegerquerynoPage number. Defaults to 1.
limitintegerquerynoItems per page. Maximum 100.
GEThttps://lirpay.org/api/v2/integration/webhook-events/{id}

Read one payload and its delivery history.

API key or OAuth tokenwebhooks:read
ParameterTypeInRequiredDescription
iduuidpathyesResource identifier returned by a list or create operation.

The delivery_history array includes attempt number, status, error, and timestamp.

POSThttps://lirpay.org/api/v2/integration/webhook-events/{id}/redeliver

Deliver an existing event again.

API key or OAuth tokenwebhooks:writeIdempotency-Key required
ParameterTypeInRequiredDescription
iduuidpathyesResource identifier returned by a list or create operation.
Idempotency-KeystringheaderyesUnique key for this monetary operation. Maximum 255 characters.

Allowlist source IPs

Production webhook deliveries come from payment-core egress. Allowlist 2.27.27.132 for both test and live events.

  • 2.27.27.132 — webhook source IP
  • Do not allowlist 2.27.27.134. That address is HTTPS ingress for lirpay.org only.
  • Deliveries currently use IPv4 only. Verify the HMAC signature even if you filter by IP.

Verify each signature

Compute a hexadecimal Hash-based Message Authentication Code using SHA-256 (HMAC-SHA256) over the untouched request body.

import { createHmac, timingSafeEqual } from "node:crypto";

const expected = createHmac("sha256", webhookSecret)
  .update(rawBody)
  .digest("hex");
const valid = timingSafeEqual(
  Buffer.from(expected, "hex"),
  Buffer.from(signature, "hex"),
);
  • Read the event identifier from X-Lirpay-Event-Id
  • Read the environment from X-Lirpay-Mode
  • Return a 2xx response after persisting the event
  • Deduplicate processing by event identifier
  • Live deliveries are retried up to eight times. Test-mode events are never retried

Subscribe to supported events

  • payment.succeeded, payment.failed, payment.expired, payment.refund_required, payment.refunded, payment.chargeback
  • balance.updated
  • withdrawal.processing, withdrawal.completed, withdrawal.failed
  • conversion.completed