Execute chained API calls defined in YAML configuration files
Project description
API Chain Runner
A powerful Python CLI tool for executing chained API calls defined in YAML. Each step can reference responses from previous steps, generate unique test data, upload files, poll for expected values, retry on failures, and add delays between steps — all logged to CSV or Excel.
Perfect for API testing, integration testing, workflow automation, and complex multi-step API scenarios.
Installation
pip install api-chain-runner
Quick Start
- Create a YAML config file (e.g.
my_chain.yaml):
chain:
- name: auth
url: "https://api.example.com/login"
method: POST
headers:
Content-Type: "application/json"
payload:
email: "${ENV:AUTH_EMAIL}"
password: "${ENV:AUTH_PASSWORD}"
- name: get_user
url: "https://api.example.com/user/${auth.userId}"
method: GET
headers:
Authorization: "Bearer ${auth.token}"
- Create a
.envfile:
AUTH_EMAIL="user@example.com"
AUTH_PASSWORD="secret"
- Run it:
api-chain-runner my_chain.yaml
That's it. Results are saved to my_chain_results.csv by default.
CLI Usage
# Basic run
api-chain-runner my_chain.yaml
# Custom output path
api-chain-runner my_chain.yaml -o output/results.csv
# Excel output
api-chain-runner my_chain.yaml -o results.xlsx -f xlsx
# Launch web UI
api-chain-runner --ui flow/
# Custom env file
api-chain-runner my_chain.yaml -e production.env
# Check version
api-chain-runner --version
Programmatic Usage
You can also use it as a Python library:
from api_chain_runner import ChainRunner, ChainResult
runner = ChainRunner("my_chain.yaml")
result: ChainResult = runner.run()
print(f"{result.passed}/{result.total_steps} steps passed")
for step in result.results:
print(f" {step.step_name}: HTTP {step.status_code}")
Features
Cross-Step References
Use ${step_name.key.path} to pass data between steps:
Authorization: "Bearer ${auth.idToken}"
url: "https://api.example.com/status?id=${create_lead.leadId}"
Environment Variables
Keep secrets out of your YAML with ${ENV:VAR_NAME}:
variables:
my_token: "${ENV:MY_TOKEN}"
firebase_key: "${ENV:FIREBASE_KEY}"
chain:
- name: auth
url: "https://api.example.com/auth?key=${ENV:API_KEY}"
method: POST
Create a .env file in your project directory:
MY_TOKEN="eyJhbGciOi..."
FIREBASE_KEY="AIzaSy..."
API_KEY="your-api-key"
The .env file is auto-loaded from the config file's directory, its parent directory, or the current working directory. No extra flags needed.
For a custom env file, use -e / --env:
api-chain-runner my_chain.yaml -e production.env
api-chain-runner --ui flow/ -e staging.env
Library usage:
runner = ChainRunner("my_chain.yaml") # auto-loads .env
runner = ChainRunner("my_chain.yaml", env_file="prod.env") # custom env file
Rules:
.envvalues don't override existing shell environment variables- Lines starting with
#are comments - Unresolved
${ENV:...}placeholders are left as-is for clear error messages
Variables
Define reusable values at the top of your config:
variables:
base_url: "https://api.example.com"
token: "static-token-value"
chain:
- name: get_data
url: "${vars.base_url}/data"
method: GET
headers:
Authorization: "Bearer ${vars.token}"
Retry Configuration
Automatically retry steps that fail due to transient errors:
- name: fetch-data
url: "https://api.example.com/data"
method: GET
retry:
max_attempts: 3 # total attempts (default: 3)
delay: 2 # seconds between retries (default: 5)
retry_on: # error types to retry on
- timeout
- connection
- 5xx
Retry types:
timeout— request timed outconnection— connection refused / DNS failure5xx— server returned 500-5994xx— server returned 400-499 (use with caution)
To disable retries: retry: false
Default behavior: 3 attempts on timeout/connection/5xx errors.
Console output during retry:
[5/21] ▶ application-creation running....
🔄 [retry] Attempt 1/3 failed — HTTP 504
🔄 [retry] Waiting 5s before next attempt...
🔄 [retry] Attempt 2/3 failed — HTTP 504
🔄 [retry] Waiting 5s before next attempt...
🔄 [retry] Succeeded on attempt 3/3
✅ Passed — HTTP 200 (1205ms)
Each retry attempt is logged to the console so you can watch the progression. Only the final result (success or exhausted retries) is logged to CSV.
Unique Data Generation
Auto-generate unique emails, PAN numbers, mobile numbers, and UDYAM IDs per run:
payload:
email: "placeholder"
pan: "placeholder"
mobile: "placeholder"
udyam: "placeholder"
unique_fields:
email: email
pan: pan
mobile: mobile
udyam: udyam
You can control the PAN entity type (the 4th character) using a suffix:
| Generator Type | 4th Character | Entity Type |
|---|---|---|
pan |
Random | Any |
pan-p |
P |
Individual |
pan-c |
C |
Company |
pan-h |
H |
HUF |
pan-f |
F |
Firm |
pan-a |
A |
AOP |
pan-t |
T |
Trust |
unique_fields:
pan: pan-p # Individual PAN
pan: pan-c # Company PAN
pan: pan # random entity type
Custom Generators (Plugin System)
Register your own generator functions when using api-chain-runner as a library:
import random
from api_chain_runner import ChainRunner
runner = ChainRunner("my_chain.yaml")
runner.generator.register_generator(
"name", lambda: random.choice(["Alice", "Bob", "Charlie"])
)
result = runner.run()
Then use it in YAML:
unique_fields:
customer_name: name
- Function must take no args and return a string.
- Cannot override built-ins (
email,pan,mobile,udyam).
Polling
Wait for async operations to complete:
polling:
key_path: "status"
expected_values: ["APPROVED", "COMPLETED"]
interval: 10
max_timeout: 120
Supports negative array indices:
polling:
key_path: "applications.-1.status" # -1 = last element
expected_values: ["APPROVED"]
interval: 5
max_timeout: 60
Delays
Add wait time between steps:
- name: check-status
url: "https://api.example.com/status"
method: GET
delay: 20
File Uploads
Upload files as multipart/form-data:
files:
document: "path/to/file.pdf"
Conditional Steps
Skip steps based on previous responses:
# Single condition
- name: generate-link
url: "https://api.example.com/link"
method: POST
condition:
step: check-status
key_path: "status"
expected_value: "PENDING"
# Multiple conditions (ALL must pass)
- name: ready-to-sanction
url: "https://api.example.com/sanction"
method: POST
condition:
- step: check-status
key_path: "kyb.udyam"
expected_value: "SUCCESS"
- step: check-status
key_path: "kyb.pan"
expected_value: "SUCCESS"
Response Evaluation
Extract and evaluate response values against conditions:
- name: check-scores
url: "https://api.example.com/report?userId=${app.userId}"
method: GET
eval_keys:
profile_score: "features.PROFILE_SCORE"
pan_score: "features.PAN_SCORE"
eval_condition: "profile_score > 0.55 and pan_score > 0.55"
success_message: "Scores above threshold - SUCCESS"
failure_message: "Scores below threshold - FAILURE"
Supports any Python comparison: >, ==, and, or, is not None, etc.
Manual Steps
Pause the chain for manual actions (e.g. filling a form in a browser):
- name: complete-registration
manual: true
instruction: "Open the link above, fill the form, then press Enter here"
print_ref:
- "generate-link.link"
Pause / Resume
Press p to pause between steps, r or Enter to resume, Ctrl+C to abort.
Web UI
API Chain Runner includes a built-in web dashboard for visualizing, editing, and running your chains from the browser.
# Launch the UI (scans current directory for YAML flows)
api-chain-runner --ui
# Point to a specific flow directory
api-chain-runner --ui flow/
# Custom port
api-chain-runner --ui flow/ --port 8080
This opens a local web server at http://127.0.0.1:5656 with:
- Dashboard — lists all discovered YAML chain files with step counts and folder grouping
- Flow Visualization — vertical flowchart with method badges, connector arrows, and status indicators
- Run from UI — execute flows live with real-time pass/fail status and color-coded HTTP status codes
- Step Responses — response table with status, duration, and resizable response body preview
- Step Editor — click any step to edit URL, headers, payload directly and save back to the YAML file
- Full YAML Editor — edit the raw YAML with save support
- Create New Flows — create new chains from the dashboard with name, folder, and initial steps
- Dark / Light Mode — toggle themes with persistent preference
No extra setup needed — the UI is included in the package.
Step Fields Reference
| Field | Required | Type | Description |
|---|---|---|---|
name |
Yes | string | Unique step identifier |
url |
No* | string | Request URL (supports ${step.key} references) — *required unless manual: true |
method |
No* | string | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) — *required unless manual: true |
headers |
No | dict | Request headers |
payload |
No | dict | JSON request body |
files |
No | dict | File uploads (field: path) |
unique_fields |
No | dict | Auto-generate unique values (path: type) |
polling |
No | object | Retry until response matches expected value |
delay |
No | int | Seconds to wait before this step |
print_keys |
No | list | Response keys to print to console |
manual |
No | bool | Manual checkpoint step |
instruction |
No* | string | Instructions for manual steps — *required if manual: true |
print_ref |
No | list | References to print from previous steps |
condition |
No | object/list | Conditional execution (single or multiple) |
continue_on_error |
No | bool | Stop chain on failure if false |
retry |
No | object/bool | Retry configuration for transient failures |
eval_keys |
No | dict | Extract response values into named variables |
eval_condition |
No | string | Python expression to evaluate using eval_keys |
success_message |
No | string | Message printed when eval_condition is true |
failure_message |
No | string | Message printed when eval_condition is false |
Output
Results are logged to CSV or Excel with timestamps, including full request/response details for each step.
============================================================
Running chain: my_chain (3 steps)
============================================================
[1/3] ▶ auth (POST https://api.example.com/login)
✅ Passed — HTTP 200 (342ms)
[2/3] ▶ create-lead (POST https://api.example.com/lead)
✅ Passed — HTTP 200 (1205ms)
[3/3] ▶ check-status (GET https://api.example.com/status)
✅ Passed — HTTP 200 (89ms)
============================================================
Done: 3 passed, 0 failed out of 3 steps
Results saved to: my_chain_results.csv
============================================================
Requirements
- Python 3.10+
All dependencies (requests, pyyaml, openpyxl, flask) are installed automatically.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file api_chain_runner-2.5.3.tar.gz.
File metadata
- Download URL: api_chain_runner-2.5.3.tar.gz
- Upload date:
- Size: 63.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55df32a3fcf651e790753bb977e55d838cc27fb69a0248662b26c248db739d08
|
|
| MD5 |
15dd812704d515add4509190ad9d64ab
|
|
| BLAKE2b-256 |
0a2a51d50349584cde69577e525fd18f16fbeee14691ba7806944cdaecc1406c
|
File details
Details for the file api_chain_runner-2.5.3-py3-none-any.whl.
File metadata
- Download URL: api_chain_runner-2.5.3-py3-none-any.whl
- Upload date:
- Size: 64.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ee0c9509840a92c4f29013af1b9026447899b0420bd8063de3475a16fb7244c
|
|
| MD5 |
f30b95b0e9f99aa9109b3d5bf57a52d6
|
|
| BLAKE2b-256 |
e2eb7d8f83406fd4536b056dd2d7890cd8a17d32c3ee382ab89def20b43dbeff
|