Models API
Models are SQL-defined datasets that sit between sources and syncs. A model runs a SQL query against a source to shape the data you want to sync, build audiences from, or define traits on.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v1/workspaces/{id}/models | List all models |
POST | /api/v1/workspaces/{id}/models | Create a model |
GET | /api/v1/workspaces/{id}/models/{modelId} | Get a model |
PUT | /api/v1/workspaces/{id}/models/{modelId} | Update a model |
DELETE | /api/v1/workspaces/{id}/models/{modelId} | Delete a model |
POST | /api/v1/workspaces/{id}/models/preview | Preview query results |
POST | /api/v1/workspaces/{id}/models/preview-table | Preview table data |
POST | /api/v1/workspaces/{id}/models/{modelId}/refresh-suggestions | Refresh value suggestions |
GET | /api/v1/workspaces/{id}/sources/{sourceId}/schemas | List schemas |
GET | /api/v1/workspaces/{id}/sources/{sourceId}/schemas/{schema}/tables | List tables |
GET | /api/v1/workspaces/{id}/sources/{sourceId}/schemas/{schema}/tables/{table}/columns | List columns |
List Models
GET /api/v1/workspaces/{id}/models
Returns all models in the workspace.
Response
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"workspace_id": "660e8400-e29b-41d4-a716-446655440000",
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"name": "Active Customers",
"description": "Customers with purchases in the last 90 days",
"sql_query": "SELECT customer_id, email, first_name, last_name FROM customers WHERE last_purchase_date > DATEADD(day, -90, CURRENT_DATE())",
"columns": [
{"name": "customer_id", "type": "VARCHAR", "nullable": false},
{"name": "email", "type": "VARCHAR", "nullable": true},
{"name": "first_name", "type": "VARCHAR", "nullable": true},
{"name": "last_name", "type": "VARCHAR", "nullable": true}
],
"entity_type": "parent",
"primary_key_column": "customer_id",
"timestamp_column": "",
"column_config": [...],
"model_type": "sql",
"source_schema": "",
"source_table": "",
"selected_columns": null,
"status": "active",
"status_error": "",
"created_by": "880e8400-e29b-41d4-a716-446655440000",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Example
curl -X GET https://agentic.zeotap.com/api/v1/workspaces/{id}/models \
-H "Authorization: Bearer <token>" \
-H "X-Workspace-ID: <workspace-id>"Create Model
POST /api/v1/workspaces/{id}/models
Creates a new model. Models can be either SQL-based (sql type) or table selectors (table_selector type).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name |
description | string | No | Description of the model’s purpose |
source_id | string (UUID) | Yes | Source to query against |
sql_query | string | Yes (for sql type) | SQL query to execute |
model_type | string | No | sql (default) or table_selector |
source_schema | string | For table_selector | Schema name for table selector |
source_table | string | For table_selector | Table name for table selector |
selected_columns | array | For table_selector | Columns to include |
primary_key_column | string | No | Column to use as primary key |
timestamp_column | string | No | Column for incremental sync tracking |
entity_type | string | No | parent, related, or event (for schema module) |
column_config | array | No | Per-column audience builder settings |
SQL Model Example
{
"name": "Active Customers",
"description": "Customers with purchases in the last 90 days",
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"sql_query": "SELECT customer_id, email, first_name, last_name, lifetime_value FROM customers WHERE last_purchase_date > DATEADD(day, -90, CURRENT_DATE())",
"primary_key_column": "customer_id",
"entity_type": "parent"
}Table Selector Example
{
"name": "Orders Table",
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"model_type": "table_selector",
"source_schema": "PUBLIC",
"source_table": "ORDERS",
"selected_columns": ["order_id", "customer_id", "total", "created_at"],
"primary_key_column": "order_id",
"entity_type": "event"
}Response
Returns the created model with status 201 Created.
Example
curl -X POST https://agentic.zeotap.com/api/v1/workspaces/{id}/models \
-H "Authorization: Bearer <token>" \
-H "X-Workspace-ID: <workspace-id>" \
-H "Content-Type: application/json" \
-d '{
"name": "Active Customers",
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"sql_query": "SELECT customer_id, email, first_name FROM customers",
"primary_key_column": "customer_id",
"entity_type": "parent"
}'Get Model
GET /api/v1/workspaces/{id}/models/{modelId}
Returns a single model by ID.
Example
curl -X GET https://agentic.zeotap.com/api/v1/workspaces/{id}/models/{modelId} \
-H "Authorization: Bearer <token>" \
-H "X-Workspace-ID: <workspace-id>"Update Model
PUT /api/v1/workspaces/{id}/models/{modelId}
Updates an existing model. You can modify the query, columns, entity type, and other configuration.
Request Body
Same fields as create. Only include fields you want to change.
Example
curl -X PUT https://agentic.zeotap.com/api/v1/workspaces/{id}/models/{modelId} \
-H "Authorization: Bearer <token>" \
-H "X-Workspace-ID: <workspace-id>" \
-H "Content-Type: application/json" \
-d '{
"name": "Active Customers (Updated)",
"sql_query": "SELECT customer_id, email, first_name, last_name, ltv FROM customers WHERE status = '\''active'\''"
}'Delete Model
DELETE /api/v1/workspaces/{id}/models/{modelId}
Deletes a model. The model cannot be deleted if it has active syncs, audiences, or traits depending on it.
Response
{
"status": "deleted"
}Example
curl -X DELETE https://agentic.zeotap.com/api/v1/workspaces/{id}/models/{modelId} \
-H "Authorization: Bearer <token>" \
-H "X-Workspace-ID: <workspace-id>"Preview Query Results
POST /api/v1/workspaces/{id}/models/preview
Executes a SQL query against a source and returns sample rows and column metadata. Use this to validate queries before saving a model.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
source_id | string (UUID) | Yes | Source to query against |
sql_query | string | Yes | SQL query to preview |
{
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"sql_query": "SELECT customer_id, email, first_name FROM customers LIMIT 10"
}Response
{
"columns": [
{"name": "customer_id", "type": "VARCHAR", "nullable": false},
{"name": "email", "type": "VARCHAR", "nullable": true},
{"name": "first_name", "type": "VARCHAR", "nullable": true}
],
"rows": [
{"customer_id": "C001", "email": "alice@example.com", "first_name": "Alice"},
{"customer_id": "C002", "email": "bob@example.com", "first_name": "Bob"}
]
}Example
curl -X POST https://agentic.zeotap.com/api/v1/workspaces/{id}/models/preview \
-H "Authorization: Bearer <token>" \
-H "X-Workspace-ID: <workspace-id>" \
-H "Content-Type: application/json" \
-d '{
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"sql_query": "SELECT customer_id, email FROM customers LIMIT 10"
}'Preview Table
POST /api/v1/workspaces/{id}/models/preview-table
Previews data from a specific table without writing a SQL query. Used by the table selector model type.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
source_id | string (UUID) | Yes | Source to query against |
schema | string | Yes | Schema name |
table | string | Yes | Table name |
{
"source_id": "770e8400-e29b-41d4-a716-446655440000",
"schema": "PUBLIC",
"table": "CUSTOMERS"
}Response
Same format as preview query results.
Refresh Value Suggestions
POST /api/v1/workspaces/{id}/models/{modelId}/refresh-suggestions
Re-scans the model’s data to update the value_suggestions in the column configuration. These stored suggestions back the audience builder’s value dropdowns whenever a live per-column lookup has nothing to show.
A refresh runs one query per suggestable column, so it is bounded:
- One refresh per model at a time. A request made while a refresh of the same model is running does not start a second one.
- Time limits. Each column query is limited to 60 seconds and a whole refresh to about 5 minutes. A refresh that stops early keeps what it found, and next time starts with the columns it scanned longest ago.
By default the endpoint always re-scans. Automatic callers, such as the audience builder refreshing a model when it opens, pass background=true. Background requests are also skipped when:
- the model was refreshed within the last hour, or within 10 minutes of a refresh that stopped early;
- the model’s warehouse source is already running two refreshes.
Query parameters
| Parameter | Type | Description |
|---|---|---|
background | boolean | Mark the refresh as automatic. It is skipped under the conditions above instead of running. Must be true or false; defaults to false. |
Response
Returns the model object with its column_config. When a background refresh was skipped, the model is returned as currently stored.
The X-Value-Suggestions-Refresh response header reports what happened: completed, partial, failed, skipped_in_progress, skipped_recent or skipped_source_busy.
Without background=true, a request made while a refresh of the same model is already running returns 409 Conflict with an explanatory error message.
Schema Discovery
These endpoints allow you to browse the schemas, tables, and columns available in a source warehouse.
List Schemas
GET /api/v1/workspaces/{id}/sources/{sourceId}/schemas
["PUBLIC", "RAW", "ANALYTICS"]List Tables
GET /api/v1/workspaces/{id}/sources/{sourceId}/schemas/{schema}/tables
["CUSTOMERS", "ORDERS", "PRODUCTS"]List Columns
GET /api/v1/workspaces/{id}/sources/{sourceId}/schemas/{schema}/tables/{table}/columns
Returns column metadata for a specific table.
Model Object
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique identifier |
workspace_id | string (UUID) | Owning workspace |
source_id | string (UUID) | Source this model queries |
name | string | Display name |
description | string | Description of the model |
sql_query | string | SQL query (for sql type models) |
columns | array | Discovered columns (name, type, nullable) |
entity_type | string | parent, related, event, or empty |
primary_key_column | string | Column used as the primary key |
timestamp_column | string | Column used for incremental sync tracking |
column_config | array | Per-column audience builder settings |
model_type | string | sql or table_selector |
source_schema | string | Schema name (for table_selector type) |
source_table | string | Table name (for table_selector type) |
selected_columns | array | Selected columns (for table_selector type) |
status | string | draft, active, or error |
status_error | string | Error message when status is error |
created_by | string (UUID) | Account that created the model |
created_at | string (ISO 8601) | Creation timestamp |
updated_at | string (ISO 8601) | Last update timestamp |
Column Config Entry
| Field | Type | Description |
|---|---|---|
name | string | Column name |
alias | string | Display alias for the audience builder |
enabled | boolean | Whether this column is available in the audience builder |
data_type | string | Data type classification |
value_suggestions | array of strings | Sample values for dropdown menus |