Full reference

Complete documentation for all bolla features, YAML fields, API endpoints, and CLI flags.

Collections & requests

A collection is a directory of *.bolla.yaml files. bolla scans recursively — no manifest needed. Each file is one request definition.

Request definition (.bolla.yaml)

FieldTypeRequiredDescription
idstringyesUnique identifier within your project. Used for cross-references in scenarios.
namestringyesHuman-readable display name.
methodstringyesGET, POST, PUT, PATCH, DELETE, HEAD
urlstringyesFull URL. Variables use {{VAR}} syntax.
headerslistnoList of {name, value, enabled} objects.
paramslistnoQuery parameters as {name, value, enabled}.
authobjectnoSee Auth section below.
bodyobjectno{type: json, content: ...} or {type: raw, content: "...", content_type: "..."}
assertionslistnoSee Assertions below.
exampleslistnoSaved responses for the mock server. See Mock server.
protocolstringnohttp (default), graphql, websocket, sse
graphqlobjectno{query, variables?, operation_name?} — used when protocol: graphql
wsobjectno{messages: [{payload, await_response}], response_timeout_ms}
sseobjectno{max_events?, timeout_ms}

Auth types

# Bearer token
auth:
  type: bearer
  token: "{{TOKEN}}"

# Basic auth
auth:
  type: basic
  username: admin
  password: "{{PASSWORD}}"

# API key header
auth:
  type: api_key
  key: X-API-Key
  value: "{{API_KEY}}"
  location: header  # or: query

# OAuth2 (token resolved by bolla-oauth2 module)
auth:
  type: oauth2
  provider_id: google
  scopes: [openid, email]

Environments

Environment files (*.env.yaml) define named variable sets. bolla scans your project for them automatically.

# staging.env.yaml
name: staging
variables:
  base_url: https://staging.api.example.com
  TOKEN: eyJhbG...
  DB_HOST: staging-db.example.com

Variables are substituted in url, header values, body content, and auth fields using {{VAR_NAME}}. Unresolved variables are left as-is and shown with a warning.

Assertions

Assertions validate a response. All assertions in a request must pass for all_passed: true.

TypeFieldsDescription
status_codevalue: intHTTP status must equal value
body_containstext: stringResponse body (as string) must contain text
body_equalsjson: objectResponse body must equal JSON exactly
body_regexpattern: stringResponse body must match regex pattern
assertions:
  - check: status_code
    value: 200
  - check: body_contains
    text: '"id"'
  - check: body_regex
    pattern: '"created_at":\s*"\d{4}-\d{2}-\d{2}'

Load scenarios

A scenario orchestrates multiple requests under a configurable load profile.

# smoke.scenario.yaml
id: smoke
name: Smoke test

load:
  type: constant       # constant | ramp | spike
  concurrency: 20
  duration_s: 60

# For ramp:
# load:
#   type: ramp
#   start_concurrency: 1
#   end_concurrency: 100
#   duration_s: 120

steps:
  - request_id: login          # references login.bolla.yaml
    extract:
      TOKEN: $.access_token    # JSONPath extraction into env variable
  - request_id: list-users
    vars:
      base_url: "{{base_url}}"  # override per-step
  - request_id: create-user
    think_time_ms: 500          # pause between steps

CI gates

Gates are pass/fail thresholds evaluated after a scenario run. bolla exits 1 if any gate fails.

gates:
  p50_ms:
    max: 100
  p95_ms:
    max: 300
  p99_ms:
    max: 800
  error_rate_pct:
    max: 0.5          # at most 0.5% errors
  rps:
    min: 50           # at least 50 requests/second

Mock server optional

The mock server serves HTTP responses from your collection without hitting a real backend. Start it headlessly:

bolla --mock --collection api/ --mock-port 3078

Or toggle it from the UI under Modules → Mock Server → Start.

Saved examples

Add an examples block to any request file. The mock server returns them by name via the X-Bolla-Example header or ?_example= query param.

examples:
  - name: success
    status: 200
    content_type: application/json
    body: '{"id":"usr_01","name":"Alice","email":"alice@example.com"}'
  - name: not-found
    status: 404
    body: '{"error":"user not found"}'
# Request a specific example:
curl http://localhost:3078/users/123 -H 'X-Bolla-Example: not-found'
# or
curl 'http://localhost:3078/users/123?_example=success'

Smart faker

If no matching example is found, the mock auto-generates realistic data from field names in the body template: email → valid email, uuid/id → UUID v4, name → "Alice Johnson", phone → phone number, price/amount → decimal, date/created_at → ISO timestamp, and so on.

OAuth2 optional

bolla implements all three common OAuth2 flows natively. Tokens are cached locally with AES-256-GCM encryption at ~/.config/bolla/oauth2.key.

Presets

ProviderPreset IDFlows
Googlegoogleauth_code+PKCE, device
GitHubgithubauth_code+PKCE, device
Microsoftmicrosoftauth_code+PKCE, client_credentials, device
Mock (local)mockAll flows (runs on port 3079)

Configuring a provider

POST /api/oauth2/providers
{
  "id": "my-api",
  "auth_url": "https://auth.example.com/oauth/authorize",
  "token_url": "https://auth.example.com/oauth/token",
  "client_id": "{{CLIENT_ID}}",
  "client_secret": "{{CLIENT_SECRET}}",
  "scopes": ["read", "write"]
}

Then use it in any request: auth: {type: oauth2, provider_id: my-api}. bolla resolves and caches the token before executing.

OpenAPI contracts optional

Import a spec

POST /api/contracts/import
{
  "content": "<paste OpenAPI YAML or JSON here>",
  "file_name": "petstore.yaml"
}

bolla generates one .bolla.yaml per endpoint, infers body templates from schemas, adds a default status_code: 200 assertion, and saves the raw spec for drift checking.

