OXYGENOxygen/ Docs
Execution

Triggers

API, cron, webhook, and event starts for workflows.

A trigger is the condition that causes a workflow to run. A workflow revision declares one trigger: API, cron, webhook, or event. The current trigger is visible in oxygen workflows get.

Four kinds

KindFires when
apiA user or agent calls oxygen workflows call or oxygen_workflows_call
cronA cron expression matches the current minute
webhookAn HTTP POST hits the workflow webhook URL
eventA subscribed event is emitted (internal or from an integration)

Every fire produces a run.

Cron

trigger:
  type: cron
  cron: "0 9 * * 1"
  timezone: "America/New_York"

Cron expressions are standard five-field, so the fastest cadence is once per minute — the scheduler evaluates schedules every minute. For sub-minute cadence use a webhook or event trigger (fires per delivery, no cadence floor), or batch the work inside one scheduled run.

Schedules faster than every 15 minutes come back with a warning on apply/enable, and every 2 minutes or faster with a stronger one. Neither blocks — confirm the cadence is intentional.

Use cron for recurring work such as weekly TAM refreshes, daily CRM hygiene, or scheduled enrichment audits.

Scheduled runs execute on Oxygen's managed workers; there is no separate per-run compute fee. Live workflow steps, tool calls, row writes, and retries each meter one automation action, priced in the pricing reference; dry_run and smoke_test cost nothing.

The per-run action count is not what the graph looks like. A recipe bills 1 action per checkpoint its code emits at runtime, so one that loops over 100 items bills 100+ actions on every fire, and a bulk row write bills 1 action per row — on a minute-level schedule that is a different order of magnitude from the same-looking three-node graph. Before arming a hot schedule read the observed burn, not the estimate: oxygen workflows get <id> --json returns usage.estimate (a floor), usage.observed (measured actions per run and the projected 30-day total), and usage.allowance.

Webhook

trigger:
  type: webhook
  trigger_id: inbound-lead

oxygen workflows get <id> --json returns the webhook URL when the workflow has a webhook trigger. POST a JSON payload; the workflow receives it as input.

Workflow webhooks require an Oxygen secret by default because they can enqueue live workflow runs. Send it in x-oxygen-workflow-secret. Use secret_required: false only for provider callbacks that cannot send custom headers and whose downstream workflow effects are safe to expose publicly.

First publish and duplication return the shared secret once; Oxygen stores only its hash. Rotate a leaked or changed sender credential with a preview followed by explicit approval:

oxygen workflows webhooks rotate <workflow> --json
oxygen workflows webhooks rotate <workflow> --approved --json

The prior secret stops authenticating immediately when rotation commits, and the replacement is shown once. Rotation does not publish, enable, or run a workflow. The visual trigger inspector exposes the same confirmation and one-time handoff.

Inspect every received delivery—including rejected authentication and verified deliveries that did not start a run—with:

oxygen workflows webhooks deliveries --workflow-id <workflow-uuid> --json

A verified delivery with outcome=ran that started a run can be replayed as a new safe dry run from its exact original revision and payload:

oxygen workflows webhooks replay <delivery-id> --json

Replay never sends the webhook again, mutates the original run, spends credits, calls a paid provider, performs an external write, or runs that historical revision live. It creates a durable, inspectable Workflow run and stores source delivery/run lineage on that run, but it does not append a synthetic inbound row to webhook delivery history. Supply --request-key when retrying an uncertain client response: the same delivery/key returns the existing replay run instead of creating another. Without one, the CLI generates a key for that invocation. Oxygen internal reads and oxygen.http_json_request outbound GETs can still execute.

Event

Start with the workspace catalog. It combines every trigger-safe event Oxygen produces internally, provider definitions for active connections with exact subscription readiness, and source/event pairs used by existing workflows:

oxygen workflows events list --kind builtin --json
oxygen workflows events get <catalog-id> --json

get returns a ready-to-copy trigger with its source, event, and any preset filters. Built-in events stay visible when setup is incomplete. In that case readiness.status is needs_setup and includes the exact action to take. You can keep that trigger in a disabled draft, but publish/enable refuses to arm it until Oxygen can verify its producer.

The visual inspector turns those filters into explicit AND clauses. Each clause selects a payload path and one supported operator: eq, neq, exists, or not_exists. Comparison values keep their declared type, so text "true" is different from boolean true. Editing a preset stores the clauses in the revisioned trigger manifest and never changes the producer's catalog entry.

The built-in catalog includes Sequencer activity and terminal outcomes, CRM timeline and signal events, and Meeting Notetaker completion. Connected integration definitions are merged into the same picker before their event subscription is enabled; those rows stay selectable as needs_setup and expose the exact repair command. Publish requires both an active provider account and the exact active subscription. Workspace-owned custom events emitted through workflows events emit need no provider setup. The lower-level integrations events commands manage provider subscriptions:

trigger:
  type: event
  source: instantly
  event: email.reply_received
  idempotency_key_path: message.id

Enable an integration event before it can deliver provider events:

oxygen integrations events list --json
oxygen integrations events enable --source instantly --event email.reply_received --json
oxygen integrations events disable --source instantly --event email.reply_received --json
oxygen integrations events deliveries --json

deliveries shows delivery status for provider events, which helps confirm that an external system actually sent the event.

API calls

oxygen workflows call <workflow-id> --input-json '{"id":"123"}' --mode dry_run --json
oxygen workflows call <workflow-id> --input-json '{"id":"123"}' --mode live --approved --max-credits 50 --json

--mode is required, and a live call is refused without both --approved and --max-credits (see Modes). call is fire-and-forget: it enqueues the workflow and returns the run id. Use oxygen workflows tail <workflow-run-id> --json to wait for completion.

Emitting events from a workflow

oxygen workflows events emit --source tenant --event lead.qualified --payload-json '{"id":"lead_123","score":87}' --mode dry_run --json

Other workflows subscribed to lead.qualified will fire. Live emission carries the same --approved / --max-credits pair, where --max-credits is the per-delivery ceiling.

  • Workflows — what triggers fire.
  • Modes — the gate on a live call.
  • Integrations — provider events that can act as triggers.
  • Approvals — even triggered fires require approval before live external writes.

On this page