Webhooks
Webhooks let you receive real-time notifications when events occur on your account. Instead of polling the API, configure a URL and Advance will POST a notification to it the moment something changes.
Configuring Webhooks in the Portal
You can create and manage webhooks without writing any code.
Navigate to: Settings → Webhooks
- Click Add Webhook
- Enter a Name, your HTTPS URL, and select the Event Types you want to receive
- Optionally add a Secret — Advance uses it to sign every delivery so your endpoint can verify the request is genuine (strongly recommended)
- Click Save
To pause delivery without deleting a webhook, set its status to inactive. To reactivate a suspended webhook after fixing delivery failures, set the status back to active.
Supported Events
Payment Events
| Event | When it fires |
|---|---|
PAYMENT_CREATED | A new payment is created |
PAYMENT_UPDATED | A payment's status changes |
PAYMENT_REQUEST_CREATED | A new payment request is initiated |
CHECK_DEPOSIT_CREATED | A check deposit is processed |
User Events
| Event | When it fires |
|---|---|
USER_INVITED | A new user is invited to the platform |
USER_INVITE_RESENT | A user invitation is resent |
USER_DELETED | A user account is removed |
USER_ROLE_UPDATED | A user's role or permissions change |
API Key Events
| Event | When it fires |
|---|---|
API_KEY_CREATE | A new API key is generated |
API_KEY_UPDATE | An API key's metadata is updated |
API_KEY_REVOKE | An API key is revoked |
API_KEY_DELETE | An API key is permanently deleted |
Fetch the current list of supported event types programmatically:
curl -X GET "https://api.advancehq.com/v1/webhooks/event-types" \
-H "Authorization: Bearer your_api_key"Managing Webhooks via API
The full request/response schemas are in the API reference. Key things to know:
POST /v1/webhooks— create a webhook;urlmust be HTTPS,event_typesis required and non-emptyGET /v1/webhooks— list all webhooks; filter by?status=active|inactive|suspendedGET /v1/webhooks/{webhook_id}— get a single webhook including delivery countersPUT /v1/webhooks/{webhook_id}— update any fields; all are optional;event_typesreplaces the full list; setstatus: activeto reactivate a suspended webhookDELETE /v1/webhooks/{webhook_id}— permanently delete; pending retries are abandoned
Webhook Payload
Advance uses a notification pattern — the payload is intentionally minimal. It tells you what happened and to which entity; your system fetches full details from the relevant REST endpoint.
{
"event_id": "evt_abc123xyz",
"event_type": "PAYMENT_CREATED",
"entity_id": "pay_456",
"timestamp": "2025-01-15T10:30:00Z",
"webhook_id": "wh_abc123xyz"
}| Field | Description |
|---|---|
event_id | Unique delivery ID — use for idempotency |
event_type | The type of event |
entity_id | ID of the affected entity — fetch this for full details |
timestamp | When the event occurred (ISO 8601, UTC) |
webhook_id | ID of the webhook configuration that sent this notification |
Fetching the full entity after receiving a notification:
| Event | Endpoint |
|---|---|
PAYMENT_CREATED / PAYMENT_UPDATED | GET /v1/payments/{entity_id} |
PAYMENT_REQUEST_CREATED | GET /v1/payment-requests/{entity_id} |
CHECK_DEPOSIT_CREATED | GET /v1/check-deposits/{entity_id} |
USER_INVITED / USER_DELETED / USER_ROLE_UPDATED | GET /v1/users/{entity_id} |
API_KEY_CREATE / API_KEY_UPDATE / API_KEY_REVOKE / API_KEY_DELETE | GET /v1/api-keys/{entity_id} |
HTTP headers sent with each delivery:
Content-Type: application/json
X-Webhook-Signature: sha256=abc123... (only when a secret is configured)
User-Agent: Advance-Webhook/1.0
Signature Verification
When you configure a secret, every delivery includes an HMAC-SHA256 signature in the X-Webhook-Signature header. Always verify this before processing the event.
How it works:
- Advance serializes the JSON payload with keys sorted alphabetically and no extra whitespace
- It computes HMAC-SHA256 over those bytes using your secret
- The result is sent as
sha256=<hex>in theX-Webhook-Signatureheader - Your endpoint performs the same computation and rejects requests where the signatures don't match
Important: Verify against the raw request body bytes received, not a re-serialized version of the parsed JSON. This ensures the computation matches exactly.
Example (Python):
import hmac
import hashlib
def verify_webhook_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
if not signature_header or not signature_header.startswith("sha256="):
return False
expected = signature_header[7:]
computed = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(computed, expected)
@app.post("/webhooks/advance")
async def handle_webhook(request: Request):
raw_body = await request.body()
sig = request.headers.get("X-Webhook-Signature", "")
if not verify_webhook_signature(raw_body, sig, WEBHOOK_SECRET):
raise HTTPException(status_code=401, detail="Invalid signature")
payload = json.loads(raw_body)
# handle event...Example (Node.js):
const crypto = require("crypto");
function verifySignature(rawBody, signatureHeader, secret) {
if (!signatureHeader?.startsWith("sha256=")) return false;
const expected = signatureHeader.slice(7);
const computed = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(expected));
}
app.post("/webhooks/advance", express.raw({ type: "application/json" }), (req, res) => {
if (!verifySignature(req.body, req.headers["x-webhook-signature"], WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
const payload = JSON.parse(req.body);
// handle event...
res.status(200).send("OK");
});Retry Policy
If your endpoint returns a non-2xx status or does not respond within 10 seconds, Advance retries automatically with exponential backoff:
| Attempt | Delay |
|---|---|
| Retry 1 | 1 min |
| Retry 2 | 2 min |
| Retry 3 | 4 min |
| Retry 4 | 8 min |
| Retry 5 | 16 min |
After 5 failed attempts the delivery is marked exhausted and no further retries are made for that event.
Automatic Suspension
A webhook is automatically suspended after 10 consecutive delivery failures. Once suspended, no new events are delivered until you reactivate it via PUT /v1/webhooks/{webhook_id} with { "status": "active" }.
The consecutive-failure counter resets to zero when a delivery succeeds.
Event Ordering
Advance does not guarantee delivery order. Retried deliveries may arrive out of sequence relative to newer events for the same entity. Design your handler to be order-independent: use the entity_id to fetch current state from the REST API rather than relying on the sequence of notifications.
Best Practices
Respond quickly. Your endpoint must reply within 10 seconds. Acknowledge the webhook immediately and process asynchronously in a background job.
Handle duplicates. Events may be delivered more than once on retry. Use event_id to deduplicate — store processed IDs and skip any already handled.
Always fetch fresh data. After receiving a notification, use entity_id to fetch the current entity state from the REST API. Don't rely solely on the order or content of webhook payloads.
Verify the signature. Always validate X-Webhook-Signature before processing. Reject requests that fail verification.
Updated 5 days ago
