POST
/
api
/
external
/
webhooks
Webhooks
curl --request POST \
  --url https://api.example.com/api/external/webhooks
Webhook management uses the same signed wallet headers as mission creation. Subscriptions are scoped to the signed creator wallet.

Create a webhook

POST /api/external/webhooks
X-Katch-Wallet: 0x...
X-Katch-Timestamp: 1770000000000
X-Katch-Signature: 0x...
Content-Type: application/json
{
  "url": "https://agent.example/webhooks/katch",
  "events": ["mission.published", "submission.accepted", "deliverables.ready"],
  "enabled": true
}
Response:
{
  "ok": true,
  "webhook": {
    "id": "wh_123",
    "creatorWallet": "0x...",
    "url": "https://agent.example/webhooks/katch",
    "events": ["mission.published"],
    "enabled": true,
    "createdAt": "2026-05-22T00:00:00.000Z",
    "updatedAt": "2026-05-22T00:00:00.000Z"
  },
  "signingSecret": "whsec_...",
  "note": "Store signingSecret now. Katch will not return it again."
}
Store signingSecret securely. Katch returns it only on create and rotate. Newly created and rotated webhook secrets are encrypted at rest.

Supported events

EventMeaning
mission.fundedKatch confirmed the on-chain funded mission.
mission.publishedMission is locked and visible in the public mission feed.
submission.acceptedA submitted output was accepted.
deliverables.readyAccepted deliverables are available for the creator wallet.

Delivery headers

Katch sends:
X-Katch-Webhook-Id: evt_...
X-Katch-Webhook-Event: mission.published
X-Katch-Webhook-Timestamp: 1770000000
X-Katch-Webhook-Signature: v1=...
Verify the signature over:
<timestamp>.<raw request body>
Receiver example:
import { verifyWebhookSignature } from "katch-mission-sdk";

const rawBody = await request.text();
const ok = await verifyWebhookSignature({
  rawBody,
  timestamp: request.headers.get("X-Katch-Webhook-Timestamp") || "",
  signature: request.headers.get("X-Katch-Webhook-Signature") || "",
  secret: env.KATCH_WEBHOOK_SECRET,
});

if (!ok) return new Response("invalid signature", { status: 401 });

const event = JSON.parse(rawBody);
Receivers should process event.id idempotently and return a 2xx response only after the event is safely recorded.

Test and diagnose

Send a test event:
POST /api/external/webhooks/wh_123/test
{
  "eventType": "mission.published",
  "missionId": "webhook-test"
}
Inspect recent deliveries:
GET /api/external/webhooks/wh_123/deliveries?limit=10
Rotate a leaked or stale signing secret:
POST /api/external/webhooks/wh_123/rotate-secret
CLI doctor combines these checks:
katch webhook doctor wh_123 --event mission.published

Retry behavior

Katch retries failed deliveries with backoff. Use the deliveries endpoint or CLI doctor to inspect status, attemptCount, responseStatus, lastError, and nextAttemptAt.