Events

Subscribe to state changes without polling the protocol.

OpenDoc exposes live SSE streams and HMAC-signed webhooks for canonical protocol events. Event payloads carry entity IDs and state metadata, not broad PHI.

SSEGET /events
WebhooksPOST /event-subscriptions
Signaturex-opendoc-signature

Event types

Discover supported events from /protocol.

The event vocabulary is returned by the protocol discovery endpoint. Use it instead of hardcoding assumptions when building an integration.

curl https://api.opendoc.com/protocol | jq '.events.types'

SSE

Use SSE for live agent or dashboard connections.

The SSE stream requires an agent token. Server clients should use Authorization. Browser EventSource clients can pass the token as a query parameter because EventSource does not allow custom headers.

curl https://api.opendoc.com/events \
  -H "Authorization: Bearer $OPENDOC_AGENT_TOKEN"

const stream = new EventSource(
  "https://api.opendoc.com/events?token=" + encodeURIComponent(agentToken)
);

stream.addEventListener("transaction.state_changed", (event) => {
  const payload = JSON.parse(event.data);
  console.log(payload);
});

Webhooks

Register a callback for server-to-server delivery.

Webhook subscriptions are owned by the calling agent token. The signing secret is returned once when the subscription is created.

curl https://api.opendoc.com/event-subscriptions \
  -X POST \
  -H "Authorization: Bearer $OPENDOC_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "callbackUrl": "https://partner.example.com/opendoc/webhooks",
    "eventTypes": ["transaction.state_changed", "receipt.finalized"]
  }'

Verification

Verify the raw body with HMAC-SHA256.

OpenDoc signs the exact request body and sends the hex digest in x-opendoc-signature. Use the one-time signing secret from subscription creation.

import crypto from "node:crypto";

function verifyOpenDocWebhook(rawBody, signature, signingSecret) {
  const expected = crypto
    .createHmac("sha256", signingSecret)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expected, "hex")
  );
}
Headers to persist: OpenDoc sends x-opendoc-event, x-opendoc-correlation-id, and x-opendoc-signature with webhook deliveries.