Base URL
https://api.deepsearch.io/v1
Endpoints
45 documented routes
All REST endpoints (except /health) require a Cognito JWT in the Authorization header:
Authorization: Bearer <access_token>
All user-facing endpoints use the CLIENT_HUB pool (CH_API_DEEPSEARCH): conversations, config, onboarding, feedback, benchmarking, and schema visualization.
Tokens expire — always handle 401 by refreshing the Cognito token.
| Status | Meaning |
|---|---|
400 Bad Request | Validation failure — see detail field |
401 Unauthorized | Missing, expired, or invalid token |
403 Forbidden | Token valid but insufficient permissions |
404 Not Found | Resource does not exist |
409 Conflict | Duplicate resource or state conflict |
429 Too Many Requests | Rate limit exceeded |
500 Internal Server Error | Unexpected server-side error — retry with backoff |
Error body:
| Group | Prefix | Auth pool |
|---|---|---|
| WebSocket Chat | wss://…/api/v1/chat | CLIENT_HUB |
| Conversations | /api/v1/conversations | CLIENT_HUB |
| Feedback (user) | /api/v1/conversations/{id}/feedback | CLIENT_HUB |
| Config — Datasources | /api/v1/deepsearch/config | CLIENT_HUB |
| Config — KPIs | /api/v1/deepsearch/config/datasource/{platform}/kpi | CLIENT_HUB |
| Config — Budgets | /api/v1/deepsearch/config/budget | CLIENT_HUB |
| Onboarding | /api/v1/deepsearch/onboarding | CLIENT_HUB |
| Schema Visualization | /schema/flow, /schema/analyze | CLIENT_HUB |
| Benchmarking | /api/v1/deepsearch/benchmark | CLIENT_HUB |
| Monitoring | /health | None |
Endpoint: wss://ds-api-dev.payintelli.com/api/v1/chat
All messages in both directions are JSON.
1. WebSocket Chat
Description
Connect with the Cognito JWT as a query parameter or via the Sec-WebSocket-Protocol header:
// Option A — query param (simplest)
const socket = new WebSocket(
`wss://ds-api-dev.payintelli.com/api/v1/chat?token=${accessToken}`
);
// Option B — subprotocol header (to resume an existing conversation)
const socket = new WebSocket(
`wss://ds-api-dev.payintelli.com/api/v1/chat?conversation_id=${conversationId}`,
[accessToken]
);
1. WebSocket Chat
Description
socket.send(JSON.stringify({
type: "message",
message: "What is total revenue this month?",
conversation_id: currentConversationId, // omit on the first message of a new conversation
}));
1. WebSocket Chat
Description
A normal conversation turn:
When the AI runs a database query (tool use):
When the AI produces a chart:
Sequence Flow
Client → { type: "message", message: "What is total revenue?" }
Server → { type: "stream_start", conversation_id, message_id }
Server → { type: "token", message_id, text: "The " }
Server → { type: "token", message_id, text: "total ..." }
... more token events ...
Server → { type: "stream_end", conversation_id, message_id, title? }Server → { type: "stream_start", ... }
Server → { type: "token", text: "Let me look that up." }
Server → { type: "tool_thinking", tool: "execute_query", loading: true }
... AI executes SQL ...
Server → { type: "tool_thinking", tool: "execute_query", loading: false }
Server → { type: "token", text: "The total revenue is..." }
Server → { type: "stream_end", ... }Server → { type: "stream_start", ... }
Server → { type: "tool_thinking", tool: "execute_query", loading: true }
Server → { type: "tool_thinking", tool: "execute_query", loading: false }
Server → { type: "tool_thinking", tool: "generate_chart_data", loading: true }
Server → { type: "chart_data", conversation_id, chart_data: { ... } }
Server → { type: "tool_thinking", tool: "generate_chart_data", loading: false }
Server → { type: "token", text: "Here is the revenue breakdown..." }
Server → { type: "stream_end", ... }1. WebSocket Chat
Description
titleinstream_endis only present on the first message of a new conversation. Use it to set the conversation name in the UI without a separate API call.
1. WebSocket Chat
Description
The chart_data event contains a ready-to-use Apache ECharts option object. The server sends data and structure only — no colours, fonts, or theme settings — so you can apply your own theme:
Pass echarts.option directly to myChart.setOption(option).
1. WebSocket Chat
Description
Used for structured tables, insights, alerts, and email drafts:
card_type values: result (data table), insight (text conclusion), alert (anomaly), email (draft).
1. WebSocket Chat
Description
For adaptive cards, chart_data.type is "adaptive_card" and card fields are spread at the top level. Check message.has_chart before rendering.
Endpoint Path
/api/v1/conversations/{id}/history1. WebSocket Chat
Description
All errors arrive as { type: "error", code: "...", message: "..." }.
Important:
AI_TIMEOUTdoes not close the WebSocket connection. Do not reconnect — just let the user resend. Reconnecting creates a new session and loses conversation context.
1. WebSocket Chat
Description
On connect — store the conversation ID:
socket.addEventListener("message", (event) => {
const data = JSON.parse(event.data);
if (data.type === "connected") {
currentConversationId = data.conversation_id;
if (data.is_new) addConversationToSidebar(data.conversation_id);
}
});
On unexpected disconnect — reconnect with the same conversation ID:
socket.addEventListener("close", () => {
setTimeout(() => reconnect(currentConversationId), 2000);
});
1. WebSocket Chat
Description
Each user is limited to 20 conversations. When the 21st is started, the oldest is automatically deleted server-side. Refresh the conversation list after a new conversation is created to reflect the deletion.
1. WebSocket Chat
Description
If a message is blocked, a moderated event fires instead of stream_start:
Show the message text inline and re-enable the input. The session remains open.
All endpoints require CLIENT_HUB auth. Conversations are scoped to the authenticated user — cross-user access returns 403.
2. Conversations
Description
List all conversations for the authenticated user, sorted by most recently updated.
Response 200
Endpoint Path
/api/v1/conversationsResponse Body
{
"conversations": [
{
"conversation_id": "01930f4a-...",
"metadata": {
"user_id": "alice@example.com",
"client_id": "100002",
"chat_title": "Revenue analysis",
"platform": "on_prem_mysql",
"last_updated": 1713174600,
"is_favourite": false
}
}
],
"count": 3,
"user_id": "alice@example.com",
"client_id": "100002"
}2. Conversations
Description
Return the full message history for a conversation, with feedback embedded in each assistant message.
Path parameters
Response 200
Messages without feedback have no feedback key. Check has_chart before rendering a visual.
Endpoint Path
/api/v1/conversations/{conversation_id}/historyParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `conversation_id` | string | Optional | UUID of the conversation |
Response Body
{
"conversation_id": "01930f4a-...",
"metadata": {
"user_id": "alice@example.com",
"chat_title": "Revenue analysis",
"platform": "on_prem_mysql",
"last_updated": 1713174600
},
"messages": [
{
"role": "user",
"content": "What was total revenue last month?"
},
{
"role": "assistant",
"content": "Total revenue last month was $1,234,567.",
"has_chart": true,
"chart_data": {
"type": "chart_data",
"chart_data": { "chart_type": "bar", "echarts": { "option": {} } }
},
"has_feedback": true,
"feedback": {
"reaction": "thumbs_up",
"feedback_text": null,
"submitted_at": "2026-04-15T10:30:00.000000+00:00",
"message_index": 1,
"submitted_by": "alice@example.com",
"client_id": "100002"
}
}
]
}2. Conversations
Description
Rename a conversation.
Path parameters
Query parameters
Response 200
Endpoint Path
/api/v1/conversations/{conversation_id}/rename/titleParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `conversation_id` | string | Optional | UUID of the conversation |
| `new_title` | string | Required | New title, 1–200 characters |
Response Body
{
"conversation_id": "01930f4a-...",
"conversation_title": "Monthly Revenue Deep Dive",
"client_id": "100002",
"status": "success"
}2. Conversations
Description
Permanently delete a conversation and all its messages.
Path parameters
Response 200
Endpoint Path
/api/v1/conversations/{conversation_id}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `conversation_id` | string | Optional | UUID of the conversation |
Response Body
{
"success": true,
"conversation_id": "01930f4a-...",
"client_id": "100002",
"message": "Conversation deleted successfully"
}2. Conversations
Description
Mark a conversation as a favourite.
Query parameters
Response 200
Endpoint Path
/api/v1/conversations/{conversation_id}/favouriteParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `is_favourite` | boolean | Required | `true` to mark, `false` to unmark |
Response Body
{
"conversation_id": "01930f4a-...",
"is_favourite": true,
"status": "success"
}2. Conversations
Description
Remove the favourite mark from a conversation.
Response 200
Endpoint Path
/api/v1/conversations/{conversation_id}/unfavouriteResponse Body
{
"conversation_id": "01930f4a-...",
"is_favourite": false,
"status": "success"
}3. Feedback (User-Facing)
Description
Submit a thumbs-up or thumbs-down rating for a specific assistant message.
Path parameters
Request body
message_indexmust point to an assistant message. Indexing into a user message returns400.
Response 200
Response fields
Errors
Feedback can only be submitted once per message. There is no update or delete endpoint.
Endpoint Path
/api/v1/conversations/{conversation_id}/feedbackParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `conversation_id` | string | Optional | The conversation containing the message to rate |
| `feedback_reaction` | string | Required | `"thumbs_up"` or `"thumbs_down"` |
| `feedback_text` | string | Optional | Optional comment, max 1000 chars. Send `null` or omit to leave empty |
| `message_index` | integer | Required | Zero-based index of the **assistant** message in the conversation |
| `feedback_id` | string | Optional | Unique ID — format: `{conversation_id}#{message_index}#{uuid}` |
| `feedback.reaction` | string | Optional | `"thumbs_up"` or `"thumbs_down"` |
| `feedback.feedback_text` | string \ | Optional | null |
| `feedback.submitted_at` | string | Optional | ISO 8601 UTC timestamp |
| `feedback.submitted_by` | string | Optional | Email of the submitting user |
Request Body
{
"feedback_reaction": "thumbs_up",
"feedback_text": "Very accurate.",
"message_index": 1
}Response Body
{
"success": true,
"message": "Feedback submitted successfully",
"conversation_id": "01930f4a-...",
"feedback_id": "01930f4a-...#1#0698639b-...",
"feedback": {
"reaction": "thumbs_up",
"feedback_text": "Very accurate.",
"submitted_at": "2026-04-15T10:30:00.000000+00:00",
"message_index": 1,
"submitted_by": "alice@example.com",
"client_id": "100002"
}
}Manage per-client datasource configurations. Requires CLIENT_HUB auth.
4. Config — Datasources
Description
Return the full configuration for the authenticated client, including all platforms, KPIs, budgets, and governance settings.
Response 200
Endpoint Path
/api/v1/deepsearch/configResponse Body
{
"platforms": [
{
"platformKey": "on_prem_mysql",
"selectedTables": ["transactions", "merchants"],
"columns": {
"transactions": ["id", "amount", "status", "created_at"],
"merchants": ["id", "name", "mcc_code"]
},
"kpis": [
{
"name": "Approval Rate",
"formula": "approved / total",
"query": "SELECT COUNT(*) FILTER (WHERE status='approved') / COUNT(*)::float FROM transactions"
}
],
"piiClassification": {
"transactions.card_number": { "contains_PII": true, "PII_Type": "Credit Card Number" }
},
"ssasMetadata": null
}
],
"budgets": [
{
"id": "uuid",
"name": "Monthly Cap",
"amount": 50000.00,
"currency": "USD",
"period": "monthly"
}
],
"governance": {},
"updatedAt": "2026-04-15T10:30:00.000000+00:00"
}4. Config — Datasources
Description
Return the config for a single platform.
Path parameters
Response 200 — same shape as a single item in the platforms array above, plus a top-level updatedAt field.
Errors: 404 if the platform is not configured for this client.
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `platform` | string | Optional | Platform key e.g. `on_prem_mysql`, `snowflake`, `azure_sql` |
4. Config — Datasources
Description
Remove a datasource and all its metadata (tables, columns, KPIs, PII classifications) from the client's config.
Response 200
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}Response Body
{ "success": true, "message": "Datasource 'on_prem_mysql' removed" }4. Config — Datasources
Description
Update connection credentials for an existing datasource. Credentials are KMS-encrypted at rest.
Request body — platform-specific credential fields, e.g.:
Response 200
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}Request Body
{
"host": "db.internal",
"port": 3306,
"username": "deepsearch_user",
"password": "new-password"
}Response Body
{ "success": true, "message": "Datasource 'on_prem_mysql' updated" }4. Config — Datasources
Description
Add or remove tables and columns from an already-connected platform without resetting credentials.
Request body
All fields are optional — omit what you don't need.
Response 200
Errors: 400 if addColumns references a table not in selectedTables.
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}/schemaParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `addTables` | string[] | Optional | Tables to add to `selectedTables` |
| `removeTables` | string[] | Optional | Tables to remove (also drops their column entries) |
| `addColumns` | object | Optional | `{ "table": ["col1", "col2"] }` — table must already be in `selectedTables` |
| `removeColumns` | object | Optional | `{ "table": ["col_to_drop"] }` |
Request Body
{
"addTables": ["refunds"],
"removeTables": ["legacy_log"],
"addColumns": {
"refunds": ["id", "amount", "reason"]
},
"removeColumns": {
"transactions": ["internal_flag"]
}
}Response Body
{
"success": true,
"platform": "on_prem_mysql",
"schema": {
"selectedTables": ["transactions", "merchants", "refunds"],
"columns": {
"transactions": ["id", "amount", "status"],
"merchants": ["id", "name"],
"refunds": ["id", "amount", "reason"]
}
}
}KPIs are stored per-platform under the client's config. Requires CLIENT_HUB auth.
5. Config — KPIs
Description
Add a new KPI to a platform.
Path parameters
Request body
Response 200
Errors: 404 if the platform is not found. 409 if a KPI with the same name already exists.
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}/kpiParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `platform` | string | Optional | Platform key |
Request Body
{
"name": "Decline Rate",
"formula": "declined / total",
"query": "SELECT COUNT(*) FILTER (WHERE status='declined') / COUNT(*)::float FROM transactions",
"description": "Fraction of transactions declined"
}Response Body
{
"success": true,
"message": "KPI 'Decline Rate' added",
"kpi": {
"name": "Decline Rate",
"formula": "declined / total",
"query": "SELECT ...",
"description": "Fraction of transactions declined"
}
}5. Config — KPIs
Description
Update an existing KPI by name.
Path parameters
Request body — any subset of KPI fields to overwrite:
Response 200
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}/kpi/{kpi_name}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `platform` | string | Optional | Platform key |
| `kpi_name` | string | Optional | Exact KPI name (URL-encode spaces) |
Request Body
{ "query": "SELECT ...", "description": "Updated description" }Response Body
{
"success": true,
"message": "KPI 'Decline Rate' updated",
"kpi": { "name": "Decline Rate", "query": "SELECT ...", "description": "Updated description" }
}5. Config — KPIs
Description
Delete a KPI by name.
Response 200
Endpoint Path
/api/v1/deepsearch/config/datasource/{platform}/kpi/{kpi_name}Response Body
{ "success": true, "message": "KPI 'Decline Rate' deleted" }Budget entries are stored at the client level, not per-platform. Requires CLIENT_HUB auth.
6. Config — Budgets
Description
Add a budget entry.
Request body
Response 200
Endpoint Path
/api/v1/deepsearch/config/budgetParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | string | Required | Display name |
| `amount` | float | Required | Budget amount |
| `currency` | string | Optional | Default `"USD"` |
| `period` | string | Required | e.g. `"monthly"`, `"quarterly"`, `"annual"` |
Request Body
{
"name": "Monthly Spend Cap",
"amount": 50000.00,
"currency": "USD",
"period": "monthly"
}Response Body
{
"success": true,
"message": "Budget added",
"budget": { "id": "uuid", "name": "Monthly Spend Cap", "amount": 50000.0, "currency": "USD", "period": "monthly" }
}6. Config — Budgets
Description
Update an existing budget. This is a full replacement, not a merge.
Path parameters
Request body — same shape as the create request.
Response 200
Endpoint Path
/api/v1/deepsearch/config/budget/{budget_id}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `budget_id` | string | Optional | UUID of the budget to update |
Response Body
{
"success": true,
"message": "Budget updated",
"budget": { "id": "uuid", "name": "Monthly Spend Cap", "amount": 60000.0, "currency": "USD", "period": "monthly" }
}6. Config — Budgets
Description
Delete a budget entry.
Response 200
Endpoint Path
/api/v1/deepsearch/config/budget/{budget_id}Response Body
{ "success": true, "message": "Budget deleted" }The onboarding flow is sequential: environment → test-connection → list-databases → list-tables → analyze-pii → analyze-kpis → complete. Requires CLIENT_HUB auth.
7. Onboarding
Description
Save business environment metadata (step 1).
Request body
Response 200
Endpoint Path
/api/v1/deepsearch/onboarding/environmentRequest Body
{
"environmentName": "Production",
"businessEntity": "Acme Corp",
"environmentType": "production",
"timeZone": "America/New_York",
"description": "Main production database"
}Response Body
{
"success": true,
"message": "Environment information saved successfully",
"data": {
"environmentName": "Production",
"businessEntity": "Acme Corp",
"environmentType": "production",
"timeZone": "America/New_York",
"description": "Main production database"
}
}7. Onboarding
Description
Validate database credentials for a given platform. On success, credentials are KMS-encrypted and stored (step 2).
Request body — fields used depend on platform:
Supported platforms and required fields:
Response 200
Errors: 400 with a descriptive message if the connection cannot be established or required fields are missing.
Endpoint Path
/api/v1/deepsearch/onboarding/test-connectionRequest Body
{
"platform": "on_prem_mysql",
"host": "db.internal",
"port": 3306,
"username": "deepsearch",
"password": "secret"
}Response Body
{
"success": true,
"message": "Connection successful",
"data": { "connectionValidated": true, "testedAt": "2026-04-15T10:30:00Z" }
}7. Onboarding
Description
Retrieve the table listing for the currently configured platform. Currently supported for Azure SQL and BigQuery only.
Response 200
Endpoint Path
/api/v1/deepsearch/onboarding/schemaResponse Body
{
"success": true,
"message": "Schema details loaded successfully",
"data": {
"platform": "azure_sql",
"schemas": [
{
"schema": "PaymentsDB",
"tables": [
{
"tableName": "transactions",
"rowCount": 5000000,
"columnCount": 12,
"primaryKeys": ["id"],
"foreignKeys": [],
"hasPII": false
}
]
}
]
}
}7. Onboarding
Description
List available databases/datasets for a connected platform (step 3).
Request body
Response 200
Endpoint Path
/api/v1/deepsearch/onboarding/list-databasesRequest Body
{ "platform": "on_prem_mysql" }Response Body
{
"success": true,
"message": "Found 3 dataset(s)",
"data": { "databases": ["payments", "analytics", "reporting"] }
}7. Onboarding
Description
List tables within a specific database (step 4).
Request body
Response 200
Endpoint Path
/api/v1/deepsearch/onboarding/list-tablesParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `platform` | string | Required | Platform key |
| `database` | string | Required | Database/dataset name returned by `list-databases` |
| `snowflakeSchema` | string | Optional | Snowflake schema name (Snowflake only) |
Request Body
{
"platform": "on_prem_mysql",
"database": "payments",
"snowflakeSchema": null
}Response Body
{
"success": true,
"message": "Found 8 table(s)",
"data": {
"database": "payments",
"tables": [
{
"table": "transactions",
"fullName": "payments.transactions",
"schema_name": "payments",
"rowCount": 5000000,
"primaryKey": ["id"],
"columns": [
{ "name": "id", "type": "bigint", "isPrimaryKey": true, "isNullable": false },
{ "name": "amount", "type": "decimal", "isPrimaryKey": false, "isNullable": false }
]
}
]
}
}7. Onboarding
Description
Analyze selected tables for PII columns using Claude AI. Returns a Server-Sent Events (SSE) stream (step 5).
Request body
SSE event stream
Consume with EventSource or fetch + ReadableStream. Each event follows the SSE format:
event: <event_type>
data: <json_payload>
Each column in a table_complete event is enriched with PII analysis fields:
Endpoint Path
/api/v1/deepsearch/onboarding/analyze-piiRequest Body
{
"name": "card_number",
"type": "varchar",
"contains_PII": true,
"Confidence_Score": 0.98,
"PII_Type": "Credit Card Number",
"Reasoning": "Column name 'card_number' strongly indicates payment card data."
}7. Onboarding
Description
Generate KPI suggestions for a set of tables using Claude AI (step 6).
Request body
Supported platform values: on_prem_mysql, on_prem_postgres, snowflake, on_prem_sql_server, bigquery, azure_sql, aws_aurora_postgres, fabric
Response 200
Endpoint Path
/api/v1/deepsearch/onboarding/analyze-kpisRequest Body
{
"platform": "on_prem_mysql",
"tableDetails": [
{
"tableName": "transactions",
"columns": ["id", "amount", "status", "created_at"]
}
]
}Response Body
{
"domains": [
{
"domain": "Transaction Performance",
"kpis": [
{
"name": "Approval Rate",
"description": "Percentage of transactions approved",
"formula": "approved_count / total_count",
"query": "SELECT COUNT(*) FILTER (WHERE status='approved') / COUNT(*)::float AS approval_rate FROM transactions"
}
]
}
]
}7. Onboarding
Description
Edit or create a KPI based on natural language instructions. Returns an SSE stream.
Request body
Set original_kpi to null to create a brand-new KPI from scratch.
SSE events
Endpoint Path
/api/v1/deepsearch/onboarding/kpi/editRequest Body
{
"original_kpi": {
"name": "Approval Rate",
"formula": "approved / total",
"query": "SELECT ..."
},
"instruction": {
"query": "Break this down by merchant category",
"selected_columns": ["transactions.mcc_code", "transactions.status", "transactions.id"]
}
}7. Onboarding
Description
Mark onboarding as complete for a platform. Saves the final schema, KPIs, PII classifications, budgets, and governance config (step 7).
Request body
Response 200
Endpoint Path
/api/v1/deepsearch/onboarding/completeRequest Body
{
"platformKey": "on_prem_mysql",
"selectedTables": ["transactions", "merchants"],
"selectedColumns": {
"transactions": ["id", "amount", "status", "created_at"],
"merchants": ["id", "name", "mcc_code"]
},
"piiClassification": {
"transactions.pan": { "contains_PII": true, "PII_Type": "Credit Card Number" }
},
"kpis": [
{
"name": "Approval Rate",
"formula": "approved / total",
"query": "SELECT COUNT(*) FILTER (WHERE status='approved') / COUNT(*)::float FROM transactions"
}
],
"budgets": [],
"governance": {},
"ssasMetadata": null
}Response Body
{
"success": true,
"platformKey": "on_prem_mysql",
"updatedAt": "2026-04-15T10:30:00.000000+00:00"
}Endpoints for React Flow schema diagrams. Requires CLIENT_HUB auth.
8. Schema Visualization
Description
Return a static demo React Flow graph (hardcoded sample schema for UI prototyping).
Response 200
Endpoint Path
/schema/flowResponse Body
{
"nodes": [
{
"id": "users",
"type": "tableNode",
"position": { "x": 50, "y": 200 },
"data": {
"label": "users",
"columns": [
{ "name": "id", "type": "UUID", "pk": true, "fk": null, "nullable": false },
{ "name": "email", "type": "VARCHAR(255)", "pk": false, "fk": null, "nullable": false }
]
}
}
],
"edges": [
{
"id": "e1",
"source": "orders",
"target": "users",
"sourceHandle": "user_id",
"targetHandle": "id",
"type": "smoothstep",
"animated": false,
"label": "user_id → users.id",
"markerEnd": { "type": "ArrowClosed" }
}
]
}8. Schema Visualization
Description
Use Claude AI to infer relationships between a set of user-provided tables and return a React Flow graph.
Request body
Response 200
Errors: 400 if no tables are provided. 502 if Claude returns invalid JSON.
Endpoint Path
/schema/analyzeRequest Body
{
"selectedTables": [
{
"table": "transactions",
"fullName": "payments.transactions",
"db_schema": "payments",
"primaryKey": ["id"],
"columns": [
{ "name": "id", "type": "bigint" },
{ "name": "merchant_id", "type": "bigint" }
]
},
{
"table": "merchants",
"fullName": "payments.merchants",
"db_schema": "payments",
"primaryKey": ["id"],
"columns": [
{ "name": "id", "type": "bigint" },
{ "name": "name", "type": "varchar" }
]
}
]
}Response Body
{
"flow": {
"nodes": [ { "id": "transactions", "type": "tableNode", "position": { "x": 60, "y": 60 }, "data": { "label": "transactions", "columns": [] } } ],
"edges": [ { "id": "e0", "source": "transactions", "target": "merchants", "sourceHandle": "merchant_id", "targetHandle": "id", "type": "smoothstep", "label": "many-to-one" } ]
},
"relationships": [
{
"from_table": "transactions",
"from_column": "merchant_id",
"to_table": "merchants",
"to_column": "id",
"type": "many-to-one"
}
],
"views": []
}All benchmarking endpoints require CLIENT_HUB auth.
9. Benchmarking
Description
Return all active benchmark metrics. Use metric_key as the parameter value in the other benchmark endpoints.
No query parameters.
Response 200
Endpoint Path
/api/v1/deepsearch/benchmark/metricsResponse Body
{
"metrics": [
{
"metric_key": "approval_rate",
"display_name": "Approval Rate",
"description": "Fraction of transactions that were approved",
"unit": "ratio"
},
{
"metric_key": "variance_to_average",
"display_name": "Variance to Average",
"description": "Statistical variance of daily approval-rate outcomes from their within-day mean",
"unit": "ratio"
}
]
}9. Benchmarking
Description
Return the client's own metric value for the most recent (or a specific) snapshot date, alongside anonymised industry percentile bands.
Query parameters
Response 200 — opted in, data available
percentile_position values
client_value and industry_bands are ratios (0–1). Multiply by 100 to display as percentages where unit = "ratio".
Response 200 — not opted in
Response 200 — opted in but cohort too small
Error — unknown metric
Endpoint Path
/api/v1/deepsearch/benchmark/industry-positionParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `metric_key` | string | Required | `approval_rate` or `variance_to_average` |
| `date` | string | Optional | ISO date `YYYY-MM-DD`. Omit to use the most recent available snapshot |
Response Body
{ "detail": "Unknown metric_key 'xyz'. Available: approval_rate, variance_to_average." }9. Benchmarking
Description
Return a rolling time-series of the client's daily value alongside industry p50 and p75 bands. Only dates where both the client has data and a snapshot exists are returned.
Query parameters
Response 200
data_points is ordered ascending by date and may contain gaps.
Response 200 — not opted in
Endpoint Path
/api/v1/deepsearch/benchmark/trendsParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `metric_key` | string | Required | `approval_rate` or `variance_to_average` |
| `days` | string | Optional | Look-back window in days, max `90` |
Response Body
{ "metric_key": "approval_rate", "opted_in": false, "data_points": [] }9. Benchmarking
Description
Opt the client in (or out) of benchmarking and set their industry profile. Safe to call repeatedly — it upserts.
Request body
Response 200
Error — invalid industry_category
Benchmarking rate limits
Endpoint Path
/api/v1/deepsearch/benchmark/opt-inParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `mcc_code` | string | Optional | 4-digit Merchant Category Code |
| `industry_category` | string | Optional | `FINTECH`, `ECOMMERCE`, `RETAIL`, `TRAVEL`, `HEALTHCARE`, `EDUCATION`, `OTHER` |
| `opted_into_benchmark` | boolean | Optional | `true` to opt in, `false` to opt out |
Request Body
{
"mcc_code": "6012",
"industry_category": "FINTECH",
"opted_into_benchmark": true
}Response Body
{ "detail": "Invalid industry_category 'GAMING'. Must be one of: FINTECH, ECOMMERCE, ..." }10. Monitoring
Description
Returns system health status. No authentication required. Used by load balancer health checks.
Response 200
status is "healthy" when all four dependencies report connected/reachable; otherwise "degraded".
Dependency fields
Endpoint Path
/healthParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `redis` | string | Optional | |
| `postgres` | string | Optional | |
| `dynamodb` | string | Optional | |
| `anthropic` | string | Optional |
Response Body
{
"status": "healthy",
"version": "1.4.2",
"model": "claude-sonnet-4-6",
"active_ws": 3,
"connections": [
{
"user_email": "alice@example.com",
"client_id": "100002",
"platform": "on_prem_mysql",
"conversation_id": "01930f4a-...",
"idle_seconds": 12,
"duration_seconds": 145
}
],
"redis": { "status": "connected", "latency_ms": 1 },
"postgres": { "status": "connected", "latency_ms": 4 },
"dynamodb": { "status": "connected", "latency_ms": 18 },
"anthropic": { "status": "reachable", "latency_ms": 42 }
}All routes are protected by Redis-backed rate limiting. Exceeded limits return HTTP 429:
The WebSocket endpoint returns { "type": "error", "code": "RATE_LIMITED", "message": "..." } instead of an HTTP response.
Benchmarking-specific limits:
| Route | Limit |
|---|---|
GET /api/v1/deepsearch/benchmark/trends | 20 requests / 60 s per user |
All other /benchmark/ routes | 60 requests / 60 s per user |