PepoSmart
IntegrationsPricingBlog
LoginSign up free
  1. Home
  2. /Blog
  3. /Scheduling Webhooks: How to Automate Everything That Happens After a Booking, With Signature Verification and Retries
Developers

Scheduling Webhooks: How to Automate Everything That Happens After a Booking, With Signature Verification and Retries

Written by

Yash Havalimane

Reviewed by

Zakir Shaikh
September 4, 2026
9 min read
Share:
Laptop on a wooden desk displaying lines of source code in a dark editor

Polling a scheduling API every minute to find out whether anyone booked is a poor way to spend compute and a worse way to find out late. Webhooks flip the direction: the scheduling tool calls you, at the moment something happens, with a signed message describing what it was. This guide is for developers wiring a scheduling tool into their own systems. It covers the events worth subscribing to, the exact request shape, signature verification in Node and Python, how to design for retries, and the automations teams actually build once the plumbing works. The examples use PepoSmart's webhooks, and the patterns apply to any well-designed sender.

Quick answer: Register an HTTPS endpoint, subscribe to the events you need, and verify every request by recomputing HMAC-SHA256 over the timestamp and raw body with the endpoint's secret. Respond with a 2xx within the sender's timeout and do slow work afterwards. Expect at-least-once delivery, so key your handler on the delivery id. PepoSmart sends booking created, cancelled, rescheduled and paid events plus meeting-notes and follow-up-draft events, retries up to 7 times with exponential backoff, and logs every delivery for 30 days.

Key takeaways

  • Webhooks are for systems you own. For no-code connections use Zapier or Make; for on-demand reads use the REST API.
  • Verify the signature over the raw body, never over re-serialised JSON.
  • Respond fast and process later. A 10-second timeout is generous for an acknowledgement and tight for a database transaction.
  • At-least-once delivery means duplicates. Idempotency is not optional.
  • The interesting automations start after the booking: payment reconciliation, CRM enrichment, and reacting to AI meeting notes.

What a scheduling webhook is

A webhook is an HTTP POST from the scheduling tool to a URL you registered, carrying a JSON body that describes one event. The tool sends it when the event happens, so your system learns about a new booking within seconds rather than on the next poll.

The shape that has become standard across payment processors and SaaS APIs, and that PepoSmart follows, has four parts: an envelope with an id, a type and a timestamp; a data object specific to the event type; headers naming the event and the delivery; and a signature header so you can prove the message came from the sender and was not altered in transit. If you have worked with Stripe's webhooks, the model will feel familiar, and the Standard Webhooks specification documents the same conventions vendor-neutrally.

Which events are worth subscribing to

PepoSmart exposes eight subscribable events, listed on the product-facts page. They fall into three groups.

EventSent whenWhat you usually do with it
booking.createdA booking is confirmedCreate a record in your system, provision access, notify a channel
booking.cancelledAn invitee or host cancelsRelease resources, update a record, trigger a win-back
booking.rescheduledA booking moves to a new timeUpdate the record; the payload carries a rescheduledFrom block
booking.paidPayment succeeds on a paid eventReconcile with accounting, issue a receipt in your own system
meeting-notes.completedThe AI notetaker finishes processingStore the summary and transcript, kick off internal review
action-item.createdAn action item is extracted from a meetingCreate tasks in a system PepoSmart does not integrate with natively
followup-draft.generatedA follow-up email draft is ready for reviewNotify the rep, route to a review queue
followup-draft.sentA reviewed draft is sentLog the outreach in your own timeline

Two details matter for the booking group. A reschedule produces two messages: booking.created for the new booking, then booking.rescheduled for that same booking with rescheduledFrom pointing at the original, so handle both without double-counting. And cancellations fire whether the invitee cancels from their email link or a host cancels from the Meetings page, so you do not need to watch two paths.

Each endpoint subscribes to every event or a chosen subset, and can be scoped to a single event type, for example only bookings of your "Enterprise demo" event. That scoping is often simpler than filtering in code.

The request, exactly

Every delivery is a POST with a JSON body. The envelope never changes; only data does.

POST https://example.com/webhooks/peposmart
Content-Type: application/json
User-Agent: PepoSmart-Webhooks/1.0
X-PepoSmart-Event: booking.created
X-PepoSmart-Delivery: 6f1c3c1e-2c2b-4a4e-9d3a-0f6c1d5b1a2e
X-PepoSmart-Signature: t=1756720800,v1=9f2c8a7d...e41b

