API reference

Pi DeepSearch

Conversational analytics and data exploration API.

Base URL

https://api.deepsearch.io/v1

Endpoints

45 documented routes

Authentication

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.

Common Error Responses

StatusMeaning
400 Bad RequestValidation failure — see detail field
401 UnauthorizedMissing, expired, or invalid token
403 ForbiddenToken valid but insufficient permissions
404 Not FoundResource does not exist
409 ConflictDuplicate resource or state conflict
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorUnexpected server-side error — retry with backoff

Error body:

Endpoint Groups

GroupPrefixAuth pool
WebSocket Chatwss://…/api/v1/chatCLIENT_HUB
Conversations/api/v1/conversationsCLIENT_HUB
Feedback (user)/api/v1/conversations/{id}/feedbackCLIENT_HUB
Config — Datasources/api/v1/deepsearch/configCLIENT_HUB
Config — KPIs/api/v1/deepsearch/config/datasource/{platform}/kpiCLIENT_HUB
Config — Budgets/api/v1/deepsearch/config/budgetCLIENT_HUB
Onboarding/api/v1/deepsearch/onboardingCLIENT_HUB
Schema Visualization/schema/flow, /schema/analyzeCLIENT_HUB
Benchmarking/api/v1/deepsearch/benchmarkCLIENT_HUB
Monitoring/healthNone

1. WebSocket Chat

Endpoint: wss://ds-api-dev.payintelli.com/api/v1/chat

All messages in both directions are JSON.

Connection

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]
);

Sending a Message

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
}));

Event Flow

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", ... }

Server Events Reference

1. WebSocket Chat

Description

title in stream_end is 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.

Chart Data Event

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).

Adaptive Card Event

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).

Restoring Visuals from Conversation History

GET

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}/history

Error Codes

1. WebSocket Chat

Description

All errors arrive as { type: "error", code: "...", message: "..." }.

Important: AI_TIMEOUT does not close the WebSocket connection. Do not reconnect — just let the user resend. Reconnecting creates a new session and loses conversation context.

Connection Lifecycle

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);
});

Conversation Cap

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.

Content Moderation

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.


2. Conversations

All endpoints require CLIENT_HUB auth. Conversations are scoped to the authenticated user — cross-user access returns 403.

Conversations

GET

2. Conversations

Description

List all conversations for the authenticated user, sorted by most recently updated.

Response 200


Endpoint Path

/api/v1/conversations

Response 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"
}

Conversations History

GET

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}/history

Parameters

ParameterTypeRequiredDescription
`conversation_id`stringOptionalUUID 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"
      }
    }
  ]
}

Conversations Rename Title

GET

2. Conversations

Description

Rename a conversation.

Path parameters

Query parameters

Response 200


Endpoint Path

/api/v1/conversations/{conversation_id}/rename/title

Parameters

ParameterTypeRequiredDescription
`conversation_id`stringOptionalUUID of the conversation
`new_title`stringRequiredNew title, 1–200 characters

Response Body

{
  "conversation_id": "01930f4a-...",
  "conversation_title": "Monthly Revenue Deep Dive",
  "client_id": "100002",
  "status": "success"
}

Conversations Delete

GET

2. Conversations

Description

Permanently delete a conversation and all its messages.

Path parameters

Response 200


Endpoint Path

/api/v1/conversations/{conversation_id}

Parameters

ParameterTypeRequiredDescription
`conversation_id`stringOptionalUUID of the conversation

Response Body

{
  "success": true,
  "conversation_id": "01930f4a-...",
  "client_id": "100002",
  "message": "Conversation deleted successfully"
}

Conversations Favourite

GET

2. Conversations

Description

Mark a conversation as a favourite.

Query parameters

Response 200


Endpoint Path

/api/v1/conversations/{conversation_id}/favourite

Parameters

ParameterTypeRequiredDescription
`is_favourite`booleanRequired`true` to mark, `false` to unmark

Response Body

{
  "conversation_id": "01930f4a-...",
  "is_favourite": true,
  "status": "success"
}

Conversations Unfavourite

GET

2. Conversations

Description

Remove the favourite mark from a conversation.

Response 200


Endpoint Path

/api/v1/conversations/{conversation_id}/unfavourite

Response Body

{
  "conversation_id": "01930f4a-...",
  "is_favourite": false,
  "status": "success"
}

3. Feedback (User-Facing)

Conversations Feedback

GET

3. Feedback (User-Facing)

Description

Submit a thumbs-up or thumbs-down rating for a specific assistant message.

Path parameters

Request body

message_index must point to an assistant message. Indexing into a user message returns 400.

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}/feedback

Parameters

ParameterTypeRequiredDescription
`conversation_id`stringOptionalThe conversation containing the message to rate
`feedback_reaction`stringRequired`"thumbs_up"` or `"thumbs_down"`
`feedback_text`stringOptionalOptional comment, max 1000 chars. Send `null` or omit to leave empty
`message_index`integerRequiredZero-based index of the **assistant** message in the conversation
`feedback_id`stringOptionalUnique ID — format: `{conversation_id}#{message_index}#{uuid}`
`feedback.reaction`stringOptional`"thumbs_up"` or `"thumbs_down"`
`feedback.feedback_text`string \Optionalnull
`feedback.submitted_at`stringOptionalISO 8601 UTC timestamp
`feedback.submitted_by`stringOptionalEmail 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"
  }
}

4. Config — Datasources

Manage per-client datasource configurations. Requires CLIENT_HUB auth.

Deepsearch Config

GET

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/config

