Skip to main content
incur can mount any HTTP API that implements the Web Fetch API as a CLI. This works seamlessly with frameworks like Hono, Bun, Deno, and Elysia.

When to Mount APIs

Mount APIs as CLIs when you:
  • Want to expose HTTP endpoints via CLI without writing separate handlers
  • Need a unified interface for both web and CLI access
  • Have an existing API and want instant CLI support
  • Want to test API endpoints directly from the command line

Basic API Mounting

1
Create an API with Fetch Handler
2
Any framework that exposes a fetch handler works:
3
import { Hono } from 'hono'

const app = new Hono()
  .get('/users', (c) => c.json({ users: [{ id: 1, name: 'Alice' }] }))
  .post('/users', async (c) => c.json({ created: true, ...(await c.req.json()) }, 201))
4
Mount with fetch Property
5
Pass the fetch handler to Cli.create():
6
import { Cli } from 'incur'

Cli.create('my-cli', {
  description: 'My CLI',
  fetch: app.fetch,  // Mount the entire API
}).serve()
7
Use curl-style Syntax
8
Arguments become path segments, flags become options:
9
my-cli api users
# → users[1]{id,name}:
# →   1,Alice

my-cli api users -X POST -d '{"name":"Bob"}'
# → created: true
# → name: Bob

curl-Style Translation

incur translates CLI arguments to HTTP requests using curl-style conventions:

Path Segments

Bare arguments become path segments:

HTTP Methods

Use -X or --method to set the HTTP method:
Default method is GET, or POST if a body is provided via -d or --data.

Request Body

Use -d, --data, or --body to send a request body:

Headers

Use -H or --header to set headers:

Query Parameters

Any unknown --flag becomes a query parameter:

Framework Examples

Hono

Bun

Deno

Elysia

Mounting as Commands

Mount APIs on specific commands instead of the root:

Base Path

Specify a base path to strip from CLI arguments:

OpenAPI Integration

Pass an OpenAPI spec alongside fetch to generate typed subcommands:

Generated Commands

incur extracts:
  • Command names from operationId
  • Descriptions from summary or description
  • Arguments from path parameters
  • Options from query parameters and request body properties

Typed Subcommands

Each operation becomes a typed command:
OpenAPI integration uses @readme/openapi-parser to resolve all $ref pointers automatically. The spec can be passed as a plain object or imported JSON.

Example OpenAPI App

Usage

Fetch Handler Help

Fetch handlers have specialized help text:

Streaming Responses

APIs that return NDJSON streams are automatically handled:
Streaming only works for responses with content-type: application/x-ndjson. Each line is parsed as JSON and output incrementally.

Error Handling

HTTP error responses are automatically converted to CLI errors:

Best Practices

Use OpenAPI for Complex APIs

For APIs with many endpoints, use OpenAPI to get typed commands automatically:

Mount on Subcommands

Keep the root clean by mounting APIs on subcommands:

Provide Base Paths

Use basePath to simplify CLI arguments:
Mounted APIs receive all remaining CLI arguments as path segments and flags. Don’t mix fetch handlers with manual command definitions in the same CLI level.