Alexandr Chibilyaev explains the AACFlow trigger system: webhook triggers, polling triggers, cron schedules, and the architecture that lets AI agents respond to real-world events in milliseconds.
An AI agent that sits idle until someone clicks a button is a toy. An AI agent that wakes up when a customer pays, when a lead appears in the CRM, or when a deployment fails—that's infrastructure.
This is what the AACFlow trigger system is built for. Not scheduled batch jobs. Not polling loops that waste CPU cycles. Real, event-driven awakening of your AI agents—exactly when something happens.
The fastest way to wake up an agent. An external service sends an HTTP POST to an AACFlow webhook URL, and the trigger fires immediately. No polling. No delay.
1
// TriggerConfig for a webhook trigger
2
{
3
id:'stripe_payment',
4
name:'Stripe Payment',
5
webhook:{
6
method:'POST',
7
},
8
subBlocks:[...],
9
outputs:{
10
eventType:{type:'string'},
11
amount:{type:'number'},
12
customerId:{type:'string'},
13
paymentStatus:{type:'string'},
14
}
15
}
Every trigger instance gets a unique webhook URL: https://api.aacflow.io/webhooks/trig_{workflowId}_{instanceId}. You paste that URL into Stripe, GitHub, AmoCRM, or any of the 50+ services we support. When an event fires—a payment succeeds, a PR is opened, a new lead is created—the webhook hits our endpoint, the trigger validates the payload, resolves it into structured outputs, and passes control to the DAG executor.
The webhook handler validates HMAC signatures where supported (Stripe, GitHub). Invalid payloads are rejected before they touch your agent. No spoofed events. No garbage-in-garbage-out.
Real example: GitHub push trigger. A developer pushes to main. GitHub fires a webhook to AACFlow. Your agent picks up the commit SHA, runs the test suite, deploys to staging, posts the result to Slack. All within seconds of the push.
Real example: Stripe payment failed. A customer's subscription payment fails. Stripe fires a charge.failed webhook. Your agent picks it up, looks up the customer in your CRM via the AmoCRM block, generates a personalized recovery email via an LLM block, sends it through Gmail, and creates a follow-up task. The customer gets an email within 30 seconds of the failed payment, not "sometime this week."
Not every service supports webhooks. For those, AACFlow supports polling triggers.
A polling trigger checks an external service every N minutes—every 1 minute, every 5 minutes, every hour, whatever makes sense for the use case. It calls the service's API, compares the current state with the previous state, and fires only when something actually changed.
The key difference from naive polling: we track state between polls. If you're checking a CRM for new leads, we store the ID of the last lead we processed. The next poll only picks up leads created after that ID. No duplicates. No missed records.
1
// Polling trigger — the `polling: true` flag
2
{
3
id:'amocrm_new_lead',
4
name:'AmoCRM New Lead',
5
polling:true,
6
subBlocks:[
7
{id:'pollInterval',type:'dropdown',
8
options:['1m','5m','15m','30m','1h']}
9
],
10
outputs:{
11
leadId:{type:'string'},
12
leadName:{type:'string'},
13
leadPhone:{type:'string'},
14
leadEmail:{type:'string'},
15
}
16
}
The trigger registry handles polling lifecycle: scheduling, state tracking, error handling, and back-pressure. If a poll fails (rate limit, network error), it retries with exponential backoff. If it keeps failing, it alerts you. Your agent doesn't silently miss events.
Sometimes the trigger isn't an external event at all. It's a time. "Every Monday at 9 AM, generate a weekly sales report." "Every day at midnight, reconcile payments." "Every hour, check if any critical metrics have crossed thresholds."
Schedule triggers use standard cron expressions. Five fields: minute, hour, day of month, month, day of week. Familiar to every developer and DevOps engineer.
1
09**1 → Every Monday at 9AM
2
00*** → Every day at midnight
3
0*/6*** → Every 6 hours
4
*/5**** → Every 5 minutes
Schedule triggers don't receive external data—they don't have outputs in the same sense. Instead, they execute a workflow at the specified time. The workflow itself queries the data it needs: call the Sber Business connector for today's transactions, call the Yandex.Metrica block for yesterday's traffic, generate a report, post it to Slack.
All triggers—webhook, polling, and schedule—are defined in a single TriggerRegistry. Adding a new trigger to the platform means:
Define a TriggerConfig with an ID, name, subBlocks (for UI configuration), and outputs (the data structure passed to the workflow)
Register it in the triggerRegistry object
The platform handles the rest — webhook URL generation, HMAC validation, polling scheduling, cron parsing, output resolution, workflow execution
The handler infrastructure is shared. A webhook trigger for GitHub and a webhook trigger for Stripe use the same HTTP handler. The only difference is the configuration UI and the output shape. This uniformity is what lets us support 50+ trigger types without duplicating infrastructure.
The trigger handler validates the incoming payload
It resolves the trigger's outputs from the payload data
It injects those outputs as the workflow's initial input variables
The DAG executor picks up the workflow graph and starts execution
The workflow doesn't know or care how it was triggered. It receives input variables—trigger_eventType, trigger_amount, trigger_customerId—and executes its graph. The trigger is decoupled from the execution. This means the same workflow can be triggered by multiple triggers. A "handle new customer" workflow can be triggered by a Stripe webhook (payment received), an AmoCRM webhook (lead created), or a manual run. Same logic, different ignition sources.
Pattern 1: Lead qualification pipeline. When a new lead appears in AmoCRM → webhook trigger fires → agent qualifies the lead against scoring criteria → enriches with Dadata and SPARK-Interfax data → assigns to the right sales rep → creates a task in Bitrix24 → sends a personalized WhatsApp message. From raw lead to in-progress opportunity in under a minute.
Pattern 2: Payment failure recovery. When a payment fails in CloudPayments → webhook trigger fires → agent looks up the customer's payment history → generates a recovery email → sends it via Gmail → schedules a retry attempt in 24 hours via a delayed queue. If the first retry fails, it escalates to a human with full context.
Pattern 3: Infrastructure monitoring. Every hour → schedule trigger fires → agent queries the VPS via SSH block → checks disk usage and service health → if anything is above threshold → posts an alert to Slack with the specific metric and a suggested fix. No more waking up to a full disk at 3 AM.
Pattern 4: Invoice processing. A new invoice arrives in Diadoc → webhook trigger fires → agent extracts line items, amounts, and counterparty data → validates against the contract in the knowledge base → if valid, triggers payment through the Sber Business connector → updates 1C with the payment record. End-to-end accounts payable automation.
Webhook reliability is harder than it looks. External services retry webhooks with varying patterns. Stripe retries for 3 days. GitHub retries for a few hours. You need idempotency at the webhook ingestion layer—processing the same event twice must not create duplicate actions. We use unique event IDs (stripe_evt_12345) as deduplication keys across the entire trigger pipeline.
Polling state management is subtle. If you track "last processed ID" and your processing fails after updating the ID, you've permanently lost that record. We use two-phase state: mark as "processing," process, then mark as "processed." If the system crashes mid-processing, the next poll picks it up again.
Cron in a distributed system. When you have multiple server instances, every instance sees the cron tick. You need leader election or a dedicated scheduler to ensure triggers fire exactly once, not N times. We run a dedicated scheduler worker that owns all cron-based triggers. No duplicates.
The hardest part: the non-technical ones. "What does this field mean in the Stripe webhook payload?" "Why does AmoCRM's webhook sometimes omit the phone number?" "How do you map the 47 possible GitHub event types to a clean output structure?" The engineering challenge isn't building the trigger infrastructure—it's understanding every external service's idiosyncratic event model and distilling it into a clean, consistent experience for the agent builder.
Triggers are the sensory system of your AI agents. Without them, agents are blind and idle. With them, agents become proactive—responding to business events faster than any human team could. Webhooks, polling, schedules—each has its place. Together, they make your agents feel alive.