Public
Cal.com + Attio sync
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

cal-attio

Free, self-hosted Cal.com → Attio booking sync. When someone books, reschedules, cancels, or no-shows a meeting, this val:

  1. verifies the webhook signature (HMAC-SHA256, fails closed),
  2. finds or creates the Attio person by attendee email,
  3. writes the booking to a Bookings list parented to People — one entry per booking, keyed on the Cal.com booking UID, so lifecycle events update the same entry instead of duplicating it.

No database. Attio is the store. Terminal statuses (cancelled / completed / no_show) never regress to confirmed, so Cal.com's unordered webhook retries can't resurrect a dead booking.

Use it yourself

Full setup guide, Attio schema script, tests, and a Cloudflare Workers variant live in the GitHub repo: miqcie/cal-attio-sync

Short version — remix this val, then:

  1. Get an Attio API key: app.attio.com → Workspace settings → Developers (needs record read-write and list read-write scopes).
  2. Run scripts/setup-attio.ts from the repo to create the Bookings list in your Attio workspace.
  3. Set two environment variables on your val (left sidebar): ATTIO_API_KEY and CAL_WEBHOOK_SECRET (any random string).
  4. In Cal.com, create a webhook at app.cal.com/settings/developer/webhooks pointing at this val's HTTP endpoint with that secret, and enable the BOOKING_CREATED, BOOKING_RESCHEDULED, BOOKING_CANCELLED, BOOKING_NO_SHOW_UPDATED, and MEETING_ENDED triggers. (Scripting it instead? Grab an API key at app.cal.com/settings/developer/api-keys and use the repo's scripts/setup-cal.ts.)

Book a test meeting; the booking appears in Attio within seconds, linked to the attendee's person record.

Files

  • main.ts — HTTP entry (thin wrapper)
  • src/core.ts — signature verification, payload normalization, event → status routing
  • src/attio.ts — minimal Attio v2 client (query + PATCH/POST; deliberately not the assert endpoint, which matches on parent and would overwrite a repeat booker's earlier booking)

MIT licensed.