Response 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"
}

Deepsearch Config Datasource

GET

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

ParameterTypeRequiredDescription
`platform`stringOptionalPlatform key e.g. `on_prem_mysql`, `snowflake`, `azure_sql`

Deepsearch Config Datasource Delete

GET

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" }

Deepsearch Config Datasource Update

GET

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" }

Deepsearch Config Datasource Schema

GET

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}/schema

Parameters

ParameterTypeRequiredDescription
`addTables`string[]OptionalTables to add to `selectedTables`
`removeTables`string[]OptionalTables to remove (also drops their column entries)
`addColumns`objectOptional`{ "table": ["col1", "col2"] }` — table must already be in `selectedTables`
`removeColumns`objectOptional`{ "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"]
    }
  }
}

5. Config — KPIs

KPIs are stored per-platform under the client's config. Requires CLIENT_HUB auth.

Deepsearch Config Datasource Kpi

GET

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}/kpi

Parameters

ParameterTypeRequiredDescription
`platform`stringOptionalPlatform 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"
  }
}

Deepsearch Config Datasource Kpi Update

GET

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

ParameterTypeRequiredDescription
`platform`stringOptionalPlatform key
`kpi_name`stringOptionalExact 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" }
}

Deepsearch Config Datasource Kpi Delete

GET

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" }

6. Config — Budgets

Budget entries are stored at the client level, not per-platform. Requires CLIENT_HUB auth.

Deepsearch Config Budget

GET

6. Config — Budgets

Description

Add a budget entry.

Request body

Response 200


Endpoint Path

/api/v1/deepsearch/config/budget

Parameters

ParameterTypeRequiredDescription
`name`stringRequiredDisplay name
`amount`floatRequiredBudget amount
`currency`stringOptionalDefault `"USD"`
`period`stringRequirede.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" }
}

Deepsearch Config Budget Update

GET

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

ParameterTypeRequiredDescription
`budget_id`stringOptionalUUID 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" }
}

Deepsearch Config Budget Delete

GET

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" }

7. Onboarding

The onboarding flow is sequential: environmenttest-connectionlist-databaseslist-tablesanalyze-piianalyze-kpiscomplete. Requires CLIENT_HUB auth.

Deepsearch Onboarding Environment

GET

7. Onboarding

Description

Save business environment metadata (step 1).

Request body

Response 200


Endpoint Path

/api/v1/deepsearch/onboarding/environment

Request 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"
  }
}

Deepsearch Onboarding Test Connection

GET

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-connection

Request 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" }
}

Deepsearch Onboarding Schema

GET

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/schema

Response 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
          }
        ]
      }
    ]
  }
}

Deepsearch Onboarding List Databases

GET

7. Onboarding

Description

List available databases/datasets for a connected platform (step 3).

Request body

Response 200


Endpoint Path

/api/v1/deepsearch/onboarding/list-databases

Request Body

{ "platform": "on_prem_mysql" }

Response Body

{
  "success": true,
  "message": "Found 3 dataset(s)",
  "data": { "databases": ["payments", "analytics", "reporting"] }
}

Deepsearch Onboarding List Tables

GET

7. Onboarding

Description

List tables within a specific database (step 4).

Request body

Response 200


Endpoint Path

/api/v1/deepsearch/onboarding/list-tables

Parameters

ParameterTypeRequiredDescription
`platform`stringRequiredPlatform key
`database`stringRequiredDatabase/dataset name returned by `list-databases`
`snowflakeSchema`stringOptionalSnowflake 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 }
        ]
      }
    ]
  }
}

Deepsearch Onboarding Analyze Pii

GET

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-pii

Request 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."
}

Deepsearch Onboarding Analyze Kpis

GET

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-kpis

Request 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"
        }
      ]
    }
  ]
}

Deepsearch Onboarding Kpi Edit

GET

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/edit

Request 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"]
  }
}

Deepsearch Onboarding Complete

GET

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/complete

Request 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"
}

8. Schema Visualization

Endpoints for React Flow schema diagrams. Requires CLIENT_HUB auth.

Schema Flow

GET

8. Schema Visualization

Description

Return a static demo React Flow graph (hardcoded sample schema for UI prototyping).

Response 200


Endpoint Path

/schema/flow

Response 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" }
    }
  ]
}

Schema Analyze

GET

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/analyze

Request 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": []
}

9. Benchmarking

All benchmarking endpoints require CLIENT_HUB auth.

Deepsearch Benchmark Metrics

GET

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/metrics

Response 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"
    }
  ]
}

Deepsearch Benchmark Industry Position

GET

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-position

Parameters

ParameterTypeRequiredDescription
`metric_key`stringRequired`approval_rate` or `variance_to_average`
`date`stringOptionalISO 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." }

Deepsearch Benchmark Opt In

GET

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-in

Parameters

ParameterTypeRequiredDescription
`mcc_code`stringOptional4-digit Merchant Category Code
`industry_category`stringOptional`FINTECH`, `ECOMMERCE`, `RETAIL`, `TRAVEL`, `HEALTHCARE`, `EDUCATION`, `OTHER`
`opted_into_benchmark`booleanOptional`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

Health

GET

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

/health

Parameters

ParameterTypeRequiredDescription
`redis`stringOptional
`postgres`stringOptional
`dynamodb`stringOptional
`anthropic`stringOptional

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 }
}

Rate Limits

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:

RouteLimit
GET /api/v1/deepsearch/benchmark/trends20 requests / 60 s per user
All other /benchmark/ routes60 requests / 60 s per user