REST API
Veilus can run a small REST API on your own machine, so other programs you run — scripts, other apps, an LLM agent — can manage profiles and proxy pools, drive a running profile’s page, and run and schedule Veilus Flow scripts.
The API is off by default. Turn it on from the API & MCP page in the app sidebar, which shows the port it’s listening on, lets you mint and revoke named tokens, and gives ready-made connection snippets.
Local only
Section titled “Local only”The API only listens on 127.0.0.1 — nothing outside your machine can reach it. It reaches every profile, so it’s gated behind the Pro plan or higher and stays off until you turn it on.
Authentication
Section titled “Authentication”Every request needs a bearer token, minted from the API & MCP page. Each token has a name (so you can tell tools apart) and can be revoked independently — a token’s full value is shown only once, at creation time.
Authorization: Bearer <token>Rate limit
Section titled “Rate limit”Each token can make at most 30 expensive calls per 60 seconds: POST to launch a profile, create profiles, create a proxy pool, run a script, run a batch, or run a schedule now. Past that the API answers 429 with a Retry-After header. Reads and cheap calls such as stopping a profile aren’t counted.
Base URL
Section titled “Base URL”The port is chosen when you turn the API on and shown on the API & MCP page. Replace <port> below with that value.
http://127.0.0.1:<port>Example
Section titled “Example”curl -X GET \ -H "Authorization: Bearer $VEILUS_API_TOKEN" \ http://127.0.0.1:<port>/v1/profilesRoutes
Section titled “Routes” GET /v1/profiles
List Veilus browser profiles, with their running state; a running profile carries `cdpUrl`.
GET /v1/capacity
Return the current browser pool capacity and usage.
GET /v1/dsl/schema
Return the JSON schema for the drag-and-drop DSL.
POST /v1/dsl/compile
Compile a drag-and-drop DSL script into runnable code.
| Field | Type | Required | Description |
|---|---|---|---|
dsl | object | yes | DSL script body |
target | string | yes |
POST /v1/profiles/:id/launch
Launch a profile's browser and wait for it to start; returns `{pid, cdpUrl}`, a full pool fails with 409 rather than queuing. Optional body `{diagnostic: true}`: the profile's proxy without its fingerprint, in a temporary directory.
| Field | Type | Required | Description |
|---|---|---|---|
diagnostic | boolean | no | Diagnostic launch: the profile's proxy, but none of its fingerprint, in a fresh temporary browser directory deleted on stop — no cookies or logins, and nothing is written to the profile. The page sees THIS machine's real values (platform, CPU cores, GPU, screen, timezone, languages): use it to tell whether a site blocks the fingerprint or the IP/proxy, never on an account you care about. The engine's CDP hiding still applies; WebRTC is restricted to the proxy. Default false. |
POST /v1/profiles/:id/stop
Stop a running profile's browser.
POST /v1/scripts/run
Start a script run on given profiles; returns the run immediately (its `id` is the run_id).
| Field | Type | Required | Description |
|---|---|---|---|
profile_ids | string[] | no | |
script_id | string (uuid) | yes | |
variables | object | no |
POST /v1/scripts
Save an agent-authored Raw script into Veilus Flow.
| Field | Type | Required | Description |
|---|---|---|---|
description | string | no | |
name | string | yes | |
script_id | string (uuid) | no | Script to replace; omit to create a new one |
source | string | yes | Full TypeScript source |
GET /v1/scripts
List every script without its source: id, name, version, mode (raw or dsl), origin and whether it is approved.
GET /v1/scripts/:id
Read a Raw script's source and approval state.
GET /v1/runs/:id
Read a script run's result by run_id.
POST /v1/profiles
Create 1-50 profiles; with a proxy pool, timezones follow each slot's geo.
| Field | Type | Required | Description |
|---|---|---|---|
content_dataset_id | string (uuid) | no | Consume dataset for the Content slot |
count | integer | yes | |
identity_dataset_id | string (uuid) | no | Fixed dataset: one unassigned row per new profile |
name_template | string | no | {n} becomes 1, 2, ... |
os | string | no | |
proxy_pool_id | string (uuid) | no | |
tags | string[] | no |
GET /v1/profiles/:id/proxy
Show a profile's proxy: pool, slot, host:port and geo, never the password.
GET /v1/proxy-pools
List proxy pools with entry counts and detected countries.
POST /v1/proxy-pools
Create a static proxy pool from proxy lines; bad lines are reported by number.
| Field | Type | Required | Description |
|---|---|---|---|
lines | string[] | yes | |
name | string | yes | |
type | string | no |
POST /v1/proxy-pools/:id/assign
Assign a proxy pool to profiles; refuses profiles that already have a proxy unless force.
| Field | Type | Required | Description |
|---|---|---|---|
force | boolean | no | |
profile_ids | string[] | yes |
POST /v1/proxy-pools/:id/test
Test every proxy in a pool now: alive, latency, exit IP and geo.
GET /v1/schedules
List schedules with their script, target profiles, timing and next run.
POST /v1/schedules
Create a schedule for an approved script on explicit profiles; a once schedule turns itself off after it runs.
| Field | Type | Required | Description |
|---|---|---|---|
concurrency | integer | no | |
cron_expr | string | no | 5 fields, e.g. "0 * * * *" |
daily_hour | integer | no | |
daily_minute | integer | no | |
enabled | boolean | no | |
interval_minutes | integer | no | interval: count of interval_unit |
interval_unit | string | no | |
name | string | yes | |
profile_ids | string[] | yes | |
run_at | string (date-time) | no | RFC 3339 with offset, e.g. 2026-10-04T09:00:00+07:00; required for once |
schedule_type | string | yes | |
script_id | string (uuid) | yes | An approved script |
stagger_ms | integer | no | |
weekly_day | integer | no | 0 = Sunday |
POST /v1/schedules/:id/enabled
Turn a schedule on or off; turning it on recomputes its next run.
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | yes |
POST /v1/schedules/:id/run
Run a schedule once now; returns the run immediately.
POST /v1/scripts/batch
Run an approved script on many profiles; returns the run immediately.
| Field | Type | Required | Description |
|---|---|---|---|
concurrency | integer | no | |
profile_ids | string[] | yes | |
script_id | string (uuid) | yes | |
stagger_ms | integer | no | |
variables | object | no |
POST /v1/profiles/:id/variables
Replace all stored variables of a profile; returns the variable names only.
| Field | Type | Required | Description |
|---|---|---|---|
variables | object | yes |
GET /v1/runs
List recent runs, newest first; query schedule_id and limit (default 20, max 100).
GET /v1/openapi.json
Return the OpenAPI 3.1 document describing this REST API.
GET /v1/profiles/:id/snapshot
Accessibility snapshot of a running profile's page, with [id=N] per element.
POST /v1/profiles/:id/click
Click the element with a node id from snapshot or wait-for-element, with a real mouse; refuses hidden or covered elements.
| Field | Type | Required | Description |
|---|---|---|---|
node_id | integer | yes |
POST /v1/profiles/:id/type
Focus an element by node id and type text into it.
| Field | Type | Required | Description |
|---|---|---|---|
node_id | integer | yes | |
text | string | yes |
POST /v1/profiles/:id/press-key
Press one named key (Enter, Tab, Escape, arrows, Backspace, Delete, Space).
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes |
POST /v1/profiles/:id/scroll
Scroll a running profile's page by about a number of pixels in one direction, with mouse-wheel steps at the pointer; reports the pixels scrolled.
| Field | Type | Required | Description |
|---|---|---|---|
amount | integer | yes | |
direction | string | yes |
POST /v1/profiles/:id/evaluate
Run JavaScript in a running profile's page; 64 KiB result cap, 10 s timeout.
| Field | Type | Required | Description |
|---|---|---|---|
expression | string | yes |
POST /v1/profiles/:id/wait-for-element
Wait until a CSS selector matches and return the element's node id.
| Field | Type | Required | Description |
|---|---|---|---|
selector | string | yes | |
timeout_ms | integer | no |
POST /v1/profiles/:id/set-file
Attach a file from the app's uploads folder to a file input by node id.
| Field | Type | Required | Description |
|---|---|---|---|
node_id | integer | yes | |
path | string | yes |
GET /v1/datasets
List datasets with their columns and row counts by state; never row values.
POST /v1/datasets
Create a fixed or consume dataset from columns and rows; bad rows are reported by number.
| Field | Type | Required | Description |
|---|---|---|---|
columns | object[] | yes | |
mode | string | yes | |
name | string | yes | |
rows | object[] | no | One object per row, keyed by column name; every value must be a string — convert numbers and dates to text before sending |
rows_per_run | integer | no |
GET /v1/datasets/:id/rows
Read a dataset's rows by page (query offset, limit); secret columns are never returned.
POST /v1/datasets/:id/rows
Append rows to a dataset; bad rows are reported by number.
| Field | Type | Required | Description |
|---|---|---|---|
rows | object[] | yes | One object per row, keyed by column name; every value must be a string — convert numbers and dates to text before sending |
POST /v1/datasets/:id/assign
Assign a dataset to profiles, into the slot its mode implies; a taken slot is refused unless force.
| Field | Type | Required | Description |
|---|---|---|---|
force | boolean | no | |
profile_ids | string[] | yes |
POST /v1/datasets/:id/unassign
Remove a dataset from profiles; their fixed rows become unassigned again.
| Field | Type | Required | Description |
|---|---|---|---|
profile_ids | string[] | yes |
POST /v1/datasets/:id/reset
Return every used row of a consume dataset to available.
OpenAPI
Section titled “OpenAPI”GET /v1/openapi.json returns the OpenAPI 3.1 document for this API (requires a token like any other route). The API & MCP page also has a Copy OpenAPI JSON button if you’d rather not curl it yourself.