Account & security
Updated July 12, 2026
Outbound webhooks
> Webhooks are a Professional and Studio Plus feature. Lower tiers see the events in-app; the outbound push is bundled with the Professional plan.
Register up to 5 HTTPS endpoints under Settings → Webhooks and Encore POSTs a signed JSON event to each subscribed endpoint the moment things happen. Point them at Zapier, your studio CRM, or your own scripts.
Events
gallery.published- a gallery transitioned into a delivered stage (Full or Album). Data: galleryId, slug, title, stage.client.favorited- an identified client favorited a photo. Data: galleryId, slug, photoId, clientEmail.download.created- a download was delivered. Data: galleryId, slug, scope ("photo" or "zip"), plus photoId + size for single-photo downloads.post.matched- a social post was matched to a delivered photo. Data: photoId, galleryId, platform, postUrl, confidence (pHash distance; null for manual matches).license.purchased- a digital license sale completed.reel.ready- an Encore Reel finished rendering.anniversary.reveal- a "one year ago tonight" email went out. Data: galleryId, slug, title.
The payload envelope
Every delivery is a JSON POST with the same four-field envelope:
```
{
"id": "3f6c…", // stable per-emission id
"type": "gallery.published",
"createdAt": "2026-07-12T22:30:00.000Z",
"data": { … } // event-specific, documented above
}
```
One emitted event fans out to every subscribed endpoint; each endpoint's delivery shares the envelope id.
Headers
encore-signature-t=<unix seconds>,v1=<hex>(see verification below)encore-event- the event type, so you can route before parsingencore-delivery- unique per delivery attempt chain. Dedupe on this: delivery is at-least-once, so a slow 200 followed by a retry can hand you the same event twice.
Verifying the signature
The v1 value is HMAC-SHA256 over ${t}.${rawBody} keyed with your endpoint's signing secret (shown once at creation, whsec_ prefix). Verify against the raw request body - never a re-serialized parse - and reject timestamps outside a 5-minute tolerance to block replays.
```
const { createHmac, timingSafeEqual } = require("node:crypto");
function verifyEncoreSignature(secret, signatureHeader, rawBody) {
const m = /t=(\d+),v1=([a-f0-9]{64})/.exec(signatureHeader ?? "");
if (!m) return false;
const [, t, sig] = m;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac("sha256", secret)
.update(t + "." + rawBody)
.digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}
```
Respond with any 2xx within 10 seconds to acknowledge. Anything else (including a timeout or a redirect) counts as a failure.
Retries
Failed deliveries retry on an exponential schedule: 1m, 5m, 30m, 2h, 6h, 24h - 6 attempts total, then the delivery is marked exhausted. The delivery log on the settings page shows the latest 30 deliveries with status, attempts, and last response code; failed and exhausted rows have a one-click Redeliver.
Auto-pause
After 20 consecutive failures across deliveries, the endpoint is automatically paused and the studio owner is emailed - a dead endpoint must not accumulate retry debt forever. Fix the receiver, then resume it from settings; resuming clears the failure counter.
Endpoint rules
- HTTPS only, on the default port. Plain http, custom ports, localhost, private IPs, and internal hostnames are rejected at registration.
- The signing secret is shown once at creation. If you lose it, delete the endpoint and create a new one.
- Use the Send test button to POST a signed
test.pingat any time - it uses the exact same signature scheme as real deliveries, so it's the fastest way to shake out a verifier.
Ordering
Events are delivered independently per endpoint and retries can reorder them. If sequence matters, order by the envelope's createdAt on your side.
More in Account & security
Still need help?
Send us a message and we'll reply within one business day. Most questions get a same-day answer.
Send a message →