Example
Fetch the latest bill for every connected utility account, every day at 6am Eastern:Definition fields
The response is the full trigger object (
trg_ prefix) with status: "active". Triggers fire on their schedule from the moment they’re created.
The schedule
condition defines when the trigger fires: a cron expression evaluated in a timezone.
An invalid cron expression or timezone is rejected at create time with a standard validation error.
Missed occurrences are skipped, not replayed. If a trigger sits
inactive across several scheduled times, reactivating it resumes at the next future occurrence; Deck never back-fills fires it missed.
Choosing credentials
Every trigger targets credentials one of two ways. Pass exactly one ofcredential_ids / credential_filter.
An explicit list
invalid or deleted when the trigger fires are skipped automatically; you don’t need to prune the list.
A filter
source_idsmatches credentials on any of the listed sources, or on every source with the["*"]wildcard.statusis an explicit allowlist of credential statuses to fan out to, typicallyunverifiedandverified. There is no default.invalidanddeletedcredentials can’t run, so they never match.
status, or an empty source_ids) is rejected when you create or update the trigger with a standard validation error, rather than accepted as a trigger that fires and creates nothing.
Invalid credentials
When a credential goesinvalid (the source rejected its login), Deck emits a credential.invalid event so you can prompt the user to re-authenticate. Under a filter, the credential drops out of the match entirely; under an explicit list, it stays listed but is skipped. Either way the trigger keeps running for every healthy credential, and once the user re-authenticates, runs resume automatically on the next fire.
The trigger doesn’t track credential failures itself; a credential’s status determines whether it runs.
Skip conditions
skip_if is evaluated per credential each time the trigger fires, before a run is created. When it’s met, the credential is skipped this time and no run is created.
last_run looks at the credential’s most recent completed run of the trigger’s task, whether that run came from this trigger or from a direct API call. If its result matches within the window, the credential is skipped.
result is the task run’s result field: success, failure, or unknown.
For a workflow target, last_run looks at the credential’s most recent run of that workflow and reads the workflow run’s result, which is success only when every task run inside it succeeded. A loop under failure_behavior: continue with one failed item makes the run a failure, so the credential runs the whole workflow again on the next fire.
Design the task so skipping self-heals
The utility bill case works when the task’s success criteria mean “did the work”: a run that fetches a bill returnsresult: success, and a run that finds no new bill completes with result: unknown. After a bill is fetched, the credential is skipped for 25 days, and checking resumes once the window lapses, in time for the next bill. This comes from how the task defines success rather than from any trigger setting. If a no-bill run reported success, it would suppress the checks that should follow.
Using skip conditions to control cost
Every run executes in a real agent session. 10,000 credentials on a daily schedule is roughly 300,000 runs a month without skipping. With a 25-day success window, each credential only runs on the few checking days before its next bill lands, roughly 50,000 runs a month. Pick a window slightly shorter than the real cadence of the data.Inputs under fan-out
If the variation is per account within a credential rather than per credential, a workflow can handle it: one step discovers the accounts on the source and a loop runs the work for each. See Targeting a workflow. The trigger’sinput is validated against the task’s input_schema, the same shape as the POST /v2/tasks/{task_id}/run body. Fields the task declares as tokenized are vaulted when you create the trigger, exactly as they are at run time.
Per-user differentiation comes from the credential, not the input. Each run executes in that credential’s authenticated session, so a task like “fetch the latest bill” runs with input: {} and fetches the right bill for whoever’s logged in. Design tasks you plan to schedule this way: operate from the logged-in context and discover what’s needed on the source, rather than expecting per-user parameters.
Targeting a workflow
Setworkflow_id instead of task_id to run a workflow on the schedule. Each fire creates one workflow run per credential in scope, and everything else about the trigger works the same way: credential scope, skip conditions, concurrency, and failure handling.
steps takes the place of input, which isn’t accepted on a workflow target. It has the same shape as the steps array on POST /v2/workflows/{workflow_id}/run: per-step overrides, each naming a step and supplying input, credential_id, or source_id. Steps you don’t list run as defined. Deck validates steps against the workflow when you create the trigger, so a bad step name is rejected here rather than at fire time.
Each step’s credential resolves in this order:
- A
credential_idorsource_idthe trigger pins insteps. - The credential the fire is running for.
- The step’s own definition.
source_id needs no credential and runs as defined.
A workflow trigger can also omit credential_ids and credential_filter entirely. Every step must then resolve its own credential or source, and each fire creates a single run instead of fanning out.
Like input, steps is fixed until you update the trigger. A value that has to change between fires, such as a cutoff date, is updated with PATCH /v2/triggers/{trigger_id} before the next fire.
Managing triggers
Creating, listing, updating, and deleting triggers is covered endpoint by endpoint in the API reference. For day-to-day management (pausing a schedule, editing a filter, checking what’s enrolled, reviewing recent fires), the Console is usually the quicker path: the Triggers page lists every trigger, and each task’s or workflow’s detail page shows its own. The semantics that aren’t obvious from the endpoint docs:- Updates take any subset of fields, and omitted fields are left unchanged. An explicit
nullclearsdescription,skip_if, orconcurrency_max, andcredential_idsreplaces the existing list wholesale. - Pause and resume by setting
statustoinactiveoractive; there are no separate endpoints. Aninactivetrigger keeps its configuration and fires nothing, and reactivating resumes at the next scheduled occurrence. - A trigger’s target can’t be changed. To point at a different task or workflow, create a new trigger.
GET /v2/triggers/{trigger_id}/credentials or the Console’s enrollment view. In the other direction, a credential’s GET response lists the triggers targeting it.
Tracing runs to a trigger
Triggered runs are normal task runs with one addition: atrigger_id field, always present and null unless the run was created by a trigger. Filter runs by it to inspect a single fire or audit a trigger’s history, combined with the existing task run filters:
trigger_id the same way, and so do the task runs inside it:
Queueing and concurrency
Triggered runs don’t all execute at the same instant. Each run needs an agent session, and runs are admitted as capacity frees up.- Per trigger.
concurrency_maxcaps simultaneous runs from one trigger. A fan-out matching 2,000 credentials withconcurrency_max: 50runs 50 at a time, with the rest queued. - Per organization. Scheduled runs draw on their own capacity pool, separate from on-demand runs, and on-demand runs are admitted first. A large overnight fan-out never delays a user-facing
POST /v2/tasks/{task_id}/run.
session_limit_exceeded for scheduled work. Deck queues internally and admits runs as slots free up.
Overlapping fires
If a trigger fires again while the previous fire’s runs are still draining, Deck coalesces: the newer fire supersedes any still-queued run for the same credential, so the freshest scheduled work wins. Runs that are already executing are left alone.Exactly-once per occurrence
Each fire is keyed by the trigger and its scheduled time, so a duplicate delivery of the same occurrence never creates a second batch of runs.Failure handling
A failed triggered run is a normal task or workflow run: queryable bytrigger_id and status, carrying the standard errors array. What happens next depends on the error class:
- Transient (
source_not_available,blocked,timeout): nothing special. The credential simply runs again on the next fire. - Credential (
auth_invalid): the agent marks the credentialinvalidand it leaves the fan-out on its own, resuming once the user re-authenticates. See Invalid credentials. Runs that fail withpassword_reset_requiredoraccount_lockeddon’t change the credential’s status; the credential stays in scope and fails on each fire until the user resolves the issue on the source. - Configuration (a deleted task or workflow, input or steps that no longer validate): these fail the fire itself, surfaced as a
trigger_run.failedevent rather than failing silently.
Auto-deactivate
If a trigger’s fires keep failing (default threshold: 5), it transitions toinactive and emits trigger.deactivated with the reason, so a misconfigured trigger doesn’t keep failing on schedule indefinitely. This deactivates the whole trigger, never individual credentials. A deactivated trigger shows on its task’s or workflow’s detail page in the Console along with the failed fires that got it there. Once the configuration is fixed, reactivate it from the same page or with PATCH { "status": "active" }.
Events
Triggers emit into the existing events system on two channels. Lifecycle events track the configuration object:
Trigger run events track each fire. A trigger run (
tgrn_ prefix) is one scheduled execution: the fan-out across credentials that creates the underlying runs.
task_run.* or workflow_run.* events, tagged with trigger_id, so existing handlers work for scheduled runs without changes.