Docs

Flows

Automations without servers: when a webhook, schedule, table or collection change, queue message or form fires, run steps — HTTP calls, functions, database writes, email, AI — with branches, loops, waits, retries and a full run history.

Updated Nov 12, 2026

A flow is a graph of steps. One or more triggers start it; each step gets the items the step before it sent, does its work, and passes items on. Flows run alongside your functions: every run is durable (a crash or restart resumes it), every step is recorded with its input, output and error, and a failed run can be retried from the step that failed.

Triggerwebhook · schedule· event · formTransformEdit fields, CodeIftrue / falseInsert rowas the serviceroleSend emailmessaging

#Triggers and steps

KindSteps
TriggersManual (Test run), Webhook, Schedule, Sovaria event (table rows, documents, auth users, storage objects, realtime messages), Queue message, Form, Sub-flow, Error flow; app triggers poll Google Drive, Sheets, Gmail, Calendar and Telegram.
Flow controlIf, Switch, Filter, Merge, Loop over items, Wait (time or a signal), Approval, Sub-flow, Respond to webhook, Stop with error.
DataEdit fields (set / rename / keep), Code (JavaScript or Python in the sandbox), Sort, Limit, Remove duplicates, Aggregate, Summarize, Split out, Date & time, Crypto, HTML extract, Convert, Compare.
SovariaSQL, Table rows (get / insert / update / upsert / delete), Documents, Storage, Send message (email, SMS, push, in-app), Realtime publish, Run a function, Send to a queue, Analytics event.
AIAI (complete, classify, extract, summarise), Agent run, Knowledge base search — billed as Sovariq credits.
Network and appsHTTP Request (any public API, with pagination), and 13 apps (Google Drive, Sheets, Gmail and Calendar; Microsoft Outlook, OneDrive and Excel; Slack, Notion, GitHub, HubSpot, Airtable, Stripe, Twilio, Discord, Telegram, OpenAI, Anthropic) plus generic OAuth2, API-key, bearer, Basic and header auth, through Integrations connections. Apps that sign in with OAuth use Sovaria's app where staff have set it up, or your project's own OAuth app (Connections › Use your own OAuth app, which shows the redirect URL to register); the Connections page says which is available.

Any text setting can hold an expression: {{ $json.email.toLowerCase() }} reads the current item, {{ $('Shape').item.json.total }} reads another step, $now, $execution.id and $vars are there too. Expressions are evaluated safely (no code runs); use a Code step for logic.

