Skip to content

apitally/cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

33 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Apitally CLI for agents

Tests Codecov Release

A command-line interface for Apitally, built for agents.

Apitally is a simple API monitoring and analytics tool that makes it easy to understand API usage, monitor performance, and troubleshoot issues.

Learn more about Apitally on our 🌎 website or check out the πŸ“š documentation.

Highlights

  • Stream API request logs from Apitally to a local DuckDB database
  • Run arbitrary SQL queries against that database to analyze API request data
  • Single binary with bundled DuckDB, no runtime dependencies, written in Rust (it's fast)

Installation

Install the CLI with the standalone installer script:

# On macOS and Linux
curl -fsSL https://apitally.io/cli/install.sh | sh
# On Windows
powershell -ExecutionPolicy Bypass -c "irm https://apitally.io/cli/install.ps1 | iex"

Alternatively, you can download the binary for your platform from the latest release on GitHub.

Authentication

To use the CLI, you need an API key. You can create one in the Apitally dashboard under Settings β†’ API keys.

Then run the auth command to configure your API key interactively:

apitally auth

Or provide the key directly:

apitally auth --api-key "your-api-key"

The API key is saved to ~/.apitally/auth.json.

You can also set the API key via the APITALLY_API_KEY environment variable or pass the --api-key flag to any command.

Commands

Run apitally --help to see all commands and options.

apps

apitally apps [--db <path>]

List all apps in your team. Use this to get app IDs for other commands.

Outputs newline-delimited JSON (one object per line). If you provide the --db example.duckdb flag, data is written to the apps table in the provided database instead. Existing records will be updated. If the database file doesn't exist, it will be created.

Example command:

apitally apps

Example output (without --db flag):

{"id":1,"name":"Example API 1","framework":"FastAPI","client_id":"76bf09e2-8996-4dd0-bdb5-ccdc3a48f64c","envs":[{"id":1,"name":"prod","created_at":"2026-01-01T00:00:00.000000Z","last_sync_at":"2026-01-01T01:00:00.000000Z"}],"created_at":"2026-01-01T00:00:00.000000Z"}
{"id":2,"name":"Example API 2","framework":"FastAPI","client_id":"339c08bb-5e88-4cba-a24d-be9d80fbd096","envs":[{"id":2,"name":"prod","created_at":"2026-01-02T00:00:00.000000Z","last_sync_at":"2026-01-02T01:00:00.000000Z"}],"created_at":"2026-01-02T00:00:00.000000Z"}

consumers

apitally consumers <app-id> [--requests-since <datetime>] [--db <path>]

List all consumers for an app. Use this to get consumer details to combine with request log data, which only includes consumer IDs.

Use the --requests-since flag to only return consumers that have made requests since a specific date/time (ISO 8601 format).

Outputs newline-delimited JSON (one object per line). If you provide the --db example.duckdb flag, data is written to the consumers table in the provided database instead. Existing records will be updated. If the database file doesn't exist, it will be created.

Example command:

apitally consumers 1 --requests-since "2026-01-01T00:00:00Z"

Example output (without --db flag):

{"id":1,"identifier":"bob@example.com","name":"Bob","group":{"id":1,"name":"Admins"},"created_at":"2026-01-01T00:00:00Z","last_request_at":"2026-01-01T01:00:00Z"}
{"id":2,"identifier":"alice@example.com","name":"Alice","group":null,"created_at":"2026-01-02T00:00:00Z","last_request_at":"2026-01-02T02:00:00Z"}

request-logs

apitally request-logs <app-id> \
  --since <datetime> [--until <datetime>] \
  [--fields <json>] [--filters <json>] [--limit <n>] \
  [--db <path>]

Retrieve request log data for an app.

The time range is --since inclusive and --until exclusive. If --until is not provided, it defaults to now. If a timestamp does not include a timezone, UTC is assumed.

Outputs newline-delimited JSON (one object per line). If you provide the --db example.duckdb flag, data is written to the request_logs table in the provided database instead. Existing records will be updated. If the database file doesn't exist, it will be created.

Results are ordered by timestamp ascending and capped at 1,000,000 records. Requests to endpoints marked as excluded in the Apitally dashboard are not returned.

Use the --fields flag to pass a JSON array of fields to include. If omitted, default fields are returned.

Field Type Default
timestamp string (datetime) βœ…
request_uuid string (ID) βœ…
app_env string βœ…
method string βœ…
path string βœ…
url string βœ…
consumer_id int (ID) βœ…
request_headers array of tuples
request_size int βœ…
request_body_json string (JSON)
status_code int βœ…
response_time_ms int βœ…
response_headers array of tuples
response_size int βœ…
response_body_json string (JSON)
client_ip string βœ…
client_country_iso_code string βœ…
exception_type string
exception_message string
exception_stacktrace string
sentry_event_id string (ID)
trace_id string (ID)

Use the --filters flag to pass a JSON array of filter objects with field, op, and value keys. Multiple filters are combined with a logical AND. Supported operators are:

  • String fields: eq, neq, in, not_in, like, not_like, ilike, not_ilike
  • Numeric fields: eq, neq, gt, gte, lt, lte, in, not_in
  • Header fields: eq, neq, in, not_in, like, not_like, ilike, not_ilike, exists, not_exists
  • ID fields: eq, neq, in, not_in

For in and not_in, value must be a JSON array. For header fields, also provide key for the header name. For exists and not_exists, omit value.

Example command:

apitally request-logs 1 \
  --since "2026-01-01T00:00:00Z" \
  --filters '[{"field":"status_code","op":"gte","value":400}]' \
  --limit 2

Example output (without --db flag):

{"timestamp":"2026-01-01T00:15:00.000Z","request_uuid":"2fbc1df6-3124-4ed1-a376-7d2c64e4d5cf","app_env":"prod","method":"GET","path":"/test/1","url":"https://api.example.com/test/1","consumer_id":1,"request_size":0,"status_code":404,"response_time_ms":122,"response_size":66,"client_ip":"203.0.113.10","client_country_iso_code":"DE"}
{"timestamp":"2026-01-01T00:16:00.000Z","request_uuid":"c6d32f8a-0bc1-43c1-b6c5-7d04363dc97c","app_env":"prod","method":"GET","path":"/test/2","url":"https://api.example.com/test/2","consumer_id":1,"request_size":0,"status_code":500,"response_time_ms":68,"response_size":66,"client_ip":"198.51.100.22","client_country_iso_code":"US"}

sql

apitally sql [<query>] --db <path>

Run a SQL query against a local DuckDB database and output the result as newline-delimited JSON (one object per line). If the query argument is omitted, the query is read from stdin.

Available tables are apps, app_envs, consumers, and request_logs.

DuckDB's SQL dialect closely matches PostgreSQL's semantics.

Example commands:

apitally sql \
  "SELECT timestamp, method, path, status_code FROM request_logs WHERE status_code >= 400" \
  --db example.duckdb
echo "SELECT COUNT(*) FROM request_logs" | apitally sql --db example.duckdb

Example output:

{"timestamp":"2026-01-01T00:16:00.000Z","method":"POST","path":"/users","status_code":500}
{"timestamp":"2026-01-01T00:15:00.000Z","method":"GET","path":"/users/{userId}","status_code":404}

Exit codes

Code Meaning
0 Success
1 General / unknown error
2 Usage error (invalid arguments, missing required flags)
3 Authentication error (missing or invalid API key)
4 Input error (invalid argument values)
5 API / network error

Getting help

If you need help please create a new discussion on GitHub or email us at support@apitally.io. We'll get back to you as soon as possible.