Documentation Index
Fetch the complete documentation index at: https://docs.gainable.dev/llms.txt
Use this file to discover all available pages before exploring further.
The closed vocabulary
Every playbook starts from one of exactly four trigger types. Nothing else. The closed vocabulary is deliberate. It keeps agents auditable, predictable, and easy to reason about.| Trigger | Started by | Use for |
|---|---|---|
| Schedule | Cron expression | Daily briefings, weekly digests, time-based SLA checks |
| Data change | Change-stream events on a collection | Reactive work tied to record state |
| Webhook | Inbound HTTP from an external system | Stripe events, SendGrid bounces, GitHub issues |
| User-triggered | Explicit button click in the app | ”Draft me a recap,” “Run this playbook now” |
Schedule
A cron-style schedule. The runtime fires the playbook at the specified time.Common cron patterns
| Pattern | Meaning |
|---|---|
0 8 * * * | Every day at 8 AM |
0 9 * * 1-5 | Weekdays at 9 AM |
0 */4 * * * | Every 4 hours |
0 0 1 * * | First of every month at midnight |
*/15 * * * * | Every 15 minutes |
Timezone handling
For personal-scope playbooks, the timezone resolves to the user’s timezone. For app-wide playbooks, the timezone is set on the trigger.When to use schedule
- Recurring digests, briefings, and reports
- Time-based SLA enforcement (“any open ticket older than 24 hours”)
- Periodic refreshes (“recompute pipeline forecast every Monday”)
Data change
A change-stream event on a collection. The runtime observes inserts, updates, and deletes, and fires the playbook when an event matches the filter.Operations
| Operation | Fires when |
|---|---|
create | A new record is inserted |
update | An existing record’s fields change |
delete | A record is removed |
Field-level filters
Thewhere clause can reference the new state of the record. For updates, it can also reference what changed:
When to use data change
- Reactive work tied to a state change (“when a deal moves to lost…”)
- Onboarding flows (“when a new contact is created…”)
- Anomaly detection (“when an order’s total exceeds $50,000…”)
The change-stream pattern is the same one Gainable uses internally for the email daemon and other observation services. The runtime does the heavy lifting; the playbook just describes the filter.
Webhook
An inbound HTTP request from an external system. The runtime exposes a unique URL per webhook and fires the playbook when a request arrives.How webhook URLs work
When you configure a webhook trigger, Gainable provisions a URL like:trigger.body to the playbook.
Common sources
| Source | Example events |
|---|---|
| Stripe | invoice.payment_failed, customer.subscription.deleted |
| SendGrid | bounce, spamreport |
| GitHub | pull_request.opened, issue_comment.created |
| Calendar | event.created, event.updated |
| Generic | Any system that can POST JSON |
When to use webhook
- Reacting to events in external systems you don’t own
- Bridging Gainable apps to third-party tools
- Receiving callbacks from long-running external jobs
User-triggered
An explicit button click in the app. A user opens a record (or a page) and clicks a button labeled “Run this playbook now.”How it appears
Gainable renders user-triggered playbooks as buttons in the Autopilot widget on the page you specified. When the user clicks:- The runtime fires the playbook with
trigger.user_idset to the clicker - The playbook runs with that user’s permissions
- The resulting draft (if any) lands in their personal Autopilot inbox
When to use user-triggered
- On-demand drafts (“write me a follow-up for this deal right now”)
- Bulk operations the user wants to start manually
- Anything the user wants control over the timing of, even if the rest of the playbook is automatic
Choosing the right trigger
| Question | Answer |
|---|---|
| Does this need to happen at a specific time of day? | Schedule |
| Does this react to a record changing? | Data change |
| Does this come from an external system? | Webhook |
| Should the user choose when this runs? | User-triggered |
Best practices
Prefer data change over polling on a schedule
Prefer data change over polling on a schedule
A
schedule trigger that scans a collection every 5 minutes is almost always worse than a data_change trigger that fires only on the relevant transition. Faster, cheaper, and more accurate.Filter at the trigger, not in the playbook
Filter at the trigger, not in the playbook
The more selective the trigger’s
where clause, the less work the runtime does and the cleaner your action log gets.Use timezones for personal schedules
Use timezones for personal schedules
A daily briefing fired at 8 AM UTC is 3 AM in California. Bind the timezone to the user.
Test webhooks in simulation
Test webhooks in simulation
Webhook triggers can be tested by replaying captured payloads. Always do this before going live.
Learn more
Playbooks
Trigger, steps, and guardrails together
Tools
What playbooks call after the trigger fires
Connect outbound
Webhooks and external systems
Inbox
Where user-triggered buttons render