This val summarizes recent Attio events on Slack.
It receives webhooks from Attio, stores them in a SQLite database, and periodically sends AI-generated summaries of recent activity to Slack. The system uses OpenAI to transform raw webhook data into human-readable summaries, helping teams stay informed about CRM activity without being overwhelmed by individual notifications.
- Remix this val
- Get a Slack webhook
& set it as
SLACK_WEBHOOK_URL
in this val's Environment variables in the left sidebar - Get an Attio Access Token
(with all read & write permissions) & set it as
ATTIO_API_KEY
in this val's Environment variables in the left sidebar - Go to
setup.ts
and click run to set up the events database and Attio webhook - Go trigger some Attio events and see the message in Slack!
attio/hydrate.ts
- Converts raw webhook events into human-readable descriptionsattio/webhook.ts
- Attio webhook management and secret handlingattio/webhook-payload-types.ts
- Complete TypeScript types for all Attio webhook eventsalert.ts
- Cron job that processes recent events and sends Slack summariesauth.ts
- Webhook signature verification middlewareopenai.ts
- AI-powered event summarization using OpenAIscratch.ts
- Development scratchpad for testing functionssetup.ts
- One-time setup script to initialize database and Attio webhookslack.ts
- Utility to send messages to Slack via webhooksqlite.ts
- Database operations for storing and retrieving Attio eventswebhook.ts
- HTTP endpoint that receives webhooks from Attio
Attio webhooks return thin events, which contain a bunch of IDs, but no human-readable data, such as:
{ event_type: "record.merged", id: { workspace_id: "b6c564a6-2cf7-49ab-9320-dea013196bd7", object_id: "a87cf74e-5ca1-4a8d-b8d3-fcca5413d4c3", record_id: "d64ff9f2-d1f1-424c-8be6-e41129e35697" }, duplicate_object_id: "a87cf74e-5ca1-4a8d-b8d3-fcca5413d4c3", duplicate_record_id: "112b5c78-1ffe-457a-8366-181b482888b4", actor: { type: "system", id: null } }
The trickiest part of this val was hydrating these events into human readable form, like "Steve commented on OpenAI: they're using Val Town!"
After trying and failing (for hours!) to get LLMs to write this code for me, I eventually bit the bullet and wrote it by hand. I only handled some of the more common event types, and left myself comments of other example events of types I haven't handled yet.
In theory, Attio has a better way to handle this, analgous to Stripe's method to fetch data for thin events, but I wasn't able to find it. If you figure it out, please send me a pull request or let me know at steve@val.town.