+ ttyinv

AUTHORITATIVE MANUAL

Portable invoice source,
from agent to A4.

Connect over MCP, call the REST API, or keep the entire workflow local with the CLI. This static guide documents public contracts.

QUICKSTART

Start with the skill and a revocable token.

  1. Download the ttyinv-invoice skill with its SHA-256 checksum, or inspect the Agents page.
  2. Sign in on the hosted app, create a named token, and store it locally as TTYINV_AGENT_TOKEN.
  3. Choose MCP or REST. Both create the same portable ttyinv/v1 Markdown.
Create and validate without a purchase. Agent tokens require GitHub authentication. Hosted HTML, PDF, and PNG rendering requires an active lifetime purchase.

DISCOVERY

Fetch the live map before you call an endpoint.

Fetch https://app.ttyinv.com/api/v1 first. Then fetch https://app.ttyinv.com/api/v1/invoices/schema for exact input and output schemas.

The discovery response lists service and contract versions, REST paths, MCP tools, authentication, purchase rules, status meanings, and response headers.

curl --fail --silent --show-error "https://app.ttyinv.com/api/v1"

AUTHENTICATION

Bearer tokens are private and shown once.

Send Authorization: Bearer $TTYINV_AGENT_TOKEN on MCP and REST requests. Tokens expire, can be revoked immediately, and are stored by ttyinv only as SHA-256 digests.

  • Keep tokens in an environment variable or secret manager, not source, command history, URLs, chat, screenshots, or logs.
  • Never use verbose HTTP output or shell tracing around authenticated commands.
  • A 401 means the token is missing, expired, invalid, or revoked. Create a replacement.
  • A 429 includes a retry boundary. Stop or wait.

1 · MCP

Prefer MCP when your agent supports tools.

Use the Streamable HTTP endpoint at https://app.ttyinv.com/mcp. Send a Bearer token on every request.

Initialize with MCP initialize over POST. Discover tools with tools/list after initialization.

{
  "mcpServers": {
    "ttyinv": {
      "type": "http",
      "url": "https://app.ttyinv.com/mcp",
      "headers": { "Authorization": "Bearer $TTYINV_AGENT_TOKEN" }
    }
  }
}
create_invoiceCreate needs no purchase. Its input and output schemas come from the live schema.
validate_invoiceValidate needs no purchase. Its input and output schemas come from the live schema.
render_invoiceRender needs an active lifetime purchase. Its input and output schemas come from the live schema.

MCP returns JSON errors with the same status meanings as REST. Common statuses include 400, 401, 402, 403, 413, 422, 429, 503, and 504.

2 · REST API

Use strict JSON over ordinary HTTP.

Discovery and authenticated REST operations use Cache-Control: no-store. The public schema uses Cache-Control: public, max-age=300, stale-while-revalidate=3600. Fetch discovery, then fetch the schema.

REST endpoint contracts
EndpointAuthentication and content typeInput and success outputPurchaseCommon failures
GET https://app.ttyinv.com/api/v1None. Server: Returns application/json.Input: none. Success: 200, discovery document.None.None expected.
GET https://app.ttyinv.com/api/v1/invoices/schemaNone. Server: Returns application/json.Input: none. Success: 200, schema envelope.None.None expected.
POST https://app.ttyinv.com/api/v1/invoicesBearer token. Client: Send application/json.Input: operations.create.input. Success: 201, operations.create.output.None.400, 401, 403, 413, 415, 422, 429.
POST https://app.ttyinv.com/api/v1/invoices/validateBearer token. Client: Send application/json.Input: operations.validate.input. Success: 200, operations.validate.output.None.400, 401, 403, 413, 415, 422, 429.
POST https://app.ttyinv.com/api/v1/invoices/renderBearer token. Client: Send application/json.Input: operations.render.input. Success: 200, operations.render.output.Active lifetime purchase.400, 401, 402, 403, 413, 415, 422, 429, 503, 504.

SCHEMA DISCOVERY

Fetch contracts; do not copy fields into agent prompts.

https://app.ttyinv.com/api/v1/invoices/schema is the authoritative JSON Schema envelope shared by REST and MCP. Fetch it before composing requests. Do not copy field lists into prompts.

curl --fail --silent --show-error "https://app.ttyinv.com/api/v1/invoices/schema"

CREATE CONTRACT

Structured input returns source first.

