Endpoints
An endpoint is the persistent product object: a base model plus pinned dataset snapshots, a configuration (target, task, thresholds), a library of system prompts, and a held-out report, served at a stable URL. Creation pins the data, evaluates held-out, and exposes the URL, in minutes.
The endpoint ID is an immutable unique ID; the name is a mutable alias. Every route accepts either, but only the id is stable across a rename. refresh and upgrade change what the endpoint serves behind the same URL, and every create, refresh, and upgrade mints an immutable held-out report.
Returned by create (on completion), retrieve, and list. Retrieve also carries the bundle already computed over the pinned data, with cursor pagination for large arrays. Reading the object runs no inference.
{
"endpoint": "churn",
"id": "{endpoint_id}",
"status": "live",
"url": "https://api.schemalabs.ai/v2/serve/{endpoint_id}",
"serve_url": "/v2/serve/{endpoint_id}",
"base": "schema-2",
"feed": "multi_table",
"created_at": "2026-03-10T14:07:02Z",
"calls": 128,
"data": {
"datasets": [
{
"dataset": "ds_crm01",
"name": "crm_contacts",
"pinned": true,
"snapshot": "dsv_91f2"
},
{
"dataset": "ds_bill01",
"name": "billing_db",
"pinned": true,
"snapshot": "dsv_c4e7"
}
],
"pinned": true,
"snapshot": "dsv_91f2",
"tables": ["ds_crm01", "ds_bill01"]
},
"config_revision": 1,
"data_revision": 2,
"system_prompts": [
{
"id": "sp_12",
"name": "default",
"active": true,
"order": 1,
"body": "You are a data assistant for this endpoint. Answer from the endpoint outputs."
}
],
"report": "churn.s2.upgrade.2026-08-14",
"report_id": "r_a7d0",
"summary": {
"tables": 2,
"records_linked": 21240,
"records_total": 22400,
"keys_used": "none",
"prediction": { "target": "crm_contacts.c3", "task": "classification", "held_out": 0.961 }
},
"tables": [
{
"id": "crm_contacts",
"rows": 22400,
"cols": 12,
"sector": {
"top1": { "name": "subscription software", "confidence": 0.88 },
"top5": [
{ "name": "subscription software", "confidence": 0.88 },
{ "name": "customer relationship management", "confidence": 0.76 },
{ "name": "telecommunications", "confidence": 0.52 },
{ "name": "consumer financial services", "confidence": 0.41 },
{ "name": "marketing services", "confidence": 0.3 }
]
},
"column_profile": [
{
"name": "c0",
"role": "email",
"role_confidence": 0.98,
"type": "categorical",
"missing_pct": 0,
"pii": true
},
{
"name": "c1",
"role": "phone",
"role_confidence": 0.97,
"type": "categorical",
"missing_pct": 0.01,
"pii": true
},
{
"name": "c2",
"role": "date",
"role_confidence": 0.95,
"type": "datetime",
"missing_pct": 0.02,
"pii": false
},
{
"name": "c3",
"role": "category",
"role_confidence": 0.92,
"type": "categorical",
"missing_pct": 0,
"pii": false
}
]
},
{
"id": "billing_db",
"rows": 22400,
"cols": 6,
"sector": {
"top1": { "name": "subscription billing", "confidence": 0.9 },
"top5": [
{ "name": "subscription billing", "confidence": 0.9 },
{ "name": "subscription software", "confidence": 0.71 },
{ "name": "payments processing", "confidence": 0.58 },
{ "name": "accounting", "confidence": 0.36 },
{ "name": "telecommunications", "confidence": 0.29 }
]
},
"column_profile": [
{
"name": "c0",
"role": "code",
"role_confidence": 0.94,
"type": "categorical",
"missing_pct": 0,
"pii": false
},
{
"name": "c1",
"role": "phone",
"role_confidence": 0.96,
"type": "categorical",
"missing_pct": 0.01,
"pii": true
},
{
"name": "c2",
"role": "measure",
"role_confidence": 0.97,
"type": "numeric",
"missing_pct": 0.03,
"pii": false
}
]
}
],
"cross_table_map": {
"summary": {
"tables": 2,
"shared_attributes": 1,
"entities_matched": 21240,
"columns_only_in_a": 11,
"columns_only_in_b": 5,
"keys_used": "none"
},
"column_alignment": [
{
"a": "crm_contacts.c1",
"b": "billing_db.c1",
"attribute": "phone",
"confidence": 0.96,
"example": { "a": "555-0142", "b": "+1 555 0142" }
}
],
"entity_matches": [
{ "a_row": 0, "b_row": 0, "confidence": 0.94, "matched_on": ["phone"] }
],
"unified_schema": {
"shared": [
{ "attribute": "phone", "from": ["crm_contacts.c1", "billing_db.c1"] }
],
"a_only": ["crm_contacts.c0 (email)", "crm_contacts.c2 (date)"],
"b_only": ["billing_db.c2 (measure)"]
}
},
"unified_rows": {
"schema": ["email", "phone", "signup_date", "monthly_spend"],
"rows": [
{
"entity": 0,
"from": { "a_row": 0, "b_row": 0 },
"confidence": 0.94,
"record": {
"email": "ana@example.io",
"phone": "555-0142",
"signup_date": "2025-01-10",
"monthly_spend": 49
},
"shared_variants": {
"phone": { "crm_contacts.c1": "555-0142", "billing_db.c1": "+1 555 0142" }
}
}
],
"total": 21240,
"sample_shown": 1
},
"imputation": {
"filled": [
{
"table": "billing_db",
"row": 17,
"column": "c2",
"value": 49,
"method": "schema-2"
}
],
"row_confidence": [
{ "table": "billing_db", "row": 17, "confidence": 0.83 }
],
"total_filled": 812
},
"target_selection": {
"mode": "auto",
"column": "crm_contacts.c3",
"overridable": true,
"reason": "most predictable target among the eligible categorical columns"
},
"task_selection": {
"mode": "auto",
"type": "classification",
"reason": "categorical target",
"overridable": true
},
"prediction": {
"target": "crm_contacts.c3",
"task_type": "classification",
"tier": "in_context",
"classes": ["retained", "churned"],
"results": [
{
"row": 0,
"label": "retained",
"confidence": 0.95,
"probabilities": { "retained": 0.95, "churned": 0.05 }
}
]
},
"held_out": {
"score": 0.961,
"metric": "accuracy",
"auc": 0.974,
"baseline_majority": 0.71,
"per_class": { "retained": 0.97, "churned": 0.91 },
"split": {
"method": "in_context_holdout",
"train_rows": 17920,
"test_rows": 4480,
"seed": 7,
"unit": "entity"
},
"data_version": "2026-08-12 09:31",
"data_snapshot": "dsv_91f2",
"weakest_slice": "tenure<3mo: 0.84",
"low_confidence": null,
"low_confidence_reason": null,
"note": "estimate of the live endpoint; serving uses the full pinned snapshot",
"report_url": "/v2/reports/r_a7d0"
}
}Attributes
idstringImmutable unique ID. Surfaces display its first 8 characters; the full ID is the identifier.endpointstringMutable display name (lowercase slug), for examplechurn.statusstringLifecycle state. The endpoint keeps serving during refresh and upgrade; watch progress on the job.creatingliveurlstringThe serve URL,https://api.schemalabs.ai/v2/serve/{id}. Never changes.serve_urlis the relative form.basestringThe Schema model currently served, for exampleschema-2.feedstringWhether the endpoint pins one table or several.single_tablemulti_tablecreated_atstringCreation time.callsintegerServe calls made against this endpoint.dataobjectPinned data:datasets[](eachdatasetds_...,name,pinned,snapshotdsv_...), plus the top-levelsnapshotandtables(dataset ids).config_revisionintegerIncrements on every configuration edit (target, task, thresholds, system prompts).data_revisionintegerIncrements on every data re-run (refresh). Independent ofconfig_revision.system_promptsarray of objectsThe endpoint’s system-prompt fragments:id(sp_...),name,active,order,body. Read them here to apply in your own LLM; Chat applies them on the platform.reportstringDisplay name of the current held-out report,{endpoint}.{base}.{op}.{YYYY-MM-DD}.report_idstringImmutable id of the current report,r_....held_outobjectThe current held-out block:score,metric, task metrics (auc,per_class,rmse,nrmse,quantile_calibration, ...), the baseline (baseline_majorityorbaseline_mean),split { method, train_rows, test_rows, seed, unit },data_version,data_snapshot,weakest_slice,low_confidencewithlow_confidence_reason, an estimatenote, andreport_url.summaryobjectHeadline counts:tables,records_linked,records_total,keys_used("none": no shared key was used to relate the tables),shared_attributes, and thepredictionheadline (target,task,tier,held_out).tablesarray of objectsOne entry per input table.Item properties 5
idstringThe table id you supplied.rowsintegerRow count.colsintegerColumn count.sectorobjectVertical-agnostic sector identification from cell values alone, any domain, no metadata:top1 { name, confidence }andtop5[], each with its own confidence.column_profilearray of objectsPer column:name,role(email, phone, date, name, code, measure, ...),role_confidence,type(categorical, numeric, datetime, text, boolean),missing_pct,pii(boolean).
cross_table_mapobject | nullPresent on two or more tables.summary,column_alignment[](each withattribute,confidence, and a format-invarianceexample),entity_matches[](row pairs,confidence,matched_on), andunified_schema(shared,a_only,b_only). Every alignment and match carries its confidence and evidence.unified_rowsobject | nullThe cross-table map materialized into joined records:schema,provenance,rows[](each withentity,from,confidence,record, andshared_variantsshowing each source’s raw value),total, andsample_shown. Paginated by cursor.imputationobjectMissing-value imputation:filled[](table, row, column, value, method),row_confidence[](table, row, confidence), andtotal_filled. Confidence is row-level, not per cell.target_selectionobjectmode(auto,user,none),column,reason,overridable, andcandidates[](per column:selected,eligible, and a plain-languagereason).nullcandidates when the target was user-specified.task_selectionobjectmode,type,reason,overridable.predictionobject | nullThe prediction slice, shaped by task type: classification (label,confidence,probabilities), regression (value,median,std,quantiles), anomaly (anomaly_score,is_anomaly,threshold).tierisin_context.dropped_rows.missing_targetcounts rows excluded because their target was missing.nullwhentarget.modeisnone.
Create an endpoint
/v2/endpointsPublishes a configuration as an endpoint: pins the referenced data, evaluates held-out by in-context split, and exposes a stable URL. Returns 202 and a job.
The endpoint id is assigned at submit time, so it appears in GET /v2/endpoints immediately with status: "creating", then flips to live when the job completes. Inline tables are accepted and are ingested as an upload-type dataset first.
A new endpoint starts with one default system-prompt fragment. Its library is edited on the endpoint page in the platform.
curl -X POST 'https://api.schemalabs.ai/v2/endpoints' \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Idempotency-Key: <unique key>" \
-H "Content-Type: application/json" \
-d '{
"name": "churn",
"base": "schema-2",
"data": ["ds_crm01", "ds_bill01"],
"target": { "mode": "auto" },
"task": { "mode": "auto" }
}'import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/endpoints",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}", "Idempotency-Key": "<unique key>"},
json={
"name": "churn",
"base": "schema-2",
"data": ["ds_crm01", "ds_bill01"],
"target": {"mode": "auto"},
"task": {"mode": "auto"},
},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/endpoints', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '<unique key>',
},
body: JSON.stringify({
name: "churn",
base: "schema-2",
data: ["ds_crm01", "ds_bill01"],
target: { mode: "auto" },
task: { mode: "auto" },
}),
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"endpoint": "churn",
"id": "{endpoint_id}",
"status": "creating",
"job_id": "job_9a5b01d4"
}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
namestringrequiredDisplay name, a lowercase slug such aschurn. Mutable; the id is what stays stable.basestringdefaultlatestThe Schema model to create on; defaults to the latest (seeGET /v2/models). Switch later withupgrade.dataarray of stringsDataset ids and connection refs to pin. Datasets referenced here are pinned automatically and stay pinned while the endpoint serves. Required unlesstablesis supplied.tablesarray of objectsInline tables. Ingested as an upload dataset (visible under Data) before pinning. Required unlessdatais supplied.Item properties 3
idstringrequiredYour name for the table. Appears in every per-table output and in cross-table references such ascrm_contacts.c1.columnsarray of stringsrequiredColumn names. They may be real names, opaque labels (c0,c1), or empty: Schema understands the values, not the names.rowsarray of arraysrequiredRow values in column order. Usenullfor missing cells; missing cells are metered like any other cell.
targetobjectdefault{ "mode": "auto" }Which column to predict.autolets Schema choose the most predictable eligible column and explains why;columnnames one;nonereturns an understanding-only bundle with no prediction slice.Properties 2
modestringauto(default) ornone. Omit when supplyingcolumn.autononecolumnstringA column name, qualified astable.columnon multi-table input (for examplecards_db.card_brand).
taskobjectdefault{ "mode": "auto" }Prediction task type.autoinfers it from the target (categorical → classification, numeric → regression). Anomaly detection runs on explicit request: settype: "anomaly", which works without a target.Properties 2
modestringInfer the task from the target.autotypestringExplicit task type. Setregressiontogether with a numerictarget.column;anomalyruns unsupervised and needs no target.classificationregressionanomaly
optionsobjectPer-request options.Properties 1
confidence_thresholdnumberMinimum confidence for cross-table column alignments and entity matches to be reported. Omit to use the service default.
Returns
202 Accepted with the endpoint id, name, status: "creating", and the job. Poll the job, or retrieve the endpoint until status is live.
Response fields 4
endpointstringThe name you supplied.idstringThe endpoint ID, final from this moment.statusstringcreating.job_idstringThe creation job.
Metering: one fresh pass over the pinned snapshot at the fresh rate, plus the storage line for pinned data. The held-out evaluation is included at no extra charge.
options.processing and options.out apply to quick runs and synthetic generation.
List endpoints
/v2/endpointsLists your organization’s endpoints, newest first, including ones still creating.
curl 'https://api.schemalabs.ai/v2/endpoints?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/endpoints?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/endpoints?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();{
"endpoints": [
{
"endpoint": "churn",
"id": "{endpoint_id}",
"status": "live",
"base": "schema-2",
"data": {
"datasets": [
{
"dataset": "ds_crm01",
"name": "crm_contacts",
"pinned": true,
"snapshot": "dsv_91f2"
},
{
"dataset": "ds_bill01",
"name": "billing_db",
"pinned": true,
"snapshot": "dsv_c4e7"
}
],
"pinned": true,
"snapshot": "dsv_91f2",
"tables": ["ds_crm01", "ds_bill01"]
},
"report_id": "r_a7d0",
"held_out": { "score": 0.961, "metric": "accuracy" },
"url": "https://api.schemalabs.ai/v2/serve/{endpoint_id}"
},
{
"endpoint": "claims-severity",
"id": "{other_endpoint_id}",
"status": "creating",
"base": "schema-2",
"data": {
"datasets": [
{
"dataset": "ds_claims",
"name": "claims_2025",
"pinned": true,
"snapshot": null
}
],
"pinned": true,
"snapshot": null,
"tables": ["ds_claims"]
},
"report_id": null,
"held_out": null,
"url": "https://api.schemalabs.ai/v2/serve/{other_endpoint_id}"
}
],
"next_cursor": null,
"total": 2
}Query parameters
limitintegerdefault50Page size.cursorstringCursor from a previous page.
Returns
A page of endpoint objects (summary fields, without the bundle) and a next_cursor.
Retrieve an endpoint
/v2/endpoints/:idReturns the endpoint object with its state, configuration, system prompts, current report, and the bundle already computed over the pinned data. Runs no inference.
curl 'https://api.schemalabs.ai/v2/endpoints/{endpoint_id}' \
-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/endpoints/{endpoint_id}",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/endpoints/{endpoint_id}', {
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"endpoint": "churn",
"id": "{endpoint_id}",
"status": "live",
"url": "https://api.schemalabs.ai/v2/serve/{endpoint_id}",
"serve_url": "/v2/serve/{endpoint_id}",
"base": "schema-2",
"feed": "multi_table",
"created_at": "2026-03-10T14:07:02Z",
"calls": 128,
"data": {
"datasets": [
{
"dataset": "ds_crm01",
"name": "crm_contacts",
"pinned": true,
"snapshot": "dsv_91f2"
},
{
"dataset": "ds_bill01",
"name": "billing_db",
"pinned": true,
"snapshot": "dsv_c4e7"
}
],
"pinned": true,
"snapshot": "dsv_91f2",
"tables": ["ds_crm01", "ds_bill01"]
},
"config_revision": 1,
"data_revision": 2,
"system_prompts": [
{
"id": "sp_12",
"name": "default",
"active": true,
"order": 1,
"body": "You are a data assistant for this endpoint. Answer from the endpoint outputs."
}
],
"report": "churn.s2.upgrade.2026-08-14",
"report_id": "r_a7d0",
"summary": {
"tables": 2,
"records_linked": 21240,
"records_total": 22400,
"keys_used": "none",
"prediction": { "target": "crm_contacts.c3", "task": "classification", "held_out": 0.961 }
},
"tables": [
{
"id": "crm_contacts",
"rows": 22400,
"cols": 12,
"sector": {
"top1": { "name": "subscription software", "confidence": 0.88 },
"top5": [
{ "name": "subscription software", "confidence": 0.88 },
{ "name": "customer relationship management", "confidence": 0.76 },
{ "name": "telecommunications", "confidence": 0.52 },
{ "name": "consumer financial services", "confidence": 0.41 },
{ "name": "marketing services", "confidence": 0.3 }
]
},
"column_profile": [
{
"name": "c0",
"role": "email",
"role_confidence": 0.98,
"type": "categorical",
"missing_pct": 0,
"pii": true
},
{
"name": "c1",
"role": "phone",
"role_confidence": 0.97,
"type": "categorical",
"missing_pct": 0.01,
"pii": true
},
{
"name": "c2",
"role": "date",
"role_confidence": 0.95,
"type": "datetime",
"missing_pct": 0.02,
"pii": false
},
{
"name": "c3",
"role": "category",
"role_confidence": 0.92,
"type": "categorical",
"missing_pct": 0,
"pii": false
}
]
},
{
"id": "billing_db",
"rows": 22400,
"cols": 6,
"sector": {
"top1": { "name": "subscription billing", "confidence": 0.9 },
"top5": [
{ "name": "subscription billing", "confidence": 0.9 },
{ "name": "subscription software", "confidence": 0.71 },
{ "name": "payments processing", "confidence": 0.58 },
{ "name": "accounting", "confidence": 0.36 },
{ "name": "telecommunications", "confidence": 0.29 }
]
},
"column_profile": [
{
"name": "c0",
"role": "code",
"role_confidence": 0.94,
"type": "categorical",
"missing_pct": 0,
"pii": false
},
{
"name": "c1",
"role": "phone",
"role_confidence": 0.96,
"type": "categorical",
"missing_pct": 0.01,
"pii": true
},
{
"name": "c2",
"role": "measure",
"role_confidence": 0.97,
"type": "numeric",
"missing_pct": 0.03,
"pii": false
}
]
}
],
"cross_table_map": {
"summary": {
"tables": 2,
"shared_attributes": 1,
"entities_matched": 21240,
"columns_only_in_a": 11,
"columns_only_in_b": 5,
"keys_used": "none"
},
"column_alignment": [
{
"a": "crm_contacts.c1",
"b": "billing_db.c1",
"attribute": "phone",
"confidence": 0.96,
"example": { "a": "555-0142", "b": "+1 555 0142" }
}
],
"entity_matches": [
{ "a_row": 0, "b_row": 0, "confidence": 0.94, "matched_on": ["phone"] }
],
"unified_schema": {
"shared": [
{ "attribute": "phone", "from": ["crm_contacts.c1", "billing_db.c1"] }
],
"a_only": ["crm_contacts.c0 (email)", "crm_contacts.c2 (date)"],
"b_only": ["billing_db.c2 (measure)"]
}
},
"unified_rows": {
"schema": ["email", "phone", "signup_date", "monthly_spend"],
"rows": [
{
"entity": 0,
"from": { "a_row": 0, "b_row": 0 },
"confidence": 0.94,
"record": {
"email": "ana@example.io",
"phone": "555-0142",
"signup_date": "2025-01-10",
"monthly_spend": 49
},
"shared_variants": {
"phone": { "crm_contacts.c1": "555-0142", "billing_db.c1": "+1 555 0142" }
}
}
],
"total": 21240,
"sample_shown": 1
},
"imputation": {
"filled": [
{
"table": "billing_db",
"row": 17,
"column": "c2",
"value": 49,
"method": "schema-2"
}
],
"row_confidence": [
{ "table": "billing_db", "row": 17, "confidence": 0.83 }
],
"total_filled": 812
},
"target_selection": {
"mode": "auto",
"column": "crm_contacts.c3",
"overridable": true,
"reason": "most predictable target among the eligible categorical columns"
},
"task_selection": {
"mode": "auto",
"type": "classification",
"reason": "categorical target",
"overridable": true
},
"prediction": {
"target": "crm_contacts.c3",
"task_type": "classification",
"tier": "in_context",
"classes": ["retained", "churned"],
"results": [
{
"row": 0,
"label": "retained",
"confidence": 0.95,
"probabilities": { "retained": 0.95, "churned": 0.05 }
}
]
},
"held_out": {
"score": 0.961,
"metric": "accuracy",
"auc": 0.974,
"baseline_majority": 0.71,
"per_class": { "retained": 0.97, "churned": 0.91 },
"split": {
"method": "in_context_holdout",
"train_rows": 17920,
"test_rows": 4480,
"seed": 7,
"unit": "entity"
},
"data_version": "2026-08-12 09:31",
"data_snapshot": "dsv_91f2",
"weakest_slice": "tenure<3mo: 0.84",
"low_confidence": null,
"low_confidence_reason": null,
"note": "estimate of the live endpoint; serving uses the full pinned snapshot",
"report_url": "/v2/reports/r_a7d0"
}
}Path parameters
idstringrequiredEndpoint ID or name.
Query parameters
cursorstringCursor for the large arrays (unified_rows.rows,prediction.results,imputation.filled).limitintegerdefault100Rows per page for the large arrays.
Returns
The endpoint object.
Serve an endpoint
/v2/serve/:idSends new data to a live endpoint and returns the full bundle for that data, scored against the endpoint’s pinned data.
A serve scores the request rows against the endpoint’s pinned snapshot. Request data is validated against the schema of the pinned snapshot; a mismatch returns 400 validation_error naming the divergence.
A serve returns the bundle; narration is yours to run. The endpoint’s system prompts and current held-out report are read from the endpoint object (GET /v2/endpoints/:id). Production systems should use a key with serve alone.
curl -X POST 'https://api.schemalabs.ai/v2/serve/{endpoint_id}' \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tables": [
{
"id": "crm_contacts",
"columns": ["c0", "c1", "c2", "c3"],
"rows": [
["ana@example.io", "555-0142", "1990-04-02", null],
["lee@example.io", "555-0199", "1988-07-19", null]
]
}
]
}'import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/serve/{endpoint_id}",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
json={
"tables": [
{
"id": "crm_contacts",
"columns": ["c0", "c1", "c2", "c3"],
"rows": [
["ana@example.io", "555-0142", "1990-04-02", None],
["lee@example.io", "555-0199", "1988-07-19", None],
],
},
],
},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/serve/{endpoint_id}', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
tables: [
{
id: "crm_contacts",
columns: ["c0", "c1", "c2", "c3"],
rows: [
["ana@example.io", "555-0142", "1990-04-02", null],
["lee@example.io", "555-0199", "1988-07-19", null],
],
},
],
}),
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"endpoint": "churn",
"id": "{endpoint_id}",
"base": "schema-2",
"mode": "serve",
"status": "complete",
"config_revision": 1,
"data": { "pinned": true, "snapshot": "dsv_91f2", "tables": ["ds_crm01", "ds_bill01"] },
"summary": {
"tables": 1,
"keys_used": "none",
"prediction": {
"target": "crm_contacts.c3",
"task": "classification",
"tier": "in_context",
"held_out": null
}
},
"tables": [
{
"id": "crm_contacts",
"rows": 2,
"cols": 4,
"sector": {
"top1": { "name": "subscription software", "confidence": 0.86 },
"top5": [
{ "name": "subscription software", "confidence": 0.86 },
{ "name": "customer relationship management", "confidence": 0.72 },
{ "name": "telecommunications", "confidence": 0.49 },
{ "name": "consumer financial services", "confidence": 0.38 },
{ "name": "marketing services", "confidence": 0.27 }
]
},
"column_profile": [
{
"name": "c0",
"role": "email",
"role_confidence": 0.98,
"type": "categorical",
"missing_pct": 0,
"pii": true
},
{
"name": "c1",
"role": "phone",
"role_confidence": 0.97,
"type": "categorical",
"missing_pct": 0,
"pii": true
},
{
"name": "c2",
"role": "date",
"role_confidence": 0.95,
"type": "datetime",
"missing_pct": 0,
"pii": false
},
{
"name": "c3",
"role": "category",
"role_confidence": 0.92,
"type": "categorical",
"missing_pct": 1,
"pii": false
}
]
}
],
"cross_table_map": null,
"unified_rows": null,
"imputation": { "filled": [], "row_confidence": [], "total_filled": 0 },
"prediction": {
"target": "crm_contacts.c3",
"task_type": "classification",
"tier": "in_context",
"classes": ["retained", "churned"],
"note": "scored by this endpoint over its pinned data plus the rows in this request",
"results": [
{
"row": 0,
"label": "retained",
"confidence": 0.95,
"probabilities": { "retained": 0.95, "churned": 0.05 }
},
{
"row": 1,
"label": "churned",
"confidence": 0.81,
"probabilities": { "retained": 0.19, "churned": 0.81 }
}
]
}
}{
"error": {
"type": "validation_error",
"message": "table crm_contacts: column c12 is not in the pinned snapshot dsv_91f2 (12 columns, c0..c11)",
"param": "tables[0].columns",
"request_id": "req_7a1c9e"
}
}Path parameters
idstringrequiredEndpoint ID or name.
Body application/json
tablesarray of objectsrequiredTables to score against the pinned data. Table ids and columns must match the pinned snapshot’s schema.Item properties 3
idstringrequiredYour name for the table. Appears in every per-table output and in cross-table references such ascrm_contacts.c1.columnsarray of stringsrequiredColumn names. They may be real names, opaque labels (c0,c1), or empty: Schema understands the values, not the names.rowsarray of arraysrequiredRow values in column order. Usenullfor missing cells; missing cells are metered like any other cell.
optionsobjectconfidence_thresholdas on a run.
Returns
The bundle for the request data, scored by the endpoint over its pinned data. The endpoint’s held-out report and system prompts are read from the endpoint object (GET /v2/endpoints/:id).
Metering: request rows bill fresh, the pinned context bills the cached rate. An idle endpoint costs nothing. Each endpoint enforces per-endpoint and per-key rate limits (429 with Retry-After).
Refresh an endpoint
/v2/endpoints/:id/refreshRe-syncs the pinned snapshot and re-scores held-out on a fresh split; only what changed bills fresh. Mints a new report. Returns 202 and a job.
Refresh is how an endpoint follows its source. Sync the dataset first with POST /v2/data/:id/sync, or let refresh sync inline. Removed rows leave the pinned context immediately; it is the only operation that makes an endpoint stop reflecting deleted rows.
One mutating job runs per endpoint at a time: a second refresh or upgrade returns 409 conflict naming the running job_id. Calls are unaffected while a refresh runs.
curl -X POST 'https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/refresh' \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Idempotency-Key: <unique key>"import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/refresh",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}", "Idempotency-Key": "<unique key>"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/refresh', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
'Idempotency-Key': '<unique key>',
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{ "endpoint": "churn", "id": "{endpoint_id}", "job_id": "job_5c07e3b1" }{
"endpoint": "churn",
"id": "{endpoint_id}",
"base": "schema-1",
"data": {
"datasets": [
{
"dataset": "ds_crm01",
"name": "crm_contacts",
"pinned": true,
"snapshot": "dsv_91f2"
},
{
"dataset": "ds_bill01",
"name": "billing_db",
"pinned": true,
"snapshot": "dsv_c4e7"
}
],
"pinned": true,
"snapshot": "dsv_91f2",
"tables": ["ds_crm01", "ds_bill01"]
},
"diff": {
"rows_added": 310,
"rows_changed": 12,
"rows_removed": 4,
"rows_unchanged": 22078
},
"reason": "source data changed",
"report": "churn.s1.refresh.2026-08-12",
"report_id": "r_b5e1",
"held_out": { "score": 0.948 }
}{
"error": {
"type": "conflict",
"message": "endpoint churn already has a mutating job running; wait for it to finish or cancel it",
"running_job_id": "job_5c07e3b1",
"request_id": "req_5d17ce"
}
}Path parameters
idstringrequiredEndpoint ID or name.
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.
Returns
202 with the job. When it completes, the endpoint object carries the new snapshot, a diff, and the new report.
Metering: added and changed rows bill fresh, unchanged context bills the cached rate, removals bill nothing.
Upgrade an endpoint
/v2/endpoints/:id/upgradeRe-runs the same pinned data on a newer base and mints a new report. The endpoint serves the new base from completion. Returns 202 and a job.
The endpoint serves the new base from completion; the previous report stays in the trail and the delta reads on the Reports page or via the reports API.
An endpoint created on a base that has since been retired keeps that base until it is upgraded; upgrade it to resume serving. The example below moves churn from schema-1 (an older base, and its base since creation on 2026-03-10) to schema-2.
curl -X POST 'https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/upgrade' \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Idempotency-Key: <unique key>" \
-H "Content-Type: application/json" \
-d '{ "base": "schema-2" }'import os
import requests
SCHEMA_API_KEY = os.environ["SCHEMA_API_KEY"]
r = requests.post(
"https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/upgrade",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}", "Idempotency-Key": "<unique key>"},
json={"base": "schema-2"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/upgrade', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '<unique key>',
},
body: JSON.stringify({ base: "schema-2" }),
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{ "endpoint": "churn", "id": "{endpoint_id}", "job_id": "job_7d3c9b2e" }{
"endpoint": "churn",
"id": "{endpoint_id}",
"base": "schema-2",
"held_out": { "score": 0.961 },
"previous": { "base": "schema-1", "held_out": 0.948 },
"delta": "+0.013",
"report": "churn.s2.upgrade.2026-08-14",
"report_id": "r_a7d0"
}Path parameters
idstringrequiredEndpoint ID or name.
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
basestringrequiredThe Schema model to move to, a newer base fromGET /v2/models.
Returns
202 with the job. On completion the endpoint object carries the new base, the new report, previous, and delta.
Metering: one fresh pass over the pinned data at the fresh rate.
Endpoint logs
/v2/endpoints/:id/logsThe endpoint’s operation log: create, pin, refresh, upgrade, and job events. Never row data.
curl 'https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/logs' \
-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/endpoints/{endpoint_id}/logs",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/endpoints/{endpoint_id}/logs', {
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"logs": [
{
"at": "2026-08-14T11:20:05Z",
"op": "upgrade",
"detail": "schema-1 -> schema-2; report r_a7d0"
},
{
"at": "2026-08-12T09:31:44Z",
"op": "refresh",
"detail": "dsv_2b81 -> dsv_91f2 (+310 / ~12 / -4 rows); report r_b5e1"
},
{
"at": "2026-03-10T14:09:31Z",
"op": "evaluate",
"detail": "held-out evaluated over 403,200 cells across 2 tables; endpoint live"
},
{
"at": "2026-03-10T14:07:02Z",
"op": "pin",
"detail": "ds_crm01 @ dsv_2b81, ds_bill01 @ dsv_c4e7"
},
{
"at": "2026-03-10T14:07:02Z",
"op": "create",
"detail": "endpoint created on schema-1, 2 tables pinned (dsv_2b81, dsv_c4e7)"
}
],
"total": 5
}Path parameters
idstringrequiredEndpoint ID or name.
Query parameters
limitintegerdefault20Page size.cursorstringCursor from a previous page.
Returns
The endpoint’s log entries (at, op, detail) and total.
Endpoint OpenAPI description
/v2/openapi/:idReturns the OpenAPI 3.1 document for one live endpoint: its serve operation, the request schema derived from the pinned snapshot (table ids and columns), and the bundle response schema. Import it into any tool that reads OpenAPI.
Agent frameworks, function-calling wrappers, and no-code HTTP nodes read this document to call the endpoint with the right table ids and columns. See Agents and LLMs.
curl 'https://api.schemalabs.ai/v2/openapi/{endpoint_id}' \
-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/openapi/{endpoint_id}",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
result = r.json()const res = await fetch('https://api.schemalabs.ai/v2/openapi/{endpoint_id}', {
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Schema API error ${res.status}`);
const result = await res.json();{
"openapi": "3.1.0",
"info": { "title": "churn", "version": "2" },
"servers": [
{ "url": "https://api.schemalabs.ai" }
],
"paths": {
"/v2/serve/{endpoint_id}": {
"post": {
"operationId": "serve",
"security": [
{ "bearerAuth": [] }
]
}
}
},
"components": {
"securitySchemes": {
"bearerAuth": { "type": "http", "scheme": "bearer" }
}
}
}Path parameters
idstringrequiredEndpoint ID or name.
Returns
The OpenAPI document as application/json.
The document follows the pinned schema: re-import it after a refresh that changes tables or columns.
Available once the endpoint is live.
Delete an endpoint
/v2/endpoints/:idTears the endpoint down immediately. Its reports remain in the org’s audit trail; its datasets remain under Data, unpinned, and are deleted separately.
curl -X DELETE 'https://api.schemalabs.ai/v2/endpoints/{endpoint_id}' \
-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/endpoints/{endpoint_id}",
headers={"Authorization": f"Bearer {SCHEMA_API_KEY}"},
)
r.raise_for_status()
print(r.json())const res = await fetch('https://api.schemalabs.ai/v2/endpoints/{endpoint_id}', {
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": "{endpoint_id}", "deleted": true }Path parameters
idstringrequiredEndpoint ID or name.
Returns
The deleted endpoint id and status.
Deletion is immediate. Callers of the URL receive 404 not_found from this moment.