Records
2 actions. Each is callable by the agent as a tool, over HTTP via /api/invoke, and (usually) from a UI page.
records.upsert
POST · mutating
Create or update one structured record (a row) in a project dataset. Columns are addressed by NAME — any missing column is auto-created (type inferred from the value). Dedups on sourceUrl (or dedupKey) so re-running a research workflow updates the existing row instead of duplicating it. This is how an agent writes findings into the platform database.
When the agent calls it: Call once per finding from a research/scrape workflow. Pass fields keyed by human column name, e.g. fields: { priceUsd: 142000, sqft: 1100, beachfront: true, location: "Baja · Rosarito" } — columns are created on first use. ALWAYS pass sourceUrl (the listing/page URL) so re-runs update the same row instead of creating duplicates. projectId must be a real research project id from research.start (or projects.create) — never invent one.
- AI tool:
records_upsert - API:
POST /api/invoke/records.upsert
Input
| Field | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | |
title |
string | — | |
sourceUrl |
string | — | |
dedupKey |
string | — | |
status |
string | — | |
fields |
object | — | |
createFields |
boolean | — |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"projectId": {
"type": "string",
"minLength": 1
},
"title": {
"type": "string"
},
"sourceUrl": {
"type": "string"
},
"dedupKey": {
"type": "string"
},
"status": {
"type": "string"
},
"fields": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
}
},
"createFields": {
"type": "boolean"
}
},
"required": [
"projectId"
]
}records.query
POST
Query the structured records (rows) in a project dataset with column predicates — server-side filtered, sorted, and paged. Returns the matching rows, the full-set total, and the column definitions.
When the agent calls it: Filter by column NAME, e.g. where: [{field:"priceUsd",op:"<",value:150000},{field:"sqft",op:">",value:1000},{field:"beachfront",op:"is_true"}]. Numeric ops require a number-typed column.
- AI tool:
records_query - API:
POST /api/invoke/records.query
Input
| Field | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | |
where |
object[] | — | |
status |
string | — | |
q |
string | — | |
orderBy |
string | — | |
orderDir |
"asc" | "desc" | — | |
limit |
integer | — | |
offset |
integer | — |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"projectId": {
"type": "string",
"minLength": 1
},
"where": {
"type": "array",
"items": {
"type": "object",
"properties": {
"field": {
"type": "string"
},
"op": {
"type": "string",
"enum": [
"=",
"!=",
"<",
"<=",
">",
">=",
"contains",
"is_true",
"is_false",
"exists"
]
},
"value": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
}
},
"required": [
"field",
"op"
]
}
},
"status": {
"type": "string"
},
"q": {
"type": "string"
},
"orderBy": {
"type": "string"
},
"orderDir": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 500
},
"offset": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"projectId"
]
}