Skip to content
moderation-apiPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Moderation API CLI

modapi is the official command-line interface for Moderation API. Use it to moderate content, manage authors, review queues, actions, wordlists, webhooks, projects and channels from your terminal, in scripts and CI, and from AI coding agents.

Summary

Moderation API: Moderate text, images, video and audio in real time, manage authors, review queues and actions, and receive webhooks.

More information about the API can be found at https://docs.moderationapi.com

Table of Contents

CLI Installation

Homebrew (macOS/Linux)

brew install moderation-api/tap/modapi

Quick Install (Linux/macOS)

curl -fsSL https://raw.githubusercontent.com/moderation-api/cli/main/scripts/install.sh | bash

Quick Install (Windows PowerShell)

iwr -useb https://raw.githubusercontent.com/moderation-api/cli/main/scripts/install.ps1 | iex

Go Install

Alternatively, install directly via Go:

go install github.com/moderation-api/cli/cmd/modapi@latest

Manual Download

Download pre-built binaries for your platform from the releases page.

Shell Completion

Shell completions are available for Bash, Zsh, Fish, and PowerShell.

Bash

# Add to ~/.bashrc:
source <(modapi completion bash)

# Or install permanently:
modapi completion bash > /etc/bash_completion.d/modapi

Zsh

# Add to ~/.zshrc:
source <(modapi completion zsh)

# Or install permanently:
modapi completion zsh > "${fpath[1]}/_modapi"

Fish

modapi completion fish | source

# Or install permanently:
modapi completion fish > ~/.config/fish/completions/modapi.fish

PowerShell

modapi completion powershell | Out-String | Invoke-Expression

CLI Example Usage

Example

modapi content submit --content '{"type":"text","text":"Hey, check out my profile for a deal!"}' --content-id message-48213 --author-id user-1092 --conversation-id room-general --metadata '{"platform":"ios"}'

Set up Moderation API in your project

Run init in your project's directory. It links one of your Moderation API projects or creates a new one, and writes the project's keys to your env file:

modapi login   # once per machine; opens the browser
modapi init    # in your project
modapi doctor  # check the setup at any time

init detects your language, framework and package manager, writes MODAPI_SECRET_KEY and MODAPI_WEBHOOK_SECRET to .env.local (Next.js) or .env, and adds that file to .gitignore. Describe your platform so the project can suggest moderation policies:

modapi init --domain acme.com \
  --context "Marketplace where buyers and sellers chat before a booking" \
  --brief "Stop contact details shared outside the platform, scams and harassment"

To connect a directory to a project you already have, run modapi link (or modapi link "<project name>"). It makes a new key for the project, so you can revoke it on its own. Agents and scripts pass init --project <id or name> or init --new instead of answering the question.

init does not change your code. To add the moderation calls, let your coding agent do it with the setup skill:

npx skills add moderation-api/skills

Then ask your agent to "set up Moderation API". The skill finds where users create content, adds the moderation call, handles the result and sets up webhooks, asking you before each change.

Without a browser (for example over SSH), use modapi login --device. In CI, skip login and set MODAPI_ORGANIZATION_KEY to an organization key from the dashboard.

Moderating content

Set your API key once, then submit content:

export MODAPI_SECRET_KEY="your-project-key"

modapi content submit --content '{"type":"text","text":"Your text here"}' --author-id user-123

Images, video and audio take a URL:

modapi content submit --content '{"type":"image","url":"https://example.com/image.jpg"}'

Use --jq to read one field of the result, for example the recommended action (allow, review or reject):

modapi content submit --content '{"type":"text","text":"Your text here"}' --jq '.recommendation.action'

Add --dry-run to any command to see the request it would send, without sending it.

For AI agents

This CLI is built to be driven by AI coding agents as well as people: everything an agent needs is discoverable from the binary itself, and every command can be validated without credentials. Work down this ladder:

Run You get
modapi --help, modapi actions list --help Commands by category, runnable examples, flags
modapi --usage, modapi actions list --usage The command surface as machine-readable KDL: commands, aliases, flags, defaults, env vars, config keys
modapi actions create --schema The exact JSON Schema of the command's request body (all $refs bundled) — build a valid --body from it
modapi actions list --dry-run The exact HTTP request (method, URL, headers, body), with no credentials or network call
modapi actions list --output-format json (or --jq) Machine-readable output

Discover the command surface

# Every command, flag, default, env var and config key, as KDL
modapi --usage

# One command's subtree only
modapi actions list --usage

Read the exact request schema

--schema is available on every command that accepts a request body (--body, stdin, or a whole-body flag where the command has one), including intent commands. It prints the JSON Schema the request is validated against and exits without calling the API.

# JSON Schema (draft 2020-12) of the request body, with every $ref bundled under $defs
modapi actions create --schema

Probe before you spend

Start quota-spending commands with --dry-run. It validates inputs, resolves the request, redacts secrets and binary payloads, makes no network call, and exits 0. It never reads the OS keychain; credentials supplied by flag, environment, or config file are included only as [REDACTED].

# Human preview: the [DRY-RUN] block is on stderr and stdout is empty
modapi actions list --dry-run

# Machine preview: compact JSON on stdout and silent stderr
modapi actions list --dry-run --output-format json

The machine form writes one object per would-be request, one per line (NDJSON for multi-request commands), with exactly this shape:

{"dry_run":true,"request":{"method":"POST","url":"https://…","headers":{"Accept":["application/json"],…},"body":<JSON value | string | null>}}

body is a parsed JSON value when the body is JSON, a string for text, "<bytes:N>" for binary data, and null when absent. An explicit caller --jq also selects this JSON preview protocol, but the filter is not applied to preview objects. Command-declared jq presets do not select or filter the preview.

Local mutation commands make no request under --dry-run: instead of a preview they emit one {"dry_run":true,"local":true,"command":"…","message":"…"} object. select(.request) keeps only would-be requests; select(.local) keeps the local no-ops.

Machine-readable output

# JSON on stdout
modapi actions list --output-format json

# Filter or reshape with a jq expression (always emits JSON, overrides --output-format)
modapi actions list --jq '.'

# Print jq string results as plain text instead of JSON strings (like jq -r)
modapi actions list --jq '.' --raw-output

--output-format toon emits TOON, a compact line-oriented format that uses fewer tokens than JSON; it is the default in agent mode.

Interactive mode

Required-input prompts and guided configure / auth login forms are enabled by default. Required-input prompts require an interactive terminal; off-TTY forms read line input from stdin. Use --no-interactive to force flag-only execution.

# Prompt for missing command inputs
modapi actions list --interactive

# Open the guided configuration form
modapi configure --interactive

# Explicitly launch the terminal command explorer
modapi explore

Agent mode and structured errors

Agent mode turns on automatically when a known agent environment is detected (CLAUDECODE, CURSOR_AGENT, CODEX, AIDER, CLINE, WINDSURF_AGENT, GITHUB_COPILOT, AMAZON_Q, GEMINI_CODE_ASSIST, SRC_CODY) or with --agent-mode (--agent-mode=false disables detection). In agent mode interactive prompts never launch, output defaults to TOON, and every failure — API errors and CLI usage errors alike — is one JSON envelope on stderr: --output-format json and --jq use the same error envelope without requiring agent mode.

{
  "error": "...",
  "error_type": "validation_error",
  "error_reason": "CLI_VALIDATION",
  "exit_code": 2,
  "message": "human-readable message",
  "hints": ["what to try next"]
}

error_type is one of authentication_error, authorization_error, not_found, validation_error, rate_limit_error, server_error, api_error, connection_error, protocol_error, runtime_error, unsupported_error, async_failed, async_timeout, async_unknown_state. Classification derives from the HTTP status and transport evidence; error_reason is absent for API errors. Status-less local failures may use CLI_VALIDATION, CLI_CONNECTION, CLI_PROTOCOL, CLI_RUNTIME, CLI_UNAVAILABLE, CLI_AUTHENTICATION, or the async polling reasons CLI_ASYNC_FAILED, CLI_ASYNC_TIMEOUT, and CLI_ASYNC_UNKNOWN_STATE. hints preserves server guidance first, adds the most specific local taxonomy guidance, then typed CLI and command-specific guidance, removing exact duplicates. exit_code is always the code for the final error_type shown in the envelope: 1 runtime, 2 usage, or 3 authentication/authorization.

Lists, streams, and files

List commands accept --all to fetch every page and stream results as they arrive (one JSON value per line with --output-format json; --max-pages N bounds the walk).

Structured output and agent mode never write pagination hints to stderr; if a later page fails or the server repeats a cursor, the command exits non-zero after the pages already written.

modapi actions list --all --output-format json

Authentication

Authentication credentials can be configured in four ways (in order of priority):

1. Command-line flags

Pass credentials directly as flags to any command:

modapi --secret-key "$MODAPI_SECRET_KEY" actions list

2. Environment variables

Set credentials via environment variables:

Variable Description
MODAPI_SECRET_KEY HTTP Bearer

3. OS Keychain (recommended for workstations)

Credentials are stored securely in your operating system's keychain when you run:

modapi configure

Secret credentials (tokens, API keys, passwords) are automatically stored in:

  • macOS: Keychain
  • Linux: GNOME Keyring / KWallet (via D-Bus Secret Service)
  • Windows: Windows Credential Locker

If no keychain is available (e.g., in CI environments), credentials fall back to the config file.

Where the keychain cannot be unlocked (e.g., headless Linux or SSH sessions with a locked GNOME Keyring), skip it entirely with --no-keyring, MODAPI_NO_KEYRING=true, or no_keyring: true in the config file. The keychain is then never read or written, and secrets are stored in the config file instead; flags and environment variables still take precedence.

4. Configuration file

Run the interactive configure command to store non-secret settings:

modapi configure

Configuration is stored in ~/.config/modapi/config.yaml.

Project and organization keys

Moderation API has two kinds of API keys:

  • A project key works with one project: content, authors, review queues, actions, wordlists, webhooks and the account.
  • An organization key works with the management API: modapi projects and modapi channels. It can also use any project's endpoints: name the project with --project-id.

A project key can't run the management commands: the API returns 403 with the code organization_key_required. To run a management command while MODAPI_SECRET_KEY holds your project key, pass the organization key for that command:

modapi projects list --secret-key "$MODAPI_ORGANIZATION_KEY"

Commands

Available commands

Request Body Input

Commands that accept a request body take it three ways, with a clear priority chain. The examples use modapi actions create; every body-bearing command works the same way and prints its exact request schema with --schema.

--body flag

Provide the entire request body as a JSON string:

modapi actions create --body '{"name":"Suspend for 24 hours","key":"suspend-24h","type":"AUTHOR_BLOCK_TEMP","queueBehaviour":"REMOVE"}'

Stdin piping (lowest priority)

Pipe JSON into any command that accepts a request body:

echo '{"name":"Suspend for 24 hours","key":"suspend-24h","type":"AUTHOR_BLOCK_TEMP","queueBehaviour":"REMOVE"}' | modapi actions create

This is useful for chaining commands, reading from files, or scripting:

# Read body from a file
modapi actions create < request.json

# Pipe from another command
curl -s https://example.com/request.json | modapi actions create

Priority

When multiple input methods are used, the priority is:

Priority Source Description
1 (highest) Individual flags A field flag always wins
2 --body flag Whole-body JSON via flag
3 (lowest) Stdin Piped JSON input

Server Selection

Override Server URL

