Webhooks
FluxiQ delivers real-time event notifications to your application via webhooks.
Overview
| Endpoint | Method | Description |
|---|---|---|
/api/v1/webhooks | POST | Register a webhook endpoint |
/api/v1/webhooks | GET | List webhook endpoints |
/api/v1/webhooks/:id | GET | Get webhook details |
/api/v1/webhooks/:id | DELETE | Delete a webhook |
/api/v1/webhooks/:id/test | POST | Send a test event |
Register a Webhook
http
POST /api/v1/webhooks
Authorization: Bearer {token}
Content-Type: application/json
{
"url": "https://your-app.com/webhooks/fluxiq",
"events": ["pix.charge.paid", "pix.payout.confirmed", "pix.payout.failed"],
"secret": "whsec_your_webhook_secret_key"
}Response:
json
{
"data": {
"id": "whk_01HQGX...",
"url": "https://your-app.com/webhooks/fluxiq",
"events": ["pix.charge.paid", "pix.payout.confirmed", "pix.payout.failed"],
"status": "active",
"created_at": "2026-02-03T12:00:00Z"
}
}Event Types
PIX Events
| Event | Description |
|---|---|
pix.charge.created | A new charge was created |
pix.charge.paid | A charge was paid |
pix.charge.expired | A charge expired without payment |
pix.charge.cancelled | A charge was cancelled |
pix.payout.processing | A payout is being processed |
pix.payout.confirmed | A payout was confirmed |
pix.payout.failed | A payout failed |
pix.payout.returned | A payout was returned |
pix.refund.requested | A refund was requested |
pix.refund.completed | A refund was completed |
Account Events
| Event | Description |
|---|---|
account.created | A new account was created |
account.updated | Account details were updated |
account.blocked | An account was blocked |
transfer.completed | An internal transfer completed |
transfer.failed | An internal transfer failed |
Webhook Payload
All webhook deliveries follow this format:
json
{
"id": "evt_01HQGX...",
"type": "pix.charge.paid",
"created_at": "2026-02-03T12:01:30Z",
"data": {
"id": "chg_01HQGX...",
"status": "paid",
"amount": 15000,
"paid_amount": 15000,
"end_to_end_id": "E1234567820260203120000000001",
"payer": {
"name": "Maria Silva",
"document": "***456789**"
},
"paid_at": "2026-02-03T12:01:30Z"
}
}Signature Verification
Every webhook delivery includes a signature header:
http
X-FluxiQ-Signature: sha256=a1b2c3d4e5f6...
X-FluxiQ-Timestamp: 1706961600
X-FluxiQ-Event-Id: evt_01HQGX...Verification Examples
JavaScript:
javascript
const crypto = require('crypto');
function verifyWebhook(payload, signature, timestamp, secret) {
const signedContent = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedContent)
.digest('hex');
return `sha256=${expected}` === signature;
}Elixir:
elixir
def verify_webhook(payload, signature, timestamp, secret) do
signed_content = "#{timestamp}.#{payload}"
expected = :crypto.mac(:hmac, :sha256, secret, signed_content)
|> Base.encode16(case: :lower)
"sha256=#{expected}" == signature
endWARNING
Always verify webhook signatures before processing events. Reject any delivery with an invalid signature.
Retry Policy
Failed webhook deliveries are retried with exponential backoff:
| Attempt | Delay | Total Elapsed |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | 30 seconds | 30s |
| 3 | 2 minutes | 2.5 min |
| 4 | 10 minutes | 12.5 min |
| 5 | 30 minutes | 42.5 min |
| 6 | 1 hour | 1h 42min |
| 7 | 2 hours | 3h 42min |
| 8 | 4 hours | 7h 42min |
After 8 failed attempts, the event is marked as failed and no further retries are made.
Best Practices
- Respond quickly — Return a 200 status within 5 seconds. Process the event asynchronously.
- Handle duplicates — Use
X-FluxiQ-Event-Idto deduplicate. - Verify signatures — Always validate the
X-FluxiQ-Signatureheader. - Use HTTPS — Webhook URLs must use HTTPS in production.
- Monitor failures — Set up alerts for webhook delivery failures.