Skip to content

Webhooks

Your tools hear when the service starts.

Voclyn’s webhooks send a signed POST to your address when a service starts, pauses, resumes or ends, so Zapier, Make, n8n or your own server can act on it. Owners and admins add endpoints in Dashboard › Integrations.

Events

EventWhen
service.startedA room went live.
service.pausedWorship, a break or a private moment began (data.service.reason says which).
service.resumedCaptions flow again after a pause.
service.endedThe service ended: its length, listeners and whether a transcript was saved.
pingOnly from Send a test, in Dashboard › Integrations.

Each endpoint chooses its events. A pause is sent once it has held for a moment, so a sound desk reconnecting mid-pause sends nothing. When the room saves transcripts, service.ended waits 10 seconds, so the transcript is whole when it arrives.

The body

Every event has the same shape: its id, type, when it happened (created), the body’s version, the church, and the service in data.service. While paused, reason is worship, private or break; the length, listeners and transcript arrive with service.ended.

{
  "id": "6f0e8a52-1c7d-4c55-9a8e-2b8f0d3c4e11",
  "type": "service.ended",
  "created": "2026-11-01T18:14:40.512Z",
  "version": "2026-10-30",
  "church": { "id": "0d6c3b1a-5e4f-4a2b-9c8d-7e6f5a4b3c2d", "name": "Grace Church" },
  "data": {
    "service": {
      "id": "9b2e5c1a-3d4f-4a6b-8c7d-1e2f3a4b5c6d",
      "room": { "id": "4f1c2a9e-8b3d-4e62-9a71-0c5d6e7f8a9b", "name": "Sanctuary", "link": "https://voclyn.com/grace" },
      "status": "ended",
      "reason": null,
      "started_at": "2026-11-01T17:02:11.004Z",
      "ended_at": "2026-11-01T18:14:40.498Z",
      "duration_seconds": 4349,
      "peak_listeners": 38,
      "languages": ["es", "zh-Hant"],
      "voice_languages": ["es", "zh-Hant"],
      "transcript": true
    }
  }
}

With transcript: true, a full API key fetches it: GET /services/{id}/transcript (how).

Headers

HeaderWhat it holds
Voclyn-Signaturet= the time it was signed (Unix seconds), v1= the signature.
Voclyn-EventThe event’s type, such as service.started.
Voclyn-DeliveryThis delivery’s id; every try of it carries the same one.
Content-Typeapplication/json

Check the signature

Each endpoint has a signing secret (whsec_…), shown when you add it and from its Signing secret button. The signature is the HMAC-SHA256 of the time, a full stop and the body exactly as it arrived, keyed with the whole secret, in hex. Compare it in constant time, and refuse one more than five minutes old, so a recorded delivery can’t be played back later.

import crypto from "node:crypto";

// The body exactly as it arrived (in Express: express.raw({ type: "application/json" })).
function fromVoclyn(rawBody, header, secret) {
  const parts = Object.fromEntries((header ?? "").split(",").map((p) => p.split("=")));
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!parts.v1 || !(age <= 300)) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
import hashlib, hmac, time

def from_voclyn(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in (header or "").split(",") if "=" in p)
    t, v1 = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > 300:
        return False
    expected = hmac.new(secret.encode(), t.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

Check the raw body, before any JSON parser touches it: the same event re-serialised won’t match.

Answer, then work

Answer with any 2xx status within 10 seconds, then do the slow work. Anything else counts as a failure and is tried again: an error, no answer in time, or a redirect, which is never followed. Deliveries go only to public https addresses.

Retries and order

A failed delivery is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours: 7 tries in all, over about a day. Then it is marked failed in the dashboard’s list of deliveries, which keeps 30 days.

A retry can arrive after a later event, and an event can arrive twice. Use the event’s id to do its work once, and its created time to tell which came first.

Test an endpoint

Send a test in Dashboard › Integrations › Webhooks delivers a ping event at once and shows how your address answered. Turning an endpoint off stops its deliveries and drops the ones still waiting; turning it on again starts with the next event.

What churches do with them

  • Tell the team. On service.started, a Zapier or Make step posts “We’re live in the Sanctuary” to Slack, Teams or WhatsApp, with the room’s link.
  • Keep every sermon. On service.ended with a transcript, a server fetches it in each language and saves it to your drive or website.
  • Follow the room. service.paused and service.resumed drive anything that should rest during worship, such as a sign or a lower third.

Checked and updated October 30, 2026.

Questions

What churches ask.

Something else on your mind? Write to us at hello@voclyn.com.

Yes: a signed POST when a service starts, pauses, resumes or ends, to up to 5 addresses per church, on the paid plans and in the free month.

Check the Voclyn-Signature header: the HMAC-SHA256 of the time, a full stop and the raw body, keyed with the endpoint's signing secret, and no more than five minutes old.

Each delivery is tried again for about a day, then marked failed in Dashboard › Integrations, where the last deliveries are listed.

Yes. Zapier's Webhooks by Zapier, Make and n8n each give you an address that catches them; paste it as an endpoint.

Try it this Sunday.

Set up your church in a minute and hear it live with your own voice. Your QR code keeps working after the free month.

Your first month is on us: the Church plan, normally $99 a month, with unlimited listeners, translation hours and AI voiceover. No card; then choose a plan, or stay on Free.