{
  "id": "6f1c3c1e-2c2b-4a4e-9d3a-0f6c1d5b1a2e",
  "type": "booking.created",
  "createdAt": "2026-09-01T10:00:00.000Z",
  "data": { ... }
}

Three points to design around:

  • id is the delivery id. It stays the same across retries, so store it and ignore a message you have already processed.
  • type is also sent as the X-PepoSmart-Event header, so you can route before parsing the body.
  • You must respond with any 2xx status within 10 seconds. Do the real work after responding if it is slow.

The booking payload

Every booking.* event carries the same object. The field names match the Zapier and Make payloads, which means an automation written for one can be moved to the other without renaming anything.

{
  "bookingId": "abc123",
  "eventId": "event456",
  "status": "confirmed",
  "startTime": "2026-09-20T14:00:00.000Z",
  "endTime": "2026-09-20T14:30:00.000Z",
  "timezone": "America/New_York",
  "location": "google-meet",
  "meetingUrl": "https://meet.google.com/abc-defg-hij",
  "attendee": { "name": "...", "email": "..." },
  "additionalGuests": [],
  "customAnswers": { "...": "..." },
  "eventDetails": { "...": "..." },
  "host": { "...": "..." },
  "payment": null,
  "cancellation": null,
  "createdAt": "2026-09-01T10:00:00.000Z"
}

booking.cancelled fills cancellation and sets status to cancelled. booking.rescheduled adds rescheduledFrom with the original booking's details. booking.paid fills payment, with the amount in the smallest currency unit, so 4900 means 49.00 in a two-decimal currency.

The meeting-notes and follow-up events use the same data shapes as the Zapier integration. One difference: transcripts longer than 100,000 characters are cut, and the payload carries transcriptTruncated: true, so check that flag before assuming you have the whole conversation. The full reference is in the webhooks documentation.

Lines of code on a dark computer screen
Verify over the raw bytes you received; the first bug in most webhook handlers is hashing re-serialised JSON

Verifying the signature

The signature header has the form t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of the string <t>.<raw request body>, keyed with the endpoint's secret. HMAC is a keyed hash: only a holder of the secret can produce a valid value, and any change to the body changes it.

Verify in four steps:

  1. Read the raw body exactly as received. Do not parse and re-serialise it first.
  2. Recompute the HMAC over t + "." + body with your secret.
  3. Compare with v1 using a constant-time comparison.
  4. Reject timestamps older than a few minutes to block replays.

Node.js

import crypto from "node:crypto";

export function verifyPepoSmartWebhook(secret, signatureHeader, rawBody) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((p) => p.split("="))
  );
  const payload = parts.t + "." + rawBody;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1 || "", "hex");
  return fresh && a.length === b.length && crypto.timingSafeEqual(a, b);
}

If you use Express, register the route with a raw body parser (express.raw({ type: "application/json" })) so req.body is the bytes, not a parsed object. That single line is the difference between a handler that works and one that fails only in production.

Python

import hashlib, hmac, time

def verify(secret: str, header: str, raw_body: bytes) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    payload = parts["t"].encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    fresh = abs(time.time() - int(parts["t"])) < 300
    return fresh and hmac.compare_digest(expected, parts.get("v1", ""))

Treat the secret like a password. Keep it out of client-side code and out of version control, and rotate it from the endpoint card if it leaks; deliveries after a rotation are signed with the new secret immediately.

Designing the handler

Acknowledge first, work second. Validate the signature, write the delivery to a queue or a table, return 200, and process from there. A handler that calls a CRM API, sends an email and updates three tables before responding will time out under load and be retried, which multiplies the load.

Make it idempotent. Delivery is at-least-once. Store processed delivery ids with a unique constraint and let a duplicate insert fail harmlessly. This also protects you when you resend a delivery from the dashboard while debugging.

Route on the header. X-PepoSmart-Event tells you the type before you parse the body. A small switch on that header keeps handlers focused.

Log the raw body on failure. When a handler throws, the raw request is the only evidence of what was sent. The sender's delivery log helps, but yours is faster to reach.

Return non-2xx only when you want a retry. A permanently unprocessable message, such as an event type you do not handle, should get a 200 and be ignored, or the retries will continue until they exhaust and the endpoint's failure counter climbs.

Retries, failures and the delivery log

