Webhooks

Webhooks

ApexMCP can notify your services in real time when tool calls are executed. Register webhook URLs in the Developer Portal → Webhooks section.

Registering a Webhook

  1. Go to Developer Portal → Webhooks → New Webhook
  2. Enter your endpoint URL (must be HTTPS)
  3. Select events to subscribe to
  4. Copy the signing secret — used to verify payloads
  5. Click Save

ApexMCP will immediately send a test ping to verify the endpoint is reachable.

Events

EventDescription
tool.calledFired after every successful tools/call execution

More events (connector health, quota warnings) are on the roadmap.

Payload Format

All webhook payloads are POST requests with Content-Type: application/json.

tool.called example

{
  "event": "tool.called",
  "id": "evt_01j9x8k2m3n4p5q6r7s8t9u0v1",
  "timestamp": "2024-11-15T14:32:01.482Z",
  "org_slug": "acme-corp",
  "data": {
    "tool_name": "query_postgres_orders",
    "connector_id": "conn_01j9x8k2m3n4p5q6r7s8t9u0v1",
    "connector_type": "postgresql",
    "agent_id": "agent_01abc",
    "duration_ms": 143,
    "success": true,
    "error_code": null
  }
}

Fields:

FieldTypeDescription
eventstringEvent type
idstringUnique event ID (idempotency key)
timestampISO 8601When the event occurred (UTC)
org_slugstringOrganisation that triggered the event
data.tool_namestringName of the tool that was called
data.connector_idstringID of the connector
data.connector_typestringType of connector (e.g. postgresql)
data.agent_idstringAgent identity if registered, else null
data.duration_msintegerTool execution time in milliseconds
data.successbooleanWhether the call succeeded
data.error_codeinteger or nullJSON-RPC error code if failed

Signature Verification

Every request includes an X-Webhook-Signature header. The signature is an HMAC-SHA256 hex digest of the raw request body, using your signing secret as the key.

Verify in Node.js:

import crypto from 'crypto';
 
function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}
 
// Express example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-webhook-signature'];
  if (!verifyWebhook(req.body, sig, process.env.APEXMCP_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // handle event...
  res.status(200).send('ok');
});

Verify in Python:

import hmac, hashlib
 
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Retry Policy

If your endpoint returns a non-2xx status or times out (> 10 seconds), ApexMCP retries with exponential backoff:

AttemptDelay
1st retry30 seconds
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry8 hours

After 5 failed attempts the event is marked failed and no further retries are made. Failed events are visible in Developer Portal → Webhooks → [name] → Event Log for 72 hours.

Use the id field for idempotency — your endpoint may receive the same event more than once during retries.