Skip to main content

Minimal curl wrapper for AI agents - test APIs with filtered, token-efficient output

Project description

reqcap

CI PyPI Python License: MIT

Minimal HTTP client that returns only what you need — status, timing, and the specific JSON fields you ask for. Run templates, save snapshots, test your features e2e quickly.

[!NOTE] ✨ Built for AI agents too. Filtered output saves tokens, --list-templates lets agents discover existing test scenarios, --diff catches regressions, and --install-skill teaches Claude Code to use reqcap automatically.

Why reqcap?

A typical curl -s https://httpbin.org/json dumps 42 lines. reqcap gives you just the fields you asked for:

reqcap GET https://httpbin.org/json -f "slideshow.title,slideshow.author"
STATUS: 200
TIME: 45ms
BODY:
{
  "slideshow": {
    "title": "Sample Slide Show",
    "author": "Yours Truly"
  }
}

Save requests as reusable templates, snapshot known-good responses, diff them later to catch regressions — all from the CLI.

reqcap -t list-users
reqcap -t list-users --snapshot baseline
reqcap -t list-users --diff baseline
reqcap --list-templates

Features

  • Templates — reusable YAML request scenarios with variables, auth, and chaining
  • Snapshots — save responses and diff to detect regressions
  • Response filtering — extract nested fields, array slices, specific indices
  • Assertions--assert status=200 exits 1 on failure
  • Request chaining — export response values and feed them into the next request
  • Template dependencies — declarative depends: for multi-step flows
  • Config file — base URLs, default headers, env var substitution
  • Placeholders{{uuid}}, {{date}}, {{env.VAR}} auto-expand in templates
  • Auth types — bearer, API key, basic auth in config or per-template
  • Form data--form for multipart uploads
  • Curl import — paste a curl command and run it through reqcap
  • History — replay recent requests
  • Project init — scaffold config and directories

Install

Requires uv.

uv tool install reqcap

Quick start

Scaffold config and directories:

reqcap --init

This creates .reqcap.yaml, templates/, and snapshots/.

Test an endpoint with filtered output:

reqcap GET https://httpbin.org/json -f "slideshow.title,slideshow.author"

POST with a JSON body:

reqcap POST https://httpbin.org/post -b '{"name": "test", "email": "test@example.com"}'

Run a saved template:

reqcap -t login -v email=admin@test.com -v password=secret

Snapshot a response, then diff later:

reqcap GET /api/health --snapshot baseline
reqcap GET /api/health --diff baseline

See what templates are available:

reqcap --list-templates

Templates

Templates are standalone YAML files — each template is its own file, not embedded in the config. This keeps templates portable, version-controllable, and easy to share.

[!TIP] For AI agents: An agent can run reqcap --list-templates at the start of a task to discover what test scenarios already exist, then re-run them as it makes changes — like lightweight e2e tests it didn't have to write.

Creating a template

Create a YAML file in your templates/ directory:

# templates/login.yaml
description: Authenticate user
url: /api/auth/login
method: POST
body:
  email: ""
  password: ""
fields:
  - name: email
    path: email
  - name: password
    path: password
exports:
  token: body.access_token
filter:
  body_fields: [access_token, expires_in]

Using templates

Run by name (resolves to templates/login.yaml):

reqcap -t login -v email=admin@test.com -v password=secret

Run by file path:

reqcap -t templates/login.yaml -v email=admin@test.com -v password=secret

List all available templates:

reqcap --list-templates

Template file location

Templates are resolved in this order:

  1. Exact file path (e.g. reqcap -t path/to/my-template.yaml)
  2. templates_dir from config + name (e.g. custom-templates/login.yaml)
  3. ./templates/ + name (e.g. templates/login.yaml)

Template properties

Property Description
name Optional identifier (defaults to filename)
description Shown in --list-templates
url Endpoint path (appended to base_url)
method HTTP method: GET, POST, PUT, PATCH, DELETE
base_url Override the default base_url for this template
headers Template-specific headers (merged with defaults)
auth Template-specific auth (overrides default)
body Request body template (JSON object)
fields Variables injected into body via -v
exports Auto-export response values (see Request chaining)
filter Template-specific response filter
depends List of template names to run first (see Template dependencies)
snapshot Auto-save response: {enabled: true, name: "..."}

Template fields

The fields array defines variables that get injected into the request body at the specified JSON path.

# templates/chat.yaml
url: /api/chat
method: POST
body:
  messages:
    - role: "user"
      content: ""

fields:
  - name: prompt
    path: messages[0].content
reqcap -t chat -v prompt="Hello, world"

The body becomes {"messages": [{"role": "user", "content": "Hello, world"}]}.

Template with per-request auth

# templates/create-user.yaml
url: /api/users
method: POST
auth:
  type: bearer
  token: "{{token}}"
body:
  id: "{{uuid}}"
  name: ""
  email: ""
  created_at: "{{date}}"
