# Webhooks and the events feed

Get every new call, booking request, urgent message and missed call in your own system the moment it happens: as a signed webhook, or by polling the events feed.

Julius Answer sends events (a summarized call, a booking request, an urgent message, a missed call and more) to your https address as signed JSON, in order, with retries. The same events are available from GET /api/v1/events for systems that poll. Both use the same shape.

## Connect a webhook
- **In the console:** Settings, Connections, Webhook. Paste your https address, choose the events and press Connect. Send a test from the same screen.
- **With the API:** PUT /api/v1/connections/webhook with {"url": "https://…"} (full access). Then POST /api/v1/connections/webhook/test sends a sample.
- **The signing secret** (whsec_…) is shown once, when the webhook is first connected. Store it with your endpoint.
- **Addresses** must be https on the public internet; private and local network addresses are refused.

## Event types

Events Julius Answer sends
| Type | When |
|---|---|
| call.summarized | A call ended and its summary is ready |
| message.urgent | A caller left an urgent message |
| booking.requested | A caller asked for an appointment or a visit |
| call.missed | A call the receptionist couldn't take (the reason is in text); a third try from the same caller sends another |
| transfer.missed | A caller asked for a person and nobody picked up |
| caller.unhappy | A caller sounded unhappy |
| promise.due | Something the business promised a caller is coming due or slipping |
| household.suggested | Two callers look like the same household; confirm in the console |
| call_list.ready | The morning's list of people worth a call today is ready |
| text.received | A caller texted your Julius Answer number (texting must be on). Clinics and law firms get it without the text |

## The payload POST /your/endpoint HTTP/1.1 Content-Type: application/json User-Agent: Julius-Webhooks/1 X-Julius-Event: booking.requested X-Julius-Delivery: ea8f0f0d-74c5-46ee-95cf-fd05a6d8c6fb X-Julius-Timestamp: 1792505805 X-Julius-Signature: sha256=5d1f… {"id": "ea8f0f0d-74c5-46ee-95cf-fd05a6d8c6fb", "type": "booking.requested", "occurred_at": "2026-10-20T14:16:45.776822+00:00", "business": "Joe Plumbing", "caller": {"name": "Maria Lopez", "phone": "+13125550142"}, "title": "Booking request: Maria Lopez", "text": "Water heater install, Saturday morning", "summary": "Water heater install, Saturday morning", "caller_type": null, "call_id": null, "link": "https://app.julius.dealsflow.ai"}
- **id** is the same on every retry: use it to ignore duplicates.
- **call_id** (when the event is about a call) works with GET /api/v1/calls/{call_id} for the transcript.
- **caller_type** on call.summarized is customer, offer (a sales pitch) or another kind of caller.
- **Healthcare and legal businesses:** caller names and reasons are left out ("Open Julius to read it") unless the owner turns on "Include caller details" for the webhook.

## Check the signature

The signature is an HMAC-SHA256, with your signing secret, of the timestamp, a dot and the raw body. Compare it in constant time and refuse old timestamps. # Python import hashlib, hmac, time def verified(secret: str, body: bytes, timestamp: str, signature: str) -> bool: if abs(time.time() - int(timestamp)) > 300: return False digest = hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest() return hmac.compare_digest("sha256=" + digest, signature) // Node.js (use the raw body, before any JSON parsing) import crypto from "node:crypto"; function verified(secret, rawBody, timestamp, signature) { if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false; const expected = "sha256=" + crypto.createHmac("sha256", secret).update(`${timestamp}.`).update(rawBody).digest("hex"); return expected.length === signature.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature)); }

## Delivery
- **Answer 2xx quickly** (within 10 seconds), then do the work. Anything else counts as a failure.
- **Retries** wait longer each time, up to an hour apart, and events stay in order: a later event never overtakes one that is being retried.
- **Turned off** at once on 404 or 410, after five refusals in a row (400, 401, 403), or after 50 failures. The console shows the reason; saving the webhook again turns it back on.
- **No old floods:** events older than a day aren't replayed, and a new webhook starts with what happens next.
- **Redirects aren't followed.** Use the final address.

## The events feed (polling)

The same events, oldest first, for systems that can't receive webhooks. Read access is enough. curl "https://app.julius.dealsflow.ai/api/v1/events?since_hours=24" -H "Authorization: Bearer $KEY" {"events": [ … ], "next": "eyJhdCI6IjIwMjYtMTAtMjBUMTQ6…", "more": false}
- **Store next** and pass it as after next time: you get only what's new, never the same event twice. next stays the same when nothing happened.
- **more: true** means there's another page right away; ask again with the new next.
- **Filters:** types=call.summarized,booking.requested; limit up to 100; since_hours up to 168 (only for the first request, without after).
- **Freshness:** events appear about 15 seconds after they happen, so a cursor never skips one that was still being written.

## Frequently asked questions

### Can I send Julius Answer calls to Zapier or Make?

Yes. Make a catch-hook URL in Zapier (Webhooks by Zapier) or Make (custom webhook), and connect it in the console under Settings, Connections, Webhook. Every new call and booking arrives there as JSON.

### Do webhooks include the transcript?

They include the call summary, the caller's name and number, a short headline and a link to the call in the console. Fetch the full transcript with GET /api/v1/calls/{call_id}.

### What if my endpoint is down?

Julius Answer retries with growing waits (up to an hour apart) and delivers in order once it's back, for up to a day. An answer of 404 or 410 turns the webhook off at once; the console shows why.

### Should I use webhooks or the events feed?

Webhooks if you can receive https requests: they arrive within seconds. The events feed if you can't (a script on a schedule, a spreadsheet, a tool without a public address): poll it every minute or so with the next value.

---
Source: https://julius.dealsflow.ai/docs/events/
Updated: 2026-10-20
