Data Quality Intelligence API Documentation

Profile supplied CSV and JSON tables, point at missing cells and duplicate rows, and propose explicit normalization without changing the source. Payment is the exact USDC price on Base with x402.

POSThttps://brainiac.software/api/v1/data-quality/csv-schema-detect$0.03 USDC

Detect a CSV schema

Infer a column type from the supplied CSV or JSON values. A column with more than one non-numeric type stays mixed. No value is rewritten.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "detected",
  "rowCount": 12,
  "columnCount": 5,
  "columns": [
    {
      "name": "id",
      "index": 1,
      "type": "integer",
      "nullable": false,
      "distinctCount": 11,
      "count": 12
    },
    {
      "name": "email",
      "index": 2,
      "type": "mixed",
      "nullable": false,
      "distinctCount": 11,
      "count": 12
    },
    {
      "name": "amount",
      "index": 3,
      "type": "integer",
      "nullable": false,
      "distinctCount": 5,
      "count": 12
    },
    {
      "name": "status",
      "index": 4,
      "type": "boolean",
      "nullable": true,
      "distinctCount": 2,
      "count": 11
    },
    {
      "name": "joined",
      "index": 5,
      "type": "mixed",
      "nullable": false,
      "distinctCount": 11,
      "count": 12
    }
  ],
  "issues": [],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-schema-detect" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-profile$0.04 USDC

Profile CSV columns

Count present, missing, and distinct values for each column and report the minimum and maximum of the supplied values.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "profiled",
  "rowCount": 12,
  "columns": [
    {
      "name": "id",
      "index": 1,
      "type": "integer",
      "count": 12,
      "missingCount": 0,
      "distinctCount": 11,
      "min": "1",
      "max": "12"
    },
    {
      "name": "email",
      "index": 2,
      "type": "mixed",
      "count": 12,
      "missingCount": 0,
      "distinctCount": 11,
      "min": "Ada@Example.com",
      "max": "not-an-email"
    },
    {
      "name": "amount",
      "index": 3,
      "type": "integer",
      "count": 12,
      "missingCount": 0,
      "distinctCount": 5,
      "min": "10",
      "max": "500"
    },
    {
      "name": "status",
      "index": 4,
      "type": "boolean",
      "count": 11,
      "missingCount": 1,
      "distinctCount": 2,
      "min": "no",
      "max": "yes"
    },
    {
      "name": "joined",
      "index": 5,
      "type": "mixed",
      "count": 12,
      "missingCount": 0,
      "distinctCount": 11,
      "min": "03/11/2026",
      "max": "2024-10-01"
    }
  ],
  "issues": [],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-profile" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-column-type-detect$0.04 USDC

Detect CSV column types

List the observed types in each column. A value that differs from the most common type is referenced by row and column and is not changed. A tie is not blamed on a row.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "detected",
  "columns": [
    {
      "name": "id",
      "index": 1,
      "type": "integer",
      "observed": [
        {
          "type": "integer",
          "count": 12
        }
      ]
    },
    {
      "name": "email",
      "index": 2,
      "type": "mixed",
      "observed": [
        {
          "type": "email",
          "count": 11
        },
        {
          "type": "string",
          "count": 1
        }
      ]
    },
    {
      "name": "amount",
      "index": 3,
      "type": "integer",
      "observed": [
        {
          "type": "integer",
          "count": 12
        }
      ]
    },
    {
      "name": "status",
      "index": 4,
      "type": "boolean",
      "observed": [
        {
          "type": "boolean",
          "count": 11
        }
      ]
    },
    {
      "name": "joined",
      "index": 5,
      "type": "mixed",
      "observed": [
        {
          "type": "date",
          "count": 11
        },
        {
          "type": "string",
          "count": 1
        }
      ]
    }
  ],
  "issues": [
    {
      "kind": "conflict",
      "code": "inconsistent_format",
      "row": 7,
      "sourceRow": 8,
      "column": "email",
      "columnIndex": 2,
      "value": "not-an-email",
      "detail": "The most common type is email. This value was not changed."
    },
    {
      "kind": "conflict",
      "code": "inconsistent_format",
      "row": 7,
      "sourceRow": 8,
      "column": "joined",
      "columnIndex": 5,
      "value": "03/11/2026",
      "detail": "The most common type is date. This value was not changed."
    }
  ],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-column-type-detect" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-missing-value-audit$0.03 USDC

Audit missing CSV values

Find empty or whitespace-only cells and give each one a row and column reference. The row stays in the table.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "checked",
  "missingCount": 1,
  "columns": [
    {
      "name": "id",
      "index": 1,
      "missingCount": 0,
      "missingRate": 0
    },
    {
      "name": "email",
      "index": 2,
      "missingCount": 0,
      "missingRate": 0
    },
    {
      "name": "amount",
      "index": 3,
      "missingCount": 0,
      "missingRate": 0
    },
    {
      "name": "status",
      "index": 4,
      "missingCount": 1,
      "missingRate": 0.0833
    },
    {
      "name": "joined",
      "index": 5,
      "missingCount": 0,
      "missingRate": 0
    }
  ],
  "issues": [
    {
      "kind": "missing",
      "code": "missing_value",
      "row": 3,
      "sourceRow": 4,
      "column": "status",
      "columnIndex": 4,
      "value": "",
      "detail": "This cell is empty or whitespace. The row was kept."
    }
  ],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-missing-value-audit" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-duplicate-row-detect$0.05 USDC

