+ 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.

QUICKSTART

Start with the skill and a revocable token.

  1. Download the ttyinv-invoice skill with its SHA-256 checksum, or use the checksum-verifying installer on the Agents page.
  2. Sign in on /agents, 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 also requires a lifetime export purchase.

DISCOVERY

Fetch the live map before you call an endpoint.

Fetch /api/v1 first. Then fetch /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.

Fetch public API discovery
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.

MCP server configuration
{
  "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. Use the schema as the input and output source.

REST endpoint contracts
EndpointAuthentication and content typeInput and success outputPurchaseCommon failures
GET /api/v1None. Server: Returns application/json.Input: none. Success: 200, discovery document.None.None expected.
GET /api/v1/invoices/schemaNone. Server: Returns application/json.Input: none. Success: 200, schema envelope.None.None expected.
POST /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 /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 /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.

/api/v1/invoices/schema is a versioned envelope generated from the actual Zod schemas shared by REST and MCP. Each operations.create, operations.validate, and operations.render entry contains its transport names plus exact input and successful output schemas.

Fetch the current transport contract
curl --fail --silent --show-error "https://app.ttyinv.com/api/v1/invoices/schema"

CLI users can inspect the underlying ttyinv/v1 document schema with ttyinv schema. The REST create-input schema additionally models structured Markdown sections.

CREATE CONTRACT

Structured input returns source first.

This fabricated payload illustrates the shape only. Consult operations.create.input in the live contract for required fields, limits, formats, and newly added capabilities.

Fabricated invoice.json
{
  "invoice": {
    "number": "INV-EXAMPLE-001",
    "title": "Fabricated services",
    "issued": "2026-08-24",
    "due": "2026-09-07",
    "currency": "USD",
    "locale": "en-US"
  },
  "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"
          ]
        ]
      }
    }
  ]
}
Create invoice 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 @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. For example, with currency: EUR, Amount (EUR) is payable and Amount (JPY) is informational. If no qualifier matches, the final amount column is payable. Conversions are authored explicitly; ttyinv does not fetch exchange rates.
  • Authored summaries: a row whose first/description cell is Subtotal, Total, or Grand Total must have an explicit numeric payable cell. It is preserved as a summary row and excluded from generated section and invoice totals, so it is not double-counted. Numeric rows without quantity/rate inputs are also valid.
  • Recap tables: set summaryOnly: true on a table section that repeats amounts from earlier sections. REST and MCP emit <!-- ttyinv:summary-only -->; every row stays visible while the whole recap section is excluded from generated total arithmetic.
  • Deterministic page breaks: set pageBreakBefore: true on a table or prose section in REST or MCP create input. The returned source emits the exact marker <!-- ttyinv:page-break-before --> immediately before that section’s H2; validation output returns pageBreakBefore: true. Omitted or false emits no marker.

The live operations.create.input and operations.create.output.document schemas carry section summaryOnly and pageBreakBefore; validation reports both when their markers are present. Fetch /api/v1/invoices/schema before composing requests so REST and MCP stay aligned.

VALIDATE CONTRACT

Validation is explicit and read-only.

Validate invoice.md
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 rather than weakening validation.

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 export purchase are required for hosted rendering. Local CLI rendering remains free.

Render a light PDF
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. Each file contains filename, mimeType, bytes, sha256, and base64. 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, activate its virtual environment, then keep source and rendering on your machine.

Install and activate the CLI from source
git clone https://github.com/kaygdotorg/ttyinv.git
cd ttyinv
make install
. .venv/bin/activate
python -m playwright install chromium
Create, lint, and render fabricated source
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.
  • ttyinv fonts lists verified local monospace fonts.
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 / MCPInvoice content is transient. When you explicitly call the API or MCP, ttyinv processes it only for that response; invoice bodies, parties, line items, signatures, payment instructions, and generated files are never logged, tracked, or stored as a record. The application does not write agent request bodies to logs. Your network or hosting provider may still process ordinary connection metadata such as an IP address and request time.
Operational recordsttyinv retains only operational records needed for account access and abuse prevention: your GitHub identity, hashed token metadata and rate-limit state, plus payment records if you purchase export access. Card details never reach ttyinv.

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