Skip to content

Webhooks

Opem posts an event to your server when something happens in a project. Add an endpoint, an https address, on the Webhooks tab of the project's Configuration page, on Professional and Enterprise, and choose its events.

Events

Each delivery's body is JSON: the event's id, type, createdAt, projectId and data. The same event sent to two endpoints shares its id, so you can ignore one you have seen.

EventWhenData
request.createdA request is raised in the widget, a hand-off from the assistant included.request
request.repliedYour team replies: in the dashboard, through the management API, or by replying to Opem's email.request, message (the reply and its channel: dashboard, api or email)
request.closedA request is closed: in the dashboard, with a reply sent with Close, or through the management API.request, closedBy (staff or api)
answer.givenThe assistant answers in the widget with some text.answer (who asked, the question, the answer, whether it read a document)
answer.handed_overA person hands an answer over to your team, which raises a request too.answer.id, request

Verify each delivery

Every delivery is signed with the endpoint's secret, whsec_…, shown once when the endpoint is made or its secret rotated. In Node.js, verifyWebhook() from @opem/node checks the signature and the time, and returns the event, typed.

app/api/opem/route.ts · a Next.js route handler
import { verifyWebhook } from "@opem/node";

export async function POST(request: Request) {
  const event = verifyWebhook({
    body: await request.text(),
    headers: request.headers,
    secret: process.env.OPEM_WEBHOOK_SECRET!, // whsec_…
  });
  if (event.type === "request.created") {
    console.log(event.data.request.reference);
  }
  return new Response(null, { status: 204 });
}

In any other language: take the raw body exactly as received and the Opem-Timestamp header, and compute HMAC-SHA256 over the timestamp, a full stop and the body, with the whole secret string, whsec_ included, as the key. Compare its lowercase hex with the value after v1= in Opem-Signature, in constant time, and refuse a timestamp more than 5 minutes from your clock.

HeaderValue
Opem-Signaturev1= and the lowercase hex HMAC-SHA256 of the signed string, with the endpoint's secret
Opem-Timestampwhen Opem signed this attempt, in unix seconds
Opem-Deliverythe delivery's id: the same on every attempt, new on a redelivery
Opem-Eventthe event, as in the body's type

Deliveries and retries

A delivery is a POST with Content-Type: application/json. Any 2xx within 10 seconds counts as delivered. Anything else, a redirect included, is tried again after 1 minute, 10 minutes, 1 hour, 6 hours, 16 hours, each attempt signed afresh. After that the delivery is marked as not delivered; the Webhooks tab lists every delivery for 30 days, and your team can send one again from there.

Redirects are never followed, and Opem only delivers to public https addresses.