.flow files
.flow files use the same syntax as .http files but add directive comments for chaining requests, extracting response values, persisting state, and asserting behavior. Requests run sequentially, top to bottom.
A complete example
Section titled “A complete example”### Step 1 · Create user# @name createUserPOST {{baseUrl}}/usersContent-Type: application/json
{ "name": "Jane", "email": "jane@example.com" }
# @extract userId = $.id# @extract userName = $.name# @assert status == 201# @assert body contains Jane
### Step 2 · Fetch created userGET {{baseUrl}}/users/{{userId}}# @assert status == 200# @assert body contains {{userName}}
### Step 3 · Delete userDELETE {{baseUrl}}/users/{{userId}}# @assert status == 204Run with ⌘Enter or the ▶ button. The Flow Runner shows an animated pipeline with pass/fail badges per step.
Extraction — @extract
Section titled “Extraction — @extract”Use JSONPath to pull values out of a response body. Extracted variables are available in all subsequent steps.
# @extract id = $.id# @extract first = $.users[0].name# @extract count = $.meta.total# @extract token = $.auth.access_tokenAssertions — @assert
Section titled “Assertions — @assert”# @assert status == 200# @assert status != 404# @assert status >= 200# @assert status < 300# @assert body contains "success"# @assert body matches ^\{ ← regex# @assert header[content-type] contains jsonAll assertions in a step are evaluated after the request completes. A failing assertion stops the flow at that step.
Naming steps — @name
Section titled “Naming steps — @name”### Login# @name loginPOST {{baseUrl}}/auth/loginContent-Type: application/json
{ "email": "dev@example.com", "password": "{{PASSWORD}}" }
# @extract token = $.access_tokenSkip & retry
Section titled “Skip & retry”### Optional step (won't run)# @skipGET {{baseUrl}}/health
### Flaky endpoint — retry up to 3 timesGET {{baseUrl}}/health# @retry 3Persist extracted values — @persist
Section titled “Persist extracted values — @persist”@persist writes an extracted value into <env>.env.local so other files and future runs can use it — even across app restarts.
### LoginPOST {{BASE_URL}}/auth/loginContent-Type: application/json
{ "email": "dev@example.com", "password": "..." }
# @extract token = $.access_token# @assert status == 200
# Save the token for future runs# @persist token
# Or write with a different key name# @persist API_TOKEN = {{token}}Rules:
- Persists run after all
@asserts — a failing assertion prevents any persist in that step. - Persists are silently skipped when the active env is named
prodorproduction. - Sendpad auto-adds
*.env.localto your workspace.gitignore.
See Environment Variables for full .env.local details.
Literate testing
Section titled “Literate testing”Non-directive # comments become prose in the test report. When you run a flow, the Results Panel renders prose alongside results — a document that reads like documentation but is also a live test.
# User CRUD Lifecycle## This flow validates the complete lifecycle of a user resource.# It creates a user, fetches them by ID, and deletes them at the end.
@baseUrl = https://api.example.com
### Step 1 · Create user# We create a new user and capture the returned ID for later steps.# @name createUserPOST {{baseUrl}}/usersContent-Type: application/json
{ "name": "Test User" }
# @extract userId = $.id# @assert status == 201Click Export as Markdown to save the report for sharing.
SSE assertions — @expect event & @extract event
Section titled “SSE assertions — @expect event & @extract event”When a step streams Server-Sent Events, you can assert on specific events without leaving the flow:
### Stream completionGET {{baseUrl}}/v1/chat/completionsAccept: text/event-stream
# @expect event completion within 10000# @expect event done# @extract event last = completion# @assert last contains "final-answer"| Directive | Description |
|---|---|
@expect event <name> | Require an SSE event of this type; optional within <ms> timeout |
@extract event <var> = <name> | Capture the last payload of the named event |
@sse-timeout <ms> | Override the default stream timeout |
@sse-reconnect on|off | Toggle automatic reconnect on disconnect |
See the SSE streaming reference for the full directive set.
Body-equality assertion — @assert body equals
Section titled “Body-equality assertion — @assert body equals”For structural JSON equality (ignoring key order, whitespace):
# @assert body equals { "id": {{userId}}, "name": "Jane" }Running a flow
Section titled “Running a flow”| Action | How |
|---|---|
| Run entire flow | ⌘Enter or ▶ button at top of file |
| View step results | Click any step in the pipeline visualization |
| Export report | Export as Markdown in the Results toolbar |