Webhook API¶
Version: 1.0 Last Updated: 2026-02-14
Overview¶
Two separate API surfaces for webhook functionality:
1. Management API (/marketplace/webhooks/...) — JWT-authenticated, creator-only CRUD
2. Ingestion API (/webhooks/{webhook_id}) — HMAC-authenticated, public endpoint for external services
Authentication¶
- Management endpoints: Bearer token via
Authorization: Bearer <token>header (creator-only) - Ingestion endpoint: HMAC-SHA256 signature via
X-Webhook-Signatureheader (no JWT)
Management Endpoints¶
Create Webhook¶
Request Body:
{
"action_id": "add_item",
"description": "Stripe payment webhook",
"payload_mapping": {
"amount": "event.data.amount"
}
}
Response (200):
{
"webhook_id": "uuid",
"secret": "64-char-hex-shown-once",
"url": "https://api.ikiro.ai/webhooks/{webhook_id}",
"action_id": "add_item",
"description": "Stripe payment webhook"
}
Errors: 400 (invalid action, max limit, not creator)
List Webhooks¶
Response (200):
{
"webhooks": [
{
"webhook_id": "uuid",
"action_id": "add_item",
"description": "Stripe payment webhook",
"is_active": true,
"url": "https://api.ikiro.ai/webhooks/{webhook_id}",
"rate_limit_per_minute": 10,
"created_at": "2026-02-14T...",
"updated_at": "2026-02-14T..."
}
],
"total": 1
}
Delete Webhook¶
Response (200):
Rotate Secret¶
Response (200):
Get Recent Events¶
Response (200):
{
"events": [
{
"event_id": "uuid",
"signature_valid": true,
"action_triggered": "add_item",
"result_status": "ok",
"error_message": null,
"ip_address": "1.2.3.4",
"created_at": "2026-02-14T..."
}
],
"total": 42
}
Ingestion Endpoint¶
Invoke Webhook¶
Headers:
- X-Webhook-Signature: HMAC-SHA256 hex digest of the request body using the webhook secret
- Content-Type: application/json
Request Body: Any valid JSON (max 64KB)
Success Response (200):
Error Responses:
- 400 — Invalid webhook ID or invalid JSON
- 401 — Invalid or missing signature
- 404 — Webhook not found or inactive
- 413 — Payload too large (>64KB)
- 429 — Rate limit exceeded
- 500 — Action execution failed
- 503 — Service unavailable
Signing Payloads¶
External services should sign the raw request body: