Diwo Catalyst — Partner API
REST interface for external partners to integrate with Catalyst without the browser UI.
Overview
The Catalyst backend exposes one partner-facing entry point: a non-streaming Chat endpoint that runs the full Catalyst agent pipeline (LLM routing, SQL generation against your configured use case, visualization card assembly) and returns a single JSON payload containing all response cards.
Everything else in the product — onboarding your use case, uploading schemas and documents, managing cases, threads, recommendations, decision flows, and executive summaries — is currently only reachable through the Catalyst web UI. If your integration needs any of those surfaces, see Not yet exposed and reach out; we prioritise based on partner demand.
The Chat endpoint is sufficient for the most common partner use case: "our product asks a question, Catalyst answers it." Configure a use case once via the UI, then call /chat with natural-language prompts against that use case.
Base URLs
| Environment | Base URL |
|---|---|
| Staging | https://catalyst-dev.getdiwo.ai |
| Production | Issued per partner on request |
All API paths below are prefixed with /api/copilot.
Authentication
We use an API Key → short-lived JWT flow. This is the same two-step pattern used by AWS STS, Google Cloud, and GitHub Apps: you hold a long-lived secret, exchange it for a 30-minute token, and send the token with every business call. The long-lived secret stays off the wire except during token issuance.
Credentials you receive from us
| Item | Description |
|---|---|
API_SECRET_KEY |
Your pre-shared API key. Treat as a credential: store in a secret manager, never commit to source. |
Each partner receives their own API_SECRET_KEY. If you suspect compromise, contact us and we will rotate it. Rotation currently invalidates the key immediately; overlapping keys are on the roadmap.
Exchange the API key for a token
POST/api/copilot/auth/token
POST /api/copilot/auth/token
Host: catalyst-dev.getdiwo.ai
X-API-Key: your-api-secret-key
Success (200):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 1800
}
Token algorithm is HS256. Default lifetime is 1800 seconds (30 minutes). expires_in is authoritative — do not hardcode 30 minutes.
Errors:
| Status | Meaning |
|---|---|
| 401 | Missing or invalid X-API-Key |
| 503 | Server has no API_SECRET_KEY configured (infrastructure issue — contact us) |
Use the token on business calls
Authorization: Bearer <access_token>
The token is stateless and verified by signature + expiry; no database lookup is performed. Refresh by re-calling /auth/token before the current token expires. We recommend refreshing at 80% of expires_in elapsed.
The Chat endpoint
POST/api/copilot/chat
POST /api/copilot/chat
Host: catalyst-dev.getdiwo.ai
Authorization: Bearer <access_token>
Content-Type: application/json
Request body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
message | string | Yes | — | The user's question or prompt. |
usecase_id | string | Yes | — | The use case the question runs against. Configured by us during onboarding. |
thread_id | string | No | auto UUID | Pass a thread_id returned from a previous call to continue the conversation. Omit for a new one. |
isNewThread | boolean | No | false | Set true explicitly when starting a new thread with a fresh message. |
mode_id | integer | No | 1 | 1 = regular, 2 = observability, 7 = analyst. Most partners use 1. |
query_type | string | No | "" | "" lets the router decide. "doc" forces a document-grounded answer, "sql" forces a SQL path. |
is_regenerate | boolean | No | null | Set true to regenerate the most recent response in a thread. |
message_id | string | No | auto UUID | Supply your own client-side ID if you want round-trip correlation. |
alert_id | integer | No | null | Used when the message originates from a recommendation alert. |
decision_flow_id | integer | No | null | Used when the message is a step in a predefined decision flow. |
Success response (200)
{
"status": "SUCCESS",
"thread_id": "550e8400-e29b-41d4-a716-446655440000",
"message_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"created_date": "2026-04-24 14:05:12",
"cards": [
{ "type": "text", "data": "Top 5 products by revenue ..." },
{ "type": "table", "data": { "columns": [...], "rows": [...] } },
{ "type": "visualization", "data": { /* chart spec */ } }
]
}
Cards is an ordered array. One card per type — if the pipeline emits multiple versions of the same card type during streaming, only the final version is returned. Common types include text, table, visualization, sql, insights, and followup.
Error responses
| Status | Body shape | Condition |
|---|---|---|
| 401 | {"error": "Missing or invalid Authorization header..."} | Header missing or malformed |
| 401 | {"error": "Token has expired"} | Call /auth/token again |
| 401 | {"error": "Invalid token"} | Signature verification failed |
| 429 | {"error": "Rate limit exceeded..."} | See Rate limits |
| 500 | {"status": "FAILURE", "error": "...", "thread_id": "...", "message_id": "..."} | Agent pipeline error — safe to retry |
| 500 | {"status": "FAILURE", "error": "...", "cards": [<error_card>]} | Unhandled server error — contact us with the message_id |
Timeouts
Rate limits
| Scope | Limit | Window |
|---|---|---|
| Per-key | Configured per partner | Configured per partner |
Limits are enforced per API key. When exceeded, you receive a 429 with the server's current window reset hint in the body. Exponential backoff starting at 2 seconds is recommended. Your provisioned limits are shared at onboarding.
/chat call. Bursty or unbounded retry loops can exhaust your partner quota and degrade service for your production users. Implement a client-side circuit breaker.
End-to-end example
The following bash snippet exchanges an API key for a token, starts a new thread, and sends a follow-up message on the same thread.
BASE_URL="https://catalyst-dev.getdiwo.ai"
# 1. Obtain a token
TOKEN=$(curl -sf -X POST "$BASE_URL/api/copilot/auth/token" \
-H "X-API-Key: $API_SECRET_KEY" | jq -r '.access_token')
# 2. Start a new thread
RESP=$(curl -sf -X POST "$BASE_URL/api/copilot/chat" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Top 5 products by revenue last quarter",
"usecase_id": "'"$USECASE_ID"'",
"isNewThread": true
}')
THREAD_ID=$(jq -r '.thread_id' <<<"$RESP")
jq '.cards' <<<"$RESP"
# 3. Follow-up turn on the same thread
curl -sf -X POST "$BASE_URL/api/copilot/chat" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Now chart that as a bar graph",
"usecase_id": "'"$USECASE_ID"'",
"thread_id": "'"$THREAD_ID"'"
}' | jq '.cards'
Python (requests) and Node (axios) reference clients are available on request.
Not yet exposed to partners
The Catalyst backend has additional endpoints covering use-case lifecycle, schema validation, document upload, cases, notifications, recommendations, decision flows, executive summaries, and thread management. These are not currently accessible via API key; they require a browser session.
If your integration needs any of the following, tell us — we are prioritising API-exposure work based on partner demand:
- Use-case lifecycle (create/update/delete use cases, upload schemas)
- Document upload (add/replace/delete documents feeding a use case)
- Thread management (list, rename, delete, share threads)
- Cases (clip an answer into a saved case, add comments, share)
- Recommendations and landing metrics (read the homepage recommendation feed)
- Executive summaries (generate and fetch summary artefacts)
- Real-time streaming (WebSocket/Socket.IO streaming of
/chatresponses token-by-token; the current REST call blocks until the full answer is assembled)
Current limitations
Honest known limits so you can plan around them:
- Single-tenant identity. All JWT-authenticated calls currently run under a synthetic org inside Catalyst. That means (a) your API calls and your UI-based team may see different data scopes, and (b) if you operate multiple downstream customers against us, we cannot yet scope per-customer within a single API key.
- No per-client usage breakdown in-app. Usage reporting currently comes from API gateway logs. Ask us for a dashboard link.
- No OpenAPI spec published. This document is the contract. A machine-readable
openapi.yamlis on the roadmap. - No versioned URL path. The API is effectively
v1. Breaking changes will be announced with a 30-day notice to partners; non-breaking additions can land at any time. - No idempotency keys yet. Retrying a 5xx on
/chatmay cause the same message to be processed twice and counted against your quota twice. Keepmessage_idstable on retries so you can deduplicate on your side. - CORS is not set for HTTP endpoints. A browser-based partner client making direct cross-origin calls will be blocked. Proxy
/chatthrough your own backend.
Support, SLAs, changelog
- Support contact: connect@diwo.ai. Include your
message_idandthread_idin bug reports. - Status page: To be added.
- Changelog: notable API changes are posted in your partner Slack channel and emailed to the addresses on your agreement.
- SLA: per your bilateral agreement. Default staging SLA is best-effort; production is 99.5%.