user
Delivers matching events for the associated user context. Use it for a direct account or one intentionally scoped consumer.
Webhooks notify your backend when accounting balances change. The configuration contract comes from the public API specification; the delivery body and signature below come directly from the proxybuild/accountant sender.
curl 'https://api.proxyrequest.com/api/v1/webhooks' \ --request POST \ --header 'Authorization: Static YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --data '{ "type": "reseller", "endpoint": "https://integrator.example/webhooks/proxy-usage", "read_timeout": 5, "write_timeout": 5, "retries": 3, "retry_timeout": 10 }'| Field | Allowed by the public schema | Default |
|---|---|---|
type | user, reseller, or system | Required |
endpoint | Public URI, maximum 500 characters | Required |
read_timeout | 1–60 seconds | 5 |
write_timeout | 1–60 seconds | 5 |
retries | 0–10 | 3 |
retry_timeout | 1–300 seconds | 10 |
The create response includes a signing secret. Store it immediately in a secret manager. List and retrieve responses use a schema without the secret, so your integration must not depend on reading it later.
user
Delivers matching events for the associated user context. Use it for a direct account or one intentionally scoped consumer.
reseller
Accepts events for the reseller account and child users whose
user.reseller_id matches that account.
system
Reserved for platform-wide context when that scope is provisioned and authorized by the deployment.
The accountant sends:
POST /webhooks/proxy-usage HTTP/1.1Content-Type: application/jsonX-Signature: BASE64_HMAC_SHA256{
"events": [
{
"event": "user.data.change",
"date": "2026-08-01T10:15:00Z",
"user": {
"id": "user_42",
"username": "acme-customer",
"reseller_id": "reseller_01"
},
"package": {
"id": "package_9",
"alias": "residential"
},
"order": {
"id": "order_71",
"data": 5368709120,
"data_remaining": 2147483648,
"ledger_id": "ledger_12"
}
}
],
"date": "2026-08-01T10:15:01Z"
}null for root and unlimited orders.The delivery body is a batch envelope: events contains one or more event objects and the outer date records when the batch was created. Inside each event, fields are grouped by responsibility:
user contains id, username, and reseller_id;package contains id and alias;order contains id, the shared-ledger data, the child-order data_remaining, and ledger_id.order.data_remaining is always serialized. It is an integer for a finite child order and JSON null for a root or unlimited order.
The signature formula is:
Base64(HMAC-SHA256(webhook_secret, raw_request_body))Verify the exact bytes received from the network. Parsing JSON and serializing it again can change whitespace, key order, or escaping and will invalidate the signature.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWebhook(rawBody, signature, secret) { if (!signature) return false;
const expected = createHmac('sha256', secret).update(rawBody).digest(); const received = Buffer.from(signature, 'base64');
return ( received.length === expected.length && timingSafeEqual(received, expected) );}import base64import hashlibimport hmac
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool: expected = base64.b64encode( hmac.new(secret.encode(), raw_body, hashlib.sha256).digest() ).decode() return hmac.compare_digest(expected, signature)func verifyWebhook(body []byte, signature string, secret []byte) bool { received, err := base64.StdEncoding.DecodeString(signature) if err != nil { return false }
mac := hmac.New(sha256.New, secret) _, _ = mac.Write(body) return hmac.Equal(received, mac.Sum(nil))}X-Signature and reject a missing or invalid value.events[], user, package, and order before reading their fields.2xx response quickly.The current sender treats any response below 400 as delivered, but your endpoint should return a direct 2xx and avoid redirects. Network errors, timeouts, and 4xx/5xx responses consume the configured attempt budget.
Build a bounded deduplication fingerprint from stable fields such as event, user.id, order.id, package.id, the event date, order.data, and order.data_remaining. Keep the raw verified delivery for investigation, and design updates so reprocessing the same balance does not double-charge a customer.
Webhooks are the reaction channel, not a complete invoice ledger. Query analytics for closed reporting windows and compare totals with your local projection. See analytics and reconciliation and the complete webhook event reference.