Documentation

Complete guide to setting up, configuring, and using OrchestAPI — the self-hosted API test orchestration platform with DAG-based dependencies, live streaming, infrastructure verification, and scheduled execution.

Prerequisites

Quick Start

1. Start PostgreSQL

Using Docker:

docker run -d \
  --name orchestapi-db \
  -e POSTGRES_USER=orchestapi \
  -e POSTGRES_PASSWORD=your_password \
  -e POSTGRES_DB=orchestapi \
  -p 5432:5432 \
  postgres:17

Or use any existing PostgreSQL instance.

2. Start the Backend

cd backend

# Set your database credentials
export DB_URL=jdbc:postgresql://localhost:5432/orchestapi
export DB_USERNAME=orchestapi
export DB_PASSWORD=your_password

# Run
./mvnw spring-boot:run

The backend starts on http://localhost:8080. Database schema and tables are created automatically via Flyway on first startup.

3. Start the Frontend

cd frontend
npm install
npm run dev

The frontend starts on http://localhost:3000 and proxies API calls to the backend.

Docker Deployment

The recommended way to deploy OrchestAPI in production is via Docker. The image bundles both frontend and backend into a single container.

Using Docker Compose (recommended)

# Clone the repository
git clone https://github.com/santhoshkumr96/orchestapi.git
cd orchestapi

# Start everything (PostgreSQL + OrchestAPI)
docker compose up -d

# Open http://localhost:8080
Tip: Set DB_PASSWORD in a .env file next to docker-compose.yml for security.

Using Docker directly

# Pull the image
docker pull santhoshkumr96/orchestapi:latest

# Run with your own PostgreSQL
docker run -d \
  --name orchestapi \
  -p 8080:8080 \
  -e DB_URL=jdbc:postgresql://your-host:5432/orchestapi \
  -e DB_USERNAME=orchestapi \
  -e DB_PASSWORD=your_password \
  santhoshkumr96/orchestapi:latest

Building the image locally

docker build -t santhoshkumr96/orchestapi:latest .

Environments

Environments hold all the configuration for a target system — variables, headers, infrastructure connectors, and files. Each test suite has a default environment, which can be overridden at run time.

Go to Environments in the sidebar, click New Environment, then configure the sections below.

Variables

Key-value pairs available to all steps via ${VAR_NAME} syntax.

FieldDescription
KeyVariable name (unique per environment)
ValueVariable value
Value TypeSTATIC (use as-is), UUID (auto-generate per request), ISO_TIMESTAMP (auto-generate current UTC time)
SecretToggle on to mask the value in API responses and UI

Common variables: BASE_URL, API_KEY, AUTH_TOKEN, TENANT_ID.

Default Headers

Headers automatically added to every API step that uses this environment. Step-level headers override these if the same key is used.

FieldDescription
Header KeyHeader name (e.g., Authorization, Content-Type)
Value TypeHow the value is generated
Header ValueThe value or variable reference

Value Types

TypeBehaviorExample
STATICUse the value as-isapplication/json
VARIABLELook up an environment variable by nameapi_token → resolves to the variable's value
UUIDAuto-generate a new UUID v4 per request550e8400-e29b-41d4-...
ISO_TIMESTAMPAuto-generate current UTC timestamp2026-02-26T10:30:00.000Z

Connectors

Infrastructure connectors for post-step verifications (e.g., check a DB row was created, verify a Kafka event was published). See Connector Reference for all types and config fields.

FieldDescription
NameUnique name (referenced in step verifications)
TypeMYSQL, POSTGRES, ORACLE, SQLSERVER, REDIS, ELASTICSEARCH, KAFKA, RABBITMQ, MONGODB
ConfigType-specific connection fields (host, port, credentials, SSL, etc.)

Use the Test Connection button to verify connectivity before saving.

Files

Binary files stored in the database, referenced in form-data requests via ${FILE:fileKey}.

