Skip to content

What every product gets

Everything around your API, live on your own domain from one deploy: CLI, MCP, SDKs, docs, a landing site, a portal and Stripe billing.

What every product gets, by what it does for you
What you getWhereWhat it does
Build
The APIeach Noun's pathREST at the paths of your Nouns and Verbs, with one error shape, Batch, and the price and a request id on every reply.
RecordsPOST, GET, PATCH and DELETE /{nouns}Create, get, list, update and delete on every Noun your Customers write, each record in its Customer's own space.
Lifecycle movesPOST /{nouns}/{id}/{verb}One Verb per move, refused with 409 from the wrong state and with 403 for the wrong Role.
The change feed/eventsEvery change as an Event in seq order, read back from any point with after.
Outbound webhooksPOST /watchesA Watch per URL your Customer picks: each change signed, retried until it lands, each attempt kept, and replayable.
Inbound webhooksa Source's deliveriesEach delivery verified, then written as an Event before anything runs.
Durable runs/actions/{id}A Workflow's run as an Action: Pending with its reason, then done, across restarts and long waits.
Launch
CLIa command per VerbA command per Verb under your API's own name, generated from the same file.
MCP/mcpOne tool per Verb with its price, then search, fetch and do, each answering the same body and price as REST; a Key or OAuth 2.1 signs in.
SDK/sdkTypeScript and Python clients under your API's name, generated from the file and published with it.
Docs/docsHTML and Markdown, a page per Noun, Verb and Event, with OpenAPI, llms.txt and agents.json.
Landing site/The pitch, Try it with a Test key, the prices and Get started, on your own domain.
Developer portal/dashboardEach Customer's keys, usage and balance, plan, invoices, spend ceiling, webhook deliveries with Replay, and why a run waits.
Monetize
The price on every replyX-Cost and /pricingThe posted price of each Verb, on /pricing and on every reply, with a miss free.
KeysTest and LiveKeys your Customers sign up for, each Live key with a Test twin whose calls never post.
Free callsthe Offer's free callsThe Offer's free calls come off each month before any credit is drawn.
Prepaid creditseach Customer's balanceEach priced call draws once from the Customer's credit balance, at the price it was served at, even when retried; a plan bills a month ahead.
Stripe billingyour own Stripe accountEach Customer buys credits through Stripe Checkout and plans through a Stripe subscription, with Stripe invoices and receipts, into your own Stripe account.
Your Adminyour accountYour revenue by Verb and by Customer, each payment beside the calls it paid for, and your margin per Verb.

Build

The API
each Noun's path
Records
POST, GET, PATCH and DELETE /{nouns}
Lifecycle moves
POST /{nouns}/{id}/{verb}
The change feed
/events
Outbound webhooks
POST /watches
Inbound webhooks
a Source's deliveries
Durable runs
/actions/{id}

Every change writes one Event: create, update, delete and restore give created, updated, deleted and restored, and each move its own past form.

A Watch sends each change your Customer picks to their URL, signed, and retries a failed delivery until it lands. Each attempt is kept, and any delivery replays from the developer portal.

Delivery
POST /hooks/pipeline HTTP/1.1
Host: hooks.acme.com
X-Webhook-Attempt: 1
X-Webhook-Signature: t=1792833000,v1=2c067386fcd9006ece95389e2fde364074ad34388decdfc0a31f3edce14d0252

{
  "id": "evt_2",
  "type": "Deal.opened",
  "at": "2026-10-24T09:10:00Z",
  "seq": 2,
  "data": {
    "id": "deal_1",
    "title": "Pilot",
    "amount": "5000.00",
    "company": "company_1",
    "stage": "opened"
  }
}
Receive it
22 lines
import { createHmac, timingSafeEqual } from 'node:crypto'

// verify(request, secret): true when the delivery was signed with your secret in the last 5 minutes
export async function verify(request: Request, secret: string) {
  const header = request.headers.get('X-Webhook-Signature') ?? ''
  const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')))
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
  const want = createHmac('sha256', secret).update(`${t}.${await request.text()}`).digest()
  const got = Buffer.from(v1 ?? '', 'hex')
  return got.length === want.length && timingSafeEqual(got, want)
}

// The receiver: verify a copy, then read the Event once by its id.
const seen = new Set<string>()
export default {
  async fetch(req: Request) {
    if (!(await verify(req.clone(), process.env.PIPELINE_WEBHOOK_SECRET!))) return new Response(null, { status: 401 })
    const event = await req.json()
    if (!seen.has(event.id)) seen.add(event.id)  // a retry carries the same id
    return new Response(null, { status: 204 })
  },
}

Launch

One call answers the same body and price on every Interface. The CLI and both SDKs carry your API's own name, generated from the file and published with it.

Request
curl https://companyfacts.apis.dev/companies/acme.com \
  -H "Authorization: Bearer $COMPANYFACTS_KEY"
Response
HTTP/1.1 200 OK
X-Cost: price=0.002, currency="USD"
X-Request-Id: req_3cd59a9a1ede10c5bf21

{ "domain": "acme.com", "employees": 240, "sector": "Software" }

Your landing site and developer portal come from the same file. The pitch is the comment above it, and the prices are its Offer.

companyfacts.apis.dev/
companyfacts.apis.dev/
PartWhat it shows
The heroThe file's name and its pitch, the comment above the file, with Get started.
Try itEach Verb with its example, called live with a Test key the page mints.
PricingA card per plan from /pricing, then each price per call, the free calls and the credit packs.
Get startedSign-up, Stripe Checkout for a plan or credits, then a Live key.
Docs and MCPThe docs, llms.txt and the MCP server, for people and for agents.
companyfacts.apis.dev/dashboard
companyfacts.apis.dev/dashboard
PartWhat it shows
KeysEach Live key and its Test twin: made, rolled and revoked.
Usage and balanceUsage by Verb and day, the credit balance, and a top-up through Checkout.
PlanThe plan and its seats, and a switch to another plan.
InvoicesEach Stripe invoice and receipt.
Spend ceilingA ceiling on each Key; past it, a call asks for Approval.
Webhook deliveriesEach Watch, its deliveries and their attempts, with Replay.
RunsEach Action that waits, and its Pending reason.

What an agent sees

An agent reads /.well-known/agents.json first, then the product's own llms.txt, then tools/list. It lists one tool per Verb, with its schemas, hints from its kind and its price.

tools/list
31 lines
{
  "tools": [
    {
      "name": "getCompany",
      "description": "Answers one company by its domain, with its headcount and sector.",
      "inputSchema": {
        "type": "object",
        "properties": { "domain": { "type": "string" } },
        "required": ["domain"]
      },
      "outputSchema": { … },
      "annotations": { "readOnlyHint": true },
      "_meta": { "price": 0.002, "currency": "USD" }
    },
    {
      "name": "searchCompanies",
      "description": "Lists the companies in one sector, each with its domain.",
      "inputSchema": {
        "type": "object",
        "properties": { "sector": { "type": "string" } },
        "required": ["sector"]
      },
      "outputSchema": { … },
      "annotations": { "readOnlyHint": true },
      "_meta": { "price": 0.005, "currency": "USD" }
    },
    { "name": "search" },
    { "name": "fetch" },
    { "name": "do" }
  ]
}

Monetize

/pricing
18 lines
{
  "currency": "USD",
  "rates": [
    { "name": "Company.get",
      "price": 0.002, "unit": "call" },
    { "name": "Company.search",
      "price": 0.005, "unit": "call" },
    { "name": "Company.watch",
      "price": 0.1, "unit": "month" }
  ],
  "free": { "Company.get": 100 },
  "credits": [
    10,
    50,
    { "pay": 200,
      "get": 220 }
  ]
}

Each priced call draws once from prepaid credits, at the price it was served at.

Each Customer pays through Stripe, into your account.

When a Customer needs more

Every refusal sells. A 402 or a 403 carries offers: credit packs, a plan or a Verb, each with its Stripe Checkout link. The call after payment goes through.

GET companyfacts.apis.dev/companies/acme.com
Request
curl https://companyfacts.apis.dev/companies/acme.com \
  -H "Authorization: Bearer $COMPANYFACTS_KEY"
Response
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
X-Cost: price=0, currency="USD"
X-Request-Id: req_71f702a3d4250104f0bf

{
  "type": "https://companyfacts.apis.dev/docs/errors#payment_required",
  "title": "Payment Required",
  "status": 402,
  "detail": "The credit balance is 0; Company.get draws 0.002 from it.",
  "code": "payment_required",
  "instance": "req_71f702a3d4250104f0bf",
  "offers": [
    {
      "kind": "credits",
      "price": 10,
      "checkout": "https://companyfacts.apis.dev/checkout/credits-10"
    },
    {
      "kind": "credits",
      "price": 50,
      "checkout": "https://companyfacts.apis.dev/checkout/credits-50"
    },
    {
      "kind": "credits",
      "price": 200,
      "checkout": "https://companyfacts.apis.dev/checkout/credits-200"
    }
  ]
}

An agent sets Max-Cost, and a call above it is refused before it runs, at no charge. A spend ceiling the owner sets on a Key answers 403 with an Approval URL.

Request
curl https://companyfacts.apis.dev/mcp \
  -H "Authorization: Bearer $COMPANYFACTS_KEY" \
  --json '{
  "jsonrpc": "2.0", "id": 1, "method": "tools/call",
  "params": { "name": "getCompany", "arguments": { "domain": "acme.com" },
    "_meta": { "maxCost": 0.001 } }
}'
Response
HTTP/1.1 200 OK
X-Cost: price=0, currency="USD"
X-Request-Id: req_30d98961416616e608d0

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": true,
    "content": [ … ],
    "structuredContent": {
      "type": "https://companyfacts.apis.dev/docs/errors#over_max_cost",
      "title": "Payment Required",
      "status": 402,
      "detail": "Company.get costs 0.002; the call allows 0.001.",
      "code": "over_max_cost",
      "instance": "req_30d98961416616e608d0"
    },
    "_meta": {
      "cost": { "price": 0, "currency": "USD" },
      "requestId": "req_30d98961416616e608d0"
    }
  }
}

Your revenue

your Admin, at apis.dev
your Admin, at apis.dev
PartWhat it shows
RevenueRevenue by Verb and by Customer, each payment beside the calls it paid for.
CustomersEach Customer with their plan, balance and usage.
MarginYour margin per Verb, from your Sources' cost.