Webhooks
Testing, signature verification, and delivery semantics for Steve webhooks.
Steve has two webhook-related behaviors:
- A live webhook connectivity test endpoint:
POST /api/v1/webhooks/test - Production session-result delivery from
convex/webhooks.ts
Connectivity test
The test endpoint validates your URL and performs a direct POST with:
Test-delivery characteristics
- Timeout: 5 seconds
- Method:
POST - Content type:
application/json - User-Agent:
steve-webhook/1.0 - Signature header: not included on test requests
If the remote endpoint returns a non-2xx status, Steve reports success: false and includes the remote statusCode.
Production delivery contract
The backend defines the following session-result delivery contract for apiSessions with a stored webhookUrl:
Important current behavior
- The live payload does not include a
typefield. resultis whatever was cached on the session record.webhookDeliveryStatusis tracked internally aspending,delivered, orfailed.- The public webhook test endpoint is live today; full result delivery becomes relevant once session-producing ingestion routes are published.
Signature verification
Production webhook requests include:
The implementation signs the raw JSON payload with HMAC-SHA256 using this secret:
That means consumers must derive the hex string first, then use that string as the HMAC key.
Node.js verification
Python verification
Retry behavior
Steve gives each production delivery attempt 10 seconds to complete. If the target does not return a 2xx response in time:
- the initial attempt fails immediately
- retry 1 is scheduled 30 seconds later
- retry 2 is scheduled 5 minutes later
- after the third failed attempt total, delivery status becomes
failed
Your endpoint should therefore be idempotent. A practical idempotency key is:
Treat processedAt as delivery metadata rather than a deduplication key, because it is regenerated for each delivery attempt.
URL validation rules
Webhook URLs must:
- be valid absolute URLs
- use
https:// - not target
localhost - not target
127.0.0.1 - not target RFC1918
10.x,192.168.x, or172.16.xthrough172.31.x - not end in
.internal - not end in
.local