fields:
  - name: name
    path: name
  - name: email
    path: email
filter:
  body_fields: [id, name, email]
reqcap -t create-user -v token=sk-abc123 -v name=Alice -v email=alice@test.com

Snapshots

Save responses and diff against them to detect regressions.

reqcap GET /api/health --snapshot baseline
reqcap GET /api/health --diff baseline
reqcap --list-snapshots

Templates can auto-save snapshots with snapshot: {enabled: true}.

[!TIP] For AI agents: Snapshot a response before making changes, then --diff after to verify nothing broke. Agents get a clear pass/fail signal without eyeballing JSON.

Response filtering

The -f/--filter flag extracts only the fields you specify from the response body.

[!TIP] For AI agents: Filtered output keeps responses small and token-efficient. An agent checking a 500-field response only sees the 3 fields it asked for.

Syntax

Pattern Meaning
field Top-level field
nested.field Nested object field
data[].id Field from every array element
data[0].id Field from a specific array index
data[-1] Last element of an array
data[2:5] Slice of array elements
headers[Content-Type] Bracket notation for dict keys
* No filtering (return everything)

Examples

reqcap GET /api/users -f "total,page"
reqcap GET /api/user/1 -f "profile.name,profile.role"
reqcap GET /api/users -f "data[].id,data[].name"
reqcap GET /api/users -f "data[-1].name"
reqcap GET /api/users -f "data[0:3].id"
reqcap GET /api/users -f "total,data[].id,data[].email"

Given this response:

{
  "total": 150,
  "page": 1,
  "data": [
    {"id": 1, "name": "Alice", "email": "alice@co.com", "metadata": {"large": "..."}},
    {"id": 2, "name": "Bob", "email": "bob@co.com", "metadata": {"large": "..."}}
  ]
}

reqcap GET /api/users -f "total,data[].id,data[].name" returns:

{
  "total": 150,
  "data": [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"}
  ]
}

Output modes

Default output includes status, timing, and filtered body. --verbose adds response headers. --raw outputs JSON body only, with no status/time lines — useful for piping:

reqcap GET /api/users --raw | jq '.data[0]'

Assertions

Assert response values and exit with code 1 on failure:

reqcap GET /api/health --assert status=200
reqcap GET /api/user/1 --assert "body.role=admin"
reqcap POST /api/items --assert "status!=500" --assert "body.id!=null"

[!TIP] For AI agents: Assertions give a clear exit code agents can branch on — no output parsing needed.

Request chaining

Chain requests together by exporting values from one response and using them in the next.

Template auto-exports

Define exports in a template to automatically extract and export values from the response:

# templates/login.yaml
url: /api/auth/login
method: POST
body: { email: "", password: "" }
fields:
  - { name: email, path: email }
  - { name: password, path: password }
exports:
  token: body.access_token
  user_id: body.user.id

Export statements are printed to stderr as shell export commands. Capture them with eval:

eval $(reqcap -t login -v email=a@b.com -v password=x 2>&1 1>/dev/null)
reqcap -t get-users -v token=$reqcap_token

CLI --export flag

Export arbitrary fields from any response:

reqcap GET /api/me --export token=body.access_token
reqcap GET /api/me --export id

The shorthand --export id is equivalent to --export id=body.id.

How chaining works

  1. --export prints export reqcap_<name>=<value> to stderr
  2. Wrap with eval $(... 2>&1 1>/dev/null) to set env vars in your shell
  3. Pass them to the next request with -v or -H

For declarative chaining, use depends: in templates instead (see Template dependencies).

Template dependencies

Templates can declare depends: to run prerequisite templates automatically. Exported variables flow through the chain.

# templates/login.yaml
method: POST
url: /api/auth/login
body: { email: "", password: "" }
fields:
  - { name: email, path: email }
  - { name: password, path: password }
exports:
  token: body.access_token
# templates/get-users.yaml
depends:
  - login
method: GET
url: /api/users
headers:
  Authorization: "Bearer {{token}}"

Running reqcap -t get-users -v email=admin -v password=secret executes login first (exporting token), then get-users with the token injected.

Dependencies execute depth-first. Circular dependencies are detected and reported.

[!TIP] For AI agents: A single reqcap -t get-users can handle login + auth + the actual request. Agents don't need to manage multi-step auth flows manually.

Config file

Create a .reqcap.yaml in your project root (or pass -c path/to/config.yaml). The config sets defaults — templates are separate files (see Templates).

reqcap auto-discovers config files in this order: .reqcap.yaml, .reqcap.yml, reqcap.yaml, reqcap.yml.

Minimal config

defaults:
  base_url: http://localhost:3000
  headers:
    Content-Type: application/json

With this config, reqcap GET /api/users resolves to http://localhost:3000/api/users.

Full config structure

