openapi: 3.1.0 info: title: Piped API version: 1.0.0 description: | Piped is a pipeline processing API that allows you to chain commands together to process text data. Each command is a separate HTTP endpoint that accepts text input and returns text output. Commands can be chained together using the pipeline language (pipe operators `|`) or executed individually. All endpoints require API key authentication via the `X-API-Key` header or `Authorization: Bearer` header. contact: name: Piped Support url: https://piped.sh license: name: MIT url: https://opensource.org/licenses/MIT servers: - url: https://piped.sh description: Production server - url: http://localhost:3000 description: Development server security: - ApiKeyAuth: [] - BearerAuth: [] tags: - name: Text Processing description: Commands for processing and manipulating text - name: Data Formats description: Commands for parsing and manipulating structured data formats - name: Storage description: Commands for file storage and management - name: Aliases description: Manage token-scoped command aliases - name: Exports description: Manage token-scoped environment variables - name: Utilities description: Utility commands for common operations - name: Control Flow description: Commands for conditional execution and control flow - name: HTTP & Communication description: Commands for HTTP requests and communication - name: AI & Analysis description: AI-powered analysis and processing - name: System description: System endpoints for API management and authentication paths: /: get: tags: - System summary: Execute pipeline (GET) description: | Execute a pipeline using GET request. Pipeline must be provided in query parameter. operationId: pipelineGet parameters: - name: pipeline in: query required: true schema: type: string description: Pipeline string (URL-encoded) responses: '200': description: Pipeline executed successfully content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' post: tags: - System summary: Execute pipeline (POST) description: | Execute a pipeline using POST request. Pipeline can be provided in POST body or query parameter. **POST Body Encoding:** For pipelines with special characters, use encoding (priority order): 1. `Content-Transfer-Encoding: urlencoded|base64|quoted-printable` header (highest priority) 2. `Content-Type: text/plain; encoding=urlencoded|base64|quoted-printable` header parameter 3. `?encoding=urlencoded|base64|quoted-printable` query parameter Supported encodings: - `urlencoded` - URL encoding (e.g., `hello%20world`) - `base64` - Base64 encoding - `quoted-printable` or `qp` - Quoted-printable encoding (RFC 2045) operationId: pipelinePost parameters: - name: pipeline in: query required: false schema: type: string description: Pipeline string (URL-encoded). If provided, POST body becomes initial input. - name: encoding in: query required: false schema: type: string enum: [urlencoded, base64, quoted-printable, qp] description: Body encoding type (alternative to Content-Transfer-Encoding header) requestBody: description: Pipeline string (if no query param) or initial input (if pipeline in query param) content: text/plain: schema: type: string application/json: schema: type: object properties: pipeline: type: string input: type: string application/x-www-form-urlencoded: schema: type: object properties: pipeline: type: string input: type: string responses: '200': description: Pipeline executed successfully content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /aliases: get: tags: - Aliases summary: List aliases (Linux-like) description: | Lists all aliases for the authenticated token. Response is `text/plain` with one alias per line: - `alias name=command` Notes: - Aliases are token-scoped and stored encrypted at rest. - Hard limit: max 200 aliases per token (no pagination; this endpoint returns all). - Alias commands may include positional variables (`$1`–`$9`, `$@`, `$*`) that are substituted when the alias is invoked. operationId: aliasesList responses: '200': description: Success content: text/plain: schema: type: string example: | alias grep-kevin=grep -i kevin alias cat-auth=cat --header='Authorization: Bearer $TOKEN' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /aliases/{alias}: post: tags: - Aliases summary: Create or update an alias description: | Creates or updates an alias for the authenticated token. Request body is `text/plain` containing the alias command. Response is `text/plain`: - `alias name=command` Rules: - Alias RHS must be a single command (rejects `|`, `&&`, `||`, `;`, `(`, `)`, `$(`, `!`, and newlines). - No chaining: RHS cannot start with another alias. - Positional arguments are supported in the alias command: - `$1`–`$9` map to the first nine arguments at call time. - `$@` expands to all arguments as separate words; `$*` expands to all arguments as one space-joined string. - Substitution occurs outside single quotes only (e.g. `'$1'` remains literal). - Max alias command length: 2048 characters. - Max 200 aliases per token. operationId: aliasesUpsert parameters: - name: alias in: path required: true schema: type: string description: Alias name requestBody: description: Alias command (text/plain) content: text/plain: schema: type: string example: "grep -i kevin" responses: '200': description: Success content: text/plain: schema: type: string example: "alias grep-kevin=grep -i kevin\n" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' delete: tags: - Aliases summary: Delete an alias description: | Deletes an alias for the authenticated token. Response is `text/plain`: `alias name=` operationId: aliasesDelete parameters: - name: alias in: path required: true schema: type: string description: Alias name responses: '200': description: Success content: text/plain: schema: type: string example: "alias grep-kevin=\n" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /alias: post: tags: - Aliases summary: Alias command endpoint (pipeline form) description: | Pipeline command endpoint for managing aliases. This endpoint is primarily used via pipeline execution, but can be called directly. Modes: - `mode=list` → list aliases - `mode=get&name=` → print one alias; if missing, returns status 200 with an error message in body - `mode=set&name=&command=` → set/update alias Response is `text/plain` (Linux-like). operationId: aliasCommand parameters: - name: mode in: query required: false schema: type: string enum: [list, get, set] default: list - name: name in: query required: false schema: type: string description: Alias name (required for get/set) - name: command in: query required: false schema: type: string description: Alias command (required for set; empty string unsets) requestBody: description: Not used content: text/plain: schema: type: string responses: '200': description: Success content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /exports: get: tags: - Exports summary: List exports (Linux-like) description: | Lists all exports for the authenticated token. Response is `text/plain` with one export per line: - `export NAME="value"` Notes: - Exports are token-scoped and stored encrypted at rest. - Hard limit: max 200 exports per token (no pagination; this endpoint returns all). operationId: exportsList responses: '200': description: Success content: text/plain: schema: type: string example: | export API_TOKEN="secret123" export URL="https://example.com" '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /exports/{name}: post: tags: - Exports summary: Create or update an export description: | Creates or updates an export for the authenticated token. Request body is `text/plain` containing the export value. Response is `text/plain`: - `export NAME="value"` Rules: - Export name must be uppercase (`^[A-Z][A-Z0-9_]*$`). - Export value must not contain newlines. - Max export value length: 2048 characters. - Max 200 exports per token. - Empty body deletes the export (returns `export NAME=""`). operationId: exportsUpsert parameters: - name: name in: path required: true schema: type: string description: Export name (must be uppercase) requestBody: description: Export value (text/plain) content: text/plain: schema: type: string example: "secret123" responses: '200': description: Success content: text/plain: schema: type: string example: 'export API_TOKEN="secret123"\n' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' delete: tags: - Exports summary: Delete an export description: | Deletes an export for the authenticated token. Response is `text/plain`: `export NAME=""` operationId: exportsDelete parameters: - name: name in: path required: true schema: type: string description: Export name responses: '200': description: Success content: text/plain: schema: type: string example: 'export API_TOKEN=""\n' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /export: post: tags: - Exports summary: Export command endpoint (pipeline form) description: | Pipeline command endpoint for managing exports. This endpoint is primarily used via pipeline execution, but can be called directly. Modes: - `mode=list` → list exports - `mode=get&name=` → print one export; if missing, returns status 200 with an error message in body - `mode=set&name=&value=` → set/update export Response is `text/plain` (Linux-like). operationId: exportCommand parameters: - name: mode in: query required: false schema: type: string enum: [list, get, set] default: list - name: name in: query required: false schema: type: string description: Export name (required for get/set; must be uppercase) - name: value in: query required: false schema: type: string description: Export value (required for set; empty string unsets) requestBody: description: Not used content: text/plain: schema: type: string responses: '200': description: Success content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /cat: post: tags: - Text Processing summary: Concatenate and display file contents description: | Reads temp files or saved pipelines and outputs their content. Can number lines, squeeze empty lines, and display metadata. Use `curl` for fetching URLs. **Resolution (per path argument):** 1) Temp file (e.g. `/tmp/file` or bare `file`; wildcards and date expansion supported), 2) Saved pipeline by name (exact, case-sensitive). Temp wins when both a temp file and a saved pipeline match. Paths starting with `/tmp/` are always temp-only (no saved-pipeline fallback). Saved pipeline names cannot start with `/tmp` (reserved). Supports reading from: - Temp files (e.g., `/tmp/file` or just `file`) - Saved pipelines (by name, e.g. `MyPipeline`) - Stdin (via `-` or `stdin` marker) operationId: cat parameters: - name: number in: query schema: type: boolean description: Number all output lines (alias: `n`) - name: nonblank in: query schema: type: boolean description: Number non-blank lines only (alias: `b`) - name: squeeze in: query schema: type: boolean description: Squeeze multiple consecutive empty lines into a single empty line (alias: `s`) - name: silent in: query schema: type: boolean description: Suppress file content output, show only metadata (alias: `S`) - name: path in: query schema: type: array items: type: string style: form explode: true description: Path(s) to read from — temp file or saved pipeline name (multiple allowed) requestBody: description: Input text to process (optional if `path` parameter is provided) content: text/plain: schema: type: string example: "line 1\nline 2\nline 3" responses: '200': description: Success content: text/plain: schema: type: string example: "line 1\nline 2\nline 3" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /ai: post: tags: - AI & Analysis summary: AI-powered text analysis description: | Performs AI-powered analysis on piped input data according to the provided prompt. Supports multiple AI providers (xAI/Grok, OpenAI/GPT, Google/Gemini, Anthropic/Claude). The AI suggests pipeline commands but does not execute them directly. Uses your own API keys if configured, otherwise uses Piped's service keys (AI-as-a-Service). operationId: ai parameters: - name: prompt in: query required: true schema: type: string description: The AI prompt/question (required) - name: provider in: query required: false schema: type: string enum: [xai, openai, google, gemini, anthropic, claude] description: | AI provider override. Valid values: `xai`, `openai`, `google`, `gemini` (alias for google), `anthropic`, or `claude` (alias for anthropic). Overrides the token's default provider setting. - name: platform in: query required: false schema: type: string enum: [user, piped] description: | API key source selection. Valid values: `user` (use your own API keys) or `piped` (use Piped's service keys). Default: uses your own keys if configured, otherwise Piped's service keys. requestBody: description: Input data to analyze (context for the AI) content: text/plain: schema: type: string example: "CSV data or text to analyze" responses: '200': description: Success content: text/plain: schema: type: string example: "AI analysis and suggested pipeline commands" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /history: get: tags: - System summary: View pipeline execution history description: | Displays a history of executed pipelines with various filtering and formatting options. Pipeline execution history is automatically stored after each pipeline execution. Supports filtering by status, time range, and limiting results. Use standard Unix tools like `grep` for searching pipeline strings. operationId: history parameters: - name: failed in: query schema: type: boolean description: Show only failed pipelines (alias: `-f`, `--failed`) - name: success in: query schema: type: boolean description: Show only successful pipelines (alias: `-s`, `--success`) - name: limit in: query schema: type: integer minimum: 1 description: Limit number of results (alias: `-n`, `--limit`) - name: since in: query schema: type: string description: Show entries since timestamp (ISO 8601 or Unix timestamp, alias: `--since`) - name: until in: query schema: type: string description: Show entries until timestamp (ISO 8601 or Unix timestamp, alias: `--until`) - name: verbose in: query schema: type: boolean description: Show detailed output in single-line format (alias: `-v`, `--verbose`) - name: time in: query schema: type: boolean description: Include execution time in default format (alias: `-t`, `--time`) - name: network in: query schema: type: boolean description: Include network bytes in default format (alias: `-b`, `--network`) - name: count in: query schema: type: boolean description: Show only count of matching entries (alias: `-c`, `--count`) - name: order in: query schema: type: string enum: [asc, desc] description: | Sort order. Default is `asc` (sequential, oldest first). Use `desc` for newest first (e.g. UI History tab). - name: ai in: query schema: oneOf: - type: boolean - type: string enum: [include, all] description: | When true or 1, filter to entries that have AI usage and attach per-model token totals (alias: `--ai`). When "include" or "all", attach ai_usage on each entry when available but do not filter the list. Entries without pipeline_id or without matching ai_completions are excluded only when filtering (ai=1). responses: '200': description: Success content: text/plain: schema: type: string example: | 123 success 0.125s 0B 2025-01-15T10:30:00Z echo hello | grep hello 122 failure 0.045s 0B 2025-01-15T10:29:45Z cat /tmp/missing.txt '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' delete: tags: - System summary: Delete all history entries description: | Deletes all pipeline execution history entries for the authenticated user. This operation cannot be undone. Returns the number of entries deleted. operationId: deleteAllHistory responses: '200': description: Success content: application/json: schema: type: object properties: message: type: string example: "All history entries deleted" deleted_count: type: integer description: Number of history entries deleted example: 42 '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' /history/{id}: delete: tags: - System summary: Delete a history entry by ID description: | Deletes a specific pipeline execution history entry by its ID. The ID can be found in the history list output. operationId: deleteHistoryEntry parameters: - name: id in: path required: true schema: type: integer description: History entry ID responses: '200': description: Success content: application/json: schema: type: object properties: message: type: string example: "History entry deleted" id: type: integer description: ID of the deleted entry example: 123 '401': $ref: '#/components/responses/Unauthorized' '404': description: History entry not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': $ref: '#/components/responses/InternalServerError' /health: get: tags: - System summary: Health check endpoint description: | Returns service health status. Checks main database connectivity. If an API key is provided, also checks the user's temp file database. No authentication required (API key is optional). operationId: health security: [] # No authentication required responses: '200': description: Service is healthy content: application/json: schema: type: object properties: status: type: string enum: [healthy, unhealthy] example: healthy timestamp: type: string format: date-time example: "2025-01-15T10:30:00.000Z" temp_db: type: string enum: [healthy, unhealthy] description: Temp file database status (only present if API key provided) example: healthy issues: type: array items: type: string description: List of health issues (only present if unhealthy) example: ["Main database connectivity check failed"] examples: healthy: value: status: healthy timestamp: "2025-01-15T10:30:00.000Z" healthyWithApiKey: value: status: healthy timestamp: "2025-01-15T10:30:00.000Z" temp_db: healthy unhealthy: value: status: unhealthy timestamp: "2025-01-15T10:30:00.000Z" issues: ["Main database connectivity check failed"] '503': description: Service is unhealthy content: application/json: schema: type: object properties: status: type: string enum: [unhealthy] example: unhealthy timestamp: type: string format: date-time temp_db: type: string enum: [unhealthy] description: Temp file database status (only present if API key provided) issues: type: array items: type: string example: ["Main database connectivity check failed", "Temp file database connectivity check failed"] /api: get: tags: - System summary: Get API key information description: Returns information about the authenticated API key including quota, metadata, and configuration operationId: apiGet responses: '200': description: Success content: application/json: schema: type: object properties: api_key: type: string description: Truncated API key (first 12 chars + "...") email: type: string label: type: string quota: $ref: '#/components/schemas/QuotaInfo' created_at: type: string format: date-time created_at_timestamp: type: integer is_active: type: boolean smtp: type: object description: SMTP configuration (if configured, password never included) '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' post: tags: - System summary: Get API key information (POST) description: Same as GET, but using POST method operationId: apiPost responses: '200': $ref: '#/paths/~1api/get/responses/200' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' patch: tags: - System summary: Update API key configuration description: Update SMTP configuration and/or xAI API key. Merges with existing config. operationId: apiPatch requestBody: description: Configuration to update content: application/json: schema: type: object properties: smtp: type: object properties: host: type: string port: type: integer user: type: string pass: type: string from: type: string xai_api_key: type: string responses: '200': description: Success - updated configuration content: application/json: schema: type: object '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' /subscription: post: tags: - System summary: Subscription status and usage description: | Displays subscription status for the authenticated token: plan name, price, status, renewal date, and (for AI subscription plans) current month input/output token usage. Use `json=true` (or query param `json`) for machine-readable JSON output. operationId: subscription parameters: - name: json in: query required: false schema: type: boolean description: If true, output as JSON (alias: -j or --json in pipeline) responses: '200': description: Success - human-readable text or JSON (when json=true) content: text/plain: schema: type: string example: "Plan: Pro (£10.00/mo)\nStatus: active\nRenews: 15 Feb 2025\n..." application/json: schema: type: object properties: has_subscription: type: boolean subscription: type: object properties: id: type: integer status: type: string plan_name: type: string plan_price: type: integer next_payment_at: type: string format: date-time usage: type: object '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' /base64: post: tags: - Utilities summary: Base64 encode/decode description: Encodes input to base64 by default. Use `decode` flag to decode base64 back to original text. operationId: base64 parameters: - name: decode in: query schema: type: boolean description: Decode base64 (default: encode) requestBody: description: Input text to encode or base64 string to decode content: text/plain: schema: type: string example: "hello world" responses: '200': description: Success content: text/plain: schema: type: string example: "aGVsbG8gd29ybGQ=" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /date: post: tags: - Utilities summary: Format date/time description: | Outputs formatted date/time using Unix `date`-style format specifiers. All dates use GMT/UTC timezone (or token timezone when set). When no format is provided, returns a GMT date string. Use the `date` (or `d`) query parameter for `-d` behavior: format a specific time by description (e.g. "1 hour ago", "yesterday", ISO or Unix timestamp). operationId: date parameters: - name: date in: query schema: type: string description: "Date description for -d (e.g. \"1 hour ago\", \"yesterday\", ISO or Unix timestamp). When set, output is that time in the given format." - name: d in: query schema: type: string description: Alias for `date`. - name: format in: query schema: type: string description: Format string (e.g., "+%Y%m%d" or "+'%Y-%m-%d'") requestBody: description: Not used (command doesn't process input) content: text/plain: schema: type: string responses: '200': description: Success content: text/plain: schema: type: string example: "20240115" '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /awk: post: tags: - Text Processing summary: Process text using awk programs description: | Processes text line-by-line using awk programs. Supports field splitting, pattern matching, built-in variables (NR, NF, $0, $1, etc.), and text transformations. **Examples:** - `{print $1}` - Print first field - `-F, '{print $2}'` - Print second comma-separated field - `/^error/` - Print lines starting with "error" - `{print NR, $0}` - Print line numbers - `$2 > 27 {print $1}` - Conditional field printing operationId: awk parameters: - name: program in: query required: true schema: type: string description: Awk program expression - name: F in: query schema: type: string description: Field separator (default: whitespace) requestBody: description: Text content to process content: text/plain: schema: type: string example: "alice,30\nbob,25\ncharlie,35" responses: '200': description: Success content: text/plain: schema: type: string example: "30\n25\n35" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /deno: post: tags: - Text Processing summary: Execute a TypeScript/JavaScript script with Deno description: | Runs a TypeScript or JavaScript script stored in temp file storage or as a saved pipeline using Deno. The script receives piped input via stdin and returns output via stdout. Resolution: temp file first, then saved pipeline by name. **Security:** Runs with `--no-prompt` and zero filesystem/network permissions by default. Use `--allow-net` to opt-in to outbound network access for specific hosts only. **Example script (`/tmp/transform.ts`):** ```ts const input = await new Response(Deno.stdin.readable).text(); const result = input.toUpperCase(); await Deno.stdout.write(new TextEncoder().encode(result)); ``` **Note:** The `source` command automatically delegates to `deno` when the path ends in `.ts` or `.js`, so `source my-script.ts` is equivalent to `deno my-script.ts`. operationId: deno parameters: - name: path in: query required: true schema: type: string description: Temp file path or saved pipeline name of the script to execute (e.g. `/tmp/transform.ts` or `my-script.ts`) - name: allow-net in: query schema: type: string description: Comma-separated list of additional hosts to allow outbound network access (e.g. `api.openai.com`). `deno.land` is always included so scripts can import modules. Localhost and private IPs are always blocked. requestBody: description: Input data piped to the script's stdin content: text/plain: schema: type: string example: "hello world" responses: '200': description: Script stdout output content: text/plain: schema: type: string example: "HELLO WORLD" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /jq: post: tags: - Data Formats summary: Process JSON using jq expressions description: | Processes JSON input using the full jq filter language (powered by jq-web/WASM). Supports pipes, functions, conditionals, object construction, array slicing, and more. Output is pretty-printed by default. **Examples:** - `.` - Identity (pretty-print input) - `.field` - Extract field - `.users[0].name` - Nested field access - `.users | length` - Pipe to function - `[.[] | .name]` - Map over array - `.items | map(select(.active))` - Filter array - `.users | sort_by(.age)` - Sort - `{name: .first, age: .years}` - Object construction operationId: jq parameters: - name: filter in: query schema: type: string default: "." description: jq filter expression (default: `.` identity) requestBody: description: JSON content to process content: text/plain: schema: type: string example: '{"users": [{"name": "Alice"}, {"name": "Bob"}]}' responses: '200': description: Success content: application/json: schema: type: string example: '["Alice","Bob"]' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /html: post: tags: - Data Formats summary: Extract content from HTML using CSS selectors description: | Extracts content from HTML using CSS selectors or extracts all text content. Supports CSS Selectors Level 3. **Supported Selectors:** - Tag: `div`, `p`, `h1` - Class: `.classname` - ID: `#idname` - Attribute: `[href]`, `[href="value"]`, `[href^="prefix"]`, `[href$="suffix"]`, `[href*="contains"]` - Descendant: `div p` - Child: `div > p` - Sibling: `h1 + p` (adjacent), `h1 ~ p` (general) - Pseudo-classes: `:first-child`, `:last-child`, `:nth-child(n)`, `:not(selector)` - Multiple: `div, p, h1` - Combined: `div.classname`, `div#id`, `div[attr]` operationId: html parameters: - name: selector in: query schema: type: string description: CSS selector to match elements (required unless `text=true`) - name: attr in: query schema: type: string description: Extract attribute value instead of text content - name: all in: query schema: type: boolean description: Return all matches (default: first match only) - name: text in: query schema: type: boolean description: Extract all text content from HTML (removes all tags, scripts, styles) - name: html in: query schema: type: boolean description: Return outer HTML of matched element(s) instead of text content - name: inner in: query schema: type: boolean description: Return inner HTML of matched element(s) instead of text content - name: base in: query schema: type: string description: Prefix relative href URLs with base URL (useful for extracted HTML fragments) requestBody: description: HTML content to parse content: text/plain: schema: type: string example: "

Title

Content

" responses: '200': description: Success content: text/plain: schema: type: string example: "Title" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /grep: post: tags: - Text Processing summary: Filter lines by pattern description: | Filters lines from input that match (or don't match) a regex pattern. Works on piped input only (no filename argument). Use `cat /tmp/file | grep pattern`. **Flags:** - `-i`, `--ignore`: Case-insensitive matching - `-v`, `--invert`: Show non-matching lines - `-c`, `--count`: Return count instead of lines - `-o`, `--only-matching`: Output only the matched part (not compatible with -v or -c) - `-n`, `--line-number`: Prefix each output line with its line number - `-w`, `--word`: Match whole words only (word boundaries) - `-x`, `--line`: Match whole lines only - `-m N`, `--max-count=N`: Stop after N matches - `-A N`: Show N lines after each match (context) - `-B N`: Show N lines before each match (context) - `-C N`: Show N lines before and after each match (context) **Note:** The `-q`/`--quiet` flag is not supported; use `test`/`exit` with `&&`/`||` for conditional logic. operationId: grep parameters: - name: match in: query required: true schema: type: string description: Regex pattern to search for (required) - name: invert in: query schema: type: boolean description: Invert match (show non-matching lines). Alias: `v` - name: ignore in: query schema: type: boolean description: Case-insensitive matching. Alias: `i` - name: count in: query schema: type: boolean description: Return count instead of lines. Alias: `c` - name: only in: query schema: type: boolean description: Output only the matched part. Alias: `o`. Not compatible with -v or -c. - name: line-number in: query schema: type: boolean description: Prefix each output line with its line number. Alias: `n` - name: word in: query schema: type: boolean description: Match whole words only. Alias: `w` - name: line in: query schema: type: boolean description: Match whole lines only. Alias: `x` - name: max-count in: query schema: type: integer description: Stop after N matches. Alias: `m` - name: A in: query schema: type: integer description: Show N lines after each match (context) - name: B in: query schema: type: integer description: Show N lines before each match (context) - name: C in: query schema: type: integer description: Show N lines before and after each match (context) requestBody: description: Input text to filter content: text/plain: schema: type: string example: "line 1\nline 2 hello\nline 3\nline 4 hello world" responses: '200': description: Success content: text/plain: schema: type: string example: "line 2 hello\nline 4 hello world" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /csv: post: tags: - Data Formats summary: Parse and process CSV data description: | Parses CSV data with filtering, aggregation, column selection, and format conversion. **Filter Expressions:** - Comparison: `age > 18`, `status == 'active'`, `price <= 100` - Logical: `age > 18 AND status == 'active'`, `category == 'A' OR category == 'B'` - String functions: `contains(name, 'John')`, `startsWith(email, 'admin')`, `endsWith(file, '.csv')` - Empty checks: `isEmpty(email)`, `isNotEmpty(phone)` - Regex: `email ~= 'example\\.com$'` - Nested: `(age > 18 AND status == 'active') OR role == 'admin'` **Aggregation Functions:** - `sum(column)` - Sum of values - `avg(column)` / `average(column)` - Average - `min(column)` / `max(column)` - Min/max values - `count()` - Row count - `median(column)` - Median value - `first(column)` / `last(column)` - First/last values operationId: csv parameters: - name: select in: query schema: type: string description: Select columns by name, index, or range (e.g., "name,age" or "1,3" or "1-3"). Alias: columns - name: filter in: query schema: type: string description: Filter expression (e.g., "age > 18 AND status == 'active'") - name: delimiter in: query schema: type: string default: "," description: Field delimiter (default: comma) - name: header-row in: query schema: type: integer default: 0 description: Row number for header (default: 0, first row) - name: no-header in: query schema: type: boolean description: Treat first row as data (no header) - name: limit in: query schema: type: integer description: Maximum number of rows to return - name: offset in: query schema: type: integer description: Number of rows to skip - name: sort in: query schema: type: string description: Sort by column(s) (e.g., "age", "age:desc", "dept:asc,age:desc") - name: aggregate in: query schema: type: string description: Aggregation functions (e.g., "sum(price),avg(age),count(),median(score)") - name: group-by in: query schema: type: string description: Group by column for aggregations - name: distinct in: query schema: type: string description: Get unique values for specified column - name: rename in: query schema: type: string description: Rename columns (e.g., "old:new,col1:name") - name: types in: query schema: type: string description: Type conversion (e.g., "age:int,price:float,active:bool") - name: skip-empty in: query schema: type: boolean description: Skip rows where all fields are empty - name: to-json in: query schema: type: boolean description: Convert output to JSON format (alias: j) - name: pretty in: query schema: type: boolean description: Pretty-print JSON output requestBody: description: CSV content to parse content: text/plain: schema: type: string example: "name,age,city\nAlice,30,NYC\nBob,25,LA" responses: '200': description: Success content: text/plain: schema: type: string example: "name,age,city\nAlice,30,NYC\nBob,25,LA" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /ls: get: tags: - Storage summary: List temp files description: | Lists temp files in `/tmp/` storage (scoped to your API key). If pattern provided, lists files matching the pattern (supports `*` and `?` wildcards). **Output formats:** - Default: one file path per line (`/tmp/`) - Long (`-l`): path, size, created, expires (tab-separated) - JSON (`-j`): array of objects with path, size, created_at, expires_at **Sort options:** name, size, time (default), expires operationId: ls parameters: - name: pattern in: query description: Pattern to match (supports `*` and `?` wildcards) schema: type: string - name: long in: query description: Show detailed info (size, created, expires). Alias: `l` schema: type: boolean - name: sort in: query description: Sort by field (name, size, time, expires). Alias: `S` schema: type: string enum: [name, size, time, expires] default: time - name: reverse in: query description: Reverse sort order. Alias: `r` schema: type: boolean - name: json in: query description: Output as JSON array. Alias: `j` schema: type: boolean responses: '200': description: Success content: text/plain: schema: type: string example: "/tmp/file1.txt\n/tmp/file2.txt" '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /tmp: get: tags: - Storage summary: List all temp files description: | Lists all temp files for the authenticated user. Returns JSON object with `files` (array of file metadata), `usage`, and `limits`. operationId: tmpList responses: '200': description: Success content: application/json: schema: type: object required: [files, usage, limits] properties: files: type: array items: type: object properties: path: type: string example: "/tmp/example.txt" created_at: type: string format: date-time example: "2025-01-15T10:30:00.000Z" expires_at: type: string format: date-time example: "2025-01-16T22:30:00.000Z" size: type: integer example: 1024 content_type: type: string nullable: true description: Stored Content-Type (e.g. application/pdf), or null usage: type: object properties: total_size: type: integer file_count: type: integer limits: type: object properties: max_file_size: type: integer max_total_storage: type: integer max_file_count: type: integer '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' /tmp/{path}: get: tags: - Storage summary: Read a temp file description: | Reads a temp file by path. Returns raw file content (binary). Path should not include `/tmp/` prefix (e.g., use `example.txt` not `/tmp/example.txt`). **Response headers:** - `Content-Type`: Stored type when uploading (e.g. application/pdf, image/png), or `application/octet-stream` - `Content-Disposition`: `inline; filename=""` so browsers can display or save with a name operationId: tmpGet parameters: - name: path in: path required: true schema: type: string description: File path (without /tmp/ prefix) responses: '200': description: Success (body is raw file bytes) headers: Content-Type: schema: type: string example: application/octet-stream Content-Disposition: schema: type: string example: 'inline; filename="example.txt"' content: application/octet-stream: schema: type: string format: binary '401': $ref: '#/components/responses/Unauthorized' '404': description: File not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': $ref: '#/components/responses/InternalServerError' post: tags: - Storage summary: Create or update a temp file description: | Creates or updates a temp file. Files are scoped to your API key, compressed (gzip), and encrypted (AES-256-GCM). Files expire after 36 hours by default (configurable per token). Path should not include `/tmp/` prefix (e.g., use `example.txt` not `/tmp/example.txt`). Request body can be text or binary. Optional `Content-Type` header is stored and used when serving the file (GET) and for display/inline behavior (e.g. application/pdf, image/png). operationId: tmpPost parameters: - name: path in: path required: true schema: type: string description: File path (without /tmp/ prefix) - name: Content-Type in: header required: false schema: type: string example: application/pdf description: Optional; stored and returned when reading the file requestBody: description: File content (text or binary) content: application/octet-stream: schema: type: string format: binary text/plain: schema: type: string example: "file content" responses: '200': description: Success content: application/json: schema: type: object properties: path: type: string example: "/tmp/example.txt" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' patch: tags: - Storage summary: Rename temp file or extend expiration description: | **With request body (text/plain):** Rename (default) or copy the file at the given path. Body = new filename only (no JSON). New name supports date format specifiers (e.g. `report-%Y-%m-%d.txt`); use `X-User-Time` header for expansion. Overwrites existing file at new name if present. Path in URL = current file (supports date expansion via `X-User-Time`). Add query **`cmd=cp`** to copy instead of rename (source file remains); omit for rename (mv). **Without body:** Extend the file's expiration time by 12 hours. Works even if the file has already expired. **Pipeline form:** In pipelines, `mv ` and `cp ` resolve the first argument as: 1) temp file (wildcards and date expansion supported), 2) saved pipeline by name, else fail. Temp file wins when both exist. For temp: dest is a temp path; for saved pipeline: dest is the new pipeline name (mv renames, cp copies with new ULID). Path should not include `/tmp/` prefix (e.g., use `example.txt` not `/tmp/example.txt`). operationId: tmpPatch parameters: - name: path in: path required: true schema: type: string description: File path (without /tmp/ prefix) - name: cmd in: query required: false schema: type: string enum: [cp] description: Set to `cp` to copy instead of rename (source remains). Omit for rename. - name: X-User-Time in: header required: false schema: type: string example: "2024-01-15T14:30:00-05:00" description: Optional ISO date for date expansion in path and in new name (body) requestBody: required: false content: text/plain: schema: type: string example: "report-2025-01-30.txt" description: New filename (for rename). Omit for extend expiration. responses: '200': description: Success - returns updated file metadata content: application/json: schema: type: object properties: path: type: string example: "/tmp/example.txt" created_at: type: string format: date-time example: "2025-01-15T10:30:00.000Z" expires_at: type: string format: date-time example: "2025-01-17T10:30:00.000Z" description: New expiration time (12 hours later than before) size: type: integer example: 1024 '401': $ref: '#/components/responses/Unauthorized' '404': description: File not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': $ref: '#/components/responses/InternalServerError' delete: tags: - Storage summary: Delete a temp file description: | Deletes a temp file by path. Path supports date expansion (e.g. `report-%Y-%m-%d.txt`); use the `X-User-Time` header (ISO 8601) for expansion; if omitted, UTC is used. **Pipeline form:** In pipelines, `rm ` resolves the first argument as: 1) temp file (wildcards and date expansion supported), 2) saved pipeline by name, else fail. Temp file wins when both exist. Returns the deleted path or name as `text/plain`; this endpoint returns JSON. Path should not include `/tmp/` prefix (e.g., use `example.txt` not `/tmp/example.txt`). operationId: tmpDelete parameters: - name: path in: path required: true schema: type: string description: File path (without /tmp/ prefix). Supports date format specifiers (e.g. %Y, %m, %d). - name: X-User-Time in: header required: false schema: type: string example: "2024-01-15T14:30:00-05:00" description: Optional ISO date for date expansion in path (e.g. report-%Y-%m-%d.txt) responses: '200': description: Success content: application/json: schema: type: object properties: message: type: string example: "File deleted" path: type: string example: "/tmp/example.txt" '401': $ref: '#/components/responses/Unauthorized' '404': description: File not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': $ref: '#/components/responses/InternalServerError' /mail: post: tags: - HTTP & Communication summary: Send email via SMTP description: | Sends email via SMTP using the configured SMTP settings on the API token. Takes piped input as email body. Requires SMTP configuration to be set on the API token. With `html=true`: Automatically detects if input is text, markdown, or HTML. If markdown, converts to HTML. If HTML, leaves as-is. If text, leaves as-is. With `test=true`: Outputs the raw SMTP message (RFC 5322 format) with all headers instead of sending. Useful for debugging. Does not require SMTP configuration. operationId: mail parameters: - name: subject in: query required: true schema: type: string description: Email subject (alias: `s`) - name: to in: query required: true schema: type: string description: Recipient email address - name: html in: query required: false schema: type: boolean default: false description: Transform piped input to HTML (detects markdown/text/HTML and converts markdown to HTML) - name: test in: query required: false schema: type: boolean default: false description: Output raw SMTP message (RFC 5322 format) instead of sending requestBody: description: Email body content content: text/plain: schema: type: string example: "This is the email body" responses: '200': description: Success content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /curl: post: tags: - HTTP & Communication summary: Fetch content from URLs description: | Fetches content from one or more HTTP(S) URLs. Supports custom headers, cookies, methods, retries, timeouts, and redirect handling. Perfect for fetching web content, API responses, and external resources. operationId: curl parameters: - name: url in: query required: true schema: type: array items: type: string style: form explode: true description: URL(s) to fetch (required, multiple allowed) - name: header in: query schema: type: array items: type: string style: form explode: true description: Custom HTTP header(s) in "key:value" format (multiple allowed) - name: bearer in: query schema: type: string description: Bearer token (shortcut for Authorization: Bearer header). Ignored if Authorization header is already set. - name: cookie in: query schema: type: array items: type: string style: form explode: true description: Cookie(s) to send (multiple allowed) - name: method in: query schema: type: string enum: [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS] description: HTTP method (default: GET) - name: data in: query schema: type: string description: Request body for POST/PUT requests - name: content-type in: query schema: type: string description: Content-Type header - name: retry in: query schema: type: integer minimum: 0 default: 0 description: Number of retries on failure - name: retry-delay in: query schema: type: integer minimum: 0 default: 1000 description: Delay between retries in milliseconds - name: timeout in: query schema: type: integer minimum: 0 description: Request timeout in milliseconds - name: no-redirects in: query schema: type: boolean description: Disable following HTTP redirects (redirects are followed by default) - name: modified in: query schema: type: boolean description: Append Last-Modified header to output requestBody: description: Optional initial input (ignored when fetching URLs) content: text/plain: schema: type: string responses: '200': description: Success content: text/plain: schema: type: string headers: X-Network-Bytes: schema: type: integer description: Total bytes transferred (request + response) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /mcp: post: tags: - HTTP & Communication summary: Call a tool on a remote MCP server description: | Calls a tool on a registered MCP (Model Context Protocol) server using JSON-RPC. The tool must be registered with type "mcp" via the tools API. Auth credentials ($EXPORT references in the MCP server config headers) are resolved internally and never appear in pipeline text. Usage in pipelines: `mcp [json-args]` When no json-args are provided and stdin has content, stdin is passed as the "input" argument (for tools that accept it). operationId: mcp parameters: - name: tool in: query required: true schema: type: string description: Registered tool name (e.g. "piped") - name: mcpTool in: query required: true schema: type: string description: MCP tool name from the server's tools/list (e.g. "execute_pipeline") - name: args in: query schema: type: string description: JSON object of arguments (e.g. '{"pipeline":"ls"}') requestBody: description: | Optional stdin input. When no args query parameter is provided, the request body is passed as the "input" argument to the MCP tool. content: text/plain: schema: type: string responses: '200': description: Success — MCP tool result content: text/plain: schema: type: string example: "/tmp/data.csv\n/tmp/notes.txt" '400': description: Bad request (missing parameters, tool not found, invalid JSON args) content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '502': description: MCP server error (remote server returned an error) content: text/plain: schema: type: string example: "MCP error: tools/call failed: Tool not found" '500': $ref: '#/components/responses/InternalServerError' /sha256: post: tags: - Utilities summary: Compute SHA-256 hash description: Computes SHA-256 hash of input and outputs hexadecimal hash string operationId: sha256 requestBody: description: Input text to hash content: text/plain: schema: type: string example: "hello world" responses: '200': description: Success content: text/plain: schema: type: string example: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /md5: post: tags: - Utilities summary: Compute MD5 hash description: | Computes MD5 hash of input and outputs hexadecimal hash string. Note: MD5 is not cryptographically secure; use sha256 for integrity or security. operationId: md5 requestBody: description: Input text to hash content: text/plain: schema: type: string example: "hello world" responses: '200': description: Success content: text/plain: schema: type: string example: "5eb63bbbe01eeed093cb22bb8f5acdc3" '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /tee: post: tags: - Storage summary: Write to temp storage description: | Writes input to temp storage AND outputs to stdout (like Unix `tee`). Use `quiet` parameter to suppress stdout output (file is still written). Files are scoped to your API key, compressed (gzip), and encrypted (AES-256-GCM). Files expire after 36 hours by default (configurable per token or per-file with `expire`). Maximum expiration is 168 hours (7 days). operationId: tee parameters: - name: path in: query required: true schema: type: array items: type: string style: form explode: true description: Path(s) in `/tmp/` storage (required, multiple allowed) - name: append in: query schema: type: boolean description: Append to existing file (default: overwrite, alias: `a`) - name: quiet in: query schema: type: boolean description: Don't output file contents to stdout (quiet mode, alias: `q`) - name: expire in: query schema: type: string description: | Expiration duration for the file. Supports a number with optional suffix: `s` (seconds), `m` (minutes), `h` (hours), `d` (days). A bare number defaults to hours. Max: 168h (7d). Default: 36h. Examples: `2h`, `30m`, `90s`, `7d`, `2.5h`, `1.5d` requestBody: description: Content to write to temp storage content: text/plain: schema: type: string example: "content to store" responses: '200': description: Success content: text/plain: schema: type: string example: "content to store" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /find: get: tags: - Storage summary: Find temp files matching criteria description: | Find temp files matching specified criteria. Similar to Unix `find` command. **Path prefix:** Finds files under the specified "directory" (temp files can have `/` in names to simulate folders). If path is omitted, searches all temp files. **Name pattern:** Filter by filename pattern. Use one of: - `-name`: Glob matching (`*` and `?` wildcards). Pattern matches against filename or full path. - `-regex`: Regex pattern matching (case-sensitive, anchored to start/end). Regex patterns are validated for ReDoS safety. - `-iregex`: Regex pattern matching (case-insensitive, anchored to start/end). Regex patterns are validated for ReDoS safety. Only one of `name`, `regex`, or `iregex` can be specified. **Modification time:** Filter by modification time (uses `created_at` field, which is updated by `touch` command). Format: `+N` (older than N), `-N` (newer than N), or `N` (within last N). Units: `d` (days), `h` (hours), `m` (minutes), `s` (seconds). Path supports date expansion (e.g. `/tmp/log-%Y-%m-%d/`); use `X-User-Time` header for expansion. Output: one file path per line (`/tmp/`), sorted alphabetically. operationId: find parameters: - name: path in: query schema: type: string description: Starting directory path (e.g., `/tmp/blah/`). Finds files under this "directory". - name: name in: query schema: type: string description: Filter by filename pattern using glob matching (`*` and `?` wildcards). Only one of `name`, `regex`, or `iregex` can be specified. - name: regex in: query schema: type: string description: Filter by regex pattern (case-sensitive, anchored to start/end). Regex patterns are validated for ReDoS safety. Only one of `name`, `regex`, or `iregex` can be specified. - name: iregex in: query schema: type: string description: Filter by regex pattern (case-insensitive, anchored to start/end). Regex patterns are validated for ReDoS safety. Only one of `name`, `regex`, or `iregex` can be specified. - name: mtime in: query schema: type: string description: | Filter by modification time. Format: `+N` (older than N), `-N` (newer than N), or `N` (within last N). Units: `d` (days), `h` (hours), `m` (minutes), `s` (seconds). Examples: `+1d`, `-2h`, `3m`, `5s` responses: '200': description: Success content: text/plain: schema: type: string example: "/tmp/file1.txt\n/tmp/file2.txt" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalError' /touch: post: tags: - Storage summary: Create or refresh temp file expiry (touch) description: | Creates an empty temp file if the path does not exist, or refreshes its expiration if it does. Like Unix `touch`: update "timestamp" (here, expiry). Content of existing files is unchanged. Path(s) support date expansion (e.g. `/tmp/log-%Y-%m-%d.txt`); use `X-User-Time` header for expansion. Default expiration is 36 hours (same as tee). Maximum expiration is 168 hours (7 days). operationId: touch parameters: - name: path in: query required: true schema: type: array items: type: string style: form explode: true description: Path(s) in `/tmp/` storage (required, multiple allowed) - name: expire in: query schema: type: string description: | Expiration duration. Supports a number with optional suffix: `s` (seconds), `m` (minutes), `h` (hours), `d` (days). A bare number defaults to hours. Default: 36h. Max: 168h (7d). Examples: `2h`, `30m`, `90s`, `7d`, `2.5h`, `1.5d` requestBody: description: Not used (touch does not write content; empty body is fine) content: text/plain: schema: type: string default: "" responses: '200': description: Success (empty body) content: text/plain: schema: type: string example: "" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' /project: get: tags: - Storage summary: Export project as YAML description: | Exports the current project (pipelines, exports, aliases) as a YAML file. Optional `name` parameter includes a project name in the export. operationId: projectExport parameters: - name: name in: query schema: type: string description: Optional project name to include in export responses: '200': description: Success - YAML content headers: Content-Disposition: schema: type: string example: 'attachment; filename="piped-project.yaml"' content: text/yaml: schema: type: string example: | # Piped Project Export project: name: My Project pipelines: - name: my-pipeline pipeline: echo hello exports: - name: MY_VAR value: my-value aliases: - alias: greet command: echo hello '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' post: tags: - Storage summary: Import project from YAML (or export if no body) description: | Imports a project from YAML content. By default, import is additive (merges with existing data). Use `replace` parameter to clear data before import. **If no body provided:** - Without `replace` param: Exports the project as YAML (same as GET) - With `replace` param: Clears specified data (creates fresh blank environment) **Replace options:** - `all` - Replace all pipelines, exports, and aliases - `pipelines` or `saved` - Replace only pipelines - `exports` - Replace only exports - `aliases` - Replace only aliases - Comma-separated: `pipelines,aliases`, `exports,aliases`, etc. **YAML format:** ```yaml project: name: optional-name pipelines: - name: my-pipeline pipeline: echo hello | grep h exports: - name: MY_VAR value: my-value aliases: - alias: greet command: echo hello ``` operationId: projectImport parameters: - name: name in: query schema: type: string description: Project name (used for export when no body provided) - name: replace in: query schema: type: string description: | What to clear before import. Values: all, pipelines (or saved), exports, aliases, or comma-separated (e.g., exports,aliases). Default: additive (no clearing). requestBody: description: YAML content to import (if empty, exports project instead) content: text/plain: schema: type: string example: | pipelines: - name: my-pipeline pipeline: echo hello text/yaml: schema: type: string responses: '200': description: Success - import result or YAML export content: application/json: schema: type: object properties: message: type: string example: "Project imported" mode: type: string enum: [additive, replace] cleared: type: object properties: pipelines: type: integer exports: type: integer aliases: type: integer imported: type: object properties: pipelines: type: integer exports: type: integer aliases: type: integer skipped: type: object properties: pipelines: type: integer exports: type: integer aliases: type: integer errors: type: array items: type: string text/yaml: schema: type: string description: YAML export (when no body provided) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '413': description: Payload too large (YAML exceeds 5MB limit) content: application/json: schema: $ref: '#/components/schemas/Error' '500': $ref: '#/components/responses/InternalServerError' /rm: post: tags: - Storage summary: Remove temp file(s) or saved pipeline description: | Deletes temp file(s) or a saved pipeline by name. Resolution: temp file first (wildcards `*`, `?` and date expansion supported; deletes all matches), then saved pipeline by name (exact, case-sensitive), else 404. Returns deleted path(s) or name as text/plain. operationId: rm parameters: - name: path in: query required: true schema: type: string description: Path or pattern in `/tmp/` storage, or saved pipeline name responses: '200': description: Deleted path(s) or pipeline name (text/plain) content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '404': description: No temp file or saved pipeline matching the path/name content: application/json: schema: type: object properties: error: { type: string } code: { type: string } '500': $ref: '#/components/responses/InternalServerError' /crontab: post: tags: - Control Flow summary: List, install, or remove cron schedules for named pipelines description: | Manages cron schedules for named (saved) pipelines in a crontab-style interface. Piped talks only to the cron server over HTTP; it does not access the cron DB directly. **List (`-l` or `--list`):** Lists named pipelines that have a cron schedule and are confirmed active on the cron server. Output format is one line per pipeline: `CRON_SPEC TIMEZONE PIPELINE_NAME` (suitable as input for install). Pipelines with cron specified in notes but not confirmed by the cron server are shown as comment lines (e.g. `# Name: not active (status: needs_auth)` or `# Name: specified in pipeline but not confirmed by cron server`). **Remove (`-r` or `--remove`):** Removes cron schedules from all saved pipelines. Each pipeline with a `notes.cron` entry has its cron removed on the cron server and the notes updated. Returns a count of removed pipelines. Can be combined with install (stdin or file) to remove all existing schedules first, then install fresh. **Timezone listing (`-tz`, `--timezone`, or `--timezones`):** Lists all IANA timezone names. If a pattern is provided (via query param `timezone`), filters timezones by case-insensitive pattern match. Returns plain text, one timezone per line. Useful for discovering valid timezone names to use in crontab entries. **Install from stdin:** Send crontab lines in the request body. Blank lines and lines starting with `#` are ignored. Each data line has format `CRON_SPEC TIMEZONE PIPELINE_NAME` (5 cron fields, IANA timezone, pipeline name; name may be quoted if it contains spaces). For each line, the named pipeline is resolved, then the cron spec is sent to the cron server and the pipeline's notes are updated. Empty cron spec removes the schedule. Strict: first parse or resolution error fails the whole install. **Install from file:** Use query param `file` = temp path (e.g. `/tmp/crontab.txt`) or saved pipeline name (that pipeline's body is read as crontab lines). Same behavior as install from stdin once content is read. operationId: crontab parameters: - name: list in: query schema: type: boolean description: Set to true for list mode (crontab -l / crontab --list) - name: remove in: query schema: type: boolean description: Set to true to remove cron schedules from all saved pipelines (crontab -r / crontab --remove) - name: timezone in: query schema: type: string description: For timezone listing mode (crontab -tz / crontab --timezone). If empty string, lists all timezones. If provided, filters timezones by case-insensitive pattern match (e.g. "americas" matches "America/New_York", "America/Los_Angeles", etc.) - name: file in: query schema: type: string description: For install from file; temp path or saved pipeline name whose content is the crontab requestBody: description: For install from stdin (when file param is omitted); crontab lines (blank and # lines allowed) content: text/plain: schema: type: string responses: '200': description: List output (text/plain, one line per active schedule or comment) or empty body on successful install content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '404': description: File or saved pipeline not found (install from file) content: application/json: schema: type: object properties: error: { type: string } '500': $ref: '#/components/responses/InternalServerError' /man: get: tags: - Utilities summary: Show command manual (GET) description: | Show manual/help for a pipeline command. Content from config/man.yaml. Query param `cmd` = command name. If omitted, lists available commands. operationId: manGet parameters: - name: cmd in: query schema: type: string description: Command name (e.g., sleep, cat). Omit to list commands. responses: '200': description: Manual entry or command list (text/plain) content: text/plain: schema: type: string '404': description: No manual entry for command content: text/plain: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' post: tags: - Utilities summary: Show command manual (POST) description: | Same as GET; command name can be provided in request body (text/plain, first line). operationId: manPost parameters: [] requestBody: content: text/plain: schema: type: string description: Command name (optional; first line used) responses: '200': description: Manual entry or command list (text/plain) content: text/plain: schema: type: string '404': description: No manual entry for command content: text/plain: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' /test: post: tags: - Utilities summary: Test file properties, string comparisons, and integer comparisons description: | Test file conditions, string comparisons, or integer comparisons. With path: file conditions (-f/-e/-s/-z) or time comparisons (-n/-o). Without path: pipeline mode tests input size (-s non-empty, -z empty). Expression mode: string comparisons (=, !=, <, >) and integer comparisons (-eq, -ne, -gt, -ge, -lt, -le). String non-null mode: test if a string is non-empty. Returns "true" if condition is true, empty output if false. Works with `&&` and `||` for conditional execution. `[[ expr ]]` is syntax sugar for `test expr` (no quoting required). operationId: test parameters: - name: condition in: query required: false schema: type: string enum: [file, exists, size, zero, newer, older, f, e, s, z, n, o] description: | File condition to test (not required when using expression or string mode): - `file` or `f`: File exists and is a regular file (file mode only) - `exists` or `e`: File exists (any type, file mode only) - `size` or `s`: Non-empty (file exists and size > 0, OR piped input has content) - `zero` or `z`: Empty (file exists and size == 0, OR piped input is empty) - `newer` or `n`: Path is newer than ref (path created_at > ref; ref = file path or date string). Requires ref and path. - `older` or `o`: Path is older than ref (path created_at < ref). Requires ref and path. - name: ref in: query schema: type: string description: Reference for -n/-o. Temp file path (exactly one) or date description (e.g. "1 hour ago", "yesterday"). - name: path in: query schema: type: string description: File path in `/tmp/` storage (optional for -f/-e/-s/-z when testing piped input; required for -n/-o) - name: left in: query schema: type: string description: Left operand for expression mode (string or integer comparison) - name: op in: query schema: type: string enum: ["=", "!=", "<", ">", "-eq", "-ne", "-gt", "-ge", "-lt", "-le"] description: | Operator for expression mode: - String: `=` (equal), `!=` (not equal), `<` (before), `>` (after) - Integer: `-eq` (equal), `-ne` (not equal), `-gt` (greater), `-ge` (greater or equal), `-lt` (less), `-le` (less or equal) - name: right in: query schema: type: string description: Right operand for expression mode (string or integer comparison) - name: string in: query schema: type: string description: String non-null test. True if the string is non-empty. requestBody: description: Input to test (used when no path provided, tests if input has content) content: text/plain: schema: type: string example: "hello" responses: '200': description: Success - returns "true" if condition is true, empty if false content: text/plain: schema: type: string example: "true" '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' post: tags: - Data Formats summary: XPath parser description: Evaluates XPath expressions on XML/HTML content operationId: xpath parameters: - name: query in: query required: true schema: type: string description: XPath expression to evaluate (required) - name: all in: query schema: type: boolean description: Return all matches (default: first match) - name: attr in: query schema: type: string description: Extract attribute value requestBody: description: XML/HTML content to parse content: text/plain: schema: type: string example: "

Title

" responses: '200': description: Success content: text/plain: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/QuotaExceeded' '500': $ref: '#/components/responses/InternalServerError' components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key description: API key in format `pk_<48 hex characters>` BearerAuth: type: http scheme: bearer bearerFormat: API Key description: API key as Bearer token (alternative to X-API-Key header) schemas: Error: type: object required: - error properties: error: type: string description: Error message example: "Invalid API key" QuotaInfo: type: object properties: quota_limit: type: integer description: Total quota limit quota_used: type: integer description: Quota used so far quota_remaining: type: integer description: Remaining quota responses: BadRequest: description: Bad request - invalid parameters or input content: application/json: schema: $ref: '#/components/schemas/Error' example: error: "Query parameter 'match' is required" Unauthorized: description: Unauthorized - invalid or missing API key content: application/json: schema: $ref: '#/components/schemas/Error' example: error: "Invalid API key" QuotaExceeded: description: Forbidden - quota exceeded content: application/json: schema: allOf: - $ref: '#/components/schemas/Error' - $ref: '#/components/schemas/QuotaInfo' example: error: "Quota exceeded" quota_limit: 50000 quota_used: 50000 quota_remaining: 0 InternalServerError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' example: error: "Internal server error"