> ## Documentation Index
> Fetch the complete documentation index at: https://terrascout.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Schema versions

> How Ploti versions each dataset's columns and tells you when they change

<Info>
  Data Feeds is in early access. [Contact us](mailto:support@ploti.ai) to set up
  a subscription; the API and sync client described here open to early access
  customers first.
</Info>

Sources change shape: a county adds a column, renames one or changes a type. Each dataset has a schema version so your pipeline can tell a safe change from one that needs a person.

## Format

A schema version is `MAJOR.MINOR`, for example `2.1`.

| Change | Bump | Safe to apply on its own |
| - | - | - |
| A column is added | MINOR | Yes |
| A column becomes nullable | MINOR | Yes |
| A column is removed | MAJOR | No |
| A column is renamed (seen as removed plus added) | MAJOR | No |
| A column's type changes | MAJOR | No |
| The key columns change | MAJOR | No, and record ids change: reload the snapshot |

A new dataset version that keeps the same columns keeps the same schema version.

## Reading a schema

```bash theme={null}
curl https://api.ploti.ai/v1/datasets/ds_orange_fl_building_permits/schema \
  -H "Authorization: Bearer $PLOTI_API_KEY"
```

```json theme={null}
{
  "datasetId": "ds_orange_fl_building_permits",
  "schemaVersion": "2.1",
  "firstVersion": 39,
  "keyColumns": ["permit_number"],
  "columns": [
    {
      "name": "permit_number",
      "type": "string",
      "nullable": false,
      "description": "The county's permit number."
    },
    {
      "name": "issued_date",
      "type": "date",
      "nullable": true,
      "sourceName": "ISSUE_DT"
    },
    { "name": "valuation", "type": "number", "nullable": true },
    { "name": "contractor_name", "type": "string", "nullable": true },
    { "name": "geometry", "type": "geometry", "nullable": true }
  ],
  "changeFromPrevious": {
    "kind": "additive",
    "previousSchemaVersion": "2.0",
    "added": [
      { "name": "contractor_name", "type": "string", "nullable": true }
    ],
    "removed": [],
    "retyped": [],
    "keyColumnsChanged": false
  }
}
```

Pass `?version=` for the schema of an older dataset version. `GET /v1/datasets/{id}/schemas` lists every schema version the dataset has had.

## When it changes

A schema change publishes with the dataset version that brings it, and sends `dataset.schema_changed` before that version's `dataset.updated`:

```json theme={null}
{
  "id": "evt_0000018f2b10",
  "type": "dataset.schema_changed",
  "createdAt": "2026-10-18T06:12:40Z",
  "subscriptionId": "sub_8f3k2m",
  "data": {
    "datasetId": "ds_orange_fl_building_permits",
    "version": 43,
    "schemaVersion": "3.0",
    "schemaChange": {
      "kind": "breaking",
      "previousSchemaVersion": "2.1",
      "added": [],
      "removed": ["valuation"],
      "retyped": [{ "name": "issued_date", "from": "string", "to": "date" }],
      "keyColumnsChanged": false
    }
  }
}
```

A common rule: apply MINOR changes automatically, and hold a dataset at its current version on a MAJOR change until someone has reviewed it. Ploti keeps the last snapshot of every MAJOR version, so a held dataset can catch up later.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.