Skip to main content
Run a task or workflow on a schedule across your connected credentials. You define a trigger once, and Deck creates and manages the runs from there. A trigger pairs a schedule with a task or a workflow and a set of credentials. Each time the schedule fires, Deck creates one task run, or one workflow run, per credential in scope, skipping any that don’t need the work. Triggered runs behave exactly like runs you create directly: same lifecycle, statuses, artifacts, and events.

Example

Fetch the latest bill for every connected utility account, every day at 6am Eastern:
Every day at 6am, Deck resolves the credentials matching the filter, skips any whose latest run of this task succeeded within the past 25 days (2,160,000 seconds), and creates a task run for each of the rest.

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 of credential_ids / credential_filter.

An explicit list

The set is static: exactly the credentials you list, one or many, until you change it with a PATCH. There’s no status allowlist because you’ve named them directly. Credentials in the list that are invalid or deleted when the trigger fires are skipped automatically; you don’t need to prune the list.

A filter

Deck resolves the filter each time the trigger fires and creates a run for every match, so enrollment is fully dynamic. A credential created tomorrow that matches the filter starts getting runs on the next fire, with no registration step. Both keys are lists and both are required:
  • source_ids matches credentials on any of the listed sources, or on every source with the ["*"] wildcard.
  • status is an explicit allowlist of credential statuses to fan out to, typically unverified and verified. There is no default. invalid and deleted credentials can’t run, so they never match.
A credential’s open or closed session state is independent of its status. A credential at rest still matches the filter, and the run authenticates a fresh session as needed. A filter that can never match anything (an empty 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 goes invalid (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 returns result: 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

A trigger has a single input, shared by every run it creates. There is no per-credential input. If each user’s run needs a different value from your system (a target date, a confirmation number), a trigger can’t supply it: create those runs from your own code with POST /v2/tasks/{task_id}/run.
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’s input 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

Set workflow_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:
  1. A credential_id or source_id the trigger pins in steps.
  2. The credential the fire is running for.
  3. The step’s own definition.
So the fanned-out credential fills in every step the trigger doesn’t pin, and a pinned step keeps its own. That’s how a scheduled workflow can log in with each user’s credential and then act on a second source with a fixed one. A step whose definition sets 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.
The first step’s input is the same for every credential and every fire. It can only come from the workflow definition or the trigger’s steps, because there’s no earlier step to reference. Later steps can vary per credential by reading what earlier steps returned, so design the first step to discover what it needs from the logged-in source rather than expecting per-user parameters.
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 null clears description, skip_if, or concurrency_max, and credential_ids replaces the existing list wholesale.
  • Pause and resume by setting status to inactive or active; there are no separate endpoints. An inactive trigger 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.
To see which credentials are currently in scope (the set that gets runs on the next fire), use 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: a trigger_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:
A triggered workflow run carries 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_max caps simultaneous runs from one trigger. A fan-out matching 2,000 credentials with concurrency_max: 50 runs 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.
You don’t manage 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 by trigger_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 credential invalid and it leaves the fan-out on its own, resuming once the user re-authenticates. See Invalid credentials. Runs that fail with password_reset_required or account_locked don’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.failed event rather than failing silently.

Auto-deactivate

If a trigger’s fires keep failing (default threshold: 5), it transitions to inactive 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.
The runs a fire creates emit their own standard task_run.* or workflow_run.* events, tagged with trigger_id, so existing handlers work for scheduled runs without changes.