defaults:
  base_url: ${API_BASE_URL}
  env_file: .env
  timeout: 30
  templates_dir: templates
  headers:
    Content-Type: application/json
  auth:
    type: bearer
    token: ${API_TOKEN}
  filter:
    status: true
    headers: false
    body_fields: []

Environment variables

Config values can reference environment variables with ${VAR_NAME}. These are resolved from:

  1. A .env file (specified by defaults.env_file)
  2. The shell environment
defaults:
  base_url: ${API_BASE_URL}
  auth:
    token: ${API_TOKEN}
# .env
API_BASE_URL=http://localhost:3000
API_TOKEN=sk-abc123

Placeholders

In templates (URLs, bodies, headers):

Placeholder Value
{{env.VAR_NAME}} Environment variable
{{uuid}} Random UUID v4
{{timestamp}} Unix timestamp (seconds)
{{timestamp_ms}} Unix timestamp (milliseconds)
{{date}} ISO 8601 datetime
{{my_var}} Variable from -v flag or dep export

In config files (.reqcap.yaml): use ${VAR_NAME} for environment variable substitution.

Example

# templates/create-item.yaml
url: /api/items
method: POST
body:
  id: "{{uuid}}"
  created_at: "{{date}}"
  owner: "{{env.USER_ID}}"
  name: ""
fields:
  - name: name
    path: name

Auth types

Configure authentication in defaults.auth or per-template auth:

Bearer token

auth:
  type: bearer
  token: ${API_TOKEN}

API key (custom header)

auth:
  type: api-key
  token: ${API_KEY}
  header: X-API-Key

Basic auth

auth:
  type: basic
  username: ${USER}
  password: ${PASS}

Form data

Submit form data and file uploads with --form:

reqcap POST /api/upload --form name=test --form file=@photo.jpg

Curl import

Parse and execute a curl command directly:

reqcap --import-curl "curl -X POST https://api.example.com/users \
  -H 'Content-Type: application/json' \
  -d '{\"name\": \"test\"}'"

Supports -X, -H, -d, --data, --data-raw, --json, and quoted strings.

History

reqcap saves the last 50 requests (auth headers excluded).

reqcap --history
reqcap --replay 0
reqcap --replay 0 -f "id,name"

Project init

Scaffold a new project with config and directories:

reqcap --init

This creates .reqcap.yaml, templates/, and snapshots/.

[!TIP] For AI agents: Run reqcap --install-skill claude to install an agent skill that teaches Claude Code how to use reqcap — no docs reading needed.

CLI flags reference

Flag Short Description
METHOD URL Direct request (positional args)
--template -t Run a template file (name or path)
--config -c Config file path
--templates-dir Override templates directory
--var -v Variable as key=value (repeatable)
--body -b Request body (JSON string)
--header -H HTTP header as Name: Value (repeatable)
--filter -f Comma-separated body fields to extract
--timeout Request timeout in seconds
--verbose Include response headers
--raw JSON body only (for piping)
--export Export response field as env var (repeatable)
--assert Assert status=200 or body.field!=val (exit 1 on fail)
--snapshot Save response as named snapshot
--diff Diff response against saved snapshot
--list-snapshots List saved snapshots
--snapshots-dir Override snapshots directory
--form Form field KEY=VALUE or KEY=@FILE (repeatable)
--import-curl Parse and run a curl command
--history Show request history
--replay Replay history entry by index
--list-templates List template files in templates dir
--init Scaffold project (config + directories)
--install-skill Install skill data to agent directory
--help Full help with all syntax docs

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

reqcap-1.0.2.tar.gz (85.1 kB view details)

Uploaded Source

Built Distribution

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

reqcap-1.0.2-py3-none-any.whl (36.0 kB view details)

Uploaded Python 3

File details

Details for the file reqcap-1.0.2.tar.gz.

File metadata

  • Download URL: reqcap-1.0.2.tar.gz
  • Upload date:
  • Size: 85.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for reqcap-1.0.2.tar.gz
Algorithm Hash digest
SHA256 2b60de817f1ed9d5e54ed6fccccb7e51173c45f4924c7587d77761f811a81d86
MD5 d01472e405233a6fa973d0251a8c9f2b
BLAKE2b-256 49d455d41312b1ed9a8ff46a74f06f61585179a6f207970a294d01977d270232

See more details on using hashes here.

Provenance

The following attestation bundles were made for reqcap-1.0.2.tar.gz:

Publisher: publish.yml on atsaplin/reqcap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file reqcap-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: reqcap-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 36.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for reqcap-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f9a9abd6dc8860397bea67cd66223eddcb44bf9c7e9a52242c66a90fea0fea6e
MD5 21139c61f737e0d4480a5c801fb9e376
BLAKE2b-256 379920cc77c7d30bcbedc73db77aaf105e62dc06ecaa017522e74bc98c8f5708

See more details on using hashes here.

Provenance

The following attestation bundles were made for reqcap-1.0.2-py3-none-any.whl:

Publisher: publish.yml on atsaplin/reqcap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page