User Journeys

Journeys are re-runnable prompts. Instead of creating a new agent from scratch every time, you define a journey once and run it repeatedly. Each run creates a new agent linked back to the journey, giving you a history of results for the same test over time.

Overview

A journey is an abstraction on top of the agent API. Where creating an agent is a one-off operation (one prompt, one run, one result), a journey lets you define a prompt once and run it as many times as you want. Each run creates a new agent that is linked back to the journey, so you build up a history of results for the same test over time.

This is the core mechanism for tracking the health of your application. If you have a journey called "checkout flow" and you run it after every deploy, you get a timeline of pass/fail results that tells you exactly when something broke and when it was fixed. The project health board aggregates this across all journeys in a project.

When you run a journey, the system resolves the role (cascading from the run parameters, to the journey defaults, to the project defaults), copies any attached mailboxes onto the new agent, renders the prompt, and queues the agent for execution.

Prompt template model

A journey's prompt_template is the instruction set the agent executes. When a journey is run as part of a test plan, its template can include references to outputs from previous steps or variables passed to the plan:

  • {{ steps.<label>.outputs.<name> }} — replaced with the output recorded by an ancestor step.
  • {{ plan.variables.<name> }} — replaced with a plan-level variable.

The starting URL is no longer a separate field. Inline it as literal text in the prompt body, typically as the opening “Navigate to …” line. The agent reads that and calls browser_navigate itself.

A minimal example:

Navigate to https://app.example.com and log in. Your order ID is {{ steps.create_order.outputs.order_id }} in environment {{ plan.variables.env }}.

When this journey runs via POST /api/v1/journeys/{id}/run, steps and plan variables are empty strings, gracefully degrading.

Success determination

Whether a journey run succeeded or failed is determined by a two-step process. First, the agent itself reports its own assessment when it finishes (success or failure with a summary). Second, a server-side verification step independently analyzes the full conversation trace and produces its own verdict.

If the agent and the server-side verification disagree, the server-side verdict wins. This means an agent cannot incorrectly report success if the evidence in the conversation shows otherwise, and vice versa. The final outcome is what you see in the API response and on the health board.

Role resolution

When a journey is run, the role is resolved using a cascading fallback. The system first checks if a role was specified in the run parameters. If not, it falls back to the default set on the journey itself. If the journey has no default, it uses the project-level default.

This lets you set sensible defaults on the journey or project and override them on individual runs when needed. For example, you might have a journey that normally runs with a "Functional QA" role but occasionally run it with a "Power User" role to test a different interaction style.

POST /api/v1/journeys

Create a new user journey

Parameters

ParameterTypeInRequiredDescription
project_iduuidbodyYesID of the project this user journey belongs to
namestringbodyYesUser journey name
descriptionstringbodyNoUser journey description
prompt_templatestringbodyYesPrompt body containing the instructions the agent executes. Inline the starting URL as literal text — the journey no longer has a separate entry_url field. See the section overview for the complete template data model.
sourcestringbodyNoOrigin of the user journey (e.g. 'discovery', 'manual')
statusstringbodyNoLifecycle status: draft (not eligible for regression/schedules), active (eligible), or archived. Defaults to active for manually created journeys, draft for generated ones. (default: active)
importancestringbodyNoUser journey importance level (e.g. 'critical', 'high', 'medium', 'low')
file_pathsstring[]bodyNoPaths of tenant files to copy into the test run workspace when running this user journey
mailbox_namesstring[]bodyNoOptional list of mailbox names to attach to the journey. Every run of the journey gains read access to these inboxes. Can be overridden at run time.

Status Codes

CodeDescription
201Journey created
400Validation error
401Unauthorized

Response Body

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "project_id": "660e8400-e29b-41d4-a716-446655440000",
  "name": "Checkout Flow",
  "description": "",
  "prompt_template": "Navigate to https://example.com and complete checkout",
  "status": "active",
  "file_paths": [],
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
POST /api/v1/journeys
cURL
Response
GET /api/v1/journeys

List user journeys

Parameters