Use --server-url to override the server URL entirely, bypassing any named or indexed server selection:

modapi --server-url https://custom-api.example.com actions list

Precedence: --server-url > --server > default

Output Formats

Every command supports a --output-format flag that controls how the response is rendered to stdout.

Available formats

Format Flag Description
Pretty --output-format pretty (default) Aligned key-value pairs with color, nested indentation. Human-readable at a glance.
JSON --output-format json JSON output. Passthrough when the response is already JSON (preserves original field order and numeric precision). Falls back to typed marshaling otherwise.
YAML --output-format yaml YAML output via standard marshaling.
Table --output-format table Tabular output for array responses.
TOON --output-format toon Token-Oriented Object Notation — a compact, line-oriented format that typically uses 30–60% fewer tokens than JSON. Well-suited for piping responses into LLM prompts.
# Default pretty output
modapi actions list

# Machine-readable JSON
modapi actions list --output-format json

# TOON for LLM-friendly compact output
modapi actions list --output-format toon

# Pipe JSON to jq without using --output-format
modapi actions list --output-format json | jq '.'

jq filtering

Use --jq to filter or transform the response inline using a jq expression. This always outputs JSON and overrides --output-format:

# Extract a single field
modapi actions list --jq '.'

# Reshape with any jq program; --raw-output prints string results as plain text (like jq -r)
modapi actions list --jq '.' --raw-output

Color control

Use --color to control terminal colors:

Value Behavior
auto (default) Color when stdout is a TTY, plain text otherwise
always Always colorize
never Never colorize

The NO_COLOR and FORCE_COLOR environment variables are also respected.

Streaming and pagination

When using --all (pagination) or streaming operations, output is written incrementally as items arrive:

Format Streaming behavior
json One compact JSON object per line (NDJSON)
yaml YAML documents separated by ---
toon One TOON-encoded object per block, separated by blank lines
pretty (default) Pretty-printed items separated by blank lines

Pagination

Some operations in this CLI support automatic pagination. These operations accept --all to automatically fetch all pages and stream results incrementally.

Basic usage

# Fetch a single page (default behavior)
modapi actions list

# Automatically fetch all pages
modapi actions list --all

Limiting pages

Use --max-pages with --all to cap the number of pages fetched. A negative value is invalid; 0 means unlimited. Passing --max-pages without --all is an error.

# Fetch at most 5 pages
modapi actions list --all --max-pages 5

Output formats

When using --all, output is streamed as each page is fetched. Operations whose pagination declaration names an outputs.results array emit one item at a time. Other operations emit one complete page object at a time, preserving the single-page response shape and any continuation cursor.

Format Behavior
--output-format json One JSON object per line (NDJSON)
--output-format yaml YAML documents separated by ---
--output-format toon One TOON-encoded block per item, separated by blank lines
Default (pretty) Pretty-printed items separated by blank lines
# Stream all results as NDJSON
modapi actions list --all --output-format json

# Pipe to jq for further processing
modapi actions list --all --output-format json | jq '.'

# Use the built-in --jq flag
modapi actions list --all --jq '.'

How it works

Under the hood, --all calls the operation once, then follows the underlying Next() pagination closure to fetch subsequent pages. Results are written to stdout as they arrive rather than buffered in memory, so this works well even with large result sets.

Without --all, paginated operations behave like any other command — pass cursor, page, offset, or limit flags manually and get a single page of results. In pretty or table output, a cursor response that proves another page exists prints a hint on stderr. JSON, YAML, TOON, --jq, and agent mode keep stderr silent on success. Offset/limit responses do not guess from a full result page. Cursor operations that declare both a results array and a mutable limit also suppress the hint because the client cannot safely reproduce the SDK's runtime limit check.

Pagination can fail after earlier pages have already been written. A later-page API failure or a repeated/cyclic continuation cursor stops with a non-zero exit status; callers should treat stdout as partial whenever the command exits non-zero. --all tracks cursor values and stops before issuing another request when the server repeats one; the same applies to next URLs when the target generator supports them.

