Webhooks Guide
Webhooks allow you to receive real-time HTTP notifications when events occur in your LuxCore account, such as when a payment completes or fails.How Webhooks Work
Setting Up Webhooks
Create a Webhook Endpoint
Response
Webhook Events
| Event | Description |
|---|---|
payment.created | Payment was initialized |
payment.completed | Payment completed successfully |
payment.failed | Payment failed |
payment.cancelled | Payment was cancelled |
payment.refunded | Payment was refunded |
balance.updated | Merchant balance was updated |
merchant.updated | Merchant configuration was updated |
ticket.created | A new support ticket was created |
ticket.updated | Support ticket status changed (e.g., reopened) |
ticket.comment_added | Support team replied to a ticket |
ticket.resolved | Support ticket was resolved (reserved) |
ticket.closed | Support ticket was closed |
Webhook Payload
All webhook payloads follow this envelope structure:Payment Fields Reference
| Field | Type | Description |
|---|---|---|
id | string | Unique payment identifier |
status | string | Current payment status (completed, failed, cancelled, expired, refunded, partial_refund) |
amount | integer | Total payment amount in minor units (centavos). Example: 100050 = 1000.50 ARS |
currency | string | ISO 4217 currency code (ARS, AUD, MXN, UYU) |
type | string | Payment type: deposit, withdrawal, deposit_pp, or withdrawal_pp |
merchant_id | integer | Your merchant ID |
merchant_reference | string | Your unique reference passed when creating the payment |
method | string | null | Payment method code (bank_transfer, spei, crypto, payid). Nullable if method not yet assigned |
fee | integer | Commission amount in minor units. Already calculated based on your merchant fee rate |
net_amount | integer | Amount you receive (deposit) or total debited (withdrawal), in minor units |
created_at | string | Payment creation timestamp (ISO 8601) |
confirmed_at | string | null | When payment was confirmed by the customer |
completed_at | string | null | When payment reached terminal completed status |
failed_at | string | null | When payment failed (if applicable) |
failure_reason | string | null | Human-readable failure description |
customer_data | object | Whitelisted metadata (see below) |
processing_time_ms | integer | Time from creation to completion in milliseconds. Only present for completed events |
refund | object | null | Refund details. Only present for payment.refunded events |
Amount, Fee, and Net Amount
All monetary values are integers in minor units (centavos). The fee is automatically calculated based on your merchant commission rate.Formula:
net_amount = amount - feeDeposit example (customer pays 1000.50 ARS, merchant fee 4.5%):amount:100050— the amount the customer paidfee:4502— commission charged (100050 × 4.5%)net_amount:95548— amount credited to your balance
amount:50000— the payout amount sent to the recipientfee:2500— commission charged (50000 × 5%)net_amount:47500— total debited from your balance: payout amount minus fee
Withdrawal Payload Example
For withdrawals, the payload includespayout details inside customer_data:
customer_data Fields
Thecustomer_data object uses a whitelist approach — only specific fields are included:
| Field | Type | Description |
|---|---|---|
note | string | Customer or merchant note |
customer_email | string | Customer email (if provided) |
customer_phone | string | Customer phone (if provided) |
customer_name | string | Customer name (if provided) |
external_id | string | External reference ID |
reference | string | Payment reference |
description | string | Payment description |
expires_at | string | Payment expiration time (ISO 8601) |
requested_payment_type | string | Original requested type (deposit or withdrawal) |
commission | object | Commission details: currency, total_minor |
payout | object | Only for withdrawals: bank_code, bank_account, recipient_name, bank_name, bsb, payid, payid_type |
Webhook Headers
Each webhook request includes these headers:| Header | Description |
|---|---|
X-Webhook-Event | Event type (e.g., payment.completed) |
X-Webhook-Timestamp | Unix timestamp when signature was created |
X-Webhook-Signature | HMAC-SHA256 signature for verification |
X-Webhook-Id | Unique identifier for this webhook delivery |
X-Webhook-Retry | Always present. true if this is a retry attempt, false otherwise |
Content-Type | Always application/json |
Signature Verification
Always verify webhook signatures to ensure requests are from LuxCore.Signature Format
Verification Algorithm
Implementation Examples
Retry Policy
If webhook delivery fails (non-2xx response or timeout), we retry with exponential backoff using the formulamin(2^n × 60s, 3600s):
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 2 minutes |
| 3 | 4 minutes |
| 4 | 8 minutes |
| 5 | 16 minutes |
maxAttempts=5), the webhook is marked as failed. You can manually retry failed events via the API.
Testing Webhooks
Send a test event to verify your endpoint:Managing Webhooks
List Webhooks
Update Webhook
Delete Webhook
In-Request Webhooks
Instead of pre-configuring webhooks via the API, you can pass awebhook_url directly in the payment creation request. This is useful when you want per-payment notification routing or a simpler integration without managing webhook endpoints.
How It Works
- Include
webhook_urlin yourPOST /paymentsrequest - LuxCore automatically creates (or reuses) a webhook endpoint for your merchant
- Events are delivered to this URL in addition to any admin-configured webhooks
- The webhook is signed using your merchant’s default webhook secret
Example
Default Events
Ifwebhook_events is not provided, the following events are subscribed by default:
payment.createdpayment.completedpayment.failedpayment.refunded
Webhook Secret
In-request webhooks are signed using your merchant’s default webhook secret. This secret is:- Automatically generated the first time you use
webhook_url - Shared across all in-request webhooks for your merchant
- Visible in the merchant settings panel of the backoffice
- Used for HMAC-SHA256 signature verification (same algorithm as admin webhooks)
Use the same signature verification logic for in-request webhooks as for admin webhooks. The only difference is the signing secret — in-request webhooks use your merchant’s default secret instead of the per-webhook secret.
Deduplication
If you send the samewebhook_url across multiple payments, the system automatically reuses the existing webhook configuration. This means:
- No duplicate webhook endpoints are created
- Event subscriptions from the first request are preserved
- The same secret key is used for all deliveries to that URL
Differences from Admin Webhooks
| Feature | Admin Webhooks | In-Request Webhooks |
|---|---|---|
| Created via | POST /webhooks API | webhook_url field in POST /payments |
| Secret key | Per-webhook (custom or generated) | Merchant default secret (shared) |
Listed in GET /webhooks | Yes (by default) | No (use ?source=in_request to view) |
| Events | Configurable per-webhook | Configurable per-request (or defaults) |
| Deduplication | Manual (create once, reuse) | Automatic (same URL = same webhook) |
Best Practices
Always Verify Signatures
Never process webhooks without verifying the signature first
Respond Quickly
Return 200 immediately, process events asynchronously
Handle Duplicates
Use payment ID for idempotency - you may receive the same event twice
Log Everything
Log webhook payloads for debugging and audit trails
Webhook endpoints must be publicly accessible HTTPS URLs. Self-signed certificates are not supported.
