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-letter

Replay failed events:

1POST /v1/webhooks/dead-letter/{eventId}/replay

MeshOS 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/subscriptions

Update 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}/resume

Delete Subscription

1DELETE /v1/webhooks/subscriptions/{subId}

Delivery Logs

1GET /v1/webhooks/subscriptions/{subId}/deliveries?limit=50
1{
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.