Error Handling

The CLI uses standard exit codes to indicate success or failure:

Exit Code Meaning
0 Success
1 Runtime/API failure
2 Usage or input failure
3 Authentication or authorization failure

On success, the response data is printed to stdout as JSON. On failure, error details are printed to stderr.

# Capture output and handle errors
modapi actions list --output-format json > output.json 2> error.log
if [ $? -ne 0 ]; then
  echo "Error occurred, see error.log"
fi

In pretty mode, each error is printed once as Error (<type>): <message>, followed by its reason/HTTP status, actionable Fix: bullets, and only non-duplicative residual details.

In agent mode, or with explicit --output-format json, --output-format toon, or --jq machine output, stderr is one classified JSON envelope with exit_code, error_type, optional error_reason, message, hints, and optional status_code — see For AI agents.

Diagnostics

The CLI includes two diagnostic flags available on all commands:

Dry Run

Preview what would be sent without making any network calls:

modapi actions list --dry-run

In human output modes, stdout is empty and the [DRY-RUN] block goes to stderr. It includes:

  • HTTP method and URL
  • Request headers (sensitive values redacted)
  • Request body preview (sensitive fields redacted)

With --output-format json, or with a caller-explicit --jq, stderr is silent and stdout is NDJSON: one compact preview object per would-be request. The jq filter is not applied, and command-declared jq presets do not select the JSON protocol.

{"dry_run":true,"request":{"method":"POST","url":"https://…","headers":{"Accept":["application/json"],…},"body":<JSON value | string | null>}}

JSON bodies remain structured; text bodies are strings; binary bodies are "<bytes:N>"; absent bodies are null. Headers retain all values as arrays, with credentials replaced by [REDACTED]. Dry-run never reads the OS keychain, but credentials supplied by flag, environment, or config file still appear redacted. The command exits successfully without contacting the API.

Local mutation commands emit one {"dry_run":true,"local":true,"command":"…","message":"…"} object in place of a preview; filter with select(.request) or select(.local).

Debug

Log request and response diagnostics while running normally:

modapi actions list --debug

Debug output goes to stderr and includes:

  • Request method, URL, headers, and body preview
  • Response status, headers, and body preview
  • Transport errors (if any)

The command still executes normally and produces its regular output on stdout.

Flag Precedence

If both --dry-run and --debug are set, --dry-run takes precedence and no network calls are made.

Security

Sensitive information is automatically redacted in diagnostic output:

  • Headers: Authorization, Cookie, Set-Cookie, X-API-Key, and other security headers show [REDACTED]
  • Body: JSON fields named password, secret, token, api_key, client_secret, etc. show [REDACTED]
  • Binary data: binary media and canonical base64 strings are replaced with <bytes:N>
  • URL query: credential-like query parameters are replaced with [REDACTED]

Diagnostic output should still be treated as potentially sensitive operational data.

Support

Found a bug? Open an issue in this repository. This package is generated from the Moderation API OpenAPI spec, so pull requests to the generated code can't be merged as they are, but we use them to fix the generator.

Development

Maturity

This CLI is in beta, and there may be breaking changes between versions without a major version update. Therefore, we recommend pinning usage to a specific package version. This way, you can install the same version each time without breaking changes unless you are intentionally looking for the latest version.

Contributions

This CLI is generated programmatically. Edits to generated files are overwritten on regeneration. To customize it:

  • Configuration and behavior: Use OpenAPI overlays in the Speakeasy workflow with x-speakeasy-* extensions (for example, x-speakeasy-cli-commands) to define commands, flags, help text, examples, authentication, and grouping.
  • Persistent code changes: Store unified diffs as patch files at .speakeasy/patches/<path-of-generated-file>.patch; they are re-applied on every generation.

CLI Created by Speakeasy

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages