Webhook Events
Planned publisher-facing webhook events for real-time commission and invoice notifications.
How commissions are created today
When a customer completes a purchase on a storefront with Drapier app installed, the order is automatically checked for click attribution. If a valid click ID is found, commissions are created in real time for the attributed publisher. Cancelled orders automatically reverse any associated commissions.
You don't need to do anything to trigger this — it happens automatically on the storefront side.
Publisher-facing webhooks (planned)
Publisher webhooks are planned but not yet implemented. The events and payload formats below represent the target design. Until launch, use the Commissions API and Click Statistics API to poll for updates.
Planned events
| Event | Trigger |
|---|---|
commission.created | A new commission is created from a tracked sale |
commission.status_changed | A commission transitions between lifecycle states |
commission.reversed | A commission is reversed (refund, cancellation, or fraud) |
invoice.generated | Your monthly invoice is created and ready for review |
invoice.paid | Payment for an invoice has been processed |
Planned payload format
Every webhook POST will carry a JSON body with a consistent envelope:
{
"event": "commission.created",
"timestamp": "2026-03-15T10:30:00Z",
"data": {
"id": "comm_abc123",
"orderId": "ORD-1234",
"orderName": "#1234",
"productTitle": "Gucci Marmont Bag",
"salePrice": 1200.00,
"commissionAmount": 240.00,
"status": "PENDING",
"currency": "USD"
}
}commission.status_changed
{
"event": "commission.status_changed",
"timestamp": "2026-03-16T08:00:00Z",
"data": {
"id": "comm_abc123",
"orderId": "ORD-1234",
"previousStatus": "PENDING",
"newStatus": "APPROVED",
"commissionAmount": 240.00,
"currency": "USD"
}
}commission.reversed
{
"event": "commission.reversed",
"timestamp": "2026-03-18T14:22:00Z",
"data": {
"id": "comm_abc123",
"orderId": "ORD-1234",
"reason": "order_refunded",
"commissionAmount": 240.00,
"currency": "USD"
}
}invoice.generated
{
"event": "invoice.generated",
"timestamp": "2026-04-01T00:05:00Z",
"data": {
"id": "inv_2026_03",
"period": "2026-03",
"totalAmount": 3420.00,
"commissionCount": 47,
"currency": "USD",
"dueDate": "2026-04-15"
}
}invoice.paid
{
"event": "invoice.paid",
"timestamp": "2026-04-15T09:00:00Z",
"data": {
"id": "inv_2026_03",
"totalAmount": 3420.00,
"currency": "USD",
"paidAt": "2026-04-15T09:00:00Z",
"paymentMethod": "bank_transfer"
}
}Planned: verifying webhook signatures
When publisher webhooks launch, every webhook will include an X-IN-Signature header containing an HMAC-SHA256 signature of the raw request body, signed with your webhook secret.
Node.js
import crypto from "node:crypto";
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Python
import hashlib
import hmac
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Planned: retry policy
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
After 3 failed retries the delivery will be marked as failed and visible in the dashboard.
Best practices
- Respond with
200immediately when publisher webhooks launch. Perform heavy processing asynchronously. - Handle duplicate deliveries. Use the
data.idfield as an idempotency key. - Log raw payloads. Store the raw JSON body before processing so you can replay events if your handler has a bug.
- Use HTTPS. Webhook URLs must use TLS.