PepoSmart's delivery behaviour, from the webhooks documentation:

  • A non-2xx response, a redirect, or no response within 10 seconds counts as a failure. Redirects are never followed.
  • Failures are retried with exponential backoff, up to 7 attempts.
  • After the last attempt the delivery is marked failed and can be resent from the dashboard once it has settled.
  • An endpoint whose deliveries fail 25 attempts in a row, about four events' worth of retries, is switched off automatically. Fix the receiver and re-enable it with the toggle. Test sends never count toward this.
  • Every delivery is listed for 30 days with its attempt count, the payload sent and the first 1 KB of your response.

Design implication: 7 attempts with backoff spans a meaningful window, so a short outage will be papered over by retries, but an endpoint that is misconfigured for a day will be disabled and needs a human to turn it back on. Alert on the disabled state, not just on individual failures.

A short security checklist

Webhook endpoints are public URLs that accept POSTs from the internet, so treat them with the same care as any other unauthenticated route.

  • Verify before you parse. Signature first, JSON second. A malformed body should never reach your business logic unsigned.
  • Reject stale timestamps. Five minutes is a common tolerance. Without it, a captured request can be replayed indefinitely.
  • Store the secret like a password. Environment variables or a secrets manager, never source control, never the browser.
  • Rotate on suspicion. A rotated secret takes effect immediately for new deliveries, so there is no reason to delay.
  • Minimise what you log. Booking payloads contain names, emails and intake answers. Log the delivery id and event type by default and the full body only on failure, with the same retention rules as the rest of your personal data.
  • Return 200 for events you ignore. Otherwise the sender keeps retrying and your endpoint's failure counter climbs toward the automatic disable.
  • Use a dedicated path with no other behaviour. A webhook route that also serves a page or accepts form posts widens what an attacker can probe.

Testing without deploying anything

Two tools make the first hour painless. Paste a URL from webhook.site as the endpoint and click Send test to see the exact headers and body. Then run your real handler locally behind ngrok, register the tunnel URL, and iterate. Test sends are rate-limited per account, 20 per minute, and resends at 60 per minute, which is plenty for development.

Endpoint rules to know before you build

  • Up to 10 endpoints per account, each with its own secret, scope and event list.
  • URLs must be https:// on a public hostname. Localhost, private network addresses, IPv6 literals and PepoSmart's own domains are refused. This is a server-side request forgery guard, and it is why ngrok exists in the previous section.
  • Endpoints keep their configuration if you downgrade below Professional, but deliveries pause until the plan is restored.
  • Team events are delivered to the event owner's endpoints, not the assigned host's.
Hand pinning cards to a wall to map a workflow
The interesting automations start after the booking: payment reconciliation, CRM enrichment, and reacting to meeting notes

Automations teams actually build

The booking event is the obvious one, but the value tends to come from the events after it.

Provision on booking. A booking.created for a paid consultation creates the client in your practice-management system and sends an intake form from your own domain. If you sell trials, it creates the trial account before the onboarding call so the call starts with a working login.

Reconcile on payment. booking.paid carries the amount and currency. Post it to your accounting system so the ledger matches the payment provider without a monthly export.

Text-message reminders. PepoSmart does not send SMS. A booking.created handler that schedules a text through an SMS provider for 24 hours and 1 hour before startTime adds the channel, and a booking.cancelled or booking.rescheduled handler cancels or moves it. The no-show reduction guide covers the timing.

Enrich the CRM you don't integrate natively. meeting-notes.completed and action-item.created carry the summary, the transcript and the extracted tasks. If your CRM is not one of the ten PepoSmart connects to directly, this is how you write the same data to it. The CRM sync guide describes what native integrations write, which is a useful template for your own handler.

Route follow-ups for review. followup-draft.generated can post to a team channel so a manager sees drafts before reps send them, and followup-draft.sent can stamp the outreach on an internal timeline.

Release resources on cancellation. Rooms, loaner equipment, interpreter bookings: anything reserved on booking.created should be released on booking.cancelled.

Webhooks, Zapier or the REST API?

NeedUse
Push events into a system you build or hostWebhooks
Connect to other apps without codeZapier or Make
Read availability or create bookings from your backendREST API (Business plan and above)
Show the booking page inside your productEmbedding

The three are complementary. A common stack is a webhook for the systems you own, Zapier for the long tail of SaaS tools, and the embed for the booking UI, which the embedding guide covers. Availability and plan details for each are on the pricing page.

