Start a Service API
A live API that sells an outcome: each Customer's annual report, drafted, checked, signed and filed, charged once when the Customer accepts it.
Open in
You need Node 20 and a GitHub account. The sample answers on filings.apis.dev; your first deploy answers at once on a free Host, and your own domain is one line.
Start the folder
Terminal $ npx apis.dev init service-api ✓ wrote definition.ts:a Service API next: npx apis.dev dev initwrites a Service API with one case, its moves and the price of its outcome.Write the file
definition.ts import { define, workflow, agentic } from 'apis.dev' /** Each Customer's annual report,drafted, signed and filed, charged once when the Customer accepts it. */ export default define({ name: 'filings', domain: 'filings.apis.dev', Filing: { // Noun: the work your buyer watches company: 'string', year: 'number', status: { // Verbs: one per move order: [], draft: { in: 'ordered', run: workflow(async ($, filing) => { const { form } = await $.generative('Draft the annual report for {company}', filing, { returns: { form: 'string' } }) await $.human('Check the draft', { form }, { role: 'paralegal' }) // unseen: a step return { form } }) }, sign: 'drafted', // seen: the Customer's turn file: { in: 'signed', run: agentic('File the signed report with the state') }, accept: 'filed', reject: 'filed', // the Customer accepts, or it is redone }, }, on: { 'Filing.ordered': 'Filing.draft', 'Filing.signed': 'Filing.file' }, offer: { 'Filing.order': { price: 25, when: 'accepted', accept: 'customer', acceptWithin: '7d', remedy: 'redo' }, }, }) A model drafts and a paralegal checks, inside one Workflow. The Customer signs, an agent files, and the Customer accepts or rejects what was filed.
Try it locally
Terminal $ npx apis.dev dev ✓ every Interface on http://localhost: 8787, against your Test twin reloads on every save Order a filing on localhost and walk it to accepted. In your Test twin the paralegal's task goes to you, and nothing is filed.
Publish it
Terminal $ npx apis.dev deploy ✓ signed in with GitHub ✓ definition.ts:filings on filings.apis.dev ✓ Stripe connected: each Customer pays into your own account ✓ 1 Noun, 9 Verbs, 2 Triggers, 1 price Filing order, get, list, update, delete, restore, sign, accept, reject Filing.ordered → Filing.draft Filing.signed → Filing.file Filing.order 25 once, when accepted ✓ published v1 to https: //filings.apis.dev: 11 Interfaces REST /filings CLI npx filings MCP /mcp SDK npm i filings, pip install filings Docs /docs OpenAPI /openapi.json llms.txt /llms.txt agents.json /.well-known/ agents.json Pricing /pricing Landing site / Developer portal /dashboard ✓ Test key: filings_test_xZ4w7ptrJjwZ2r8pvwKjvZzH5pqCGj040acc draftandfileserve no path:Filing.orderedandFiling.signedstart them, so they are internal. Your Customer makes the other moves.Read the price list
/pricing { "currency": "USD", "rates": [ { "name": "Filing.order", "price": 25, "unit": "outcome", "when": "accepted" } ] }Your Customers and their agents read one price, and when it is charged: on acceptance, never by the hour.
Order one with no credits
POST filings.apis.dev/filingsRequest curl https://filings.apis.dev/ filings \ -H "Authorization: Bearer $FILINGS_KEY" \ -H "Prefer: code= 402" \ --json '{"company": "acme.com", "year": 2026}' Response HTTP/1.1 402 Payment Required Content-Type:application/ problem+json X-Cost: price= 0, currency= "USD" X-Request-Id: req_3684ba7186b965f12f33 { "type": "https: //filings.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Filing.order holds 25 until accepted.", "code": "payment_required", "instance": "req_3684ba7186b965f12f33", "offers": [ { "kind": "credits", "price": 50, "checkout": "https: //filings.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //filings.apis.dev/ checkout/ credits-200" } ] } TypeScript import { Filings } from 'filings' const api = new Filings({ key: process.env.FILINGS_KEY }) const { error, meta } = await api.orderFiling({ company: 'acme.com', year: 2026 }) // error:{ status: 402, code: 'payment_required' } // meta.cost: { price: 0, currency: 'USD' } Response HTTP/1.1 402 Payment Required Content-Type:application/ problem+json X-Cost: price= 0, currency= "USD" X-Request-Id: req_3684ba7186b965f12f33 { "type": "https: //filings.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Filing.order holds 25 until accepted.", "code": "payment_required", "instance": "req_3684ba7186b965f12f33", "offers": [ { "kind": "credits", "price": 50, "checkout": "https: //filings.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //filings.apis.dev/ checkout/ credits-200" } ] } Python import os from filings import Filings api = Filings(key=os.environ["FILINGS_KEY"]) error, meta = api.order_filing(company="acme.com", year=2026) # error:{ "status": 402, "code": "payment_required" } # meta.cost: { "price": 0, "currency": "USD" } Response HTTP/1.1 402 Payment Required Content-Type:application/ problem+json X-Cost: price= 0, currency= "USD" X-Request-Id: req_3684ba7186b965f12f33 { "type": "https: //filings.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Filing.order holds 25 until accepted.", "code": "payment_required", "instance": "req_3684ba7186b965f12f33", "offers": [ { "kind": "credits", "price": 50, "checkout": "https: //filings.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //filings.apis.dev/ checkout/ credits-200" } ] } Terminal $ npx filings login --key $FILINGS_KEY $ npx filings filings order --company acme.com --year 2026 error 402 payment_required price 0 USD · req_3684ba7186b965f12f33Response HTTP/1.1 402 Payment Required Content-Type:application/ problem+json X-Cost: price= 0, currency= "USD" X-Request-Id: req_3684ba7186b965f12f33 { "type": "https: //filings.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Filing.order holds 25 until accepted.", "code": "payment_required", "instance": "req_3684ba7186b965f12f33", "offers": [ { "kind": "credits", "price": 50, "checkout": "https: //filings.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //filings.apis.dev/ checkout/ credits-200" } ] } Request curl https://filings.apis.dev/ mcp \ -H "Authorization: Bearer $FILINGS_KEY" \ -H "Prefer: code= 402" \ --json '{ "jsonrpc": "2.0", "id": 1, "method": "tools/ call", "params": { "name": "orderFiling", "arguments": { "company": "acme.com", "year": 2026 } } }' Response HTTP/1.1 200 OK X-Cost:price= 0, currency= "USD" X-Request-Id: req_58df8b1113d14ca2e5ab { "jsonrpc": "2.0", "id": 1, "result": { "isError": true, "content": [ { "type": "text", "text": "{\"status\":402, \"code\":\"payment_required\"}" } ], "structuredContent": { "status": 402, "code": "payment_required" }, "_meta": { "cost": { "price": 0, "currency": "USD" }, "requestId": "req_58df8b1113d14ca2e5ab" } } } An order holds its price from the credits until the Customer accepts. With none to hold, it answers 402 at price 0, with packs that cover it.
Buy credits and order it
POST filings.apis.dev/filingsRequest curl https://filings.apis.dev/ filings \ -H "Authorization: Bearer $FILINGS_KEY" \ --json '{"company": "acme.com", "year": 2026}' Response HTTP/1.1 201 Created Location:/filings/ filing_1 X-Action-Id: act_1 X-Cost: price= 0, currency= "USD" X-Request-Id: req_cbec164c216729631ad5 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "ordered", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 00Z" } TypeScript import { Filings } from 'filings' const api = new Filings({ key: process.env.FILINGS_KEY }) const { data, meta } = await api.orderFiling({ company: 'acme.com', year: 2026 }) // data:{ // 'id': 'filing_1', // 'company': 'acme.com', // 'year': 2026, // 'status': 'ordered', // 'createdAt': '2026-10-24T09: 00: 00Z', // 'updatedAt': '2026-10-24T09: 00: 00Z' // } // meta.cost: { price: 0, currency: 'USD' } Response HTTP/1.1 201 Created Location:/filings/ filing_1 X-Action-Id: act_1 X-Cost: price= 0, currency= "USD" X-Request-Id: req_cbec164c216729631ad5 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "ordered", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 00Z" } Python import os from filings import Filings api = Filings(key=os.environ["FILINGS_KEY"]) data, meta = api.order_filing(company="acme.com", year=2026) # data:{ # "id": "filing_1", # "company": "acme.com", # "year": 2026, # "status": "ordered", # "createdAt": "2026-10-24T09: 00: 00Z", # "updatedAt": "2026-10-24T09: 00: 00Z" # } # meta.cost: { "price": 0, "currency": "USD" } Response HTTP/1.1 201 Created Location:/filings/ filing_1 X-Action-Id: act_1 X-Cost: price= 0, currency= "USD" X-Request-Id: req_cbec164c216729631ad5 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "ordered", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 00Z" } Terminal $ npx filings login --key $FILINGS_KEY $ npx filings filings order --company acme.com --year 2026 { "id": "filing_1","company": "acme.com", "year": 2026, "status": "ordered", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 00Z" } price 0 USD · req_cbec164c216729631ad5 Response HTTP/1.1 201 Created Location:/filings/ filing_1 X-Action-Id: act_1 X-Cost: price= 0, currency= "USD" X-Request-Id: req_cbec164c216729631ad5 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "ordered", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 00Z" } Request curl https://filings.apis.dev/ mcp \ -H "Authorization: Bearer $FILINGS_KEY" \ --json '{ "jsonrpc": "2.0", "id": 1, "method": "tools/ call", "params": { "name": "orderFiling", "arguments": { "company": "acme.com", "year": 2026 } } }' Response HTTP/1.1 200 OK X-Cost:price= 0, currency= "USD" X-Request-Id: req_3c004458951158691c9c { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "{\"id\":\"filing_1\",\"company\":\"acme.com\",\"year\":2026, \"status\":\"ordered\",\"createdAt\":\"2026-10-24T09: 00: 00Z\",\"updatedAt\":\"2026-10-24T09: 00: 00Z\"}" } ], "structuredContent": { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "ordered", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 00Z" }, "_meta": { "cost": { "price": 0, "currency": "USD" }, "requestId": "req_3c004458951158691c9c" } } } After Checkout, the order answers 201 at price 0 and holds $25.
Filing.orderedstarts the draft.Watch the work, then sign
Request curl https://filings.apis.dev/ filings/ filing_1 \ -H "Authorization: Bearer $FILINGS_KEY" Response HTTP/1.1 200 OK X-Cost:price= 0, currency= "USD" X-Request-Id: req_f781a6ad9678c1e5146d { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "drafting", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-24T09: 00: 01Z" } Request curl -X POST https://filings.apis.dev/ filings/ filing_1/ sign \ -H "Authorization: Bearer $FILINGS_KEY" Response HTTP/1.1 200 OK X-Action-Id:act_3 X-Cost: price= 0, currency= "USD" X-Request-Id: req_47d0a7b035cb42c3265d { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "signed", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-25T16: 40: 00Z" } Your Customer watches the filing move:
draftingwhile the model and the paralegal work, thendrafted, their turn. Signing starts the filing.Accept it
POST filings.apis.dev/filings/filing_1/acceptRequest curl -X POST https://filings.apis.dev/ filings/ filing_1/ accept \ -H "Authorization: Bearer $FILINGS_KEY" Response HTTP/1.1 200 OK X-Action-Id:act_5 X-Cost: price= 25, currency= "USD" X-Request-Id: req_0978142c439357dbbea3 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "accepted", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-26T08: 15: 00Z" } TypeScript import { Filings } from 'filings' const api = new Filings({ key: process.env.FILINGS_KEY }) const { data, meta } = await api.acceptFiling('filing_1') // data:{ // 'id': 'filing_1', // 'company': 'acme.com', // 'year': 2026, // 'status': 'accepted', // 'createdAt': '2026-10-24T09: 00: 00Z', // 'updatedAt': '2026-10-26T08: 15: 00Z' // } // meta.cost: { price: 25, currency: 'USD' } Response HTTP/1.1 200 OK X-Action-Id:act_5 X-Cost: price= 25, currency= "USD" X-Request-Id: req_0978142c439357dbbea3 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "accepted", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-26T08: 15: 00Z" } Python import os from filings import Filings api = Filings(key=os.environ["FILINGS_KEY"]) data, meta = api.accept_filing("filing_1") # data:{ # "id": "filing_1", # "company": "acme.com", # "year": 2026, # "status": "accepted", # "createdAt": "2026-10-24T09: 00: 00Z", # "updatedAt": "2026-10-26T08: 15: 00Z" # } # meta.cost: { "price": 25, "currency": "USD" } Response HTTP/1.1 200 OK X-Action-Id:act_5 X-Cost: price= 25, currency= "USD" X-Request-Id: req_0978142c439357dbbea3 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "accepted", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-26T08: 15: 00Z" } Terminal $ npx filings login --key $FILINGS_KEY $ npx filings filings accept filing_1 { "id": "filing_1","company": "acme.com", "year": 2026, "status": "accepted", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-26T08: 15: 00Z" } price 25 USD · req_0978142c439357dbbea3 Response HTTP/1.1 200 OK X-Action-Id:act_5 X-Cost: price= 25, currency= "USD" X-Request-Id: req_0978142c439357dbbea3 { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "accepted", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-26T08: 15: 00Z" } Request curl https://filings.apis.dev/ mcp \ -H "Authorization: Bearer $FILINGS_KEY" \ --json '{ "jsonrpc": "2.0", "id": 1, "method": "tools/ call", "params": { "name": "acceptFiling", "arguments": { "id": "filing_1" } } }' Response HTTP/1.1 200 OK X-Cost:price= 25, currency= "USD" X-Request-Id: req_223e1f7801aa5d6f104b { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "{\"id\":\"filing_1\",\"company\":\"acme.com\",\"year\":2026, \"status\":\"accepted\",\"createdAt\":\"2026-10-24T09: 00: 00Z\",\"updatedAt\":\"2026-10-26T08: 15: 00Z\"}" } ], "structuredContent": { "id": "filing_1", "company": "acme.com", "year": 2026, "status": "accepted", "createdAt": "2026-10-24T09: 00: 00Z", "updatedAt": "2026-10-26T08: 15: 00Z" }, "_meta": { "cost": { "price": 25, "currency": "USD" }, "requestId": "req_223e1f7801aa5d6f104b" } } } Delivery POST /hooks/filings HTTP/1.1 Host: hooks.acme.com X-Webhook-Attempt: 1 X-Webhook-Signature: t= 1793002500, v1= b8aad23b578b9e3d90ceca7c000bf3e2d6ffe9bf7deaa592147920ed358a0845 { "id": "evt_11", "type": "Filing.accepted", "at": "2026-10-26T08: 15: 00Z", "seq": 11, "data": { "id": "filing_1", "status": "accepted" }, "charged": { "price": 25, "currency": "USD" } } Acceptance is the one move with a price: it charges the held $25 once, and
Filing.acceptedcarries the charge to every Watch. A rejected filing is redone at no charge.Get paid
Filing.order 1 × 25 25.00
───────────────────────────────────
Total 25.00
Paid from 50.00 of credits 25.00
Balance 25.00The accepted filing is one line on your Customer's Stripe receipt, and the money lands in your own Stripe account.
Result
Your API answers on https://filings.apis.dev: a filing a model drafts, a paralegal checks and the Customer signs, charged $25 once the Customer accepts it.
A rejected filing is redone at no charge. You wrote no case tracker, no hold on the price and no acceptance window.
Next steps
- Start a Content product → sell what you publish, by the read and by the month.
- Service API: outcomes and acceptance, grades, review and supervision.
- Work: the steps agents and people do, reviewed and signed off.