Start a Function API
A live API that sells answers, each priced per call by who works it out: a model in seconds, an agent in minutes.
Open in
You need Node 20 and a GitHub account. The sample answers on summaries.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 function-api ✓ wrote definition.ts:a Function API next: npx apis.dev dev initwrites a Function API that publishes as it is. This track builds a shorter one, with two Verbs.Write the file
definition.ts import { define, generative, agentic } from 'apis.dev' /** Answers about any company by its domain:what it sells in seconds, its head of sales in minutes. */ export default define({ name: 'summaries', domain: 'summaries.apis.dev', Company: { // Noun: the Noun it acts on domain: 'url!#', summarize: generative('Two sentences on what {domain} sells', { returns: { summary: 'string' } }), // Verb: a model writes it research: agentic('Find the head of sales at {domain}', { returns: { headOfSales: 'string' } }), // Verb: an agent finds it }, offer: { // Offer: a price per call, by kind 'Company.summarize': 0.02, 'Company.research': 0.5, }, }) Each Verb names its Function kind, and the kind sets how long it takes.
returnstypes the answer on every Interface.Try it locally
Terminal $ npx apis.dev dev ✓ every Interface on http://localhost: 8787, against your Test twin reloads on every save Call each Verb on localhost before anyone pays for one. A model or an agent run in your Test twin spends your allowance, never a Customer's credits.
Publish it
Terminal $ npx apis.dev deploy ✓ signed in with GitHub ✓ definition.ts:summaries on summaries.apis.dev ✓ Stripe connected: each Customer pays into your own account ✓ 1 Noun, 2 Verbs, 2 prices Company summarize, research Company.summarize 0.02 a call Company.research 0.5 a call ✓ published v1 to https: //summaries.apis.dev: 11 Interfaces REST /companies CLI npx summaries MCP /mcp SDK npm i summaries, pip install summaries Docs /docs OpenAPI /openapi.json llms.txt /llms.txt agents.json /.well-known/ agents.json Pricing /pricing Landing site / Developer portal /dashboard ✓ Test key: summaries_test_t3EzMtZA2rs3DRNtaj3rv3JBPtcp4r647d42 Deploy prints each Verb with its price. The first run signs you in with GitHub and connects Stripe to your own account.
Read the price list
/pricing { "currency": "USD", "rates": [ { "name": "Company.summarize", "price": 0.02, "unit": "call" }, { "name": "Company.research", "price": 0.5, "unit": "call" } ] }Your Customers and their agents read this before the first call, on
/pricingand on the offer card.Call it with no credits
POST summaries.apis.dev/companies/acme.com/summarizeRequest curl -X POST https://summaries.apis.dev/ companies/ acme.com/ summarize \ -H "Authorization: Bearer $SUMMARIES_KEY" \ -H "Prefer: code= 402" Response HTTP/1.1 402 Payment Required Content-Type:application/ problem+json X-Cost: price= 0, currency= "USD" X-Request-Id: req_e01eab0d5cdfbb1619d4 { "type": "https: //summaries.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Company.summarize draws 0.02 from it.", "code": "payment_required", "instance": "req_e01eab0d5cdfbb1619d4", "offers": [ { "kind": "credits", "price": 10, "checkout": "https: //summaries.apis.dev/ checkout/ credits-10" }, { "kind": "credits", "price": 50, "checkout": "https: //summaries.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //summaries.apis.dev/ checkout/ credits-200" } ] } TypeScript import { Summaries } from 'summaries' const api = new Summaries({ key: process.env.SUMMARIES_KEY }) const { error, meta } = await api.summarizeCompany('acme.com') // 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_e01eab0d5cdfbb1619d4 { "type": "https: //summaries.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Company.summarize draws 0.02 from it.", "code": "payment_required", "instance": "req_e01eab0d5cdfbb1619d4", "offers": [ { "kind": "credits", "price": 10, "checkout": "https: //summaries.apis.dev/ checkout/ credits-10" }, { "kind": "credits", "price": 50, "checkout": "https: //summaries.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //summaries.apis.dev/ checkout/ credits-200" } ] } Python import os from summaries import Summaries api = Summaries(key=os.environ["SUMMARIES_KEY"]) error, meta = api.summarize_company("acme.com") # 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_e01eab0d5cdfbb1619d4 { "type": "https: //summaries.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Company.summarize draws 0.02 from it.", "code": "payment_required", "instance": "req_e01eab0d5cdfbb1619d4", "offers": [ { "kind": "credits", "price": 10, "checkout": "https: //summaries.apis.dev/ checkout/ credits-10" }, { "kind": "credits", "price": 50, "checkout": "https: //summaries.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //summaries.apis.dev/ checkout/ credits-200" } ] } Terminal $ npx summaries login --key $SUMMARIES_KEY $ npx summaries companies summarize acme.com error 402 payment_required price 0 USD · req_e01eab0d5cdfbb1619d4Response HTTP/1.1 402 Payment Required Content-Type:application/ problem+json X-Cost: price= 0, currency= "USD" X-Request-Id: req_e01eab0d5cdfbb1619d4 { "type": "https: //summaries.apis.dev/ docs/ errors#payment_required", "title": "Payment Required", "status": 402, "detail": "The credit balance is 0; Company.summarize draws 0.02 from it.", "code": "payment_required", "instance": "req_e01eab0d5cdfbb1619d4", "offers": [ { "kind": "credits", "price": 10, "checkout": "https: //summaries.apis.dev/ checkout/ credits-10" }, { "kind": "credits", "price": 50, "checkout": "https: //summaries.apis.dev/ checkout/ credits-50" }, { "kind": "credits", "price": 200, "checkout": "https: //summaries.apis.dev/ checkout/ credits-200" } ] } Request curl https://summaries.apis.dev/ mcp \ -H "Authorization: Bearer $SUMMARIES_KEY" \ -H "Prefer: code= 402" \ --json '{ "jsonrpc": "2.0", "id": 1, "method": "tools/ call", "params": { "name": "summarizeCompany", "arguments": { "id": "acme.com" } } }' Response HTTP/1.1 200 OK X-Cost:price= 0, currency= "USD" X-Request-Id: req_ee3ed8704e1b3cd592b5 { "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_ee3ed8704e1b3cd592b5" } } } A new Customer's first call answers 402 at price 0. Its
offersare credit packs, each a Stripe Checkout link.Buy credits and call again
POST summaries.apis.dev/companies/acme.com/summarizeRequest curl -X POST https://summaries.apis.dev/ companies/ acme.com/ summarize \ -H "Authorization: Bearer $SUMMARIES_KEY" Response HTTP/1.1 200 OK X-Cost:price= 0.02, currency= "USD" X-Request-Id: req_fa5075382229d67f1ce9 { "id": "act_1", "verb": "Company.summarize", "status": "done", "output": { "summary": "Acme sells pipeline software to B2B sales teams." } } TypeScript import { Summaries } from 'summaries' const api = new Summaries({ key: process.env.SUMMARIES_KEY }) const { data, meta } = await api.summarizeCompany('acme.com') // data:{ // 'id': 'act_1', // 'verb': 'Company.summarize', // 'status': 'done', // 'output': { // 'summary': 'Acme sells pipeline software to B2B sales teams.' // } // } // meta.cost: { price: 0.02, currency: 'USD' } Response HTTP/1.1 200 OK X-Cost:price= 0.02, currency= "USD" X-Request-Id: req_fa5075382229d67f1ce9 { "id": "act_1", "verb": "Company.summarize", "status": "done", "output": { "summary": "Acme sells pipeline software to B2B sales teams." } } Python import os from summaries import Summaries api = Summaries(key=os.environ["SUMMARIES_KEY"]) data, meta = api.summarize_company("acme.com") # data:{ # "id": "act_1", # "verb": "Company.summarize", # "status": "done", # "output": { "summary": "Acme sells pipeline software to B2B sales teams." } # } # meta.cost: { "price": 0.02, "currency": "USD" } Response HTTP/1.1 200 OK X-Cost:price= 0.02, currency= "USD" X-Request-Id: req_fa5075382229d67f1ce9 { "id": "act_1", "verb": "Company.summarize", "status": "done", "output": { "summary": "Acme sells pipeline software to B2B sales teams." } } Terminal $ npx summaries login --key $SUMMARIES_KEY $ npx summaries companies summarize acme.com { "id": "act_1","verb": "Company.summarize", "status": "done", "output": { "summary": "Acme sells pipeline software to B2B sales teams." } } price 0.02 USD · req_fa5075382229d67f1ce9 Response HTTP/1.1 200 OK X-Cost:price= 0.02, currency= "USD" X-Request-Id: req_fa5075382229d67f1ce9 { "id": "act_1", "verb": "Company.summarize", "status": "done", "output": { "summary": "Acme sells pipeline software to B2B sales teams." } } Request curl https://summaries.apis.dev/ mcp \ -H "Authorization: Bearer $SUMMARIES_KEY" \ --json '{ "jsonrpc": "2.0", "id": 1, "method": "tools/ call", "params": { "name": "summarizeCompany", "arguments": { "id": "acme.com" } } }' Response HTTP/1.1 200 OK X-Cost:price= 0.02, currency= "USD" X-Request-Id: req_f08587376f0b234c2cd7 { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "{\"id\":\"act_1\",\"verb\":\"Company.summarize\",\"status\":\"done\",\"output\":{\"summary\":\"Acme sells pipeline software to B2B sales teams.\"}}" } ], "structuredContent": { "id": "act_1", "verb": "Company.summarize", "status": "done", "output": { "summary": "Acme sells pipeline software to B2B sales teams." } }, "_meta": { "cost": { "price": 0.02, "currency": "USD" }, "requestId": "req_f08587376f0b234c2cd7" } } } After Checkout, the same call answers with the summary, and
X-Costdraws $0.02 from the credits.Ask for research
Request curl -X POST https://summaries.apis.dev/ companies/ acme.com/ research \ -H "Authorization: Bearer $SUMMARIES_KEY" Response HTTP/1.1 202 Accepted Location:/actions/ act_2 Retry-After: 60 X-Cost: price= 0.5, currency= "USD" X-Request-Id: req_0a6b1dbf299819cd7076 { "id": "act_2", "verb": "Company.research", "status": "pending", "reason": "Running", "poll": "/actions/ act_2" } Request curl https://summaries.apis.dev/ actions/ act_2 \ -H "Authorization: Bearer $SUMMARIES_KEY" Response HTTP/1.1 200 OK X-Cost:price= 0, currency= "USD" X-Request-Id: req_6fcd6e915495e75ebee0 { "id": "act_2", "verb": "Company.research", "status": "done", "output": { "headOfSales": "Dana Ito" }, "provenance": "Inferred" } An agent takes minutes, so the call answers 202 at once with an Action to poll. Its answer arrives stamped Inferred, and a failed Action costs nothing.
Get paid
Stripe receipt · October 2026 · USD Company.summarize 1,800 × 0.02 36.00 Company.research 40 × 0.5 20.00 ─────────────────────────────────────── Total 56.00 Paid from 200.00 of credits 56.00 Balance 144.00 Each Live call lands on your Customer's Stripe receipt, a line per Verb, and the money lands in your own Stripe account. This is one Customer's month.
Result
Your API answers on https://summaries.apis.dev: 2 Verbs, a model's answer at once for $0.02 and an agent's as an Action for $0.50.
Each is typed on every Interface. A call with no credits answers 402 with packs on Stripe Checkout, and a failed Action costs nothing. You wrote no prompt pipeline, no job queue and no metering.
Next steps
- Start an Agent API → sell a worker instead of an answer, billed by what each run consumes.
- Function API: the four kinds, one Verb behind several, and pricing by kind.
- Runtime: the gate every call passes, and the Action every Verb answers.