Webhooks API
Receive real-time notifications when events occur across MeshOS, Axis, and Smart Contracts. All three platforms use the same webhook infrastructure.
Creating a Subscription
1POST /v1/webhooks/subscriptions
2{
3 "name": "My CI/CD Integration",
4 "url": "https://your-app.com/webhooks/meshos",
5 "events": [
6 "review.completed",
7 "approval.granted"
8 ],
9 "platform": "meshos",
10 "secret": "whsec_your_secret_string"
11}Response:
1{
2 "subscription_id": "sub_01HXYZ",
3 "name": "My CI/CD Integration",
4 "url": "https://your-app.com/webhooks/meshos",
5 "events": ["review.completed", "approval.granted"],
6 "status": "active",
7 "created_at": "2024-01-15T10:30:00Z"
8}Webhook Payload Structure
All webhook deliveries use the same envelope format:
1{
2 "id": "evt_01HXYZ",
3 "subscription_id": "sub_01HXYZ",
4 "event": "review.completed",
5 "timestamp": "2024-01-15T10:40:15Z",
6 "platform": "meshos",
7 "data": {
8 // Event-specific payload
9 }
10}Signature Verification
Every delivery is signed with HMAC-SHA256 using your webhook secret:
Header: X-Signature: sha256={signature}
Verify in Node.js:
1import crypto from 'crypto';
2
3function verifyWebhookSignature(
4 rawBody: string,
5 signature: string,
6 secret: string
7): boolean {
8 const expected = `sha256=${crypto
9 .createHmac('sha256', secret)
10 .update(rawBody, 'utf8')
11 .digest('hex')}`;
12
13 return crypto.timingSafeEqual(
14 Buffer.from(signature),
15 Buffer.from(expected)
16 );
17}
18
19app.post('/webhooks/meshos', (req, res) => {
20 const signature = req.headers['x-signature'] as string;
21 const rawBody = req.rawBody; // Use raw body, not parsed JSON
22
23 if (!verifyWebhookSignature(rawBody, signature, process.env.WEBHOOK_SECRET)) {
24 return res.status(401).json({ error: 'Invalid signature' });
25 }
26
27 // Process event
28 const event = JSON.parse(rawBody);
29 handleEvent(event);
30
31 res.status(200).json({ received: true });
32});Always use timingSafeEqual. Regular string comparison is vulnerable to timing attacks.
Delivery and Retry
Delivery Policy
- First delivery attempt within 5 seconds of event
- Delivery considered successful: 2xx response within 10 seconds
- Delivery considered failed: non-2xx response, timeout, or connection error
Retry Schedule
| Attempt | Delay After Previous | |---------|---------------------| | 1st | Immediate | | 2nd | 1 minute | | 3rd | 5 minutes | | 4th | 30 minutes | | 5th | 2 hours |
After 5 failed attempts, event moves to dead-letter queue.
Dead-Letter Queue
1GET /v1/webhooks/dead-letterReplay failed events:
1POST /v1/webhooks/dead-letter/{eventId}/replayMeshOS Events
| Event | Trigger |
|-------|---------|
| application.uploaded | ZIP upload received |
| analysis.started | Code analysis began |
| analysis.completed | Static analysis finished |
| review.started | AI review started |
| review.completed | All agents finished |
| approval.granted | Application approved |
| approval.rejected | Application rejected |
| component.promoted | Component promoted to registry |
| component.deprecated | Component deprecated |
review.completed payload:
1{
2 "review_id": "rev_01HXYZ",
3 "application_id": "app_01HXYZ",
4 "status": "completed",
5 "scores": {
6 "cloud_readiness": 74,
7 "library_readiness": 82,
8 "mesh_readiness": 61
9 },
10 "findings": {
11 "critical": 0,
12 "high": 3,
13 "medium": 12,
14 "low": 32
15 },
16 "patches_generated": 8,
17 "duration_seconds": 285
18}Axis Events
| Event | Trigger |
|-------|---------|
| campaign.created | New campaign created |
| campaign.launched | Campaign execution started |
| campaign.paused | Campaign paused |
| campaign.completed | All sequences finished |
| lead.imported | Import job completed |
| lead.enriched | Lead enrichment finished |
| communication.sent | Message delivered |
| communication.opened | Email opened |
| communication.replied | Reply received |
| meeting.booked | Meeting scheduled |
| slo.violated | SLO threshold breached |
| budget.threshold_reached | Spend alert triggered |
meeting.booked payload:
1{
2 "lead_id": "lead_01HXYZ",
3 "campaign_id": "camp_01HXYZ",
4 "meeting_time": "2024-01-22T14:00:00Z",
5 "duration_minutes": 30,
6 "sales_rep": "user_01HXYZ",
7 "attribution": {
8 "first_touch": "email_1",
9 "last_touch": "linkedin_dm_3",
10 "touchpoints": 5
11 }
12}Smart Contracts Events
| Event | Trigger |
|-------|---------|
| contract.created | Contract registered |
| contract.deployed | Deployment confirmed |
| contract.deployment_failed | Deployment failed |
| execution.confirmed | Function execution confirmed |
| execution.failed | Transaction reverted |
| alert.triggered | Monitoring alert fired |
| backup.completed | Backup finished |
| backup.failed | Backup failed |
| scaling.event | Node scaled up or down |
execution.failed payload:
1{
2 "execution_id": "exec_01HXYZ",
3 "contract_id": "contract_01HXYZ",
4 "network": "ethereum_mainnet",
5 "function": "transfer",
6 "transaction_hash": "[HASH]",
7 "error": {
8 "type": "revert",
9 "reason": "ERC20: transfer amount exceeds balance",
10 "gas_used": 28000
11 }
12}Managing Subscriptions
List Subscriptions
1GET /v1/webhooks/subscriptionsUpdate Subscription
1PUT /v1/webhooks/subscriptions/{subId}
2{
3 "events": ["review.completed", "approval.granted", "approval.rejected"],
4 "url": "https://your-app.com/webhooks/new-endpoint"
5}Pause/Resume
1POST /v1/webhooks/subscriptions/{subId}/pause
2POST /v1/webhooks/subscriptions/{subId}/resumeDelete Subscription
1DELETE /v1/webhooks/subscriptions/{subId}Delivery Logs
1GET /v1/webhooks/subscriptions/{subId}/deliveries?limit=501{
2 "deliveries": [
3 {
4 "delivery_id": "del_01HXYZ",
5 "event": "review.completed",
6 "status": "success",
7 "response_code": 200,
8 "response_time_ms": 145,
9 "delivered_at": "2024-01-15T10:40:15Z",
10 "attempt": 1
11 },
12 {
13 "delivery_id": "del_01HXYA",
14 "event": "review.completed",
15 "status": "failed",
16 "response_code": 503,
17 "response_time_ms": 10000,
18 "last_attempt_at": "2024-01-15T12:40:15Z",
19 "attempt": 3,
20 "next_retry_at": "2024-01-15T14:40:15Z"
21 }
22 ]
23}Testing Webhooks
Send a test event to verify your endpoint:
1POST /v1/webhooks/subscriptions/{subId}/test
2{
3 "event": "review.completed"
4}Sends a realistic sample payload with "test": true in the envelope. Your endpoint should return 200. Useful for verifying signature verification code.