Kadrin Docs Kadrin Batch

Get started with the API

In about five minutes you'll get numbers for a place from your own code. You need a Kadrin account (the beta is by invitation) and one of: curl, Python 3 with the requests package (pip install requests), or Node.js 18 or later.

1. Make a test key

Sign in to Kadrin Batch, open Keys, and make a test key. A test key is free and gives made-up numbers, in exactly the shape of real ones, so you can build and try things without spending credits. Copy it: we show it only once.

Keep the key in an environment variable rather than in your code:

export KADRIN_API_KEY="kdr_test_..."

Call the API from your own computer or server, never from a web page: anyone can read a key in a page.

2. Check that your key works

Ask how many credits you have. This is free.

curl https://api.kadrindata.com/v1/usage -H "Authorization: Bearer $KADRIN_API_KEY"
import os

import requests

r = requests.get(
    "https://api.kadrindata.com/v1/usage",
    headers={"Authorization": f"Bearer {os.environ['KADRIN_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.kadrindata.com/v1/usage", {
  headers: { Authorization: `Bearer ${process.env.KADRIN_API_KEY}` },
});
if (!r.ok) throw new Error(await r.text());
console.log(await r.json());

To run the JavaScript, save it in a file ending .mjs, such as usage.mjs, and run node usage.mjs. You'll see something like:

{"balance": 50000, "free_credits_remaining_today": 50, "daily_cap": null, "days": []}

3. Get numbers for a place

Ask for the population and median household income within 3 miles of Boston City Hall. A place goes in areas, with an id you choose and its geometry: here a buffer, which is a radius around a point given as [longitude, latitude].

curl https://api.kadrindata.com/v1/enrich \
  -H "Authorization: Bearer $KADRIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "areas": [{"id": "city-hall",
               "geometry": {"type": "buffer", "center": [-71.0589, 42.3601], "radius": 3, "unit": "mi"}}],
    "variables": ["demographics.population.total", "income.household.median"]
  }'
import os

import requests

r = requests.post(
    "https://api.kadrindata.com/v1/enrich",
    headers={"Authorization": f"Bearer {os.environ['KADRIN_API_KEY']}"},
    json={
        "areas": [{"id": "city-hall",
                   "geometry": {"type": "buffer", "center": [-71.0589, 42.3601], "radius": 3, "unit": "mi"}}],
        "variables": ["demographics.population.total", "income.household.median"],
    },
)
r.raise_for_status()
for measure, v in r.json()["results"][0]["values"].items():
    print(f"{measure}: {v['value']:,.0f} {v['unit']}, give or take {v['moe']:,.0f}")
const r = await fetch("https://api.kadrindata.com/v1/enrich", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.KADRIN_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    areas: [{ id: "city-hall",
              geometry: { type: "buffer", center: [-71.0589, 42.3601], radius: 3, unit: "mi" } }],
    variables: ["demographics.population.total", "income.household.median"],
  }),
});
if (!r.ok) throw new Error(await r.text());
const { results } = await r.json();
for (const [measure, v] of Object.entries(results[0].values)) {
  console.log(`${measure}: ${v.value.toLocaleString()} ${v.unit}, give or take ${v.moe.toLocaleString()}`);
}

The answer looks like this, shortened, from a live key. The numbers here are made up, as a test key's are; a live key gets real ones.

{
  "request_id": "req_5239cfca03d24a6bb6a0",
  "release": "2026.11.1",
  "credits_used": 2,
  "results": [{
    "id": "city-hall",
    "area": {"type": "buffer", "area_km2": 73.23, "units_intersected": 112, "units_fully_contained": 81},
    "values": {
      "demographics.population.total": {"value": 46147, "unit": "people", "aggregation": "sum",
        "source": "acs5", "vintage": "2020-2024", "moe": 3236, "resolution": "block_group"},
      "income.household.median": {"value": 78390, "unit": "dollars", "aggregation": "interpolated_median",
        "source": "acs5", "vintage": "2020-2024", "moe": 5538, "resolution": "block_group"}
    }
  }],
  "sources": [{"id": "acs5", "name": "U.S. Census Bureau, American Community Survey 5-year estimates",
               "vintage": "2020-2024"}]
}

4. Read the answer

Each measure in values has:

area says how big the place is and how many official areas it touches. A number you should know something about before relying on it comes with a warning, such as high_cv when few households were surveyed: see Errors and warnings.

The headers say what the request cost: Kadrin-Credits-Used and Kadrin-Credits-Remaining. This one used 2 credits, one for each group of measures. A test key is never charged.

5. See the cost first

Set options.dry_run to true to find out what a request would cost, for free. This one asks for a site report, a ready-made set of measures, for a 10-minute drive-time area: everywhere you can reach by car in 10 minutes.

curl https://api.kadrindata.com/v1/enrich \
  -H "Authorization: Bearer $KADRIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "areas": [{"id": "city-hall",
               "geometry": {"type": "isochrone", "center": [-71.0589, 42.3601], "mode": "drive", "minutes": 10}}],
    "preset": "site_report",
    "options": {"dry_run": true}
  }'
import os

import requests

r = requests.post(
    "https://api.kadrindata.com/v1/enrich",
    headers={"Authorization": f"Bearer {os.environ['KADRIN_API_KEY']}"},
    json={
        "areas": [{"id": "city-hall",
                   "geometry": {"type": "isochrone", "center": [-71.0589, 42.3601], "mode": "drive", "minutes": 10}}],
        "preset": "site_report",
        "options": {"dry_run": True},
    },
)
r.raise_for_status()
print("This would cost", r.json()["estimated_credits"], "credits")
const r = await fetch("https://api.kadrindata.com/v1/enrich", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.KADRIN_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    areas: [{ id: "city-hall",
              geometry: { type: "isochrone", center: [-71.0589, 42.3601], mode: "drive", minutes: 10 } }],
    preset: "site_report",
    options: { dry_run: true },
  }),
});
if (!r.ok) throw new Error(await r.text());
console.log("This would cost", (await r.json()).estimated_credits, "credits");

It costs 10 credits: 8 for the report's groups of measures, and 2 to draw the drive-time area. Take out dry_run to run it. A site report also compares each number with the county, the state and the US, in each value's benchmarks.

6. Go live

When you're ready for real numbers, make a live key on the same Keys page. A live key uses your account's credits, starting with the 50 free credits each day. To be sure one request never costs more than you expect, send the most it may cost in the Kadrin-Max-Credits header: a request that would cost more is refused, for nothing.

Each key can make 60 requests a minute to /enrich, with up to 100 places in each. For more places, send a file: see Send a file of places.

Next