Skip to main content

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

  1. 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}"
  1. Create a .env file:
AUTH_EMAIL="user@example.com"
AUTH_PASSWORD="secret"
  1. 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:

  • .env values 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 out
  • connection — connection refused / DNS failure
  • 5xx — server returned 500-599
  • 4xx — 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

Condition operators include equals (the default), not_equals, contains, not_contains, greater_than, greater_than_or_equal, less_than, less_than_or_equal, starts_with, ends_with, is_null, and is_not_null. Multiple conditions are ANDed. Use contains for list membership; unlike eval_condition, a condition controls whether the dependent step runs.

# Single condition (operator defaults to `equals`)
- name: generate-link
  url: "https://api.example.com/link"
  method: POST
  condition:
    step: check-status
    key_path: "status"
    expected_value: "PENDING"

# List membership
- name: next-step
  url: "https://api.example.com/next"
  method: POST
  condition:
    step: get-lead-status
    key_path: "lead_status"
    operator: contains
    expected_value: "okyc"

# 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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

api_chain_runner-2.5.6.tar.gz (74.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

api_chain_runner-2.5.6-py3-none-any.whl (74.5 kB view details)

Uploaded Python 3

File details

Details for the file api_chain_runner-2.5.6.tar.gz.

File metadata

  • Download URL: api_chain_runner-2.5.6.tar.gz
  • Upload date:
  • Size: 74.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for api_chain_runner-2.5.6.tar.gz
Algorithm Hash digest
SHA256 b74ade70c42086faf05edc3f4358432ce4eee8811e5d542ae98c7e2074586ea4
MD5 38f49a36504b5c0cf4bc676d1deebad0
BLAKE2b-256 11fbd89ec30db2e8c63f736ab846cab0005a8fe09da49273f43d5576a861cf4d

See more details on using hashes here.

File details

Details for the file api_chain_runner-2.5.6-py3-none-any.whl.

File metadata

File hashes

Hashes for api_chain_runner-2.5.6-py3-none-any.whl
Algorithm Hash digest
SHA256 b0da739b8ee91585259acc1b01d136ee5fb35cdec7677800e9f336b40f273dee
MD5 dfd0e10c05c24a46bd538809e47660a9
BLAKE2b-256 90fb217c78cf9f18992eafdf28e5a3eca1ff145694ed7eb1771e8c81538d47d3

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2.5.6 This release

2 files

2.5.5

2 files

2.5.3

2 files

1.1.1

2 files

1.1.0

2 files

1.0.5

2 files

1.0.4

2 files

1.0.3

2 files

1.0.2

2 files

1.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page