bymundi API

Webhooks

Get a signed HTTPS call when trips, quotes, travelers or documents change.

bymundi calls your HTTPS endpoint when something changes — whoever changed it: someone in the app, the assistant, or the API.

Subscribe

Create an endpoint with your key (or in Integrations → API & MCP → Webhooks):

curl -X POST https://api.bymundi.com/v1/webhook-endpoints \
  -H "Authorization: Bearer $BYMUNDI_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"url":"https://example.com/hooks/bymundi","eventTypes":["trip.updated","quote.accepted"]}'

The answer includes the endpoint's signing secret (whsec_…), shown once. An endpoint belongs to the key that created it: it reads with that key's permissions and stops when the key is revoked. A key can have up to 10.

The event

{
  "id": "evt_…",
  "type": "trip.updated",
  "timestamp": "2027-05-01T09:00:00Z",
  "subject": { "object": "trip", "id": "…", "tripId": "…" },
  "changed": ["title", "startDate"],
  "data": { "object": "trip", "id": "…", "title": "…" }
}

data is the object exactly as its REST GET returns it, read when the event is delivered. changed names the fields that changed. Bursts of edits are grouped: an *.updated event is sent 5 seconds after the last edit, and at most 60 seconds after the first.

Verifying signatures

Deliveries follow Standard Webhooks. Three headers:

The signature is HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw body}, keyed with the base64-decoded part of your secret after whsec_. Verify against the raw body, before parsing it, and refuse timestamps more than 5 minutes away:

import crypto from "node:crypto";

export function verify(secret, headers, rawBody) {
  const id = headers["webhook-id"], ts = headers["webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = crypto.createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest("base64");
  return headers["webhook-signature"].split(" ").some((s) => {
    const sig = s.split(",")[1] ?? "";
    return sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  });
}

Any Standard Webhooks library (JavaScript, Python, Go, Ruby, PHP…) does the same.

Answering

Answer any 2xx within 10 seconds; do slow work afterwards. Anything else — or no answer — is retried after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours. An endpoint with no successful delivery for 3 days is switched off; turn it back on with PATCH and enabled: true.

Events

Operations