Free · no key · CORS-open

Sampuli REST API

Format-true synthetic data for 90 countries over plain HTTP. No sign-up, no key, no rate-limit dance — fetch() it from anywhere.

GET https://sampuli.site/api/v1/ke/person?n=3

Endpoints

/api/v1/countriesEvery country + metadata (code, name, currency, group)
/api/v1/{country}A country’s available fields & preset scenarios
/api/v1/{country}/{selector}Generate data — see selectors & params below
/api/v1/fetch?q=a+swift+code+for+chinaAsk in plain language — Sampuli maps “China” → cn and “SWIFT code” → swift, then generates. Great for AI agents.
/api/v1/batchMany specs in one request — see below

Plain-language fetch — for AI agents

Don’t know the country code or field name? Just describe what you want. /api/v1/fetch?q=… resolves the country and field from the words, then generates — and the JSON echoes the spec it chose so you can see how it was read.

/api/v1/fetch?q=a+swift+code+for+chinaReturns { "spec": "cn.swift", "country": "cn", "field": "swift", "data": "ICBKCNBJ" }
/api/v1/fetch?q=kenya+phone+number&n=5&format=csvFive Kenyan phone numbers as CSV
/api/v1/fetch?q=german+passportA German passport number
/api/v1/resolve?q=uk+ibanJust the interpretation — { "spec": "gb.iban", … }, no data

Same params as generate (n, seed, format). If no country is recognised you get a 422 with a hint — pass a country name (“China”, “Kenya”) or a code (cn.swift).

Batch — many countries in one call

Need a mix — one thing from Nigeria, three from Kenya, a company from Germany? Ask for it all at once instead of firing several requests.

/api/v1/batch?specs=ng.phone,ke.full:3,de.companyGET: comma-separated country.selector[:count][@fields]. :N = count; @all or @name+card = fields; preset:kyc keeps its colon.
POST /api/v1/batchBody { "requests": [ { "spec": "ke.person", "n": 3, "fields": ["name","phone"], "key": "customers" } ] } — per-request fields, seed and your own key.

Returns { count, results: [ { spec, data } | { spec, error } ] }. Up to 50 requests / 1,000 total rows per batch; one bad spec never fails the rest.

Generic types — shape data however you need

Next to the country-accurate fields, Sampuli has country-agnostic primitives — including validated ones (VIN, ISBN-13, IMEI all carry real check digits, UUIDs are RFC-4122 v4).

/api/v1/typesList every generic type (uuid, enum, int, float, date, vin, isbn, imei, mac, email, colour…)
/api/v1/any/uuidA single generic value
/api/v1/any/int:1,100Parameterised — int:min,max · enum:a,b,c · date:2020,2025 · float:0,9,2

Custom schema — the whole point

Mix generic types and country-accurate fields into one row, exactly like a Mockaroo schema — over a plain POST.

POST /api/v1/schema
{
  "count": 100,
  "seed": "demo",
  "fields": [
    { "name": "id",       "type": "uuid" },
    { "name": "phone",    "type": "ke.phone" },
    { "name": "iban",     "type": "de.iban" },
    { "name": "plan",     "type": "enum:free,pro,team" },
    { "name": "mrr",      "type": "int:0,500", "blank": 0.1 },
    { "name": "joined",   "type": "date:2021,2025" }
  ]
}

A field type is a generic type or a country field spec (ke.phone, de.iban). blank (0–1) makes it null that often, so you can test null handling. Add ?format=csv for CSV.

Selectors

ke/personA coherent record — the core fields
ke/fullA record with every field — card, CVV, passport + MRZ, transaction, IP, licence, income, employer…
ke/companyA synthetic company (name, industry, VAT, …)
ke/productA product / catalogue row with a valid EAN-13
ke/phoneA single field value (any field key)
ke/preset:kycA scenario — ordered label/value rows

person returns the common fields; the heavier PII (cards, passports, income…) is opt-in — use full, or list exactly what you want with ?fields=. Call /api/v1/{country} to see every field and which are on by default.

Query parameters

n=1..1000How many rows (omit for one). Larger volumes: the npm package, no cap.
fields=name,account,cardWhich fields, comma-separated — or all, or a group: identity, contact, payment, banking, tax, transaction
seed=anythingReproducible output — same seed, same data
format=json|csv|ndjson|xmlResponse format (default json)
pretty=1Pretty-print JSON

Examples

/api/v1/de/person?fields=name,account,card&n=50&format=csvFifty German rows as CSV
/api/v1/ng/bvn?n=100A hundred Nigerian BVNs
/api/v1/gb/ibanOne UK IBAN
/api/v1/ke/preset:kycA Kenyan KYC scenario

Build against it

OpenAPI 3.1 spec: /api/v1/openapi.json — import it into Postman or Insomnia (Import → Link → that URL) to get every endpoint, or feed it to openapi-generator for a typed client in any language.

Postman collection ↓ · Copy-paste recipes for curl, fetch, Node, Prisma, Drizzle, Playwright, SQL, Python and CI · Validate a value (GET /api/v1/validate)

Use it from your AI assistant (MCP)

Sampuli is also a Model Context Protocol server, so Claude, Cursor and Copilot can generate country-accurate test data inline. Two ways:

Hosted (no install): add https://sampuli.site/api/mcp as a remote MCP server (Streamable HTTP) — keyless, CORS-open. Local: npx -y @sampuli/mcp. Tools: sampuli_fetch (plain-language, e.g. “a SWIFT code for China”), sampuli_generate (exact spec), sampuli_list_countries, sampuli_describe_country, sampuli_list_types, sampuli_schema. It also exposes browsable resourcessampuli://catalog, sampuli://fields, sampuli://country/{code}, sampuli://field/{field}.

Notes

Every value is entirely synthetic — real formats, never real or registered data. Output is byte-identical to the @sampuli/data npm package and the website: one engine, one source of truth. Responses are CORS-open and not cached.