Skip to main content
A contract is the expected schema for a dataset — a list of columns and their types that you define once and reuse in every check. Think of it like a type definition for your data. If an incoming schema no longer matches the contract, DriftGuard tells you exactly what changed and how severe it is.

What a Contract Contains

{
  "name": "users_production",
  "schema": {
    "columns": [
      { "name": "user_id",    "type": "integer",   "required": true  },
      { "name": "email",      "type": "string",    "required": true  },
      { "name": "created_at", "type": "timestamp", "required": true  },
      { "name": "plan",       "type": "string",    "required": false }
    ]
  }
}
FieldRequiredDescription
nameHuman-readable label for this contract. Must be unique per account.
schema.columnsArray of column definitions
schema.columns[].nameColumn name — case-sensitive
schema.columns[].typeExpected data type — see supported types below
schema.columns[].requiredIf true, this column must be present in every check. Absence scores +40 severity points. If false, absence scores +20.

Supported Column Types

DriftGuard enforces a fixed set of column types. Any type outside this list will be rejected with a 400 error.
TypeDescription
stringText values
integerWhole numbers
numberFloating point / decimal numbers
booleanTrue / false values
dateDate without time (YYYY-MM-DD)
timestampDate with time
jsonNested JSON / object values
Types like float, array, uuid, and unknown are not supported and will be rejected. Use number instead of float, and json instead of array for nested structures.

Contract Versioning

Every contract has a version field that starts at 1. It is designed to increment each time the contract schema is updated — so you always know which version of a contract a historical check was run against.
The PUT /api/v1/contracts/{id} update endpoint is not yet available. To change a contract’s schema today, create a new contract via POST /api/v1/contracts with the updated column definitions.

One Contract Per Dataset

Use one contract per logical dataset, table, or feed. For example:
  • One contract per warehouse table (users, orders, events)
  • One contract per partner data feed
  • One contract per dbt model output
This keeps checks scoped and makes it easy to identify exactly which dataset drifted when a breaking result comes in.

Inferring a Contract from Sample Data

Not sure what columns to define? Use the infer endpoint to generate a contract schema automatically from a sample JSON payload:
curl -s -X POST https://api.driftguard.dev/api/v1/contracts/infer \
  -H "X-API-Key: $DRIFTGUARD_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sample": {
      "user_id": 1,
      "email": "user@example.com",
      "created_at": "2026-01-01T00:00:00Z"
    }
  }'
DriftGuard will return a ready-to-use schema.columns array you can pass directly into POST /api/v1/contracts.

Creating and Managing Contracts

ActionEndpoint
Create a contractPOST /api/v1/contracts
List all contractsGET /api/v1/contracts
Get a single contractGET /api/v1/contracts/
Infer schema from samplePOST /api/v1/contracts/infer

Run a Check

Learn how checks compare incoming schemas against contracts.

Severity Levels

Understand how the required vs optional distinction affects your severity score.