This fabricated payload illustrates the shape only. Consult the live schema for required fields, limits, formats, and newly added capabilities.

{
  "invoice": {
    "number": "INV-EXAMPLE-001",
    "title": "Fabricated services",
    "issued": "2026-08-24",
    "due": "2026-09-07",
    "currency": "USD"
  },
  "from": { "name": "Northstar Example Studio", "email": "billing@example.com" },
  "to": { "name": "Acme Example Client" },
  "sections": [{
    "title": "Services",
    "table": { "headers": [{ "label": "Description" }, { "label": "Amount (USD)", "align": "right" }],
      "rows": [["Fabricated accessibility review", "125.00"]] }
  }]
}
curl --fail-with-body --silent --show-error \
  --config <(cat <<EOF
header = "Authorization: Bearer $TTYINV_AGENT_TOKEN"
header = "Content-Type: application/json"
EOF
) --data-binary @invoice.json "https://app.ttyinv.com/api/v1/invoices" > created.json

A successful response contains source, the normalized document, a calculation summary, and warnings. Save source as the portable artifact.

SOURCE FIDELITY

Keep the authored invoice’s meaning intact.

  • Payable currency: when a table has several amount columns, exactly one qualified column matching invoice.currency is payable. Conversions are authored explicitly; ttyinv does not fetch exchange rates.
  • Authored summaries: rows named Subtotal, Total, or Grand Total remain visible and are excluded from generated totals.
  • Recap tables: set summaryOnly: true when a table repeats amounts from earlier sections. Its rows remain visible while the section is excluded from generated totals.
  • Deterministic page breaks: set pageBreakBefore: true on a table or prose section. The returned source emits the exact page-break marker.

Fetch https://app.ttyinv.com/api/v1/invoices/schema before composing requests so REST and MCP stay aligned.

VALIDATE CONTRACT

Validation is explicit and read-only.

jq -n --rawfile source invoice.md '{source:$source}' | \
  curl --fail-with-body --silent --show-error \
  --config <(cat <<EOF
header = "Authorization: Bearer $TTYINV_AGENT_TOKEN"
header = "Content-Type: application/json"
EOF
) --data-binary @- "https://app.ttyinv.com/api/v1/invoices/validate"

Continue only when valid is true. Invalid responses include safe errors and warnings; revise the identified source.

RENDER CONTRACT

Render only validated source.

Input is { source, format, theme? }. Formats are html, pdf, or png; themes are light or dark.

A valid agent token and an active lifetime purchase are required for hosted rendering. Local CLI rendering remains free.

jq -n --rawfile source invoice.md '{source:$source,format:"pdf",theme:"light"}' | \
  curl --fail-with-body --silent --show-error \
  --config <(cat <<EOF
header = "Authorization: Bearer $TTYINV_AGENT_TOKEN"
header = "Content-Type: application/json"
EOF
) --data-binary @- "https://app.ttyinv.com/api/v1/invoices/render" > render-manifest.json

The output manifest reports format, pageCount, warnings, and files. PNG returns one ordered file per page; HTML and PDF return one file.

3 · CLI · LOCAL-FIRST

Use the CLI when contents must not cross the network.

Python 3.11+ and Chromium are required. Install from the source repository, then keep source and rendering on your local machine.

git clone https://github.com/kaygdotorg/ttyinv.git
cd ttyinv
make install
ttyinv init invoice.md --with-assets
ttyinv lint invoice.md --strict
ttyinv render invoice.md --format both --theme light

Useful CLI commands

  • ttyinv init invoice.md creates a fabricated starter.
  • ttyinv lint invoice.md --strict validates schema, tables, amounts, assets, and layout warnings.
  • ttyinv render invoice.md --format pdf|html|both renders client files.
  • ttyinv schema --output ttyinv-v1.schema.json writes the document schema.
Read the complete CLI reference

PRIVACY & DATA FLOW

Choose the boundary deliberately.

Browser editorDraft and local uploads stay in the browser.
CLISource, assets, HTML, and PDF stay on the local machine.
REST / MCPPayload crosses the network for transient processing. It is not stored or written to request logs.
Token metadataDigest, scope, expiry, usage count, and timestamps support authentication and abuse controls.

Use fabricated example.com identities for testing. Never commit a real invoice, customer record, signature, tax identifier, payment coordinate, token, or rendered artifact.