AI Agents
Agent webhooks

Agent webhooks

Workspace webhooks let your own Claude Code process, automation, or queue consumer react to mdedit activity without continuously polling. mdedit can deliver:

  • review.mentioned when a new comment or reply contains an @handle
  • review.replied when someone replies to a review thread
  • article.updated when document content is committed or checkpointed

Create a webhook

Workspace owners and admins can manage webhooks with a JWT or an API key scoped with workspaces:write. The destination must use HTTPS and resolve only to public addresses.

curl -X POST "https://apiv2.mdedit.ai/workspaces/$WORKSPACE_ID/webhooks" \
  -H "x-api-key: $MDEDIT_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://agents.example.com/mdedit",
    "events": ["review.mentioned", "review.replied", "article.updated"]
  }'

The create response contains a secret beginning with whsec_. It is shown only once; store it in your secret manager. GET lists configured webhooks without secrets. PATCH /workspaces/{workspaceId}/webhooks/{webhookId} updates the URL, subscriptions, or active state; send { "rotateSecret": true } to receive a new one-time secret.

Verify a delivery

Verify the signature against the exact raw request body before parsing JSON. The signed message is <timestamp>.<raw-body> and the digest uses HMAC-SHA256:

import { createHmac, timingSafeEqual } from 'node:crypto';
 
export function verifyMdeditWebhook({ rawBody, timestamp, signature, secret }) {
  const expected = `v1=${createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex')}`;
  const left = Buffer.from(expected);
  const right = Buffer.from(signature ?? '');
  return left.length === right.length && timingSafeEqual(left, right);
}

Deliveries include x-mdedit-event, x-mdedit-delivery, x-mdedit-timestamp, and x-mdedit-signature. Reject stale timestamps according to your own replay window and deduplicate work by x-mdedit-delivery.

Delivery behavior

The JSON body includes id, event, createdAt, workspaceId, and event-specific data. mdedit treats any non-2xx response or network error as a failed attempt and retries with exponential backoff. Redirects are not followed. A webhook that is deleted, disabled, or unsubscribed before a queued attempt runs is skipped.

For a process that already has an article ID and should remain attached to one document, you can also stream events with mdedit article watch <articleId>.