Webhooks
Fluxis uses account-level webhooks to notify your application in real time when events occur, such as payment status changes. This guide covers registration, delivery behavior, and a short overview of signature verification.
For the full HMAC verification walkthrough (canonical JSON, worked example, test endpoint), see Webhook Signature Verification.
Overview
When you register a webhook for an account, Fluxis sends HTTP POST requests to your URL whenever matching events occur. Each request includes:
- A JSON payload with event data
- Security headers for signature verification
Always verify webhook signatures before processing the payload. See Webhook Signature Verification.
Webhook headers
Every webhook request includes the following headers:
| Header | Description |
|---|---|
X-Request-Signature | HMAC-SHA256 signature of the payload |
X-Request-Timestamp | Unix timestamp (seconds) when the request was generated |
Content-Type | Always application/json |
Registering webhooks
Webhooks are managed at the account level (not per Point of Sale). Use your organization credentials to register an HTTPS endpoint for the account tied to your POS.
Create webhook: POST /v1/account/{accountID}/webhook
Code
The response includes a secret — store it immediately; it is only returned on create.
event_type | When it fires |
|---|---|
payment_request | Payment request status changes (see below) |
incoming_transfer | Incoming transfer events (reserved / future use) |
refund | Refund events |
Other management endpoints:
| Action | Endpoint |
|---|---|
| List | GET /v1/account/{accountID}/webhook/list |
| Update URL | PUT /v1/account/{accountID}/webhook/{webhookID}/url |
| Activate | PATCH /v1/account/{accountID}/webhook/{webhookID}/activate |
| Deactivate | PATCH /v1/account/{accountID}/webhook/{webhookID}/deactivate |
| Delete | DELETE /v1/account/{accountID}/webhook/{webhookID}/delete |
| Test delivery | POST /v1/account/{accountID}/webhook/{webhookID}/test |
| Delivery logs | GET /v1/account/{accountID}/webhook/logs?page=1&page_size=20 |
See the API Reference — Webhooks.
Webhook management requires organization-level API credentials. The account must belong to your organization.
Verifying webhook signatures (summary)
Fluxis signs the full parsed JSON body — for example { "data": { … } } — not raw request bytes and not the inner data object alone.
Algorithm:
- Serialize the parsed body to canonical JSON (compact, keys sorted alphabetically at every object level)
- Build the signed string:
<unix_timestamp>.<canonical_json> - Compute
HMAC-SHA256(webhook_secret, signed_string)and hex-encode the result - Compare to
X-Request-Signatureusing a constant-time function - Reject if the timestamp is older than 300 seconds (5 minutes)
Signed string example (timestamp 1712345678, sample payment_request payload):
Code
::::note Optional fields
Fields such as external_reference_id and account_id use omitempty in the API — they are omitted from the JSON when unset. Your verifier must canonicalize the parsed body as received, not a fixed schema template.
::::
Quick Node.js check (see the full guide for Python, Go, and a worked example):
Code
Which statuses trigger webhooks
Fluxis delivers payment_request webhooks when a payment request enters processing (payment detected) or a terminal confirmation state (completed, underpaid, or overpaid).
Status changes such as expired or failed are not sent via webhook — poll the payment request endpoint or reconcile via transactions.
Webhook payload structure
Payment request status update webhooks have the following structure:
Code
| Field | Description |
|---|---|
notification_type | Type of notification (e.g., payment_request_status_update) |
payment_request_id | Unique identifier of the payment request |
payment_request_type | Type of payment request (e.g., fixed) |
external_reference_id | Your internal reference ID (optional; omitted if not set) |
status | New status of the payment request |
point_of_sale_id | ID of the Point of Sale |
account_id | ID of the associated account (optional; omitted if not set) |
Best practices
Respond quickly
Your endpoint must return HTTP 200 OK within 2 seconds. If you need to perform heavy processing, acknowledge the webhook immediately and queue the work for background execution.
Code
Handle duplicates (idempotency)
You may receive the same webhook event multiple times. Use the payment_request_id and status to deduplicate.
Implement retry logic awareness
If your endpoint does not respond with HTTP 200, Fluxis may retry the webhook. Ensure your handler is idempotent.
Testing webhooks
- Expose your local server with ngrok or similar during development.
- Register the public URL via
POST /v1/account/{accountID}/webhook. - Trigger a test delivery:
POST /v1/account/{accountID}/webhook/{webhookID}/test— uses the same signing path as production. - Confirm your handler verifies the signature and returns HTTP
200.
See Webhook Signature Verification for step-by-step verification and common failure modes.
Troubleshooting
| Issue | What to check |
|---|---|
| Signature fails | Correct secret from create response; sign parsed body {data:…}; canonical JSON rules — full guide |
| Not receiving events | Public HTTPS URL; HTTP 200 within 2s; webhook enabled; correct event_type |
Missing expired / failed webhooks | Expected — poll GET /v1/pos/{posID}/payment-request/{paymentRequestID} |
Need help?
Contact [email protected] with your account ID, webhook ID, and timestamp of the problematic delivery.