#Build one in the console

  1. Functions › Flows › New flow

    Start blank or from a template (Stripe payment → row + email, form → Slack, nightly report…).

  2. Pick a trigger, then add steps

    Click + on a step’s output to add the next one, or drag from an output handle onto a step. Hover or click a connection for + (add a step in between; later steps move right) and the bin (remove it); Delete removes a selected connection. From the keyboard: select a step, press ] or [ to move through its connections, or use the Connections list in the step’s settings. Click a step to set it up; settings with {{ }} take expressions.

  3. Test run

    Run the draft once with sample data (JSON), or listen for one real request on the webhook’s test URL. Each step shows the items it got and sent; click a step to see its input and output.

  4. Publish, then turn it on

    Edits save as a draft. Publish makes a version; the live flow runs only the published version, and only while it’s on. Versions lets you put an older version back in the draft.

#Webhooks are always protected

A webhook URL looks like https://<project-ref>.sovaria.in/hooks/flows/<flow-id>/<path>?token=<flow token>. Every webhook checks the caller one of four ways:

AuthenticationThe caller sends
URL token (default)The full URL from the editor (it ends in ?token=…), or the token in an X-Flow-Token header. Sovaria makes one token per flow; New token in the step panel (or sov flows rotate-token) replaces it and old URLs get 401 at once.
Header valueA header (default X-Webhook-Token) equal to a project secret.
Basic authAuthorization: Basic … matching a project secret user:password.
HMAC signatureA signature with a project secret in the sender's own format. Signature format: Stripe (Stripe-Signature: t=…,v1=…), Slack (X-Slack-Signature with X-Slack-Request-Timestamp), GitHub (X-Hub-Signature-256: sha256=…), Shopify (X-Shopify-Hmac-Sha256, base64), Standard Webhooks (webhook-id, webhook-timestamp, webhook-signature: Svix, Resend, Clerk), or a plain HMAC-SHA256 of the body as hex or base64. Detect from the header (the default) picks the format from the header name.
  • Stripe, Slack and Standard Webhooks sign a timestamp too: a request more than 5 minutes old (change it with Timestamp tolerance, 30 seconds to 1 hour) is refused. A second delivery of a request already accepted (a sender's retry, GitHub's Redeliver) is answered 200 {"ok": true, "duplicate": true} without running the flow again; GitHub and Shopify sign no timestamp, so their repeats are matched by delivery id and body: that catches duplicate deliveries, but a captured request replayed with a new delivery id isn't caught. Keep their URLs and secrets private.
  • Signatures are compared in constant time. Put the provider's signing secret in a project secret (for Stripe the endpoint's whsec_…, for Slack the app's Signing Secret) and name it in Secret.
  • Slack's Events API checks a new URL with a signed url_verification request: the webhook answers its challenge itself and the flow doesn't run. The Slack event → database row template is set up for this.

#Runs, errors and retries

  • Run history (Runs in the editor, sov flows runs): every execution with its mode (test run, webhook, schedule, event…), version, time and status; open one to see each step’s items, time and error.
  • When a step fails it stops the run by default. Per step you can instead *continue* with the error as the item, send the error to an extra error output, and retry up to 10 times with a wait between tries.
  • Retry a run from the step that failed — it gets the same input the failed step had — or from the start on the latest published version. Cancel stops a run that is still going.
  • Error flow: in the flow’s settings, name another flow to run whenever this one fails (it starts with an Error trigger).
  • Secrets never show in runs. Any project secret or connection token a step used is replaced by [secret] in that step’s output, errors and webhook responses, even when an API echoes it back.

#Security

  • HTTP Request steps reach public addresses only: URLs are checked (no IP literals, no localhost or internal names) and calls go through the same egress proxy as functions, which refuses private, loopback and link-local addresses on every redirect.
  • Steps that touch your data (SQL, rows, documents, storage, messages) call the Sovaria API as the project’s service role: your access rules for the service role, plan limits, metering and the audit log all apply.
  • Flows belong to one project and environment; nothing crosses projects. Editing and publishing need functions.deploy; test runs, retries and approvals need functions.invoke; viewing needs functions.read.
  • Every run is capped: steps per run (loops count every round), items per step, data per run and the longest wait — see the limits below. A runaway loop stops with PLAN_LIMIT_REACHED.

#Plan limits

FreeProUltraTeamEnterprise
Flows per project (flow.flows)5502005002,000
Flow runs per month (flow.executions_month)1,00025,000100,000500,0002,000,000
Steps per run, every loop round counted (flow.nodes_per_run)2002,0005,00010,00020,000
Shortest gap between scheduled runs (flow.schedule_min_minutes)15 min5 min1 min1 min1 min
Highest form submissions a minute per visitor a flow may allow (flow.form_per_visitor_per_min)301203006001,000
Unfinished runs per project (flow.executions_active)201,0005,00020,000100,000
Run history kept (flow.history_days)1 day7 days14 days30 days30 days
Longest Wait or Approval (flow.wait_days)1 day7 days30 days90 days365 days
Items one step may output (flow.items_per_node)2,00020,00050,000100,000100,000
Data one run may hold (flow.execution_bytes)4 MB16 MB32 MB64 MB64 MB

Runs per month count executions started by triggers (webhooks, forms, schedules, events, queues, app polling). Test runs, retries and sub-flow calls don’t count. A redelivered event starts nothing new and isn’t counted twice. When the month’s runs are used up, triggers are refused with PLAN_LIMIT_REACHED and the flow’s run history shows each refused run. Schedules faster than your plan allows are refused when you turn the flow on; app triggers poll no faster than it. A public form takes at most 20 submissions a minute from one visitor (an IPv6 /64 counts as one) and the flow’s webhook rate limit overall. A kiosk or an event check-in where everyone shares one network can raise the per-visitor cap in the flow’s settings (Form submissions per visitor a minute, form_per_visitor_per_min, up to your plan’s flow.form_per_visitor_per_min; after a downgrade the plan’s value applies); a webhook that answers after the flow ran waits up to 25 seconds, or answers 202 with the execution id at once when Sovaria is already waiting on many such calls.

#From code and the CLI

sov flows create "New signup" --template stripe-paid
sov flows pull flw_123 > flow.json     # edit the graph, then
sov flows push flw_123 flow.json
sov flows test flw_123 --data '{"email": "ada@example.com"}'
sov flows publish flw_123 --note "first version" && sov flows on flw_123
sov flows runs flw_123 --status error
sov flows retry fex_456                # from the failed step
sov flows rotate-token flw_123         # new webhook URL token

#Coming from Firebase or Supabase?

PlatformWhat this is called there
FirebaseCloud Workflows / Eventarc (and Zapier-style tools)
SupabaseNo built-in equivalent (n8n or Zapier alongside Supabase)
SovariaFlows

Moving an existing app? Migrate from Supabase or Firebase imports users (with their passwords), data, files and rules.