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
- Go to Developer Portal → Webhooks → New Webhook
- Enter your endpoint URL (must be HTTPS)
- Select events to subscribe to
- Copy the signing secret — used to verify payloads
- Click Save
ApexMCP will immediately send a test ping to verify the endpoint is reachable.
Events
| Event | Description |
|---|---|
tool.called | Fired 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:
| Field | Type | Description |
|---|---|---|
event | string | Event type |
id | string | Unique event ID (idempotency key) |
timestamp | ISO 8601 | When the event occurred (UTC) |
org_slug | string | Organisation that triggered the event |
data.tool_name | string | Name of the tool that was called |
data.connector_id | string | ID of the connector |
data.connector_type | string | Type of connector (e.g. postgresql) |
data.agent_id | string | Agent identity if registered, else null |
data.duration_ms | integer | Tool execution time in milliseconds |
data.success | boolean | Whether the call succeeded |
data.error_code | integer or null | JSON-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:
| Attempt | Delay |
|---|---|
| 1st retry | 30 seconds |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 8 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.