Detect duplicate CSV rows

Group records that match after trimming each compared cell. When key columns are supplied, only those columns are compared. No record is removed.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "checked",
  "groupCount": 1,
  "groups": [
    {
      "count": 2,
      "rows": [
        {
          "row": 2,
          "sourceRow": 3
        },
        {
          "row": 5,
          "sourceRow": 6
        }
      ]
    }
  ],
  "issues": [
    {
      "kind": "conflict",
      "code": "duplicate_row",
      "row": 5,
      "sourceRow": 6,
      "column": "",
      "columnIndex": 0,
      "value": "",
      "detail": "This record matches record 2 after trimming the compared cells. No record was removed."
    }
  ],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-duplicate-row-detect" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-outlier-detect$0.05 USDC

Detect statistical outliers

Flag numeric values outside a Tukey fence of 1.5 times the interquartile range when a column has at least eight numbers. Each flag is a possible outlier, not a confirmed error.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "checked",
  "outlierCount": 1,
  "columns": [
    {
      "name": "id",
      "index": 1,
      "status": "checked",
      "count": 12,
      "lower": "-7",
      "upper": "19"
    },
    {
      "name": "email",
      "index": 2,
      "status": "not_checked",
      "count": 0,
      "lower": "",
      "upper": ""
    },
    {
      "name": "amount",
      "index": 3,
      "status": "checked",
      "count": 12,
      "lower": "8.875",
      "upper": "13.875"
    },
    {
      "name": "status",
      "index": 4,
      "status": "not_checked",
      "count": 0,
      "lower": "",
      "upper": ""
    },
    {
      "name": "joined",
      "index": 5,
      "status": "not_checked",
      "count": 0,
      "lower": "",
      "upper": ""
    }
  ],
  "outliers": [
    {
      "row": 9,
      "sourceRow": 10,
      "column": "amount",
      "columnIndex": 3,
      "value": "500",
      "rule": "tukey_1_5_iqr",
      "confirmed": false,
      "detail": "The value is outside the Tukey fence 8.875 to 13.875. This is a statistical outlier, not a confirmed error."
    }
  ],
  "issues": [],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-outlier-detect" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-normalize$0.04 USDC

Propose CSV normalization

Propose trim, email lowercase, boolean tokens, and unambiguous thousands separators. Each change names its rule and keeps the original cell. Dates that are not already YYYY-MM-DD are not rewritten.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "proposed",
  "rowCount": 12,
  "changedCount": 13,
  "unchangedCount": 1,
  "changes": [
    {
      "row": 1,
      "sourceRow": 2,
      "column": "email",
      "columnIndex": 2,
      "original": "Ada@Example.com",
      "normalized": "ada@example.com",
      "rule": "email_lower"
    },
    {
      "row": 1,
      "sourceRow": 2,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 2,
      "sourceRow": 3,
      "column": "amount",
      "columnIndex": 3,
      "original": " 12",
      "normalized": "12",
      "rule": "trim"
    },
    {
      "row": 2,
      "sourceRow": 3,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 4,
      "sourceRow": 5,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 5,
      "sourceRow": 6,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 6,
      "sourceRow": 7,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 7,
      "sourceRow": 8,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 8,
      "sourceRow": 9,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 9,
      "sourceRow": 10,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 10,
      "sourceRow": 11,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 11,
      "sourceRow": 12,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 12,
      "sourceRow": 13,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    }
  ],
  "issues": [],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-normalize" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON
POSThttps://brainiac.software/api/v1/data-quality/csv-report$0.12 USDC

Report CSV quality

Combine the schema, profile, missing cells, duplicate groups, possible outliers, and proposed normalization for one supplied table. No record is removed and no outlier is confirmed.

Body

FieldRequiredNotes
recordsNoarray; Array
csvNostring
jsonNostring
fileNoobject; Object
keyColumnsNoarray; Array

Request exampleJSON

{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}

Response exampleJSON

