CureData · 00.1/A validation workbench

Data you can actually trust.

CureData catches the errors spreadsheets hide. Upload a file, compose a ruleset from dozens of primitives, and get a precise, auditable report of what's wrong — and where.

Formats
3
csv · xlsx · json
Rules
40+
built-in primitives
Residency
local
files stay in browser
run_2025_10_27.txt
datasetorders_q4.csv
rows scanned12,847
rules applied23
issues found41
r.0143email✕ pattern"wrong@"
r.0143dates✕ orderstart > end
r.0207amount✕ range-12.50
r.0389country✕ enum"UK" (use "GB")
r.0891postal✕ format"9410A" (US)
36 more — export to csv
fig 01 · validation outputv0.1.0
Method

Three movements, one loop.

  1. 01Source

    Ingest the thing you're worried about.

    Drop in a CSV, XLSX, or JSON. We sniff headers, sample a few rows, and infer types so you have a starting point — not a blank slate.

    Try the uploader
  2. 02Compose

    Assemble rules the way you'd explain them.

    Required, type, length, range, enum, regex, date order, cross-field logic — and a slot for custom TypeScript when the spec gets weird.

    See the primitives
  3. 03Run

    Get a report you'd put in a PR.

    KPIs, column profiles, and a CSV of issues keyed by row. Rerun with the same ruleset against next week's file. Deterministic output.

    Export format
Rule packs

Curated, not conjured.

Every primitive in CureData is small, named, and explainable. Packs group them by domain so you don't rebuild the wheel for every vendor file that lands on your desk.

Browse all packs

Healthcare

6

NPI, NPPES status, taxonomy codes, DEA shape, specialty coherence.

· npi_luhn · dea_format · spec_vs_taxonomy

Identity & contact

6

Email shape, MX lookup, E.164 phone, name heuristics, DOB bounds, UUID/ULID.

· email_pattern · e164_format · uuid_v4

Address & geo

6

Postal formats, ISO-3166, state coherence, lat/lon bounds.

· iso3166_alpha2 · zip_us · lat_between

Finance

6

Luhn, IBAN, SWIFT/BIC, ISO-4217 currency, precision and scale, tax-id lengths.

· luhn · iban_format · iso4217

Data quality

9

Required, enum, regex, min/max, ISO-8601 dates, uniqueness, referential.

· required · enum · unique_in_file

Cross-field logic

4

"If A then B", conditional ranges, temporal ordering, dependency graphs.

· if_then · lte:otherField · coalesce
Shape

Rules as text you can read at 2am.

CureData's schemas are JSON first, TypeScript when you need to reach further. Version them with your code, diff them in review, and send a failure report back to the team that produced the file.

Declarative
Rules live next to schemas, not in helper closets.
Composable
A column carries 0..n rules; ordering doesn't matter.
Auditable
Every issue points back to a named rule and a row index.
orders.rules.json
{
  "entity": "Orders",
  "columns": {
    "orderId":        ["required", "uuid_v4"],
    "email":          ["required", "email_pattern"],
    "currency":       ["iso4217"],
    "amount":         ["number", "precision:2", "min:0"],
    "createdAt":      ["date_iso"],
    "shipTo.country": ["iso3166_alpha2"],
    "shipTo.postal":  ["postal_by_country:shipTo.country"]
  },
  "policy": { "fail": "any" }
}
custom/postalByCountry.ts
export default function postalByCountry({ get, add }: any) {
  const c = String(get('shipTo.country') || '').toUpperCase()
  const p = String(get('shipTo.postal')  || '')
  const MAP: Record<string, RegExp> = {
    US: /^[0-9]{5}(-[0-9]{4})?$/,
    CA: /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/,
    GB: /^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$/i
  }
  const re = MAP[c]
  if (re && !re.test(p)) add('postal.pattern', `Postal does not match ${c}`)
}
Begin

Your files. Your rules. Your browser.

No sign-up to try it. Sign in only when you want to save a ruleset.