Format-true synthetic data for 90 countries over plain HTTP. No sign-up, no key, no rate-limit dance — fetch() it from anywhere.
/api/v1/countries | Every 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+china | Ask in plain language — Sampuli maps “China” → cn and “SWIFT code” → swift, then generates. Great for AI agents. |
/api/v1/batch | Many specs in one request — see below |
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+china | Returns { "spec": "cn.swift", "country": "cn", "field": "swift", "data": "ICBKCNBJ" } |
/api/v1/fetch?q=kenya+phone+number&n=5&format=csv | Five Kenyan phone numbers as CSV |
/api/v1/fetch?q=german+passport | A German passport number |
/api/v1/resolve?q=uk+iban | Just 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).
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.company | GET: comma-separated country.selector[:count][@fields]. :N = count; @all or @name+card = fields; preset:kyc keeps its colon. |
POST /api/v1/batch | Body { "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.
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/types | List every generic type (uuid, enum, int, float, date, vin, isbn, imei, mac, email, colour…) |
/api/v1/any/uuid | A single generic value |
/api/v1/any/int:1,100 | Parameterised — int:min,max · enum:a,b,c · date:2020,2025 · float:0,9,2 |
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.
ke/person | A coherent record — the core fields |
ke/full | A record with every field — card, CVV, passport + MRZ, transaction, IP, licence, income, employer… |
ke/company | A synthetic company (name, industry, VAT, …) |
ke/product | A product / catalogue row with a valid EAN-13 |
ke/phone | A single field value (any field key) |
ke/preset:kyc | A 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.
n=1..1000 | How many rows (omit for one). Larger volumes: the npm package, no cap. |
fields=name,account,card | Which fields, comma-separated — or all, or a group: identity, contact, payment, banking, tax, transaction |
seed=anything | Reproducible output — same seed, same data |
format=json|csv|ndjson|xml | Response format (default json) |
pretty=1 | Pretty-print JSON |
/api/v1/de/person?fields=name,account,card&n=50&format=csv | Fifty German rows as CSV |
/api/v1/ng/bvn?n=100 | A hundred Nigerian BVNs |
/api/v1/gb/iban | One UK IBAN |
/api/v1/ke/preset:kyc | A Kenyan KYC scenario |
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)
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 resources — sampuli://catalog, sampuli://fields, sampuli://country/{code}, sampuli://field/{field}.
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.