The hitspec server exposes a REST API on http://localhost:8080 (default) when you run hitspec serve. All endpoints are prefixed with /api/v1. Responses are JSON with Content-Type: application/json.
hitspec serve --port 8080
All error responses follow a consistent structure:
{
"error": "Bad Request",
"message": "file is required"
}
| Field | Type | Description |
|---|
error | string | HTTP status text (e.g., "Bad Request", "Not Found") |
message | string | Human-readable error detail |
Workspace & Files
Get Workspace Overview
Returns the workspace file tree, total request count, active environment, and whether a config file exists.
curl http://localhost:8080/api/v1/workspace
Response 200 OK
{
"root": "/Users/you/project",
"files": [
{
"path": "tests",
"name": "tests",
"dir": "",
"isDir": true,
"children": [
{
"path": "tests/api.http",
"name": "api.http",
"dir": "tests",
"isDir": false,
"requestCount": 5
}
]
},
{
"path": "smoke.http",
"name": "smoke.http",
"dir": "",
"isDir": false,
"requestCount": 3
}
],
"totalRequests": 8,
"environment": "dev",
"hasConfig": true
}
List Files
Returns a flat list of all .http and .hitspec files in the workspace with metadata.
curl http://localhost:8080/api/v1/files
Response 200 OK
[
{
"path": "/Users/you/project/tests/api.http",
"relativePath": "tests/api.http",
"name": "api.http",
"size": 1234,
"modTime": "2026-02-10T12:00:00Z",
"requestCount": 5
}
]
Get Parsed File
Returns the fully parsed content of a single .http or .hitspec file, including all requests, variables, assertions, and captures.
curl http://localhost:8080/api/v1/files/tests/api.http
Relative path to the file within the workspace. Uses wildcard path matching ({path...}).
Response 200 OK
{
"path": "tests/api.http",
"variables": [
{ "name": "baseUrl", "value": "http://localhost:3000", "line": 1 }
],
"requests": [
{
"name": "Get Users",
"description": "Fetch all users",
"tags": ["users"],
"method": "GET",
"url": "{{baseUrl}}/users",
"headers": [
{ "key": "Accept", "value": "application/json", "line": 5 }
],
"queryParams": [
{ "key": "limit", "value": "10", "line": 6 }
],
"assertions": [
{ "subject": "status", "operator": "equals", "expected": 200, "line": 8 }
],
"captures": [
{ "name": "userId", "source": "body", "path": "$.data[0].id", "line": 9 }
],
"line": 3,
"metadata": {
"timeout": 5000,
"retry": 2,
"depends": ["Auth Login"]
}
}
]
}
Get Raw File Content
Returns the raw text content of a file. Use this for source editing.
curl http://localhost:8080/api/v1/files/raw/tests/api.http
Relative path to the file within the workspace.
Response 200 OK with Content-Type: text/plain
@baseUrl = https://api.example.com
### Get Users
GET {{baseUrl}}/users
Create File
Create a new .http or .hitspec file in the workspace.
curl -X POST http://localhost:8080/api/v1/files \
-H "Content-Type: application/json" \
-d '{"path": "tests/new-api.http", "content": "### Health Check\nGET https://api.example.com/health\n"}'
Request Body
{
path: string; // Required. Relative path for the new file
content?: string; // Optional. Initial file content
}
Relative path for the new file. Must end in .http or .hitspec and be within the workspace.
Response 201 Created
{ "path": "tests/new-api.http" }
Save File
Save raw text content to an existing file. The file watcher suppresses the corresponding change notification to prevent UI reload loops.
curl -X PUT http://localhost:8080/api/v1/files/tests/api.http \
-H "Content-Type: text/plain" \
-d '@baseUrl = https://api.example.com
### Get Users
GET {{baseUrl}}/users
'
Relative path to the file within the workspace.
Request Body: Raw file content as text/plain.
Response 200 OK
{ "path": "tests/api.http" }
Delete File
Delete a .http or .hitspec file from the workspace.
curl -X DELETE http://localhost:8080/api/v1/files/tests/old-api.http
Relative path to the file within the workspace.
Response 204 No Content
Execution
Execute Request
Execute one or more requests from a specific file. When requestName is provided, only that request runs (filtered by name). When omitted, all requests in the file execute.
Real-time progress is broadcast over the WebSocket connection during execution.
curl -X POST http://localhost:8080/api/v1/execute \
-H "Content-Type: application/json" \
-d '{"file": "tests/api.http", "requestName": "Get Users", "environment": "dev"}'
Request Body
{
file: string; // Required. Relative path to the .http/.hitspec file
requestName?: string; // Optional. Filter to a single request by name
environment?: string; // Optional. Override the active environment
}
Relative path to the .http or .hitspec file within the workspace.
Name of a specific request to execute. When omitted, all requests in the file are executed.
Environment name to use for variable interpolation. Overrides the server’s active environment.
Response 200 OK
{
"file": "tests/api.http",
"duration": 245,
"passed": 1,
"failed": 0,
"skipped": 0,
"results": [
{
"name": "Get Users",
"description": "Fetch all users",
"passed": true,
"duration": 245,
"request": {
"method": "GET",
"url": "http://localhost:3000/users",
"headers": { "Accept": "application/json" }
},
"response": {
"statusCode": 200,
"status": "200 OK",
"headers": { "Content-Type": "application/json" },
"body": "{\"data\":[{\"id\":1,\"name\":\"Alice\"}]}",
"duration": 243,
"size": 42
},
"assertions": [
{
"subject": "status",
"operator": "equals",
"expected": 200,
"actual": 200,
"passed": true
}
],
"captures": { "userId": 1 }
}
]
}
Run File
Run all requests in a file. Similar to execute but always runs every request (no name filter).
curl -X POST http://localhost:8080/api/v1/run \
-H "Content-Type: application/json" \
-d '{"file": "tests/api.http", "environment": "staging"}'
Request Body
{
file: string; // Required. Relative path to the file
environment?: string; // Optional. Override the active environment
}
Relative path to the .http or .hitspec file within the workspace.
Environment name to use. Overrides the server’s active environment.
Response 200 OK — same RunResultDTO structure as the Execute Request endpoint.
Environments
List Environments
Returns all environments defined in hitspec.yaml, including the currently active environment.
curl http://localhost:8080/api/v1/environments
Response 200 OK
[
{
"name": "dev",
"variables": {
"baseUrl": "http://localhost:3000",
"token": "dev-token"
}
},
{
"name": "staging",
"variables": {
"baseUrl": "https://staging.api.example.com",
"token": "staging-token"
}
}
]
Set Active Environment
Switch the server’s active environment. Broadcasts an environment_changed event over WebSocket.
curl -X PUT http://localhost:8080/api/v1/environments/active \
-H "Content-Type: application/json" \
-d '{"name": "staging"}'
Request Body
{
name: string; // Required. Environment name to activate
}
The name of the environment to set as active.
Response 204 No Content
Get Environment
Get the variables for a specific environment.
curl http://localhost:8080/api/v1/environments/dev
Response 200 OK
{
"name": "dev",
"variables": {
"baseUrl": "http://localhost:3000",
"token": "dev-token"
}
}
Update Environment
Create or update the variables for a named environment.
curl -X PUT http://localhost:8080/api/v1/environments/dev \
-H "Content-Type: application/json" \
-d '{"variables": {"baseUrl": "http://localhost:4000", "token": "new-token"}}'
Request Body
{
variables: Record<string, any>; // Key-value pairs of environment variables
}
Map of variable names to values for this environment.
Response 200 OK
{
"name": "dev",
"variables": {
"baseUrl": "http://localhost:4000",
"token": "new-token"
}
}
Config
Get Configuration
Returns the current hitspec.yaml configuration. Returns an empty object if no config file is present.
curl http://localhost:8080/api/v1/config
Response 200 OK
{
"defaultEnvironment": "dev",
"timeout": 30000,
"retries": 0,
"followRedirects": true,
"validateSSL": true,
"proxy": "",
"headers": {
"User-Agent": "hitspec/1.0"
},
"parallel": false,
"concurrency": 5
}
Update Configuration
Partially update the server configuration. Only provided fields are updated; omitted fields remain unchanged. Changes are persisted to the hitspec.yaml config file on disk. If no config file exists, one is created in the workspace root.
curl -X PUT http://localhost:8080/api/v1/config \
-H "Content-Type: application/json" \
-d '{"timeout": 60000, "parallel": true, "concurrency": 10}'
Request Body
{
defaultEnvironment?: string;
timeout?: number; // Milliseconds
retries?: number;
followRedirects?: boolean;
validateSSL?: boolean;
proxy?: string;
headers?: Record<string, string>;
parallel?: boolean;
concurrency?: number;
}
Request timeout in milliseconds. Must be greater than 0.
Number of automatic retries on failure. Must be greater than 0.
Whether to follow HTTP 3xx redirects.
Whether to validate SSL/TLS certificates.
HTTP proxy URL (e.g., http://proxy:8080).
Whether to run independent requests in parallel.
Maximum number of concurrent requests in parallel mode. Must be greater than 0.
Response 200 OK — returns the updated configuration object.
History
hitspec maintains two layers of history: a lightweight in-memory history for the current session and a persistent SQLite-backed history stored at ~/.hitspec/history.db.
Get In-Memory History
Returns the in-memory execution history for the current server session.
curl http://localhost:8080/api/v1/history
Response 200 OK
[
{
"id": "a1b2c3d4",
"file": "tests/api.http",
"requestName": "Get Users",
"method": "GET",
"url": "http://localhost:3000/users",
"statusCode": 200,
"duration": 245,
"passed": true,
"timestamp": "2026-02-10T12:00:00Z"
}
]
Clear In-Memory History
Clear all in-memory history entries.
curl -X DELETE http://localhost:8080/api/v1/history
Response 204 No Content
List Persistent Runs
Returns paginated persistent run history from the SQLite database.
curl "http://localhost:8080/api/v1/history/runs?limit=20&offset=0"
Number of runs to return. Maximum 100.
Number of runs to skip for pagination.
Response 200 OK
{
"runs": [
{
"id": 42,
"filePath": "tests/api.http",
"environment": "dev",
"startedAt": "2026-02-10T12:00:00Z",
"finishedAt": "2026-02-10T12:00:01Z",
"durationMs": 1200,
"passed": 5,
"failed": 0,
"skipped": 1,
"total": 6
}
],
"total": 150,
"limit": 20,
"offset": 0
}
Get Run Details
Returns a single run with its full results and assertion details.
curl http://localhost:8080/api/v1/history/runs/42
Response 200 OK
{
"id": 42,
"filePath": "tests/api.http",
"environment": "dev",
"startedAt": "2026-02-10T12:00:00Z",
"finishedAt": "2026-02-10T12:00:01Z",
"durationMs": 1200,
"passed": 5,
"failed": 0,
"skipped": 1,
"total": 6,
"results": [
{
"id": 101,
"requestName": "Get Users",
"method": "GET",
"url": "http://localhost:3000/users",
"statusCode": 200,
"durationMs": 243,
"passed": true,
"description": "Fetch all users",
"bodyPreview": "{\"data\":[{\"id\":1,\"name\":\"Alice\"}]}",
"assertions": [
{
"id": 201,
"operator": "equals",
"subject": "status",
"expected": "200",
"actual": "200",
"passed": true
}
]
}
]
}
Delete a Run
Delete a specific run and all its associated results and assertions (cascade delete).
curl -X DELETE http://localhost:8080/api/v1/history/runs/42
Response 204 No Content
Delete All Runs
Delete all persistent run history.
curl -X DELETE http://localhost:8080/api/v1/history/runs
Response 204 No Content
List Results by Request Name
Retrieve historical results for a specific request, filtered by file path. Useful for comparing how a single request’s responses have changed over time. Results are ordered by run start time (newest first).
curl "http://localhost:8080/api/v1/history/results?requestName=GetUsers&filePath=api.http&limit=20&offset=0"
The name of the request to look up.
The file path containing the request.
Maximum number of results to return (1–100).
Number of results to skip for pagination.
Response 200 OK
{
"results": [
{
"id": 101,
"runId": 42,
"requestName": "GetUsers",
"method": "GET",
"url": "https://api.example.com/users",
"statusCode": 200,
"durationMs": 134,
"passed": true,
"skipped": false,
"error": null,
"bodyPreview": "{\"users\": [...]}",
"filePath": "api.http",
"environment": "staging",
"runStartedAt": "2026-02-19T15:30:00Z",
"assertions": []
}
],
"total": 15,
"limit": 20,
"offset": 0
}
Stress Testing
Start Stress Test
Start a load test against the requests defined in one or more files. Metrics are broadcast in real time over the WebSocket connection via stress_update messages.
curl -X POST http://localhost:8080/api/v1/stress/start \
-H "Content-Type: application/json" \
-d '{
"files": ["tests/api.http"],
"duration": "30s",
"rate": 50,
"vus": 10,
"maxVUs": 20
}'
Request Body
{
files: string[]; // Required. List of .http/.hitspec files (relative paths)
duration: string; // Required. Go duration string (e.g., "30s", "5m", "1h")
rate?: number; // Optional. Target requests per second
vus?: number; // Optional. Number of virtual users (switches to VU mode)
maxVUs?: number; // Optional. Maximum concurrent virtual users
}
List of .http or .hitspec file paths relative to the workspace.
Duration of the stress test as a Go duration string (e.g., "30s", "5m", "1h").
Target requests per second in rate mode.
Number of virtual users. Setting this switches from rate mode to VU mode.
Maximum number of concurrent virtual users.
Response 200 OK
Error 409 Conflict if a stress test is already running.
Stop Stress Test
Stop a running stress test. If no test is currently running, the endpoint returns 200 OK with an "already_stopped" status instead of an error.
curl -X POST http://localhost:8080/api/v1/stress/stop
Response 200 OK
When no test is running:
{ "status": "already_stopped" }
Get Stress Test Status
Returns whether a stress test is running and, if so, the current metrics.
curl http://localhost:8080/api/v1/stress/status
Response 200 OK
{
"running": true,
"elapsed": 15.3,
"stats": {
"total": 750,
"success": 745,
"errors": 5,
"rps": 49.8,
"p50Ms": 12.5,
"p95Ms": 45.2,
"p99Ms": 120.0,
"maxMs": 350.0,
"errorRate": 0.0067,
"activeVUs": 10
}
}
When no stress test is running:
{ "running": false, "elapsed": 0, "stats": null }
Get Stress Test Result
Returns the result of the last completed stress test, including summary metrics, latency percentiles, and per-request breakdown.
curl http://localhost:8080/api/v1/stress/result
Response 200 OK
{
"duration": 30.0,
"totalRequests": 1500,
"successCount": 1485,
"errorCount": 15,
"avgRps": 50.0,
"latency": {
"min": 2.1,
"max": 350.0,
"mean": 25.3,
"stddev": 18.7,
"p50": 12.5,
"p95": 45.2,
"p99": 120.0
},
"thresholds": [
{ "metric": "p95", "threshold": "200ms", "actual": 45.2, "passed": true },
{ "metric": "errors", "threshold": "1%", "actual": 1.0, "passed": true }
],
"perRequest": [
{
"name": "Get Users",
"count": 750,
"successCount": 745,
"errorCount": 5,
"avgMs": 22.1,
"minMs": 2.1,
"maxMs": 200.0,
"p50Ms": 11.0,
"p95Ms": 40.0,
"p99Ms": 100.0
}
]
}
When no result is available:
{ "error": "Not Found", "message": "no stress test result available" }
List Stress Profiles
Returns the stress test profiles defined in hitspec.yaml.
curl http://localhost:8080/api/v1/stress/profiles
Response 200 OK
[
{
"name": "smoke",
"duration": "10s",
"rate": 5
},
{
"name": "load",
"duration": "5m",
"rate": 100,
"thresholds": {
"p95": "200ms",
"errors": "1%"
}
},
{
"name": "spike",
"duration": "2m",
"vus": 200,
"maxVUs": 500,
"rampUp": "30s",
"thinkTime": "500ms"
}
]
Create Stress Profile
Create a new stress profile. The profile is persisted to hitspec.yaml.
curl -X POST http://localhost:8080/api/v1/stress/profiles \
-H "Content-Type: application/json" \
-d '{
"name": "smoke",
"duration": "30s",
"rate": 10,
"maxVUs": 5
}'
Request Body
{
name: string; // Required. Unique profile name
duration: string; // Required. Go duration string (e.g., "30s", "5m")
rate?: number; // Optional. Target requests per second
vus?: number; // Optional. Number of virtual users
maxVUs?: number; // Optional. Maximum concurrent virtual users
rampUp?: string; // Optional. Ramp-up duration
thinkTime?: string; // Optional. Think time between requests per VU
thresholds?: { // Optional. Pass/fail thresholds
p95?: string;
p99?: string;
errors?: string;
};
}
Unique name for the profile. Must not conflict with an existing profile.
Duration of the stress test as a Go duration string.
Response 201 Created
Error 409 Conflict if a profile with the same name already exists.
Update Stress Profile
Update an existing stress profile. The changes are persisted to hitspec.yaml.
curl -X PUT http://localhost:8080/api/v1/stress/profiles/smoke \
-H "Content-Type: application/json" \
-d '{"duration": "1m", "rate": 20, "maxVUs": 10}'
Name of the profile to update.
Request Body: Same fields as Create Stress Profile (except name).
Response 200 OK
Error 404 Not Found if the profile does not exist.
Delete Stress Profile
Delete a stress profile. The deletion is persisted to hitspec.yaml.
curl -X DELETE http://localhost:8080/api/v1/stress/profiles/smoke
Name of the profile to delete.
Response 204 No Content
Error 404 Not Found if the profile does not exist.
Mock Server
Start Mock Server
Start a mock server that serves responses based on the request/response pairs defined in your .http files. Incoming requests to the mock server are broadcast over WebSocket as mock_request events.
curl -X POST http://localhost:8080/api/v1/mock/start \
-H "Content-Type: application/json" \
-d '{"files": ["mocks/users.http"], "port": 3000, "delay": "100ms"}'
Request Body
{
files: string[]; // Required. List of .http/.hitspec files with mock definitions
port?: number; // Optional. Port for the mock server (default: 3000)
delay?: string; // Optional. Artificial response delay (Go duration, e.g., "100ms")
}
List of .http or .hitspec file paths containing request/response pairs.
Port on which the mock server will listen.
Artificial delay before each response, as a Go duration string (e.g., "100ms", "1s").
Response 200 OK
{
"running": true,
"port": 3000,
"routes": [
{
"method": "GET",
"path": "/users",
"name": "Get Users",
"statusCode": 200,
"contentType": "application/json"
},
{
"method": "POST",
"path": "/users",
"name": "Create User",
"statusCode": 201,
"contentType": "application/json"
}
]
}
Error 409 Conflict if a mock server is already running.
Stop Mock Server
Stop the running mock server.
curl -X POST http://localhost:8080/api/v1/mock/stop
Response 200 OK
Get Mock Routes
Returns the current status and registered routes of the mock server.
curl http://localhost:8080/api/v1/mock/routes
Response 200 OK (when running)
{
"running": true,
"port": 3000,
"routes": [
{
"method": "GET",
"path": "/users",
"name": "Get Users",
"statusCode": 200,
"contentType": "application/json"
}
]
}
Response 200 OK (when not running)
Contract Testing
Verify Contracts
Run contract verification against a live provider. Sends each request defined in the contract files to the provider URL and validates the responses match expectations.
curl -X POST http://localhost:8080/api/v1/contract/verify \
-H "Content-Type: application/json" \
-d '{
"providerUrl": "http://localhost:3000",
"stateHandler": "http://localhost:3000/_state",
"files": ["contracts/users.http"]
}'
Request Body
{
providerUrl: string; // Required. Base URL of the provider to verify against
stateHandler?: string; // Optional. URL for provider state setup endpoint
files?: string[]; // Optional. Specific contract files (defaults to all workspace files)
}
The base URL of the provider service to verify contracts against.
URL of an endpoint that accepts state setup requests before each interaction.
List of contract file paths. When omitted, all .http/.hitspec files in the workspace are used.
Response 200 OK
[
{
"file": "contracts/users.http",
"passed": 3,
"failed": 0,
"skipped": 0,
"duration": 450,
"results": [
{
"name": "Get Users",
"provider": "UserService",
"state": "users exist",
"passed": true,
"duration": 150
},
{
"name": "Create User",
"provider": "UserService",
"state": "no users",
"passed": true,
"duration": 200
}
]
}
]
List Contract Files
Returns all .http/.hitspec files in the workspace that can be used as contract files.
curl http://localhost:8080/api/v1/contract/files
Response 200 OK
{
"files": [
"contracts/users.http",
"contracts/orders.http",
"tests/api.http"
]
}
Recording Proxy
Start Recording
Start a recording proxy that captures HTTP traffic passing through it. The proxy forwards requests to the target URL and records both request and response.
curl -X POST http://localhost:8080/api/v1/record/start \
-H "Content-Type: application/json" \
-d '{
"targetUrl": "http://localhost:3000",
"port": 8081,
"deduplicate": true
}'
Request Body
{
targetUrl: string; // Required. URL to proxy requests to
port?: number; // Optional. Proxy listen port (default: 8081)
deduplicate?: boolean; // Optional. Remove duplicate request recordings
exclude?: string[]; // Optional. URL patterns to exclude from recording
sanitize?: string[]; // Optional. Header names to sanitize in recordings
}
The upstream URL that the proxy forwards requests to.
Port on which the recording proxy will listen.
When true, duplicate requests with the same method and path are only recorded once.
List of URL path patterns to exclude from recording.
List of header names whose values should be sanitized (replaced with placeholders) in the recorded output.
Response 200 OK
{
"status": "started",
"port": 8081
}
Error 409 Conflict if a recording proxy is already running.
Stop Recording
Stop the recording proxy.
curl -X POST http://localhost:8080/api/v1/record/stop
Response 200 OK
Get Recording Status
Returns whether the recording proxy is running, how many requests have been captured, and the captured request details.
curl http://localhost:8080/api/v1/record/status
Response 200 OK (when running)
{
"running": true,
"targetUrl": "http://localhost:3000",
"port": 8081,
"count": 12,
"recordings": [
{
"method": "GET",
"path": "/users",
"url": "http://localhost:3000/users",
"contentType": "application/json",
"statusCode": 200,
"duration": 45
},
{
"method": "POST",
"path": "/users",
"url": "http://localhost:3000/users",
"contentType": "application/json",
"statusCode": 201,
"duration": 67
}
]
}
Response 200 OK (when not running)
{ "running": false, "count": 0 }
Export Recordings
Export all captured recordings as .http file content. The proxy must be running.
curl -X POST http://localhost:8080/api/v1/record/export
Response 200 OK
{
"content": "### Get Users\nGET http://localhost:3000/users\nAccept: application/json\n\n### Create User\nPOST http://localhost:3000/users\nContent-Type: application/json\n\n{\"name\": \"Alice\"}\n"
}
Clear Recordings
Clear all captured recordings without stopping the proxy.
curl -X DELETE http://localhost:8080/api/v1/record/clear
Response 200 OK
Import
Import curl
Convert a curl command or a file containing curl commands into .http format.
# From a command string
curl -X POST http://localhost:8080/api/v1/import/curl \
-H "Content-Type: application/json" \
-d '{"command": "curl -X GET https://api.example.com/users -H \"Authorization: Bearer token\""}'
# From a file
curl -X POST http://localhost:8080/api/v1/import/curl \
-H "Content-Type: application/json" \
-d '{"filePath": "exports/commands.sh"}'
Request Body
{
command?: string; // A curl command string to convert
filePath?: string; // Path to a file containing curl commands (relative to workspace)
}
One of command or filePath is required.
A curl command string to convert to .http format.
Path to a file containing curl commands, relative to the workspace.
Response 200 OK
{
"content": "### Imported Request\nGET https://api.example.com/users\nAuthorization: Bearer token\n",
"requestCount": 1
}
Import Insomnia
Convert an Insomnia export (JSON) into .http format.
# From inline JSON data
curl -X POST http://localhost:8080/api/v1/import/insomnia \
-H "Content-Type: application/json" \
-d '{"data": "{\"_type\":\"export\",\"resources\":[...]}"}'
# From a file
curl -X POST http://localhost:8080/api/v1/import/insomnia \
-H "Content-Type: application/json" \
-d '{"filePath": "insomnia-export.json"}'
Request Body
{
data?: string; // Insomnia export JSON as a string
filePath?: string; // Path to an Insomnia export file (relative to workspace)
}
One of data or filePath is required.
Insomnia export JSON content as a string.
Path to an Insomnia JSON export file, relative to the workspace.
Response 200 OK
{
"content": "### Get Users\nGET https://api.example.com/users\n\n### Create User\nPOST https://api.example.com/users\nContent-Type: application/json\n\n{\"name\":\"Alice\"}\n",
"requestCount": 2
}
Import OpenAPI
Convert an OpenAPI specification (YAML or JSON, v2 or v3) into .http format. The spec can be a local file path or a URL.
# From a local file
curl -X POST http://localhost:8080/api/v1/import/openapi \
-H "Content-Type: application/json" \
-d '{"specPath": "openapi.yaml", "baseUrl": "http://localhost:3000"}'
# From a URL
curl -X POST http://localhost:8080/api/v1/import/openapi \
-H "Content-Type: application/json" \
-d '{"specPath": "https://petstore.swagger.io/v2/swagger.json"}'
Request Body
{
specPath: string; // Required. Path or URL to the OpenAPI spec
baseUrl?: string; // Optional. Override the base URL in the spec
}
Path to the OpenAPI specification file (relative to workspace) or a URL. Supports YAML and JSON, OpenAPI v2 and v3.
Override the base URL from the spec. Useful when the spec references a production URL but you want to target localhost.
Response 200 OK
{
"content": "### List Pets\nGET http://localhost:3000/pets\n\n### Create Pet\nPOST http://localhost:3000/pets\nContent-Type: application/json\n\n{\"name\":\"Fido\",\"tag\":\"dog\"}\n",
"requestCount": 2
}
Export
Export as curl
Convert requests from a .http/.hitspec file into curl commands.
# Export all requests in a file
curl -X POST http://localhost:8080/api/v1/export/curl \
-H "Content-Type: application/json" \
-d '{"file": "tests/api.http"}'
# Export a specific request
curl -X POST http://localhost:8080/api/v1/export/curl \
-H "Content-Type: application/json" \
-d '{"file": "tests/api.http", "requestName": "Create User"}'
Request Body
{
file: string; // Required. Relative path to the file
requestName?: string; // Optional. Export only this named request
}
Relative path to the .http or .hitspec file in the workspace.
Name of a specific request to export. When omitted, all requests are exported.
Response 200 OK
{
"commands": [
"curl -X GET 'http://localhost:3000/users' -H 'Accept: application/json'",
"curl -X POST 'http://localhost:3000/users' -H 'Content-Type: application/json' -d '{\"name\":\"Alice\"}'"
]
}
System
Get System Info
Returns version, build time, Go version, and platform information.
curl http://localhost:8080/api/v1/system/info
Response 200 OK
{
"version": "2.6.0",
"buildTime": "2026-02-10T12:00:00Z",
"goVersion": "go1.25.0",
"os": "darwin",
"arch": "arm64"
}
WebSocket
Connect
Establish a WebSocket connection for real-time event streaming. The server pushes events as they occur — no polling required.
ws://localhost:8080/api/v1/ws
The WebSocket endpoint accepts connections from localhost, 127.0.0.1, and [::1] origins only.
Connection Example
const ws = new WebSocket('ws://localhost:8080/api/v1/ws');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(msg.type, msg.payload);
};
// Keep alive with ping/pong
setInterval(() => {
ws.send(JSON.stringify({ type: 'ping' }));
}, 30000);
Message Envelope
All WebSocket messages use this envelope format:
{
type: string; // Message type identifier
payload: any; // Type-specific payload
timestamp: string; // ISO 8601 timestamp (UTC)
}
Message Types
execution_start
Sent when a request execution begins.
{
"type": "execution_start",
"payload": {
"id": "a1b2c3d4",
"file": "tests/api.http",
"status": "started",
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
request_progress
Sent for each individual request as it starts and completes during an execution.
{
"type": "request_progress",
"payload": {
"execId": "a1b2c3d4",
"file": "tests/api.http",
"requestName": "Get Users",
"status": "completed",
"index": 0,
"total": 3,
"passed": true,
"duration": 245,
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
The status field is either "started" or "completed". The passed and duration fields are only present when status is "completed".
execution_complete
Sent when an entire execution finishes. The result payload contains the full RunResultDTO.
{
"type": "execution_complete",
"payload": {
"id": "a1b2c3d4",
"file": "tests/api.http",
"status": "completed",
"result": { "file": "tests/api.http", "duration": 500, "passed": 3, "failed": 0, "skipped": 0, "results": [] },
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
error
Sent when an execution fails with an error.
{
"type": "error",
"payload": {
"id": "a1b2c3d4",
"file": "tests/api.http",
"status": "error",
"error": "parse error: unexpected token at line 5",
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
environment_changed
Sent when the active environment is switched via PUT /api/v1/environments/active.
{
"type": "environment_changed",
"payload": {
"name": "staging",
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
file_changed
Sent when a .http or .hitspec file is created, modified, or deleted in the workspace (via filesystem watcher).
{
"type": "file_changed",
"payload": {
"path": "tests/api.http",
"operation": "write",
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
stress_update
Sent every 500ms during an active stress test with current metrics. The running and completed booleans indicate the test lifecycle — the UI uses these to detect when a test finishes naturally (without an explicit stop) and transition to the results view.
{
"type": "stress_update",
"payload": {
"running": true,
"completed": false,
"stats": {
"total": 750,
"success": 745,
"errors": 5,
"rps": 49.8,
"p50Ms": 12.5,
"p95Ms": 45.2,
"p99Ms": 120.0,
"maxMs": 350.0,
"errorRate": 0.0067,
"activeVUs": 10
},
"elapsed": 15.3,
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
mock_request
Sent when the mock server receives a request, or when it starts/stops.
{
"type": "mock_request",
"payload": {
"event": "request",
"method": "GET",
"path": "/users",
"status": 200,
"duration": 1.2,
"timestamp": "2026-02-10T12:00:00Z"
},
"timestamp": "2026-02-10T12:00:00Z"
}
The event field can be "started", "stopped", or "request".
ping / pong
Clients can send {"type": "ping"} messages and the server will respond with a pong:
{
"type": "pong",
"payload": null,
"timestamp": "2026-02-10T12:00:00Z"
}