FieldDescription
File KeyUnique identifier (used in ${FILE:key} syntax)
FileThe uploaded file (any type, max 50 MB)

Test Suites

A test suite is a collection of API steps with an optional dependency graph (DAG). Go to Test Suites in the sidebar.

FieldDescription
NameSuite name (unique)
DescriptionOptional description
Default EnvironmentEnvironment used unless overridden at run time

Steps within a suite can depend on each other, forming a directed acyclic graph. The execution engine resolves this graph and runs steps in the correct order.

Steps

Each step represents a single API call. Click + Add Step or use Import from curl to create one. The step editor has a familiar tabbed interface:

HTTP Methods

GET POST PUT DELETE PATCH

The URL supports placeholders: ${BASE_URL}/api/users/{{Create User.id}}

Headers

Step-level headers that override environment defaults when the same key is used. Each header is a key-value pair. Placeholders work in both key and value.

Default Headers: Environment default headers are auto-applied to every step. Toggle individual default headers on/off per step in the Headers tab.

Request Body

Body TypeDescription
NoneNo request body (default for GET/DELETE)
JSONRaw JSON body with syntax validation. Content-Type set to application/json
Form DataMultipart form-data with text and file fields

Form Data Fields

FieldTypeValue
KeyForm field name
TypetextPlain text (supports ${VAR} and {{step.path}} placeholders)
TypefileFile reference using ${FILE:fileKey} syntax

Query Parameters

Key-value pairs appended to the URL as ?key=value&key2=value2. Placeholders supported in both key and value.

Dependencies

Steps that must execute before this one. Select from other steps in the same suite.

OptionDefaultDescription
Use CachetrueReuse the dependency's cached response if TTL hasn't expired. Set false to always re-execute.
Reuse Manual InputtrueIf the dependency has #{param} placeholders and the value was already provided, silently reuse it. Set false to prompt again.

Once a dependency is added, reference its response data with {{StepName.jsonPath}} in any field.

Variable Extraction

Extract values from a step's response for use in later steps.

FieldDescription
Variable NameName to store the extracted value
JSON PathPath to the value in the response
SourceWhere to extract from

Extraction Sources

SourceJSON Path / KeyDescription
RESPONSE_BODY$.data.idExtract from JSON response body
RESPONSE_HEADERAuthorizationExtract a response header value by name
STATUS_CODE(not used)Stores the HTTP status code as a string
REQUEST_BODY$.orderIdExtract from the resolved request body
REQUEST_HEADERX-Request-IDExtract a resolved request header value
QUERY_PARAMpageExtract a resolved query parameter value
REQUEST_URL(not used)Stores the full resolved request URL
Resolved values: All extracted values are the actual runtime values, not the placeholder templates. For example, extracting from REQUEST_HEADER with key X-Request-ID returns the generated UUID, not ${REQUEST_ID}.

JSON Path Syntax

PatternExampleDescription
$.field$.idTop-level field
$.nested.field$.data.user.nameNested field
$.array[0]$.items[0]First array element
$.array[0].field$.items[0].idField in first array element
$.length()$.items.length()Array or string length
$.size()$.items.size()Same as length()

Response Handlers

Define what action to take for each HTTP status code. Handlers are evaluated in priority order. Specific codes take precedence over ranges.

FieldDescription
Match CodeHTTP status code or range: 200, 404, 2xx, 4xx, 5xx
ActionWhat to do when matched
PriorityEvaluation order (0 = first)

Actions

ActionDescriptionExtra Fields
SUCCESSMark step as successful, proceed to dependents
ERRORMark step as failed, skip dependents
RETRYRe-execute the step after a delayretryCount (max attempts), retryDelaySeconds
FIRE_SIDE_EFFECTExecute another step as a side effectsideEffectStepId (which step to trigger)

Example Setup

Match CodeActionPriorityNotes
2xxSUCCESS0Any 2xx is success
500RETRY1Retry on server error (3 times, 5s delay)
4xxERROR2Client errors are failures

