usestring-ai · Schema
Build
A build, as the customer sees it. Some fields the core holds are deliberately not projected — a feeds-repo pull request URL and the brain's tool arguments — because they are operator detail rather than customer copy.
Web ScrapingData ExtractionMarkdownJSON
Properties
| Name | Type | Description |
|---|---|---|
| activity | array | |
| auto_proceed | boolean | Whether the build advances past gates that can be auto-answered. Change it with PATCH /v1/builds/{id}. |
| completed_at | string | |
| created_at | string | |
| error | string | Requester-facing failure copy — the same string the run-finished email carries. Not an operator diagnostic. |
| gate_history | array | |
| id | string | |
| messages | array | |
| object | string | |
| pending_gate | object | |
| progress | object | |
| query | string | |
| report | object | |
| status | string | One of `running`, `completed`, `errored`, `cancelled`, `awaiting_input`, `unknown`. `awaiting_input` means the build is parked on a gate waiting for you, and it is exactly equivalent to `pending_gate` |
| updated_at | string | |
| version | integer |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/usestring-ai/json-schema/usestring-ai-build-schema.json",
"title": "Build",
"description": "A build, as the customer sees it. Some fields the core holds are deliberately not projected — a feeds-repo pull request URL and the brain's tool arguments — because they are operator detail rather than customer copy.",
"x-generated": "2026-10-31",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/feedbuilder-usestring-ai-openapi.yaml#/components/schemas/Build",
"properties": {
"activity": {
"items": {
"$ref": "#/$defs/Activity"
},
"type": "array"
},
"auto_proceed": {
"description": "Whether the build advances past gates that can be auto-answered. Change it with PATCH /v1/builds/{id}.",
"type": "boolean"
},
"completed_at": {
"format": "date-time",
"type": "string"
},
"created_at": {
"format": "date-time",
"type": "string"
},
"error": {
"description": "Requester-facing failure copy — the same string the run-finished email carries. Not an operator diagnostic.",
"type": "string"
},
"gate_history": {
"items": {
"$ref": "#/$defs/GateRecord"
},
"type": "array"
},
"id": {
"type": "string"
},
"messages": {
"items": {
"$ref": "#/$defs/InputRecord"
},
"type": "array"
},
"object": {
"type": "string"
},
"pending_gate": {
"$ref": "#/$defs/Gate"
},
"progress": {
"$ref": "#/$defs/Progress"
},
"query": {
"type": "string"
},
"report": {
"$ref": "#/$defs/Report"
},
"status": {
"description": "One of `running`, `completed`, `errored`, `cancelled`, `awaiting_input`, `unknown`. `awaiting_input` means the build is parked on a gate waiting for you, and it is exactly equivalent to `pending_gate` being present — the two never disagree, so either one answers \"is this waiting on me?\". A terminal build never reports a pending gate, even if it was holding one when it ended.",
"type": "string"
},
"updated_at": {
"format": "date-time",
"type": "string"
},
"version": {
"format": "int64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"id",
"object",
"version",
"status",
"query",
"auto_proceed"
],
"type": "object",
"$defs": {
"Activity": {
"properties": {
"at": {
"format": "date-time",
"type": "string"
},
"text": {
"type": "string"
},
"tool_name": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
"Choice": {
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"label": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"ChoiceOptions": {
"properties": {
"choices": {
"items": {
"$ref": "#/$defs/Choice"
},
"type": "array"
}
},
"required": [
"choices"
],
"type": "object"
},
"Field": {
"properties": {
"description": {
"type": "string"
},
"key": {
"type": "string"
},
"repeated": {
"type": "boolean"
},
"required": {
"type": "boolean"
},
"type": {
"type": "string"
}
},
"required": [
"key",
"type",
"repeated",
"required"
],
"type": "object"
},
"Gate": {
"properties": {
"expires_at": {
"format": "date-time",
"type": "string"
},
"id": {
"type": "string"
},
"kind": {
"description": "Which of the eight gate kinds this is: `choice`, `confirm`, `schema_review`, `text`, `source_picker`, `publish_review`, `initial_query`, `questionnaire`. Read off the options payload, so the kind and the options can never disagree. NEW KINDS APPEAR WITHOUT A VERSION BUMP — treat an unrecognised kind as answerable with a plain `{\"text\": \"...\"}`.",
"type": "string"
},
"object": {
"type": "string"
},
"options": {
"description": "The gate's payload. Its shape follows `kind`: `choice` carries ChoiceOptions, `schema_review` SchemaReviewOptions, `source_picker` SourcePickerOptions, `publish_review` PublishReviewOptions, `initial_query` InitialQueryOptions, `questionnaire` QuestionnaireOptions, and `confirm` and `text` carry an empty object. A kind you do not recognise is still answerable with a plain {\"text\": \"...\"}.",
"oneOf": [
{
"$ref": "#/$defs/ChoiceOptions"
},
{
"$ref": "#/$defs/SchemaReviewOptions"
},
{
"$ref": "#/$defs/SourcePickerOptions"
},
{
"$ref": "#/$defs/PublishReviewOptions"
},
{
"$ref": "#/$defs/InitialQueryOptions"
},
{
"$ref": "#/$defs/QuestionnaireOptions"
},
{
"additionalProperties": false,
"description": "`confirm` and `text` gates carry no options.",
"title": "EmptyOptions",
"type": "object"
}
]
},
"prompt": {
"type": "string"
},
"raised_at": {
"format": "date-time",
"type": "string"
},
"suggested": {
"$ref": "#/$defs/GateAnswer"
}
},
"required": [
"id",
"object",
"kind",
"prompt"
],
"type": "object"
},
"GateAnswer": {
"description": "One gate resolution. EXACTLY ONE member may be set, and which member is set picks the answer kind — there is no `kind` property, deliberately: a discriminator that can disagree with its payload is a second thing to validate and a way for a caller to be coerced onto an arm they did not fill in. Setting more than one member is a 400 (`gate_answer_ambiguous`); setting none is a 400 (`gate_answer_required`).\n\n`text` IS THE ESCAPE HATCH: a plain {\"text\": \"...\"} is a valid answer to EVERY gate kind, including kinds that did not exist when your client was generated. The brain raises kinds dynamically and new ones appear without a version bump, so a client that meets a `kind` it has no renderer for should show the gate's `prompt` and send the operator's typed reply as `text` rather than failing the build.\n\nAn answer whose member does not match the gate's kind is refused by the core with a 400. This API does not know the gate's kind and never guesses one.",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"choice_id": {
"type": "string"
}
},
"required": [
"choice_id"
],
"title": "choice_id",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"confirm": {
"type": "boolean"
}
},
"required": [
"confirm"
],
"title": "confirm",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"schema": {
"$ref": "#/$defs/SchemaReviewAnswer"
}
},
"required": [
"schema"
],
"title": "schema",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"text": {
"description": "A free-text answer. Valid against EVERY gate kind — this is the escape hatch for kinds your client does not recognise.",
"type": "string"
}
},
"required": [
"text"
],
"title": "text",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"source": {
"$ref": "#/$defs/SourcePickerAnswer"
}
},
"required": [
"source"
],
"title": "source",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"publish": {
"$ref": "#/$defs/PublishReviewAnswer"
}
},
"required": [
"publish"
],
"title": "publish",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"initial_query": {
"type": "string"
}
},
"required": [
"initial_query"
],
"title": "initial_query",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"questionnaire": {
"$ref": "#/$defs/QuestionnaireAnswer"
}
},
"required": [
"questionnaire"
],
"title": "questionnaire",
"type": "object"
}
]
},
"GateRecord": {
"properties": {
"answer": {
"$ref": "#/$defs/GateAnswer"
},
"answered_at": {
"format": "date-time",
"type": "string"
},
"id": {
"type": "string"
},
"kind": {
"description": "Which of the eight gate kinds this was. See `Gate.kind`.",
"type": "string"
},
"options": {
"description": "The gate's payload. Its shape follows `kind`: `choice` carries ChoiceOptions, `schema_review` SchemaReviewOptions, `source_picker` SourcePickerOptions, `publish_review` PublishReviewOptions, `initial_query` InitialQueryOptions, `questionnaire` QuestionnaireOptions, and `confirm` and `text` carry an empty object. A kind you do not recognise is still answerable with a plain {\"text\": \"...\"}.",
"oneOf": [
{
"$ref": "#/$defs/ChoiceOptions"
},
{
"$ref": "#/$defs/SchemaReviewOptions"
},
{
"$ref": "#/$defs/SourcePickerOptions"
},
{
"$ref": "#/$defs/PublishReviewOptions"
},
{
"$ref": "#/$defs/InitialQueryOptions"
},
{
"$ref": "#/$defs/QuestionnaireOptions"
},
{
"additionalProperties": false,
"description": "`confirm` and `text` gates carry no options.",
"title": "EmptyOptions",
"type": "object"
}
]
},
"origin": {
"type": "string"
},
"prompt": {
"type": "string"
},
"raised_at": {
"format": "date-time",
"type": "string"
}
},
"required": [
"id",
"kind",
"prompt",
"origin"
],
"type": "object"
},
"InitialQueryOptions": {
"properties": {
"refined_request": {
"type": "string"
},
"source_url": {
"type": "string"
}
},
"required": [
"refined_request"
],
"type": "object"
},
"InputRecord": {
"properties": {
"interrupt": {
"type": "boolean"
},
"sent_at": {
"format": "date-time",
"type": "string"
},
"text": {
"type": "string"
}
},
"required": [
"text",
"interrupt"
],
"type": "object"
},
"Progress": {
"properties": {
"eta_seconds": {
"format": "int32",
"type": "integer"
},
"percent": {
"format": "int32",
"type": "integer"
},
"summary": {
"type": "string"
}
},
"type": "object"
},
"PublishReviewAnswer": {
"properties": {
"approve": {
"description": "REQUIRED. Send `true` or `false` explicitly. A body that OMITS this key is refused with 400 `approve_required`; it is never read as `false`. A silent `false` here withholds a FINISHED FEED and ends the run — the single most expensive way for a client bug to be invisible. If your generated client models this as a plain boolean defaulting to false, fix the client. `null` earns the same 400, so the member is typed as a plain boolean and not a nullable one.",
"type": "boolean"
},
"cadence": {
"type": "string"
},
"delivery_target": {
"items": {
"type": "string"
},
"type": "array"
},
"notes": {
"type": "string"
}
},
"required": [
"approve"
],
"type": "object"
},
"PublishReviewOptions": {
"properties": {
"feed_name": {
"type": "string"
},
"fields": {
"items": {
"$ref": "#/$defs/Field"
},
"type": "array"
},
"proposed_schedule": {
"type": "string"
},
"rows_written": {
"format": "int32",
"minimum": 0,
"type": "integer"
},
"sample_rows": {
"description": "Rows as ARRAYS, positionally aligned with `fields`.",
"items": {
"items": {},
"type": "array"
},
"type": "array"
},
"source_url": {
"type": "string"
}
},
"required": [
"feed_name",
"rows_written"
],
"type": "object"
},
"Question": {
"properties": {
"choices": {
"description": "Empty means the question is open — a typed answer.",
"items": {
"$ref": "#/$defs/Choice"
},
"type": "array"
},
"id": {
"type": "string"
},
"prompt": {
"type": "string"
}
},
"required": [
"id",
"prompt"
],
"type": "object"
},
"QuestionnaireAnswer": {
"properties": {
"answers": {
"additionalProperties": {
"type": "string"
},
"description": "Keyed by `Question.id`. A question you are SKIPPING must be ABSENT, never present with an empty value — the brain has to be able to tell a skip from an answer. At least one entry is required on a request.",
"type": "object"
}
},
"required": [
"answers"
],
"type": "object"
},
"QuestionnaireOptions": {
"properties": {
"questions": {
"items": {
"$ref": "#/$defs/Question"
},
"type": "array"
}
},
"required": [
"questions"
],
"type": "object"
},
"Report": {
"properties": {
"feed_name": {
"type": "string"
},
"fields": {
"items": {
"$ref": "#/$defs/Field"
},
"type": "array"
},
"first_run_ok": {
"type": "boolean"
},
"merged": {
"type": "boolean"
},
"notes": {
"type": "string"
},
"rows_written": {
"format": "int32",
"minimum": 0,
"type": "integer"
},
"sample_rows": {
"description": "Rows as ARRAYS, positionally aligned with `fields` — never objects keyed by column name, which would silently drop a duplicate or reordered column instead of preserving the positions the producer promised.",
"items": {
"items": {},
"type": "array"
},
"type": "array"
},
"schedule": {
"type": "string"
},
"source_url": {
"type": "string"
}
},
"required": [
"feed_name",
"rows_written"
],
"type": "object"
},
"SchemaColumnEdit": {
"properties": {
"drop": {
"description": "Omitted means KEEP the column — the non-destructive default. That is the opposite of `approve`, whose omitted default would be the destructive one, which is why `approve` is refused when absent and this is not.",
"type": "boolean"
},
"key": {
"type": "string"
},
"rename_to": {
"type": "string"
},
"required": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object"
},
"SchemaReviewAnswer": {
"properties": {
"approve": {
"description": "REQUIRED. Send `true` or `false` explicitly. A body that OMITS this key is refused with 400 `approve_required`; it is never read as `false`. The field is presence-tracked on purpose: a silent `false` at a review gate is not \"unanswered\" but a considered refusal that withholds the work and ends the run, with nothing recording that nobody decided. If your generated client models this as a plain boolean defaulting to false, fix the client — an absent decision must never reach this API as a decline. `null` is not an escape either: it earns the same 400, which is why this schema types the member as a plain boolean rather than a nullable one.",
"type": "boolean"
},
"edits": {
"items": {
"$ref": "#/$defs/SchemaColumnEdit"
},
"type": "array"
},
"notes": {
"type": "string"
}
},
"required": [
"approve"
],
"type": "object"
},
"SchemaReviewOptions": {
"properties": {
"decision_summary": {
"type": "string"
},
"proposed_fields": {
"items": {
"$ref": "#/$defs/Field"
},
"type": "array"
},
"sample_rows": {
"description": "Rows as ARRAYS, positionally aligned with `proposed_fields`.",
"items": {
"items": {},
"type": "array"
},
"type": "array"
}
},
"required": [
"proposed_fields"
],
"type": "object"
},
"SourceCandidate": {
"properties": {
"rationale": {
"type": "string"
},
"recommended": {
"type": "boolean"
},
"score": {
"format": "double",
"type": "number"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"url",
"recommended"
],
"type": "object"
},
"SourcePickerAnswer": {
"properties": {
"chosen_url": {
"description": "Set exactly one of `chosen_url` or `re_discover`. Both, or neither, is a 400 (`source_answer_ambiguous`).",
"type": "string"
},
"re_discover": {
"type": "boolean"
}
},
"type": "object"
},
"SourcePickerOptions": {
"properties": {
"candidates": {
"items": {
"$ref": "#/$defs/SourceCandidate"
},
"type": "array"
}
},
"required": [
"candidates"
],
"type": "object"
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/usestring-ai-build"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.