.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.
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 |