Caching

Within-run response caching to avoid re-executing the same dependency multiple times.

FieldDefaultDescription
CacheablefalseEnable caching for this step's response
Cache TTL (seconds)0How long the cache is valid. 0 = valid until run ends
Per-run only: Cache is not shared across different runs. When a dependent step needs this step's result and the cache has expired, the step is automatically re-executed.

Dependency-Only Steps

FieldDefaultDescription
Dependency OnlyfalseWhen true, the step is skipped during suite runs. It only executes when a dependent step needs it. The individual Run button still works.

Use this for setup steps (e.g., "Create Auth Token") that should only run when another step depends on them.

Verifications (Infrastructure)

Run queries against infrastructure connectors after the API call completes, then assert on the results. Verify side effects like database rows, Kafka events, or Redis keys.

FieldDescription
ConnectorWhich environment connector to use (by name)
QueryThe query/command to execute (connector-specific)
Timeout (s)Overall verification timeout (default 30)
Query Timeout (s)Query execution timeout (default 30)
Pre-ListenStart listening BEFORE the step executes (for Kafka, RabbitMQ)

Pre-Listen Mode

For asynchronous systems where the event is published during the API call:

  1. Verification sets up a listener (e.g., Kafka consumer) before the API call
  2. Step executes the API call
  3. Listener waits for a matching message within the timeout
  4. Assertions run on the received message

Assertions

Each verification can have multiple assertions on the query result:

OperatorDescriptionExample
EQUALSExact match$.status EQUALS "active"
NOT_EQUALSNot equal$.status NOT_EQUALS "deleted"
CONTAINSSubstring match$.message CONTAINS "success"
NOT_CONTAINSDoesn't contain$.error NOT_CONTAINS "fatal"
REGEXRegex pattern match$.email REGEX ^.+@.+\..+$
GTGreater than (numeric)$.count GT 0
LTLess than (numeric)$.latency LT 1000
GTEGreater than or equal$.count GTE 1
LTELess than or equal$.retries LTE 3
EXISTSField exists$.id EXISTS
NOT_EXISTSField doesn't exist$.error NOT_EXISTS

Response Validation

Validate the HTTP response itself (separate from infrastructure verifications). Four validation types are available:

1. Header Validation

Assert response headers match expected values. Useful for checking content types, cache headers, auth tokens.

FieldDescription
Header NameResponse header to check
OperatorEQUALS, CONTAINS, REGEX, EXISTS, etc.
Expected ValueValue to compare against

2. Body Exact Match

Compare the entire response body against an expected payload.

Match ModeDescription
STRICTExact match — same keys, same values, same structure
FLEXIBLESubset match — expected fields must be present, extra fields allowed
STRUCTUREShape match — validates structure and types only, ignores actual values

3. Body Field Assertion

Target specific fields via JSON path and apply assertion operators.

FieldDescription
JSON PathPath to the value (e.g., $.data.orders[0].total)
OperatorEQUALS, CONTAINS, GT, LT, REGEX, EXISTS, etc.
Expected ValueValue to compare against

4. Body Data Type

Verify field types at any JSON path.

Expected TypeMatches
STRINGJSON string values
NUMBERInteger or decimal numbers
BOOLEANtrue or false
ARRAYJSON arrays
OBJECTJSON objects
NULLNull values

Placeholders & Autocomplete

OrchestAPI supports four types of dynamic placeholders. All placeholder-enabled fields show an autocomplete dropdown.

Environment Variables — ${VAR_NAME}

