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)
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique identifier within your project. Used for cross-references in scenarios. |
name | string | yes | Human-readable display name. |
method | string | yes | GET, POST, PUT, PATCH, DELETE, HEAD |
url | string | yes | Full URL. Variables use {{VAR}} syntax. |
headers | list | no | List of {name, value, enabled} objects. |
params | list | no | Query parameters as {name, value, enabled}. |
auth | object | no | See Auth section below. |
body | object | no | {type: json, content: ...} or {type: raw, content: "...", content_type: "..."} |
assertions | list | no | See Assertions below. |
examples | list | no | Saved responses for the mock server. See Mock server. |
protocol | string | no | http (default), graphql, websocket, sse |
graphql | object | no | {query, variables?, operation_name?} — used when protocol: graphql |
ws | object | no | {messages: [{payload, await_response}], response_timeout_ms} |
sse | object | no | {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.
| Type | Fields | Description |
|---|---|---|
status_code | value: int | HTTP status must equal value |
body_contains | text: string | Response body (as string) must contain text |
body_equals | json: object | Response body must equal JSON exactly |
body_regex | pattern: string | Response 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
| Provider | Preset ID | Flows |
|---|---|---|
google | auth_code+PKCE, device | |
| GitHub | github | auth_code+PKCE, device |
| Microsoft | microsoft | auth_code+PKCE, client_credentials, device |
| Mock (local) | mock | All 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
| Method | Path | Description |
|---|---|---|
| GET | /api/health | Health check — {"ok":true} |
| POST | /api/project/open | Open a project directory |
| GET | /api/collections | List all collections in current project |
| GET | /api/environments | List all environments |
| POST | /api/request/execute | Execute a request, returns RunResult |
| POST | /api/request/save | Save a request definition |
| GET | /api/history | Recent 100 runs |
| GET | /api/history/runs | Filtered run search |
| GET | /api/history/runs/:id | Single run by ID |
| GET | /api/history/compare | Compare two load runs |
Load
| Method | Path | Description |
|---|---|---|
| POST | /api/load/run | Start a load run (streaming SSE updates) |
| POST | /api/load/stop | Stop the active load run |
| GET | /api/load/runs | Recent load run history |
| GET | /api/load/runs/:id | Single load run details |
| GET | /api/load/scenarios | List available scenarios |
CLI flags
| Flag | Description |
|---|---|
--server | Start HTTP server only (no native window). Open http://localhost:<port> yourself. |
--port <n> | Main server port (default: 3077) |
--ci | Headless 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>/) |
--mock | Headless 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 }