Every API 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 apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
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.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/textql-v2-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no email required.
A second provider on the same verified email joins the account you already have.
openapi: 3.1.0
info:
title: TextQL v2 API
version: "2.0"
description: |
REST API for TextQL platform operations. All endpoints require Bearer token authentication.
servers:
- url: https://app.textql.com
security:
- bearerAuth: []
tags:
- name: Chat
description: Create and manage AI chat sessions
- name: Connectors
description: List available data connectors
- name: Playbooks
description: Create, configure, and run automated playbooks
- name: Sandcastles
description: Manage Python sandbox environments for code execution
- name: Changes
description: Review, approve, and deny Ontology changes
- name: API Keys
description: Mint and revoke scoped platform API keys
paths:
/v2/chats:
get:
tags:
- Chat
summary: List Chats
description: List chats with optional search and pagination. Returns chats owned by the authenticated API key.
operationId: v2.listChats
parameters:
- name: limit
in: query
schema:
type: integer
format: int32
default: 20
minimum: 1
maximum: 100
description: Maximum number of chats to return (default 20, max 100)
- name: offset
in: query
schema:
type: integer
format: int32
minimum: 0
description: Number of chats to skip
- name: search_term
in: query
schema:
type: string
description: Filter chats by summary or first message content
- name: sort_by
in: query
schema:
type: string
enum:
- name
- created_at
- updated_at
default: updated_at
description: Field to sort by
- name: sort_direction
in: query
schema:
type: string
enum:
- asc
- desc
default: desc
description: Sort direction
responses:
"200":
description: Paginated list of chats
content:
application/json:
schema:
$ref: "#/components/schemas/ListChatsResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
post:
tags:
- Chat
summary: Create Chat
description: |
Send a question and receive a synchronous response. Supports JSON or multipart
form-data (for file uploads). The response includes the model's answer and any
generated assets.
operationId: v2.createChat
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ChatRequest"
multipart/form-data:
schema:
type: object
required:
- question
properties:
question:
type: string
description: The question to ask
chat_id:
type: string
format: uuid
description: Existing chat ID to continue a conversation
model:
type: string
description: >-
Optional model `id` from `GET /v2/models` (e.g.
`gemini_3_5_flash`). Omit for the org default. New chats only.
example: gemini_3_5_flash
connector_ids:
type: array
items:
type: integer
format: int32
description: Connector IDs to query
files:
type: array
items:
type: string
format: binary
maxItems: 10
description: One or more files to upload with the question
responses:
"200":
description: Chat response
content:
application/json:
schema:
$ref: "#/components/schemas/ChatResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/chats/stream:
post:
tags:
- Chat
summary: Stream Chat
description: |
Send a question and receive a streaming response via Server-Sent Events.
Supports the same request format as Create Chat. The stream emits metadata,
text deltas, execution cells, assets, and a final done event.
operationId: v2.streamChat
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ChatRequest"
multipart/form-data:
schema:
type: object
required:
- question
properties:
question:
type: string
chat_id:
type: string
format: uuid
model:
type: string
description: >-
Optional model `id` from `GET /v2/models` (e.g.
`gemini_3_5_flash`). Omit for the org default. New chats only.
example: gemini_3_5_flash
connector_ids:
type: array
items:
type: integer
format: int32
files:
type: array
items:
type: string
format: binary
maxItems: 10
responses:
"200":
description: Server-Sent Events stream
content:
text/event-stream:
schema:
type: string
description: |
SSE stream with JSON data payloads. Event types:
- `{"type":"metadata","id":"...","created_at":"...","model":"...","chat_id":"...","is_continuation":bool}`
- `{"type":"text","text":"..."}`
- `{"type":"cell","cell":{...}}` — an execution step (same shape as ChatCell), emitted once when the step starts running (carrying the generated SQL or code) and again when it finishes (carrying outputs, result previews, and timing)
- `{"type":"asset","asset":{...}}`
- `{"type":"done","status":"completed|failed","error":"..."}`
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/chats/{id}:
get:
tags:
- Chat
summary: Get Chat
description: Retrieve a chat by ID, including its messages and generated assets.
operationId: v2.getChat
parameters:
- $ref: "#/components/parameters/ChatId"
responses:
"200":
description: Chat details
content:
application/json:
schema:
$ref: "#/components/schemas/GetChatResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/chats/{id}/cells:
get:
tags:
- Chat
summary: Get Chat Cells
description: "Retrieve a chat's cells, the per-step execution detail behind each answer: user and assistant messages, generated SQL and Python with their outputs, and the assets each step produced, in conversation order. Paginated newest-first: the default page returns the most recent cells, and offset skips past them toward older ones. Pages extend backward to the start of a conversation turn, so a page can contain slightly more than limit cells."
operationId: v2.getChatCells
parameters:
- $ref: "#/components/parameters/ChatId"
- name: limit
in: query
schema:
type: integer
format: int32
default: 200
maximum: 500
description: Maximum cells per page (values outside 1-500 fall back to 200)
- name: offset
in: query
schema:
type: integer
format: int32
default: 0
description: Number of most-recent cells to skip
responses:
"200":
description: Chat cells
content:
application/json:
schema:
$ref: "#/components/schemas/GetChatCellsResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/chats/{id}/cells/{cellId}:
get:
tags:
- Chat
summary: Get Chat Cell
description: Retrieve a single cell from a chat by ID.
operationId: v2.getChatCell
parameters:
- $ref: "#/components/parameters/ChatId"
- $ref: "#/components/parameters/CellId"
responses:
"200":
description: Chat cell
content:
application/json:
schema:
$ref: "#/components/schemas/ChatCell"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/chats/{id}/cancel:
post:
tags:
- Chat
summary: Cancel Stream
description: Cancel a running chat stream.
operationId: v2.cancelStream
parameters:
- $ref: "#/components/parameters/ChatId"
responses:
"200":
description: Cancellation result
content:
application/json:
schema:
type: object
properties:
cancelled:
type: boolean
description: Whether the stream was successfully cancelled
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/models:
get:
tags:
- Chat
summary: List Models
description: >-
List the models the authenticated organization may run chats on. The
result is scoped to the org's enabled-model catalog and the caller's role
allow-list, so it reflects exactly what `POST /v2/chats` will accept in
its `model` field. Pass an entry's `id` back as that field.
operationId: v2.listModels
responses:
"200":
description: Available models
content:
application/json:
schema:
$ref: "#/components/schemas/ListModelsResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/connectors:
get:
tags:
- Connectors
summary: List Connectors
description: List all data connectors available to the authenticated organization.
operationId: v2.listConnectors
responses:
"200":
description: List of connectors
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Connector"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
post:
tags:
- Connectors
summary: Create Connector
description: |
Create a new data connector from the supplied configuration. Creation
validates the config but does not open a connection — call
`POST /v2/connectors/test` first if you want to verify reachability.
operationId: v2.createConnector
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateConnectorRequest"
responses:
"201":
description: Created connector
content:
application/json:
schema:
$ref: "#/components/schemas/Connector"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"409":
$ref: "#/components/responses/Conflict"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/connectors/types:
get:
tags:
- Connectors
summary: List Connector Types
description: |
Enumerate every supported connector type and the fields each requires,
so you can build a valid `config` without reading the proto. For each
type, `connector_type` is the value to set as `config.connector_type`
and `config_key` is the metadata object to nest under `config`.
Fields flagged `confidential` are write-only (passwords, keys, tokens) —
they are never returned by read endpoints, and when `optional_on_update`
is true they may be omitted on `PATCH` to preserve the stored value.
operationId: v2.listConnectorTypes
responses:
"200":
description: Supported connector types and their field schemas
content:
application/json:
schema:
$ref: "#/components/schemas/ListConnectorTypesResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/connectors/test:
post:
tags:
- Connectors
summary: Test Connector
description: |
Test a connector configuration without persisting it. A failed
connection is reported as `200` with `{"success": false, "error": "..."}`
— the request itself succeeded, only the downstream connection failed.
HTTP error statuses are reserved for an invalid config (`400`) or
auth/permission failures.
Pass `connector_id` to test changes against an existing connector:
confidential fields left empty in the request are filled in from the
stored connector before the connection is attempted.
operationId: v2.testConnector
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TestConnectorRequest"
responses:
"200":
description: Test result
content:
application/json:
schema:
$ref: "#/components/schemas/TestConnectorResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/connectors/{id}:
patch:
tags:
- Connectors
summary: Update Connector
description: |
Update an existing connector. The `connector_type` in the body must
match the stored connector's type. Confidential fields (passwords, keys,
tokens) left empty are preserved from the stored connector, so you only
need to send the fields you are changing.
operationId: v2.updateConnector
parameters:
- $ref: "#/components/parameters/ConnectorId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateConnectorRequest"
responses:
"200":
description: Updated connector
content:
application/json:
schema:
$ref: "#/components/schemas/Connector"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
delete:
tags:
- Connectors
summary: Delete Connector
description: |
Delete a connector by id. Example/system connectors cannot be deleted
(TextQL Usage connectors return `400`; example connectors are hidden
rather than removed).
operationId: v2.deleteConnector
parameters:
- $ref: "#/components/parameters/ConnectorId"
responses:
"200":
description: Deletion result
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int32
success:
type: boolean
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/connectors/{id}/access:
get:
tags:
- Connectors
summary: Get Connector Access
description: |
Get a connector's access configuration: its org-wide visibility and the
member, role, and group grants on it. Requires read access to the
connector.
operationId: v2.getConnectorAccess
parameters:
- $ref: "#/components/parameters/ConnectorId"
responses:
"200":
description: Current access configuration
content:
application/json:
schema:
$ref: "#/components/schemas/ConnectorAccess"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
put:
tags:
- Connectors
summary: Update Connector Access
description: |
Declaratively replace a connector's access configuration. Grants not in
the request are revoked, new ones are created, and `is_public` sets
org-wide visibility. The caller's own owner grant is always preserved,
even when omitted from `grants`.
Requires owner access to the connector (or org admin). Grants are
validated (members, roles, and groups must exist in the organization)
up front, and the replacement is applied atomically in a single
transaction, so a failed request leaves access unchanged.
operationId: v2.updateConnectorAccess
parameters:
- $ref: "#/components/parameters/ConnectorId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateConnectorAccessRequest"
responses:
"200":
description: Resulting access configuration
content:
application/json:
schema:
$ref: "#/components/schemas/ConnectorAccess"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/playbooks:
get:
tags:
- Playbooks
summary: List Playbooks
description: List playbooks with optional filtering, sorting, and pagination.
operationId: v2.listPlaybooks
parameters:
- name: limit
in: query
schema:
type: integer
format: int64
description: Maximum number of playbooks to return
- name: offset
in: query
schema:
type: integer
format: int64
description: Number of playbooks to skip
- name: search_term
in: query
schema:
type: string
description: Filter playbooks by name
- name: sort_by
in: query
schema:
type: string
enum:
- name
- created_at
- updated_at
description: Field to sort by
- name: sort_direction
in: query
schema:
type: string
enum:
- asc
- desc
description: Sort direction
- name: status_filter
in: query
schema:
type: string
enum:
- draft
- deployed
description: Filter by playbook status
responses:
"200":
description: Paginated list of playbooks
content:
application/json:
schema:
$ref: "#/components/schemas/ListPlaybooksResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
post:
tags:
- Playbooks
summary: Create Playbook
description: Create a new empty playbook with default settings.
operationId: v2.createPlaybook
responses:
"201":
description: Created playbook
content:
application/json:
schema:
$ref: "#/components/schemas/Playbook"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/playbooks/{id}:
get:
tags:
- Playbooks
summary: Get Playbook
description: Retrieve a playbook by ID, including its recent reports.
operationId: v2.getPlaybook
parameters:
- $ref: "#/components/parameters/PlaybookId"
- name: limit
in: query
schema:
type: integer
format: int64
description: Maximum number of reports to return
- name: offset
in: query
schema:
type: integer
format: int64
description: Number of reports to skip
responses:
"200":
description: Playbook details with reports
content:
application/json:
schema:
$ref: "#/components/schemas/GetPlaybookResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
patch:
tags:
- Playbooks
summary: Update Playbook
description: |
Update a playbook's configuration. All fields are optional; only provided
fields are updated.
operationId: v2.updatePlaybook
parameters:
- $ref: "#/components/parameters/PlaybookId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdatePlaybookRequest"
responses:
"200":
description: Updated playbook
content:
application/json:
schema:
$ref: "#/components/schemas/Playbook"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
delete:
tags:
- Playbooks
summary: Delete Playbook
description: Delete a playbook by ID.
operationId: v2.deletePlaybook
parameters:
- $ref: "#/components/parameters/PlaybookId"
responses:
"200":
description: Deletion confirmation
content:
application/json:
schema:
type: object
properties:
playbook_id:
type: string
format: uuid
deleted_at:
type: string
format: date-time
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/playbooks/{id}/deploy:
post:
tags:
- Playbooks
summary: Deploy Playbook
description: Deploy a playbook, making it active and ready to run on its schedule.
operationId: v2.deployPlaybook
parameters:
- $ref: "#/components/parameters/PlaybookId"
responses:
"200":
description: Deployment confirmation
content:
application/json:
schema:
type: object
properties:
playbook_id:
type: string
format: uuid
deployed_at:
type: string
format: date-time
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
/v2/playbooks/{id}/run:
post:
tags:
- Playbooks
summary: Run Playbook
description: |
Execute a playbook and return the generated report. Use `dry_run: true` to
validate without executing. Returns 504 if execution times out.
operationId: v2.runPlaybook
parameters:
- $ref: "#/components/parameters/PlaybookId"
requestBody:
content:
application/json:
schema:
type: object
properties:
dry_run:
type: boolean
default: false
description: If true, validate without executing
responses:
"200":
description: Playbook execution result
content:
application/json:
schema:
$ref: "#/components/schemas/RunPlaybookResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"429":
$ref: "#/components/responses/RateLimited"
"500":
$ref: "#/components/responses/InternalError"
"504":
description: Execution timed out
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/v2/sandcastles:
get:
tags:
- Sandcastles
summary: List Sandcastles
description: |
List sandboxes for the authenticated organization with cursor-based
pagination.
Each item reports a `status`:
- `running` — a live worker record was seen recently. Liveness is
eventually consistent: a sandbox that died abruptly may continue to
report `running` for a short window (up to ~1 hour).
- `stale` — the lease is open but no live worker record exists; the
worker is likely gone. Call `DELETE /v2/sandcastles/{id}` (Stop Sandbox)
to clear it.
- `unknown` — liveness could not be determined (cache unavailable); the
lease is open.
- `stopped` — the sandbox has been released.
`GET /v2/sandcastles/{id}` is the authoritative live check for a single
sandbox.
operationId: v2.listSandboxes
parameters:
- name: status
in: query
schema:
type: string
enum:
- running
- stopped
- all
default: running
description: |
Filter by lease state. `running` (default) returns sandboxes with an
open lease — individual items may report `running`, `stale`, or
`unknown`. `stopped` returns released sandboxes. `all` returns both.
- name: limit
in: query
schema:
type: integer
format: int32
minimum: 1
maximum: 200
default: 50
description: Maximum number of sandboxes to return (default 50, max 200)
- name: cursor
in: query
schema:
type: string
description: |
Opaque pagination cursor from a previous response's `next_cursor`.
Omit to start from the first page.
responses:
"200":
description: Paginated list of sandboxes
content:
application/json:
schema:
$ref: "#/components/schemas/ListSandboxesResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/respons
# --- truncated at 32 KB (125 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/textql/refs/heads/main/openapi/textql-v2-openapi.yml