Type ${ to trigger autocomplete. Resolves to the variable value from the active environment. Works in URL, headers, body, query params, and verification queries.

Highlighted in green in the editor.

Step Response References — {{StepName.path}}

Type {{ to trigger autocomplete. References extracted variables or any JSON path from a dependency step's response. Two-step autocomplete:

  1. Type {{ → shows dependent step names
  2. Select a step → type . → shows extracted variable names
  3. You can also type a custom JSON path (e.g., {{StepName.data.items[0].id}})
Highlighted in blue in the editor.

Manual Input — #{paramName}

SyntaxExampleBehavior
#{paramName}#{otp}Prompts user at runtime (required)
#{paramName:default}#{env:production}Prompts with pre-filled default (optional)

During execution, the UI pauses and shows an input modal. Enter the value and execution resumes.

Scheduled runs: Only #{param:default} placeholders work (the default is applied automatically). #{param} without a default is skipped.
Highlighted in red/orange in the editor.

File References — ${FILE:fileKey}

Type ${FILE: to trigger autocomplete. References an uploaded file from the environment's Files section. Used in form-data fields to attach files to multipart requests.

Running Tests

Single Step

Click the play button next to any step. The step and all its transitive dependencies execute in order. Results show the target step at top level with dependencies in a collapsible accordion.

Full Suite

Click Run Suite at the top of the suite detail page. Optionally override the default environment. All non-dependency-only steps execute in topological order based on the dependency graph.

Live Streaming (SSE)

Both single step and suite runs stream results in real time via Server-Sent Events:

EventDescription
run-startedRun initiated, returns runId
stepA step completed — includes full result with status, response, verifications
input-requiredExecution paused — a step needs manual input
completeAll steps finished — includes final status and total duration
run-errorFatal error during run

Manual Input During Runs

When a step contains #{param} placeholders, execution pauses and shows a modal. Each parameter is shown with its name, optional default, and cached value from earlier steps.

Run Results

Each step result includes:

FieldDescription
StatusSUCCESS, ERROR, SKIPPED, VERIFICATION_FAILED, VALIDATION_FAILED
Response CodeHTTP status code
Response BodyFull response body
Response HeadersAll response headers
DurationExecution time in milliseconds
Request URLThe resolved URL that was called
Request BodyThe resolved request body
Extracted VariablesVariables extracted from the response
Verification ResultsEach verification's pass/fail with assertion details
Validation ResultsResponse validation pass/fail details
From CacheWhether the result was served from cache

Step Status Values

StatusColorDescription
SUCCESSGreenStep and all verifications/validations passed
ERRORRedHTTP call failed or response handler returned ERROR
SKIPPEDGrayDependency failed or step not needed
VERIFICATION_FAILEDPurpleAPI call succeeded but infrastructure verification assertions failed
VALIDATION_FAILEDTealAPI call succeeded but response validation failed

Suite Status Values

StatusDescription
SUCCESSAll steps passed
PARTIAL_FAILURESome steps failed but suite continued
FAILUREA critical step failed

Scheduling

Go to Runs page → Schedules tab.

Create a Schedule

FieldDescription
Test SuiteWhich suite to run
EnvironmentWhich environment to use
Cron ExpressionStandard 5-field cron pattern
DescriptionOptional label
ActiveToggle on/off without deleting

Cron Format

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, 0=Sunday)
│ │ │ │ │
* * * * *

Examples

ExpressionDescription
0 0 * * *Every day at midnight
0 9 * * *Every day at 9:00 AM
*/15 * * * *Every 15 minutes
0 */4 * * *Every 4 hours
0 9 * * MONEvery Monday at 9:00 AM
0 0 1 * *First of every month at midnight

Use Preview to see the next fire times before saving.

Scheduled run behavior: Runs are non-interactive. #{param:default} uses the default automatically. #{param} without a default is skipped. Results are saved with trigger type SCHEDULED.

Run History

Go to Runs page → Run History tab.

FilterDescription
SuiteFilter by test suite
EnvironmentFilter by environment
StatusSUCCESS, FAILURE, PARTIAL_FAILURE, CANCELLED, RUNNING
Trigger TypeMANUAL or SCHEDULED
Date RangeFilter by start date range

Click any row to expand full step-by-step results. Export results to JSON.

Dashboard

The dashboard shows execution statistics at a glance:

Mock Server

Create standalone mock API endpoints to simulate external services during testing. Go to Mock Server in the sidebar.

Mock Servers

FieldDescription
NameServer name (unique)
DescriptionOptional description
EnabledToggle to enable/disable the mock server

Each mock server gets a unique URL: http://your-host/mock/{serverId}/...

Mock Endpoints

Each endpoint defines a path pattern, HTTP method, and configurable response.

FieldDescription
NameEndpoint name
HTTP MethodGET, POST, PUT, DELETE, PATCH, or ANY
Path PatternURL path to match (supports :param and /** wildcard)
Response StatusHTTP status code to return
Response BodyBody to return
Response HeadersCustom headers to include
Delay (ms)Artificial delay before responding
Match RulesAdditional conditions (header, query param, body JSON path)

Path Matching

PatternMatches
/api/usersExact path
/api/users/:idParameterized segment (/api/users/123)
/api/**Wildcard — any path under /api/

Match Rules

All rules must match (AND logic). Endpoints are evaluated in sort order — first match wins.

TypeDescription
HEADERMatch a request header key (and optionally value)
QUERY_PARAMMatch a query parameter key (and optionally value)
BODY_JSON_PATHMatch a JSON path in the request body

Request Logging

All incoming requests are logged with method, path, headers, body, response status, duration, and whether an endpoint was matched.

Webhook Tester

Receive and inspect incoming HTTP requests in real-time — like webhook.site, but self-hosted. Go to Webhooks in the sidebar.

Creating a Webhook

FieldDescription
NameWebhook name (unique)
DescriptionOptional description
Default Response StatusHTTP status code returned to the caller (default: 200)
Default Response BodyBody returned to the caller
Default Response HeadersCustom headers returned to the caller

Each webhook gets a unique URL: http://your-host/webhook/{webhookId}/...

Any HTTP method can be used. The webhook captures everything and returns the configured response.

Request Inspection

The detail page shows a two-panel layout:

Captured Data

FieldDescription
HTTP MethodGET, POST, PUT, etc.
PathPath after /webhook/{id}/
HeadersAll request headers
Query ParametersURL query string parameters
BodyText/JSON as-is, binary base64-encoded
Content-TypeRequest content type
Source IPCaller's IP (supports X-Forwarded-For)
FilesMultipart uploads with preview and download

File Handling

Content TypeBehavior
JSON / textStored as-is, formatted in the UI
Images (image/*)Base64-encoded, rendered inline with preview button
Binary (pdf, audio, video)Base64-encoded, download button available
MultipartFiles extracted with preview (images) and download buttons

Real-Time Streaming

The detail page connects via SSE and shows new requests instantly with a green “Live” indicator. Multiple browser tabs can monitor the same webhook simultaneously.

Limits

LimitValue
Max request body size10 MB (returns 413 if exceeded)
Max stored requests per webhook500 (oldest auto-trimmed)
SSE connection timeout60 minutes

When a webhook is disabled, incoming requests receive a 503 Service Unavailable response.

Curl Import

Quickly create a step from a curl command. Click Import from curl in the suite detail page.

Supported Flags

FlagDescription
-X METHOD / --requestHTTP method
-H "Key: Value" / --headerRequest headers (multiple allowed)
-d data / --dataRequest body
--data-rawRaw body data
--data-binaryBinary body data
URL query paramsAuto-extracted from the URL

Line continuations (\) are handled. Step name is auto-generated from the URL path. Method defaults to POST if body is present, GET otherwise.

Connector Reference

JDBC (MySQL, PostgreSQL, Oracle, SQL Server)

FieldDescription
hostDatabase host
portPort (MySQL: 3306, PG: 5432, Oracle: 1521, MSSQL: 1433)
databaseDatabase name
usernameDatabase user
passwordDatabase password
ssl / caCertificateSSL/TLS config (empty CA = trust all)

Query: Standard SQL SELECT statements.

Result: { "rows": [{ "id": 1, "name": "test" }], "rowCount": 1 }

Redis

FieldDescription
host / portRedis host and port (default 6379)
passwordAuth password (optional)
databaseDatabase index 0-15 (default 0)

Query: GET key, HGET hash field, HGETALL hash, EXISTS key, LRANGE key 0 -1, SISMEMBER set member.

Result: { "value": "data", "type": "string", "exists": true }

Elasticsearch

FieldDescription
urlBase URL (e.g., https://localhost:9200)
username / passwordBasic auth credentials

Query: METHOD /path body — e.g., GET /my-index/_search {"query":{"match_all":{}}}

Kafka

FieldDescription
brokersComma-separated broker list
securityProtocolOptional: SSL, SASL_SSL, SASL_PLAINTEXT
saslMechanismOptional: PLAIN, SCRAM-SHA-256, SCRAM-SHA-512
saslUsername / saslPasswordSASL credentials

Query (newline-separated):

topic=events_topic
key=order-123

Creates an isolated consumer group per verification (UUID-based). Seeks to latest offset and waits for new messages.

Result: { "found": true, "key": "order-123",
  "value": { "eventType": "ORDER_CREATED" },
  "partition": 0, "offset": 42 }

RabbitMQ

FieldDescription
host / portHost and port (5672 or 5671 for SSL)
virtualHostVirtual host (default /)
username / passwordAuth credentials

Query (space-separated): queue=my_queue routingKey=order.created

Result: { "found": true, "routingKey": "order.created",
  "body": { "orderId": "123" }, "headers": {} }

MongoDB

Option A: connectionString — full MongoDB URI.

Option B: Individual fields — host, port, database, username, password.

Query: collection.{filter_json} — e.g., orders.{"orderId":"abc123"}

Result: { "documents": [{ "orderId": "abc123", "status": "completed" }], "count": 1 }

Deployment

Context Path (Reverse Proxy / Kubernetes)

When deploying behind a reverse proxy or Kubernetes Ingress with a path prefix (e.g., https://company.com/orchestapi), set two environment variables:

VariableLayerEffect
CONTEXT_PATHBackend (Spring Boot)Sets server.servlet.context-path — all API routes are prefixed
VITE_BASE_PATHFrontend (Vite/React)Sets Vite base + React Router basename + axios interceptor

VITE_BASE_PATH is a Docker build argument (compiled into the frontend at build time), while CONTEXT_PATH is a runtime environment variable. Both must have the same value.

# Build with custom base path
docker build --build-arg VITE_BASE_PATH=/orchestapi -t orchestapi .

# Run with context path
docker run -d \
  --name orchestapi \
  -p 8080:8080 \
  -e CONTEXT_PATH=/orchestapi \
  -e DB_URL=jdbc:postgresql://db:5432/orchestapi \
  -e DB_USERNAME=orchestapi \
  -e DB_PASSWORD=your_password \
  orchestapi
Tip: For local development, both default to / — no configuration needed.

Nginx Reverse Proxy

location /orchestapi/ {
    proxy_pass http://orchestapi:8080/orchestapi/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Kubernetes Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orchestapi
spec:
  rules:
    - host: company.com
      http:
        paths:
          - path: /orchestapi
            pathType: Prefix
            backend:
              service:
                name: orchestapi
                port:
                  number: 8080

Configuration

Server Environment Variables

VariableDefaultDescription
DB_URLjdbc:postgresql://localhost:5432/testPostgreSQL JDBC URL
DB_USERNAME(required)Database username
DB_PASSWORD(required)Database password
SERVER_PORT8080Backend server port
CONTEXT_PATH/Servlet context path (e.g., /orchestapi)
VITE_BASE_PATH/Frontend base path (Docker build arg, must match CONTEXT_PATH)

Limits

LimitValue
Max file upload size50 MB
Max request body size50 MB
Max page size (pagination)100
Default page size10

Database

© 2026 OrchestAPI. Self-hosted API test orchestration platform.