QUICKSTART
Start with the skill and a revocable token.
- Download the ttyinv-invoice skill with its SHA-256 checksum, or use the checksum-verifying installer on the Agents page.
- Sign in on /agents, create a named token, and store it locally as
TTYINV_AGENT_TOKEN. - Choose MCP or REST. Both create the same portable
ttyinv/v1Markdown.
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.
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
401means the token is missing, expired, invalid, or revoked. Create a replacement. - A
429includes 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. Use the schema as the input and output source.
| Endpoint | Authentication and content type | Input and success output | Purchase | Common failures |
|---|---|---|---|---|
GET /api/v1 | None. Server: Returns application/json. | Input: none. Success: 200, discovery document. | None. | None expected. |
GET /api/v1/invoices/schema | None. Server: Returns application/json. | Input: none. Success: 200, schema envelope. | None. | None expected. |
POST /api/v1/invoices | Bearer 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/validate | Bearer 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/render | Bearer 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.
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.
{
"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"
]
]
}
}
]
}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.jsonA 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.currencyis payable. For example, withcurrency: EUR,Amount (EUR)is payable andAmount (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, orGrand Totalmust 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: trueon 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: trueon 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 returnspageBreakBefore: 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.
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.
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.jsonThe 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.
git clone https://github.com/kaygdotorg/ttyinv.git
cd ttyinv
make install
. .venv/bin/activate
python -m playwright install chromiumttyinv init invoice.md --with-assets
ttyinv lint invoice.md --strict
ttyinv render invoice.md --format both --theme lightUseful CLI commands
ttyinv init invoice.mdcreates a fabricated starter.ttyinv lint invoice.md --strictvalidates schema, tables, amounts, assets, and layout warnings.ttyinv render invoice.md --format pdf|html|bothrenders client files.ttyinv schema --output ttyinv-v1.schema.jsonwrites the document schema.ttyinv fontslists verified local monospace fonts.
PRIVACY & DATA FLOW
Choose the boundary deliberately.
Use fabricated example.com identities for testing. Never commit a real invoice, customer record, signature, tax identifier, payment coordinate, token, or rendered artifact.