Receive real-time notifications when events occur in your NAWA account. Webhooks use HMAC-SHA256 signatures for security.
Event types
Event Description Trigger classification.completedA classification request succeeded After /v1/classify completes classification.failedA classification request failed On provider or internal errors comment.newA new comment was ingested When a connected platform receives a comment comment.repliedA reply was posted After /v1/comments/:id/reply succeeds credits.lowCredit balance below threshold Balance drops below $5 credits.exhaustedCredit balance is $0 Balance reaches $0
Webhook payload
{
"id" : "evt_abc123" ,
"type" : "classification.completed" ,
"created_at" : "2025-01-15T12:00:00Z" ,
"data" : {
"request_id" : "req_def456" ,
"text" : "متى الجزء الثاني؟" ,
"intent" : "question" ,
"sentiment" : "neutral" ,
"dialect" : "gulf"
}
}
Webhook signing secret
Your webhook signing secret starts with nawa_wh_ and is generated when you register a webhook endpoint. Store it securely - it’s shown only once.
Signature verification
Every webhook request includes an X-NAWA-Signature header containing the HMAC-SHA256 signature of the request body.
TypeScript (Express)
Python (FastAPI)
import crypto from 'crypto'
import express from 'express'
const app = express ()
app . post ( '/webhooks/nawa' , express . raw ({ type: 'application/json' }), ( req , res ) => {
const signature = req . headers [ 'x-nawa-signature' ] as string
const timestamp = req . headers [ 'x-nawa-timestamp' ] as string
const body = req . body
// Verify timestamp is within 5 minutes
const now = Math . floor ( Date . now () / 1000 )
if ( Math . abs ( now - parseInt ( timestamp )) > 300 ) {
return res . status ( 400 ). send ( 'Timestamp too old' )
}
// Compute expected signature
const payload = ` ${ timestamp } . ${ body } `
const expected = crypto
. createHmac ( 'sha256' , process . env . NAWA_WEBHOOK_SECRET ! )
. update ( payload )
. digest ( 'hex' )
if ( ! crypto . timingSafeEqual ( Buffer . from ( signature ), Buffer . from ( expected ))) {
return res . status ( 400 ). send ( 'Invalid signature' )
}
const event = JSON . parse ( body )
console . log ( 'Received event:' , event . type )
// Handle the event
switch ( event . type ) {
case 'classification.completed' :
// Process classification result
break
case 'credits.low' :
// Alert team about low balance
break
}
res . status ( 200 ). send ( 'OK' )
})
Always verify webhook signatures before processing events. Never trust the payload without signature validation.
Retry policy
If your endpoint returns a non-2xx status code, NAWA retries with exponential backoff:
Attempt Delay 1st retry 1 minute 2nd retry 5 minutes 3rd retry 30 minutes 4th retry 2 hours 5th retry 8 hours Continues… Up to 3 days
After 10 consecutive failures , the webhook endpoint is automatically disabled and you’ll receive an email notification. Re-enable it from the dashboard after fixing the issue.
Testing webhooks
A dedicated webhook test-fire endpoint is planned. In the meantime, you can test your webhook handler by sending a POST request directly to your own endpoint with a sample payload matching the format above.