Drift detection

After each request execution, bolla can compare the live response against the spec's response schema. Violations are logged to schema_drift_events in SQLite and surfaced in the UI.

POST /api/contracts/check
{
  "response_body": {"id": 1, "name": "Fluffy"},
  "spec_content": "<OpenAPI YAML>",
  "api_path": "/pets",
  "method": "post",
  "strict": false
}

History & export optional

Every request run and load run is stored in SQLite. The history module adds filtering, single-record lookup, export, and run-to-run comparison.

Filtered search

GET /api/history/runs?request_id=create-user&passed=false&from=2026-06-01&limit=50
GET /api/history/load-runs?scenario_id=smoke&from=2026-06-01

Export

GET /api/history/runs/export?format=csv
GET /api/history/runs/export?format=html
GET /api/history/load-runs/export?format=csv&scenario_id=smoke

Run comparison

GET /api/history/compare?a=<run-id-A>&b=<run-id-B>

Returns a diffs array with metric, a, b, delta, delta_pct, and improved for p50/p90/p95/p99/error_rate/rps.

Polish bundle optional

Code snippet generation

POST /api/polish/snippet
{
  "request_id": "create-user",
  "lang": "python"   // curl | python | javascript | go
}

Import from cURL

POST /api/polish/import/curl
{
  "command": "curl -X POST 'https://api.example.com/users' -H 'Authorization: Bearer tok' -d '{\"name\":\"Alice\"}'",
  "save": true   // writes to project as .bolla.yaml
}

Import from HAR

POST /api/polish/import/har
{
  "har": { /* paste HAR log object here */ },
  "save": true
}

Security lint

POST /api/polish/lint
{ "request_id": "create-user" }

Returns a list of findings with severity (High/Medium/Low), code, and message. Checks include: insecure HTTP URL, hardcoded tokens/secrets, secrets in URL query params, missing auth, missing assertions, missing Content-Type.

HTML docs site

GET /api/polish/docs?collection=api
# Returns a self-contained HTML page with nav sidebar and all request details

Team dashboard

GET /api/polish/dashboard
# Returns: total_runs, pass_rate_pct, avg_p50_ms, avg_p95_ms, avg_rps, top_failing_requests

AI assist optional

AI assist uses the Anthropic API (claude-haiku-4-5, fast and cheap). You supply your own API key — bolla never stores it to disk.

Set your key

POST /api/ai/key
{ "api_key": "sk-ant-..." }
# Or set env var: ANTHROPIC_API_KEY=sk-ant-...

Assertion suggestions

POST /api/ai/suggest
{ "run_id": "<uuid>" }
# Returns: suggestions — list of assertion objects ready to paste

Report summarization

POST /api/ai/summarize/ci
{ "run_id": "<uuid>" }

POST /api/ai/summarize/load
{ "load_run_id": "<uuid>" }
# Returns: summary — plain-English bullet points

REST API

All endpoints return JSON unless noted. The server defaults to http://localhost:3077.

Core

MethodPathDescription
GET/api/healthHealth check — {"ok":true}
POST/api/project/openOpen a project directory
GET/api/collectionsList all collections in current project
GET/api/environmentsList all environments
POST/api/request/executeExecute a request, returns RunResult
POST/api/request/saveSave a request definition
GET/api/historyRecent 100 runs
GET/api/history/runsFiltered run search
GET/api/history/runs/:idSingle run by ID
GET/api/history/compareCompare two load runs

Load

MethodPathDescription
POST/api/load/runStart a load run (streaming SSE updates)
POST/api/load/stopStop the active load run
GET/api/load/runsRecent load run history
GET/api/load/runs/:idSingle load run details
GET/api/load/scenariosList available scenarios

CLI flags

FlagDescription
--serverStart HTTP server only (no native window). Open http://localhost:<port> yourself.
--port <n>Main server port (default: 3077)
--ciHeadless CI mode. Requires --request or --scenario.
--request <id>Run a single request in CI mode
--scenario <id>Run a scenario in CI mode
--env <name>Environment name to use
--project <path>Project directory (default: current directory)
--report-dir <path>Where to write CI reports (default: .bolla/runs/<run-id>/)
--mockHeadless mock server mode. Requires --collection.
--collection <path>Collection directory to mock
--mock-port <n>Mock server port (default: 3078)

YAML schema reference

Full .bolla.yaml example

id: create-user
name: Create user
method: POST
url: "{{base_url}}/users"
protocol: http   # http | graphql | websocket | sse

headers:
  - name: content-type
    value: application/json
    enabled: true

params:
  - name: dry_run
    value: "false"
    enabled: false

auth:
  type: bearer
  token: "{{TOKEN}}"

body:
  type: json
  content:
    name: Alice
    email: alice@example.com

assertions:
  - check: status_code
    value: 201
  - check: body_contains
    text: '"id"'
  - check: body_regex
    pattern: '"id":"[a-z0-9-]+'

examples:
  - name: success
    status: 201
    content_type: application/json
    body: '{"id":"usr_01","name":"Alice","email":"alice@example.com"}'
  - name: conflict
    status: 409
    body: '{"error":"email already exists"}'

Full .scenario.yaml example

id: api-smoke
name: API smoke test

load:
  type: ramp              # constant | ramp | spike
  start_concurrency: 1
  end_concurrency: 50
  duration_s: 120

steps:
  - request_id: login
    extract:
      TOKEN: $.access_token    # JSONPath → env var for next steps
  - request_id: create-user
    think_time_ms: 200
  - request_id: list-users

gates:
  p50_ms:   { max: 100 }
  p95_ms:   { max: 300 }
  p99_ms:   { max: 800 }
  error_rate_pct: { max: 0.5 }
  rps:      { min: 100 }