Data
Connections and datasets are one group under /v2/data. A connection is where data comes from; a dataset is an ingested or registered table, auto-classified and profiled. Each ingest or sync mints an immutable snapshot (dsv_...), which is what endpoints pin and held-out reports stamp.
Four families of source: upload (CSV, Excel, JSON), databases (PostgreSQL, MySQL, Supabase, MongoDB, Databricks, Snowflake, Pinecone, Chroma), cloud storage (Google Drive, GCP Storage, AWS S3), and APIs (REST, GraphQL). Small files upload directly through the platform; everything else is a registered connection referenced at run or creation time.
GET /v2/data returns both kinds. A dataset carries its current snapshot and pin state; a connection carries its scheme ref. Neither carries analytical outputs (sector, profile): those come from a run and live on results and reports.
{
"id": "ds_crm01",
"kind": "dataset",
"name": "crm_contacts",
"source": "snowflake://example/sales/public/live_accounts",
"snapshot": "dsv_91f2",
"snapshot_at": "2026-08-12T09:31:00Z",
"rows": 22400,
"cols": 12,
"cells": 268800,
"size_bytes": 3145728,
"pinned": true,
"pinned_by": ["{endpoint_id}"]
}Attributes
idstringds_...for a dataset,conn_...for a connection. Immutable.kindstringObject kind.datasetconnectionnamestringDisplay name.sourcestringScheme ref for connections (snowflake://sales/live,s3://bucket/exports/,postgres://...,rest+https://...);uploadfor direct uploads.snapshotstring | nullDatasets: the currentdsv_...snapshot id.snapshot_atstring | nullTimestamp of the current snapshot.rowsintegerDatasets: row count of the current snapshot.colsintegerDatasets: column count.cellsintegerDatasets:rows x cols, the exact metering size of a fresh pass over it.size_bytesintegerStored size, for the storage line.pinnedbooleanDatasets: pinned datasets bill the cached rate on repeat calls indefinitely and count toward plan storage.pinned_byarray of stringsEndpoint ids currently serving this dataset. A dataset pinned by a live endpoint stays pinned until that endpoint is deleted or refreshed onto other data.
Connect a source
/v2/data/connectRegisters a connection to a database, cloud bucket, or API, and ingests an initial snapshot.
Credentials are stored encrypted at rest and are write-only; rotation is by re-entering them. Every connection creation and every sync is recorded in the audit log.
curl -X POST 'https://api.schemalabs.ai/v2/data/connect' \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "snowflake://acme/sales/public/live_accounts",
"name": "sales_live",
"credentials": {
"user": "schema_reader",
"password": "••••••••",
"role": "READER",
"warehouse": "WH_XS"
}
}'import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/data/connect",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
json={
"source": "snowflake://acme/sales/public/live_accounts",
"name": "sales_live",
"credentials": {
"user": "schema_reader",
"password": "••••••••",
"role": "READER",
"warehouse": "WH_XS",
},
},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data/connect', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
source: "snowflake://acme/sales/public/live_accounts",
name: "sales_live",
credentials: {
user: "schema_reader",
password: "••••••••",
role: "READER",
warehouse: "WH_XS",
},
}),
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"connection": {
"id": "conn_3f9a",
"kind": "connection",
"name": "sales_live",
"source": "snowflake://acme/sales/public/live_accounts"
},
"dataset": {
"id": "ds_sales01",
"kind": "dataset",
"name": "live_accounts",
"source": "snowflake://acme/sales/public/live_accounts",
"snapshot": "dsv_0c44",
"rows": 51200,
"cols": 18,
"cells": 921600,
"pinned": false,
"pinned_by": []
}
}Body application/json
sourcestringrequiredScheme ref: the provider scheme followed by the provider’s own path to the table or location, for examplesnowflake://...,postgres://...,s3://bucket/prefix/,gdrive://folder-id,rest+https://host/path.namestringDisplay name. Defaults to the last path segment.credentialsobjectProvider-specific credentials (for exampleuser,password,role,warehousefor Snowflake;access_key_id,secret_access_keyfor S3). Never returned.optionsobjectProvider options such asquery(a SQL statement to materialize as the dataset) orsheet.
Returns
The connection object and the dataset it produced, with the first snapshot.
List data
/v2/dataLists connections and datasets with their snapshot and pin state.
curl 'https://api.schemalabs.ai/v2/data?limit=20' \
-H "Authorization: Bearer $SCHEMA_API_KEY"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.get(
"https://api.schemalabs.ai/v2/data?limit=20",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data?limit=20', {
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"datasets": [
{
"id": "ds_crm01",
"kind": "dataset",
"name": "crm_contacts",
"source": "snowflake://example/sales/public/live_accounts",
"snapshot": "dsv_91f2",
"rows": 22400,
"cols": 12,
"cells": 268800,
"pinned": true,
"pinned_by": ["{endpoint_id}"]
},
{
"id": "ds_bill01",
"kind": "dataset",
"name": "billing_db",
"source": "postgres://billing/live",
"snapshot": "dsv_c4e7",
"rows": 22400,
"cols": 6,
"cells": 134400,
"pinned": true,
"pinned_by": ["{endpoint_id}"]
},
{
"id": "ds_claims",
"kind": "dataset",
"name": "claims_2025",
"source": "upload",
"snapshot": "dsv_77e0",
"rows": 500000,
"cols": 30,
"cells": 15000000,
"pinned": true,
"pinned_by": ["{other_endpoint_id}"]
},
{
"id": "conn_3f9a",
"kind": "connection",
"name": "sales_live",
"source": "snowflake://acme/sales/public/live_accounts",
"dataset": "ds_sales01",
"snapshot": "dsv_1d09"
}
],
"next_cursor": null,
"total": 4
}Query parameters
limitintegerdefault20Page size.cursorstringCursor from a previous page.
Returns
A page of data objects and a next_cursor.
Retrieve data
/v2/data/:idReturns a dataset’s profile (rows, columns, current snapshot, pin state) or a connection’s status.
curl 'https://api.schemalabs.ai/v2/data/ds_crm01' \
-H "Authorization: Bearer $SCHEMA_API_KEY"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.get(
"https://api.schemalabs.ai/v2/data/ds_crm01",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data/ds_crm01', {
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"id": "ds_crm01",
"kind": "dataset",
"name": "crm_contacts",
"source": "snowflake://example/sales/public/live_accounts",
"snapshot": "dsv_91f2",
"snapshot_at": "2026-08-12T09:31:00Z",
"rows": 22400,
"cols": 12,
"cells": 268800,
"size_bytes": 3145728,
"pinned": true,
"pinned_by": ["{endpoint_id}"]
}Path parameters
idstringrequiredds_...orconn_....
Returns
The data object.
Sync a connection
/v2/data/:id/syncRe-pulls a connection and mints a new immutable snapshot (dsv_...) on its dataset. Endpoints pinned to the dataset keep serving the previous snapshot until you refresh them.
curl -X POST 'https://api.schemalabs.ai/v2/data/conn_3f9a/sync' \
-H "Authorization: Bearer $SCHEMA_API_KEY"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/data/conn_3f9a/sync",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data/conn_3f9a/sync', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"id": "conn_3f9a",
"dataset": "ds_sales01",
"snapshot": "dsv_1d09",
"previous_snapshot": "dsv_0c44",
"diff": {
"rows_added": 310,
"rows_changed": 12,
"rows_removed": 4,
"rows_unchanged": 51184
},
"synced_at": "2026-08-16T09:00:03Z"
}Path parameters
idstringrequiredconn_...or the dataset id it feeds.
Returns
202 with a job for large sources, or 200 with the new snapshot for small ones.
A sync itself is not metered. What a subsequent pass pays follows the diff: added and changed rows bill fresh, unchanged rows bill the cached rate, removed rows bill nothing.
Pin a dataset
/v2/data/:id/pinPins a dataset: repeat calls over it bill the cached rate indefinitely, and it counts toward plan storage. Endpoint creation pins its datasets automatically.
curl -X POST 'https://api.schemalabs.ai/v2/data/ds_sales01/pin' \
-H "Authorization: Bearer $SCHEMA_API_KEY"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/data/ds_sales01/pin",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data/ds_sales01/pin', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{ "id": "ds_sales01", "kind": "dataset", "pinned": true, "pinned_by": [] }Path parameters
idstringrequiredds_....
Returns
The dataset object with pinned: true.
Unpin a dataset
/v2/data/:id/unpinUnpins a dataset. The cached rate expires shortly after last use; the next pass bills fresh. A dataset pinned by a live endpoint stays pinned (409 names the endpoint).
curl -X POST 'https://api.schemalabs.ai/v2/data/ds_crm01/unpin' \
-H "Authorization: Bearer $SCHEMA_API_KEY"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/data/ds_crm01/unpin",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data/ds_crm01/unpin', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{ "id": "ds_crm01", "kind": "dataset", "pinned": false }{
"error": {
"type": "conflict",
"message": "dataset ds_crm01 is pinned by live endpoint churn ({endpoint_id}); delete the endpoint or refresh it onto other data first",
"request_id": "req_2c8f1b"
}
}Path parameters
idstringrequiredds_....
Returns
The dataset object with pinned: false, or 409 conflict naming the dependent endpoint.
Generate synthetic data
/v2/data/generateProduces a synthetic tabular dataset for a sector with realistic per-column ranges. The result is an ordinary dataset (ds_...), useful for cold-start when representative data is thin.
curl -X POST 'https://api.schemalabs.ai/v2/data/generate' \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Idempotency-Key: <unique key>" \
-H "Content-Type: application/json" \
-d '{ "sector": "hospital operations", "rows": 5000, "name": "hospital_ops_synth" }'import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/data/generate",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}", "Idempotency-Key": "<unique key>"},
json={
"sector": "hospital operations",
"rows": 5000,
"name": "hospital_ops_synth",
},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/data/generate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '<unique key>',
},
body: JSON.stringify({
sector: "hospital operations",
rows: 5000,
name: "hospital_ops_synth",
}),
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"dataset": "ds_synth03",
"name": "hospital_ops_synth.csv",
"sector": "hospital operations",
"rows": 5000,
"columns": ["patient_id", "age", "sex", "diagnosis_code", "lvef_pct", "admission_date"],
"processing": { "mode": "realtime" }
}Headers
Idempotency-KeystringOptional. A unique key for this request. Retrying a POST with the same key and body never creates a duplicate job; the same key with a different body returns409 conflict.
Body application/json
sectorstringrequiredSector name, in the same vocabulary the sector output uses, for example"hospital operations"or"consumer financial services".rowsintegerrequiredRows to generate.namestringDataset display name.optionsobjectprocessing: "batch"runs the generation as a batch job at the batch rate.
Returns
The new dataset: id, name, columns, rows, and the processing block. Large generations run as batch jobs and return 202 with a job.
Metering: C = cells generated at the synthetic rate; the output grid is the meter.
Delete data
/v2/data/:idRemoves a dataset or connection immediately and irreversibly.
A dataset pinned by a live endpoint cannot be deleted: the 409 conflict names the dependency, so delete the endpoint or refresh it onto other data first.
curl -X DELETE 'https://api.schemalabs.ai/v2/data/ds_old01' \
-H "Authorization: Bearer $SCHEMA_API_KEY"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.delete(
"https://api.schemalabs.ai/v2/data/ds_old01",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
print(r.json())const res = await fetch('https://api.schemalabs.ai/v2/data/ds_old01', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{ "id": "ds_old01", "status": "deleted", "deleted_at": "2026-08-16T10:11:02Z" }Path parameters
idstringrequiredds_...orconn_....
Returns
The deleted id and status, or 409 conflict naming dependent endpoints.