{
  "checkedAt": "2026-11-03T14:00:00.000Z",
  "recordsDiscarded": false,
  "dataModified": false,
  "outliersConfirmed": false,
  "format": "csv",
  "recordsRead": 12,
  "recordsOmitted": 0,
  "columnsOmitted": 0,
  "blankRows": 0,
  "status": "checked",
  "rowCount": 12,
  "columnCount": 5,
  "columns": [
    {
      "name": "id",
      "index": 1,
      "type": "integer",
      "nullable": false,
      "count": 12,
      "missingCount": 0,
      "distinctCount": 11,
      "min": "1",
      "max": "12"
    },
    {
      "name": "email",
      "index": 2,
      "type": "mixed",
      "nullable": false,
      "count": 12,
      "missingCount": 0,
      "distinctCount": 11,
      "min": "Ada@Example.com",
      "max": "not-an-email"
    },
    {
      "name": "amount",
      "index": 3,
      "type": "integer",
      "nullable": false,
      "count": 12,
      "missingCount": 0,
      "distinctCount": 5,
      "min": "10",
      "max": "500"
    },
    {
      "name": "status",
      "index": 4,
      "type": "boolean",
      "nullable": true,
      "count": 11,
      "missingCount": 1,
      "distinctCount": 2,
      "min": "no",
      "max": "yes"
    },
    {
      "name": "joined",
      "index": 5,
      "type": "mixed",
      "nullable": false,
      "count": 12,
      "missingCount": 0,
      "distinctCount": 11,
      "min": "03/11/2026",
      "max": "2024-10-01"
    }
  ],
  "groups": [
    {
      "count": 2,
      "rows": [
        {
          "row": 2,
          "sourceRow": 3
        },
        {
          "row": 5,
          "sourceRow": 6
        }
      ]
    }
  ],
  "outlierCount": 1,
  "outliers": [
    {
      "row": 9,
      "sourceRow": 10,
      "column": "amount",
      "columnIndex": 3,
      "value": "500",
      "rule": "tukey_1_5_iqr",
      "confirmed": false,
      "detail": "The value is outside the Tukey fence 8.875 to 13.875. This is a statistical outlier, not a confirmed error."
    }
  ],
  "changes": [
    {
      "row": 1,
      "sourceRow": 2,
      "column": "email",
      "columnIndex": 2,
      "original": "Ada@Example.com",
      "normalized": "ada@example.com",
      "rule": "email_lower"
    },
    {
      "row": 1,
      "sourceRow": 2,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 2,
      "sourceRow": 3,
      "column": "amount",
      "columnIndex": 3,
      "original": " 12",
      "normalized": "12",
      "rule": "trim"
    },
    {
      "row": 2,
      "sourceRow": 3,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 4,
      "sourceRow": 5,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 5,
      "sourceRow": 6,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 6,
      "sourceRow": 7,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 7,
      "sourceRow": 8,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 8,
      "sourceRow": 9,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 9,
      "sourceRow": 10,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    },
    {
      "row": 10,
      "sourceRow": 11,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 11,
      "sourceRow": 12,
      "column": "status",
      "columnIndex": 4,
      "original": "yes",
      "normalized": "true",
      "rule": "boolean_token"
    },
    {
      "row": 12,
      "sourceRow": 13,
      "column": "status",
      "columnIndex": 4,
      "original": "no",
      "normalized": "false",
      "rule": "boolean_token"
    }
  ],
  "issues": [
    {
      "kind": "conflict",
      "code": "inconsistent_format",
      "row": 7,
      "sourceRow": 8,
      "column": "email",
      "columnIndex": 2,
      "value": "not-an-email",
      "detail": "The most common type is email. This value was not changed."
    },
    {
      "kind": "conflict",
      "code": "inconsistent_format",
      "row": 7,
      "sourceRow": 8,
      "column": "joined",
      "columnIndex": 5,
      "value": "03/11/2026",
      "detail": "The most common type is date. This value was not changed."
    },
    {
      "kind": "missing",
      "code": "missing_value",
      "row": 3,
      "sourceRow": 4,
      "column": "status",
      "columnIndex": 4,
      "value": "",
      "detail": "This cell is empty or whitespace. The row was kept."
    },
    {
      "kind": "conflict",
      "code": "duplicate_row",
      "row": 5,
      "sourceRow": 6,
      "column": "",
      "columnIndex": 0,
      "value": "",
      "detail": "This record matches record 2 after trimming the compared cells. No record was removed."
    }
  ],
  "limitations": [
    "No business system is contacted or updated.",
    "Rows past the 2,000-row limit and columns past the 40-column limit are not read. recordsOmitted and columnsOmitted state how many.",
    "Rows that were read stay in the counts. None of those rows is deleted.",
    "Normalization is a proposal. The original cell is kept beside the proposed value.",
    "A statistical outlier is not a confirmed error.",
    "A date is normalized only when it is already a real YYYY-MM-DD day."
  ]
}

cURL

curl -i -X POST "https://brainiac.software/api/v1/data-quality/csv-report" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
  --data-binary @- <<'JSON'
{
  "csv": "id,email,amount,status,joined\n1,Ada@Example.com,10,yes,2024-01-15\n2,ada@example.com, 12,no,2024-02-01\n3,grace@example.com,11,,2024-03-01\n4,bea@example.com,13,yes,2024-04-01\n2,ada@example.com,12,no,2024-02-01\n6,cy@example.com,10,yes,2024-05-01\n7,not-an-email,11,no,03/11/2026\n8,di@example.com,12,yes,2024-06-01\n9,ed@example.com,500,no,2024-07-01\n10,fay@example.com,11,yes,2024-08-01\n11,gus@example.com,12,yes,2024-09-01\n12,hoa@example.com,10,no,2024-10-01\n"
}
JSON