Skip to content

Dataset API

Sell the facts about a thing, priced per answer.

firms.example.com answers
5 lines
{
  "website": "acme.com",
  "headcount": 240,
  "industry": "Software"
}
companyfacts.apis.dev/companies/acme.com?include=provenance
HTTP/1.1 200 OK
X-Cost: price=0.002, currency="USD"

{
  "domain": "acme.com",
  "employees": 240,
  "sector": "Software",
  "provenance": {
    "domain": {
      "basis": "Observed",
      "writer": "firms",
      "at": "2026-10-19T06:00:00Z"
    },
    "employees": {
      "basis": "Observed",
      "writer": "firms",
      "at": "2026-10-19T06:00:00Z"
    },
    "sector": {
      "basis": "Observed",
      "writer": "firms",
      "at": "2026-10-19T06:00:00Z"
    }
  }
}

How a field is filled

It is not a proxy. A Source answers in its own shape, a Mapping reads each field into yours, and each value carries its Provenance.

firms: the Source
7 lines
firms: {
  origin: 'https://firms.example.com',
  key: secret('FIRMS_KEY'),           // set with npx apis.dev secrets set
  resources: { companies: { detail: '/companies/{website}' } },
  schedule: 'every Mon 06:00',        // Trigger: read again each Monday
  license: 'CC-BY-4.0',
},

The credential is a secret you set once, never a line of the file, and no Customer ever sees it. A value is a kept copy read again on its schedule, or a live answer through a cache. A ranked from tries each writer in order until one answers.

definition.ts
3 lines
    employees: { type: 'number?', from: 'firms', map: 'headcount' },
    employees: { type: 'number?', map: 'headcount',
      from: ['firms', agentic('Find headcount for {domain}')] },

A Source's write is Observed, an agent's Inferred, and Observed wins for facts. So the agent's guess at headcount stands until firms observes the real one.

A Source holds only the members its grammar names: an unknown one is refused on publish.

What your Customers call

A get by the # key, and a search by any field, on every Interface.

GET companyfacts.apis.dev/companies?sector=Software
Request
curl https://companyfacts.apis.dev/companies?sector=Software \
  -H "Authorization: Bearer $COMPANYFACTS_KEY"
Response
HTTP/1.1 200 OK
X-Cost: price=0.005, currency="USD"
X-Request-Id: req_1e9cb0ffe275994adbe7

{
  "items": [{ "domain": "acme.com", "employees": 240, "sector": "Software" }],
  "total": 1,
  "next": null
}

The price

A price per answer, a Watch on one Company by the month, free calls each month, and the credit packs Checkout sells.

definition.ts · offer
7 lines
  offer: { 'Company.get': 0.002, 'Company.search': 0.005 },
  offer: {
    'Company.get': 0.002, 'Company.search': 0.005,
    'Company.watch': { month: 0.1 },
    free: { 'Company.get': 100 },
    credits: [10, 50, { pay: 200, get: 220 }],
  },

A miss costs nothing. Each refresh writes Company.refreshed, so a Customer's Watch on employees delivers each change it makes.

Dataset API: its five blocks
Nounthe shape you promiseVerbwhat can be done to itSourcewhere its data comes fromTriggerwhat reacts to a changeOfferthe price
Company, keyed by its domainget by key, search by a fieldthe API you resell, mapped into yoursa refresh on a schedulea price per answer, from credits; a miss is free

Start a Dataset API →