Skip to content

Start a Dataset API

A live, priced API people and agents pay for in about 30 seconds, written as one file: a Source, a Mapping and a price.

You need Node 20 and a GitHub account. The first deploy answers at once on companyfacts.apis.dev; your own domain is one line.

  1. Start the folder

    Terminal
    $ npx apis.dev init dataset-api
    ✓ wrote definition.ts: a Dataset API
      next: npx apis.dev dev

    init writes the file this track builds, so every step after it runs as printed.

  2. Write the file

    definition.ts
    15 lines
    import { define, secret } from 'apis.dev'
    
    /** Any company by its domain, with its headcount and sector. */
    export default define({
      name: 'companyfacts', domain: 'companyfacts.apis.dev',
      sources: {                                    // Source: the API you resell
        firms: { origin: 'https://firms.example.com', key: secret('FIRMS_KEY') },
      },
      Company: {                                    // Noun: the shape you promise
        domain:    { type: 'url!#',   from: 'firms', map: 'website' },  // Mapping
        employees: { type: 'number?', from: 'firms', map: 'headcount' },
        sector:    { type: 'string?', from: 'firms', map: 'industry' },
      },
      offer: { 'Company.get': 0.002, 'Company.search': 0.005 },  // Offer: the price
    })

    firms answers { website, headcount, industry }; each map picks one, and !# makes domain the key. The comment above the file is its pitch on every Interface, and secret('FIRMS_KEY') reads the credential you set with npx apis.dev secrets set FIRMS_KEY.

  3. Try it locally

    Terminal
    $ npx apis.dev dev
    ✓ firms answered in 212 ms; their field → your field:
        website    → domain     "acme.com"
        headcount  → employees  240
        industry   → sector     "Software"
    ✓ every Interface on http://localhost:8787, against your Test twin
      reloads on every save

    dev asks the Source once and prints the record it maps, then serves every Interface on localhost against your Test twin.

  4. Publish it

    Terminal
    $ npx apis.dev deploy
    ✓ signed in with GitHub
    ✓ definition.ts: companyfacts on companyfacts.apis.dev
    ✓ Stripe connected: each Customer pays into your own account
    ✓ 1 Noun, 2 Verbs, 1 Source, 2 prices
        Company  get, search
        Company.get     0.002 a call
        Company.search  0.005 a call
    ✓ published v1 to https://companyfacts.apis.dev: 11 Interfaces
        REST              /companies/{domain}, /companies?sector=
        CLI               npx companyfacts
        MCP               /mcp
        SDK               npm i companyfacts, pip install companyfacts
        Docs              /docs
        OpenAPI           /openapi.json
        llms.txt          /llms.txt
        agents.json       /.well-known/agents.json
        Pricing           /pricing
        Landing site      /
        Developer portal  /dashboard
    ✓ Test key: companyfacts_test_NNTTj83hyuMNRNk85nzuQNW8h8y3wu33c155

    The first run signs you in with GitHub and connects Stripe to your own account. Your product answers at once on https://companyfacts.apis.dev, with each Verb, each price and each Interface printed, and a Test key. Set domain to a domain of your own and deploy again to move every Interface there; deploy checks it once by a TXT record.

  5. Call it with the Test key

    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" }

    Call with the Test key the first run printed: its calls never bill. A Live Key answers the same, and bills.

  6. Get paid

    Stripe receipt · October 2026 · USD
    Company.get       100 free      0.00
    Company.get    12,400 × 0.002  24.80
    Company.search  1,300 × 0.005   6.50
    Company.watch       3 × 0.1     0.30
    ────────────────────────────────────
    Total                          31.60
    Paid from 50.00 of credits     31.60
    Balance                        18.40

    Every Live call your Customers make lands on their Stripe receipt, a line per Verb, and the money lands in your own Stripe account. This is one Customer's month.

  7. See every Interface

    Every Interface, on https://companyfacts.apis.dev
    Every Interface, on https://companyfacts.apis.dev
    InterfacePath
    REST/companies/{domain}, /companies?sector=
    CLInpx companyfacts
    MCP/mcp
    SDKnpm i companyfacts, pip install companyfacts
    Docs/docs
    OpenAPI/openapi.json
    llms.txt/llms.txt
    agents.json/.well-known/agents.json
    Pricing/pricing
    Landing site/
    Developer portal/dashboard
  8. Change the price

    definition.ts
    2 lines
      offer: { 'Company.get': 0.002, 'Company.search': 0.005 },
      offer: { 'Company.get': 0.003, 'Company.search': 0.005 },
    Terminal
    $ npx apis.dev deploy
    ✓ definition.ts: 1 Noun, 2 Verbs, 1 Source, 2 prices
    ✓ published v2 to https://companyfacts.apis.dev: every Interface at once
    The price on three Interfaces
    The price on three Interfaces
    InterfaceAt 0.002At 0.003
    price in X-Costprice=0.002price=0.003
    /pricing"price": 0.002"price": 0.003
    /llms.txt($0.002)($0.003)

    Publish again, and all three move at once: the price in your docs is the price on the reply. A higher price is a breaking change: each Key keeps the Version it first called until it sends Api-Version.

  9. Ask for one nobody has

    GET companyfacts.apis.dev/companies/nobody.example.com
    Request
    curl https://companyfacts.apis.dev/companies/nobody.example.com \
      -H "Authorization: Bearer $COMPANYFACTS_KEY"
    Response
    HTTP/1.1 404 Not Found
    Content-Type: application/problem+json
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_84326ad21bc488454616
    
    {
      "type": "https://companyfacts.apis.dev/docs/errors#not_found",
      "title": "Not Found",
      "status": 404,
      "detail": "No Company has domain nobody.example.com.",
      "code": "not_found",
      "instance": "req_84326ad21bc488454616"
    }

    A miss answers a Problem with its code, and its price is 0.

Result

Build: you wrote 10 lines: a Source with its Mapping, a Noun and an Offer, and ran it on localhost first. Launch: one command published 11 Interfaces and 2 Verbs on companyfacts.apis.dev, with a Test key. Monetize: each call draws its posted price from prepaid credits bought through Stripe Checkout, and a miss is free. You wrote no Verb, no docs and no price page.

definition.ts
15 lines
import { define, secret } from 'apis.dev'

/** Any company by its domain, with its headcount and sector. */
export default define({
  name: 'companyfacts', domain: 'companyfacts.apis.dev',
  sources: {                                    // Source: the API you resell
    firms: { origin: 'https://firms.example.com', key: secret('FIRMS_KEY') },
  },
  Company: {                                    // Noun: the shape you promise
    domain:    { type: 'url!#',   from: 'firms', map: 'website' },  // Mapping
    employees: { type: 'number?', from: 'firms', map: 'headcount' },
    sector:    { type: 'string?', from: 'firms', map: 'industry' },
  },
  offer: { 'Company.get': 0.002, 'Company.search': 0.005 },  // Offer: the price
})

Next steps