Documentation Index Fetch the complete documentation index at: https://guide.withvayu.com/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks let Vayu push notifications to your server when billing events occur. You subscribe per event type with a callback URL, and Vayu sends a signed POST request whenever that event fires.
Subscribing
Endpoint: POST /webhook
{
"callbackUrl" : "https://your-server.com/webhooks/vayu" ,
"eventType" : "Overage"
}
curl -X POST "https://connect.withvayu.com/webhook" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN " \
-H "x-api-key: $VAYU_CLIENT_ID " \
-d '{
"callbackUrl": "https://your-server.com/webhooks/vayu",
"eventType": "Overage"
}'
Available event types
Event type Description OverageCustomer exceeds their provisioned amount for a product AnonymousCustomerEvent received for an unrecognized customer alias — auto-created as anonymous UpcomingRenewalCustomer contract is approaching its renewal date InvoiceApprovedAn invoice has been approved and is ready to send UnchargedEventsEvents exist that have not been counted against any meter TierCrossedCustomer usage has crossed into a new pricing tier CommitmentCrossedCustomer has crossed their committed usage threshold FinalTierExceededCustomer usage has exceeded the final pricing tier InvoicePaymentStatusChangedAn invoice payment status has changed (e.g. paid, failed, overdue)
Webhook payloads
Overage
{
"type" : "Overage" ,
"productId" : "prod_123456789" ,
"productName" : "API Calls" ,
"provisionedAmount" : 1000 ,
"consumedAmount" : 1200 ,
"usagePercentage" : 120 ,
"hasAccess" : false ,
"remainingAmount" : 0 ,
"exceededAmount" : 200
}
AnonymousCustomer
{
"type" : "AnonymousCustomer" ,
"id" : "cust_123456789" ,
"externalId" : "ext_987654321" ,
"aliases" : [ "ext_987654321" ],
"name" : "Anonymous Customer"
}
UpcomingRenewal
{
"type" : "UpcomingRenewal" ,
"customerId" : "cust_123456789" ,
"customerName" : "Acme Corp" ,
"contractId" : "contract_abc123" ,
"renewalDate" : "2026-02-01T00:00:00Z"
}
InvoiceApproved
{
"type" : "InvoiceApproved" ,
"invoiceId" : "inv_123456789" ,
"customerId" : "cust_123456789" ,
"customerName" : "Acme Corp" ,
"amount" : 1500.00 ,
"currency" : "USD" ,
"dueDate" : "2026-02-15T00:00:00Z"
}
InvoicePaymentStatusChanged
{
"type" : "InvoicePaymentStatusChanged" ,
"invoiceId" : "inv_123456789" ,
"customerId" : "cust_123456789" ,
"previousStatus" : "PENDING" ,
"currentStatus" : "PAID" ,
"amount" : 1500.00 ,
"currency" : "USD"
}
TierCrossed
{
"type" : "TierCrossed" ,
"customerId" : "cust_123456789" ,
"productId" : "prod_123456789" ,
"productName" : "API Calls" ,
"previousTier" : 1 ,
"currentTier" : 2 ,
"currentUsage" : 10001 ,
"tierThreshold" : 10000
}
CommitmentCrossed
{
"type" : "CommitmentCrossed" ,
"customerId" : "cust_123456789" ,
"contractId" : "contract_abc123" ,
"committedAmount" : 50000 ,
"currentUsage" : 50001
}
FinalTierExceeded
{
"type" : "FinalTierExceeded" ,
"customerId" : "cust_123456789" ,
"productId" : "prod_123456789" ,
"productName" : "API Calls" ,
"finalTierThreshold" : 100000 ,
"currentUsage" : 100500
}
UnchargedEvents
{
"type" : "UnchargedEvents" ,
"customerId" : "cust_123456789" ,
"eventCount" : 42 ,
"earliestEventTimestamp" : "2026-01-10T08:00:00Z"
}
Handling webhook events
A minimal server that receives Vayu webhooks, routes by event type, and reads the payload:
TypeScript (Express)
Python (Flask)
Go (net/http)
import express from 'express' ;
import { Vayu } from 'vayu-ts' ;
const vayu = new Vayu ( process . env . VAYU_API_KEY );
const app = express ();
app . use ( express . json ());
// Register the webhook (run once)
// await vayu.webhooks.subscribe({
// callbackUrl: 'https://your-server.com/webhooks/vayu',
// eventType: 'Overage',
// });
app . post ( '/webhooks/vayu' , ( req , res ) => {
const event = req . body ;
switch ( event . type ) {
case 'Overage' :
console . log (
` ${ event . productName } : ${ event . consumedAmount } / ${ event . provisionedAmount } used ` +
`( ${ event . exceededAmount } over limit)`
);
break ;
case 'InvoiceApproved' :
console . log ( `Invoice ${ event . invoiceId } for ${ event . customerName } : $ ${ event . amount } ${ event . currency } ` );
break ;
case 'TierCrossed' :
console . log ( ` ${ event . productName } : customer moved from tier ${ event . previousTier } → ${ event . currentTier } ` );
break ;
case 'AnonymousCustomer' :
console . log ( `New anonymous customer created: ${ event . externalId } ` );
break ;
default :
console . log ( `Unhandled event: ${ event . type } ` );
}
res . sendStatus ( 200 );
});
app . listen ( 3000 , () => console . log ( 'Listening on :3000' ));
Webhook security
All Vayu webhook requests include headers for signature verification:
Header Description X-TimestampUnix timestamp (seconds) of when the request was sent X-SignatureBase64-encoded RSA-SHA256 signature of timestamp.JSON(payload) X-Signature-VersionSignature scheme version (currently v1)
The signed message is: ${timestamp}.${JSON.stringify(payload)}
Only HTTPS callback URLs are supported.
Verifying signatures
The TypeScript SDK provides a built-in helper. Built-in verification for the Python and Go SDKs is coming soon — in the meantime, verify manually using Vayu’s public key.
TypeScript (SDK)
Python (manual)
Go (manual)
import { Vayu } from 'vayu-ts' ;
const vayu = new Vayu ( process . env . VAYU_API_KEY );
app . post ( '/webhooks' , async ( req , res ) => {
const payload = JSON . stringify ( req . body );
const timestamp = Number ( req . headers [ 'x-timestamp' ]);
const signature = String ( req . headers [ 'x-signature' ]);
const isValid = vayu . webhooks . verifyWebhookSignature ({
payload ,
timestamp ,
signature ,
tolerance: 300 , // optional — reject if older than 5 minutes (default)
});
if ( ! isValid ) {
return res . sendStatus ( 401 );
}
const event = req . body ;
console . log ( 'Received webhook:' , event . type );
res . sendStatus ( 200 );
});