Summary

Scheduling webhooks let your systems react to bookings, payments and meeting notes the moment they happen. Verify every request over the raw body with HMAC-SHA256, acknowledge quickly and process asynchronously, key your handler on the delivery id, and alert on a disabled endpoint rather than on individual failures. PepoSmart's webhooks are available on the Professional plan and above, with eight events, signed deliveries, 7-attempt retries and a 30-day delivery log. The full reference, including the meeting-notes payload shapes, is in the developer documentation.

Frequently asked questions

What is a booking webhook?
A booking webhook is an HTTP POST that a scheduling tool sends to a URL you choose the moment something happens: a booking is created, cancelled, rescheduled or paid, or a recorded meeting's notes are ready. Your server receives a JSON message describing the event and can react immediately, without polling an API.
How do I verify a webhook signature?
Read the raw request body exactly as received, recompute an HMAC-SHA256 over the timestamp plus a dot plus the raw body using your endpoint's secret, and compare it with the signature header using a constant-time comparison. Reject timestamps older than a few minutes to block replays. Never re-serialise parsed JSON before hashing, because whitespace differences will break the match.
What happens if my endpoint is down when a webhook is sent?
A well-designed sender retries. PepoSmart treats a non-2xx response, a redirect or no response within 10 seconds as a failure and retries with exponential backoff up to 7 attempts. An endpoint that fails 25 attempts in a row is switched off until you re-enable it, and every delivery is logged for 30 days so it can be resent.
Why did I receive the same webhook twice?
Because delivery is at-least-once. A retry can arrive after your endpoint processed the first attempt but failed to respond in time. Treat the delivery id, which stays the same across retries, as an idempotency key and make your handler safe to run twice.
Should I use webhooks, Zapier or the REST API?
Use webhooks when you own the receiving system and want signatures, retries and a delivery log. Use Zapier or Make when you want to connect to other apps without writing code. Use the REST API when you need to read availability or create bookings on demand from your own backend. Many teams use two of the three.
Which plans include PepoSmart webhooks?
Webhooks are included on the Professional plan and above, the same tier as Zapier and Make. Each account can register up to 10 endpoints, each with its own secret, scope and event list.

Written by

Yash Havalimane

Reviewed by

Zakir Shaikh

Every PepoSmart article is written by a member of our team and checked by a second reviewer before it is published. Product facts are verified against the published product-facts page.

Related Articles

A team lead presenting at a whiteboard to four colleagues seated with laptops in a loft office
Team Scheduling

Round-Robin Scheduling Explained: How It Works, When to Use It, and How to Set It Up

Read More
An empty modern conference room with a long table and chairs beside a floor-to-ceiling window
Scheduling

How to Reduce No-Shows for Appointments and Sales Meetings: 15 Tactics That Actually Work

Read More

Ready to Transform Your Scheduling?

Booking pages, availability rules and an AI notetaker in one place. Free to start, no card required.

PepoSmart

The AI-powered meeting intelligence platform — from scheduling to CRM sync, coaching, and deal intelligence.

Support: +1 (713) 782-7183
Scheduling
  • Unlimited Booking Pages
  • Availability Rules
  • Team Events
  • Reminder Emails
  • Payments at Booking
  • Website Embeds
AI Intelligence
  • AI Meeting Notes
  • Coaching Scorecards
  • Relationship Intelligence
  • Chat With Meetings
  • Follow-up Emails
  • AI Call Prep
Bulk Emailing
  • Broadcasts
  • Email Sequences
  • Mailing Lists
  • Email Templates
  • SMTP Settings
  • Open Tracking
Integrations
  • Google Calendar & Meet
  • Outlook & Microsoft Teams
  • Zoom
  • Slack
  • CRM integrations
  • Stripe & PayPal
Compare
  • Calendly Alternative
  • Cal.com Alternative
  • SavvyCal Alternative
  • Acuity Alternative
  • Chili Piper Alternative
  • All Alternatives
Company
  • Product facts
  • All Features
  • Solutions
  • About
  • Pricing
  • Blog
  • Use Cases
  • Contact
  • Privacy Policy
  • Terms of Service
© 2026 PepoSmart. All rights reserved.
Operated by Peposmart Inc · 18510 Green Land Way, Ste C, Houston, TX 77084, US
Terms of ServicePrivacy Policy