ParameterTypeInRequiredDescription
limitintegerqueryNoNumber of results to return (default: 20)
cursoruuidqueryNoCursor for pagination
project_iduuidqueryNoFilter by project ID (alias: project)
statusstringqueryNoFilter by lifecycle status: draft, active, or archived

Status Codes

CodeDescription
200OK
401Unauthorized

Response Body

{
  "journeys": [
    {
      "id": "770e8400-e29b-41d4-a716-446655440000",
      "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
      "project_id": "660e8400-e29b-41d4-a716-446655440000",
      "name": "Checkout Flow",
      "description": "",
      "prompt_template": "Navigate to https://example.com and complete checkout",
      "status": "active",
      "file_paths": [],
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-15T10:30:00Z"
    }
  ],
  "next_cursor": "880e8400-e29b-41d4-a716-446655440000"
}
GET /api/v1/journeys
cURL
Response
GET /api/v1/journeys/{id}

Get user journey by ID

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesUser journey ID

Status Codes

CodeDescription
200OK
400Invalid UUID
401Unauthorized
404Journey not found

Response Body

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "project_id": "660e8400-e29b-41d4-a716-446655440000",
  "name": "Checkout Flow",
  "description": "",
  "prompt_template": "Navigate to https://example.com and complete checkout",
  "status": "active",
  "file_paths": [],
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
GET /api/v1/journeys/{id}
cURL
Response
PATCH /api/v1/journeys/{id}

Update a user journey

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesUser journey ID
namestringbodyNoUser journey name
descriptionstringbodyNoUser journey description
prompt_templatestringbodyNoPrompt body containing the instructions the agent executes. See the section overview.
sourcestringbodyNoOrigin of the user journey
statusstringbodyNoLifecycle status: draft, active, or archived
importancestringbodyNoUser journey importance level
file_pathsstring[]bodyNoPaths of tenant files to copy into the test run workspace when running this user journey
mailbox_namesstring[]bodyNoReplace the journey's attached mailbox set with this list. Omit the field to leave attachments unchanged; pass an empty array to detach all mailboxes.

Status Codes

CodeDescription
200Journey updated
400Validation error
401Unauthorized
404Journey not found

Response Body

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "project_id": "660e8400-e29b-41d4-a716-446655440000",
  "name": "Checkout Flow",
  "description": "",
  "prompt_template": "Navigate to https://example.com and complete checkout",
  "status": "active",
  "file_paths": [],
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
PATCH /api/v1/journeys/{id}
cURL
Response
DELETE /api/v1/journeys/{id}

Delete a user journey

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesUser journey ID

Status Codes

CodeDescription
204Journey deleted
400Invalid UUID
401Unauthorized
404Journey not found
DELETE /api/v1/journeys/{id}
cURL
Response
POST /api/v1/journeys/{id}/run

Run a user journey

Creates a new test run from the user journey. Files attached to the user journey are automatically copied into the test run workspace.

Parameters

ParameterTypeInRequiredDescription
iduuidpathYesUser journey ID
role_iduuidbodyNoRole for prompt injection context
mailbox_namesstring[]bodyNoOverride the journey's attached mailboxes for this run. When omitted, the journey's stored attachments are inherited.
modelstringbodyNoLLM model override for this run
max_iterationsintegerbodyNoMax iterations override for this run
browser_typestringbodyNoBrowser to use (default: chrome)

Status Codes

CodeDescription
201Agent created from journey
400Validation error or template rendering failed
401Unauthorized
404Journey not found

Response Body

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "660e8400-e29b-41d4-a716-446655440000",
  "project_id": "770e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "prompt": "Navigate to https://example.com and complete checkout",
  "model": "gemini-3.5-flash",
  "browser_type": "chrome",
  "is_discovery": false,
  "messages": [],
  "iteration": 0,
  "max_iterations": 200,
  "tokens_used": 0,
  "journey_id": "990e8400-e29b-41d4-a716-446655440000",
  "source": "api",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
POST /api/v1/journeys/{id}/run
cURL
Response