Integration API
Every endpoint an integration key, an embed key, or no credential at all can reach — the set you build against.
These are the endpoints you can call from your own product. 12 of them take an sk_live_ integration key, an origin-locked embed_live_ key, or no credential at all, and a further 10 belong to Extract. Nothing on this page needs a dashboard login.
Everything your key opens
| Endpoint | Credential | What it does |
|---|---|---|
GET /v1/public/share/{slug} | Public | Bootstrap the hosted share page for a slug and mint a short-lived chat token. |
POST /v1/chat | Integration or embed key | Ask a question against a project's documents and get a grounded answer with citations. |
POST /v1/chat/stream | Integration or embed key | The same question, answered as a Server-Sent Events stream of tokens. |
POST /v1/chat/feedback | Integration key | Record a visitor's thumbs up or down on an assistant message. |
POST /v1/projects/{projectId}/conversations/{conversationId}/escalate | Integration key | Hand a public conversation to a human, over a webhook, an email, or both. |
POST /v1/projects/{projectId}/leads | Integration key | Record a lead captured by the widget's contact form. |
POST /v1/projects/{projectId}/tickets | Integration key | Create an escalation ticket from a conversation. |
GET /widget.js | Public | Embed widget bundle (301 to CDN when configured) |
GET /v1/widget/{projectId}/config | Public | Public display configuration for a project's chat widget. |
GET /health | Public | Liveness check |
GET /config | Public | Cognito pool/client IDs, API URL, Hosted UI domain prefix, SPA OAuth callback, and enabled socialProviders (Google, GitHub). Used by the dashboard and MCP clients to bootstrap auth. |
GET /dev/info | Public | Dev testing credentials, MCP login steps, and the live API route catalog. |
Chat
Ask questions against a project's documents, stream answers, and record feedback. The endpoints most integrations start and end with.
/v1/chat Ask a question against a project's documents and get a grounded answer with citations.
Auth Integration keyEmbed keyShare token Embed keys require a browser `Origin`; share tokens use `X-Oprag-Share-Token`
Path parameters
None.
Query parameters
None.Everything it needs is in the request body.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
question | string | Required | The visitor's question. Trimmed; an empty question is rejected with 400. |
sessionId | string | Optional | Groups turns into one conversation. Send back the value from the previous response to keep multi-turn context. |
conversationId | string | Optional | Server-assigned conversation identifier. Echo it back so the conversation stays one thread in the dashboard. |
visitorId | string | Optional | Stable identifier for the end user. Ties leads and escalations to the person who asked. |
Request
{
"question": "What is your refund policy?",
"sessionId": "sess_abc123",
"conversationId": "conv_abc123",
"visitorId": "visitor_abc123"
} Responses
200 Answer
The usual branch. type is answer and sources carries the passages it was grounded in.
{
"type": "answer",
"answer": "You can cancel any time from Account → Billing. Refunds are available within 30 days of purchase.",
"sessionId": "sess_abc123",
"conversationId": "conv_abc123",
"visitorId": "visitor_abc123",
"assistantMessageId": "msg_abc123",
"sources": [
{
"documentTitle": "Billing FAQ",
"excerpt": "Refunds are available within 30 days of purchase...",
"location": "billing-faq.pdf",
"pageNumber": 2,
"score": 0.89
}
],
"suggestedFollowUps": ["How long do refunds take?", "Can I pause my plan instead?"]
} 200 Lead capture prompt
Returned when smart lead capture is enabled and the documents cannot answer. There is no answer field on this branch — branch on type before reading it.
{
"type": "lead_capture_prompt",
"promptMessage": "I could not find that in the docs. Leave your email and someone will follow up.",
"fields": ["name", "email"],
"conversationId": "conv_abc123",
"visitorId": "visitor_abc123",
"sessionId": "sess_abc123"
} 200 Test key fixture
What an sk_test_ or embed_test_ key returns. It omits type — a legacy-shaped payload that clients treat as the answer branch.
{
"answer": "This is a test response from oprag. Your integration is working correctly. Replace this with a live key to get real answers from your documents.",
"sources": [],
"conversationId": "conv_abc123",
"sessionId": "sess_abc123"
} Status codes
curl
curl -X POST 'https://api.dev.oprag.ai/v1/chat' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"question": "What is your refund policy?","sessionId": "sess_abc123","conversationId": "conv_abc123","visitorId": "visitor_abc123"}' SDK equivalent `oprag.chat.ask()`
/v1/chat/stream The same question, answered as a Server-Sent Events stream of tokens.
Auth Integration keyEmbed keyShare token Same auth as `POST /v1/chat`
Path parameters
None.
Query parameters
None.Everything it needs is in the request body.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
question | string | Required | The visitor's question. Trimmed; an empty question is rejected with 400. |
sessionId | string | Optional | Groups turns into one conversation. Send back the value from the previous response to keep multi-turn context. |
conversationId | string | Optional | Server-assigned conversation identifier. Echo it back so the conversation stays one thread in the dashboard. |
visitorId | string | Optional | Stable identifier for the end user. Ties leads and escalations to the person who asked. |
Request
{
"question": "What is your refund policy?",
"sessionId": "sess_abc123",
"conversationId": "conv_abc123",
"visitorId": "visitor_abc123"
} Response
Status codes
curl
curl -X POST 'https://api.dev.oprag.ai/v1/chat/stream' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"question": "What is your refund policy?","sessionId": "sess_abc123","conversationId": "conv_abc123","visitorId": "visitor_abc123"}' SDK equivalent `oprag.chat.stream()`
/v1/chat/feedback Record a visitor's thumbs up or down on an assistant message.
Auth Integration key
Before you call it
messageIdis theassistantMessageIdfrom the answer being rated.visitorIdbecomes required once the conversation already has one.- Respects the widget's
feedbackEnabledsetting, which defaults to on, and is rate limited per IP.
Path parameters
None.
Query parameters
None.Everything it needs is in the request body.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string | Required | Conversation this relates to. |
messageId | string | Required | The assistantMessageId from the answer being rated. |
rating | "up" | "down" | Required | up or down. |
visitorId | string | Optional | Stable identifier for the end user. |
Request
{
"conversationId": "conv_xyz789",
"messageId": "msg_abc123",
"rating": "up",
"visitorId": "visitor_001"
} Response
200 Success
{
"ok": true,
"messageId": "msg_abc123",
"rating": "up",
"ratedAt": "2026-08-11T18:00:00.000Z"
} Status codes
curl
curl -X POST 'https://api.dev.oprag.ai/v1/chat/feedback' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"conversationId": "conv_xyz789","messageId": "msg_abc123","rating": "up","visitorId": "visitor_001"}' Conversations
Read conversation history, review it, export it, and escalate a thread to a human.
/v1/projects/{projectId}/conversations/{conversationId}/escalate Hand a public conversation to a human, over a webhook, an email, or both.
Auth Integration key
Before you call it
- The project needs
escalationWebhookUrlorescalationEmailin its settings; without one there is nowhere to escalate to. - On the Growth plan and above the escalation is also stored as a native ticket, and emits
ticket.created. - When a webhook is configured, oprag POSTs the transcript to it over HTTPS with an
X-Oprag-Signature: sha256=…header, includingticketIdwhen one was created. - Email escalation needs
SES_FROM_EMAILconfigured.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
projectId | string | Required | Project the request applies to. Must belong to the calling workspace. |
conversationId | string | Required | Conversation within the project. |
Query parameters
None.Everything it needs is in the request body.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
visitorId | string | Required | The visitor asking for a human. Required. |
subject | string | Optional | Short summary line. |
requesterEmail | string | Optional | Email to reply to. |
requesterName | string | Optional | Name of the person asking. |
message | string | Optional | Body text. |
Request
{ "visitorId": "visitor_001", "message": "Need billing help" } Response
200 Success
{ "escalated": true, "ticketId": "tkt_abc123" } Status codes
| Status | Meaning |
|---|---|
| 200 | Escalated. The body is { escalated: true, ticketId? }. |
| 400 | The request body failed validation. |
| 401 | Missing, revoked, or wrong-environment key. |
| 403 | Origin or IP not allowed for this project. |
| 404 | No such resource in this workspace. |
| 409 | This conversation has already been escalated. |
| 429 | Rate limited. See rate limits. |
| 500 | A webhook URL is configured but its signing secret is missing. |
curl
curl -X POST 'https://api.dev.oprag.ai/v1/projects/{projectId}/conversations/{conversationId}/escalate' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{ "visitorId": "visitor_001", "message": "Need billing help" }' SDK equivalent `oprag.conversations.escalate()`
Leads & tickets
Capture leads from chat, export them, and manage the tickets escalation creates.
/v1/projects/{projectId}/leads Record a lead captured by the widget's contact form.
Auth Integration key
Before you call it
- The project needs
leadCaptureEnabled, and the body needsvisitorIdplus at least one ofnameoremail. - Built-in lead fields are unlimited on every plan — there is no monthly cap.
customFieldsneeds the Growth plan or above withleadFormFieldsconfigured on the project.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
projectId | string | Required | Project the request applies to. Must belong to the calling workspace. |
Query parameters
None.Everything it needs is in the request body.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
visitorId | string | Required | Stable identifier for the end user. |
name | string | Optional | Display name. |
email | string | Optional | Email address. |
conversationId | string | Optional | Conversation this relates to. |
sourceQuestion | string | Optional | The question that triggered capture, for context in the dashboard. |
customFields | object | Optional | Values for any custom lead form fields configured on the project. |
Request
{
"visitorId": "visitor_001",
"name": "Jane Doe",
"email": "jane@example.com",
"conversationId": "conv_xyz789",
"customFields": {
"company_size": "50-200",
"plan_tier": "Growth"
}
} Response
200 Success
{ "leadId": "lead_abc123" } Status codes
| Status | Meaning |
|---|---|
| 201 | Created. The body is { leadId }. |
| 400 | The request body failed validation. |
| 401 | Missing, revoked, or wrong-environment key. |
| 402 | customFields were sent on the Free plan. |
| 403 | Origin or IP not allowed for this project. |
| 404 | No such resource in this workspace. |
| 429 | More than 10 submissions from one visitor within an hour. |
curl
curl -X POST 'https://api.dev.oprag.ai/v1/projects/{projectId}/leads' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"visitorId": "visitor_001","name": "Jane Doe","email": "jane@example.com","conversationId": "conv_xyz789","customFields": {"company_size": "50-200","plan_tier": "Growth"}}' SDK equivalent `oprag.leads.create()`
/v1/projects/{projectId}/tickets Create an escalation ticket from a conversation.
Auth Integration key
Before you call it
- Delivery is the same as
escalate— webhook, email, or both.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
projectId | string | Required | Project the request applies to. Must belong to the calling workspace. |
Query parameters
None.Everything it needs is in the request body.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string | Required | Conversation the ticket is raised from. |
visitorId | string | Optional | Stable identifier for the end user. |
subject | string | Optional | Short summary line. |
requesterEmail | string | Optional | Email to reply to. |
requesterName | string | Optional | Name of the person asking. |
message | string | Optional | Body text. |
Request
{
"conversationId": "conv_abc123",
"visitorId": "visitor_001",
"subject": "Billing question"
} Response
200 Success
{ "ticketId": "tkt_abc123", "escalated": true } Status codes
| Status | Meaning |
|---|---|
| 200 | Free plan — the escalation was delivered but no ticket is stored: { escalated: true }. |
| 201 | Growth and above — a native ticket was stored: { ticketId, escalated: true }. |
| 400 | The request body failed validation. |
| 401 | Missing, revoked, or wrong-environment key. |
| 403 | Origin or IP not allowed for this project. |
| 404 | No such resource in this workspace. |
| 429 | Rate limited. See rate limits. |
curl
curl -X POST 'https://api.dev.oprag.ai/v1/projects/{projectId}/tickets' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"conversationId": "conv_abc123","visitorId": "visitor_001","subject": "Billing question"}' Channels
Where chat is exposed: the embeddable widget, its public configuration, and WhatsApp.
/widget.js Embed widget bundle (301 to CDN when configured)
Auth Public — no credential
Path parameters
None.
Query parameters
None.Serves a fixed document and takes no input at all.
Body parameters
None.GET requests carry no body.
Response
Status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 429 | Rate limited. See rate limits. |
curl
curl -X GET 'https://api.dev.oprag.ai/widget.js' \
-H 'X-Oprag-Key: sk_live_...' /v1/widget/{projectId}/config Public display configuration for a project's chat widget.
Auth Public — no credential
Before you call it
- Only served while the project is live or indexing and its widget is enabled.
- Returns
displayName,welcomeMessage, andtheme(primaryColor,position, and an optionalmode). theme.modeisauto,light, ordark.autofollows the visitor'sprefers-color-scheme.quickPromptsand the lead-capture fields appear only when those features are on, andescalationEnabledonly when the project has an escalation webhook or email.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
projectId | string | Required | Project the request applies to. Must belong to the calling workspace. |
Query parameters
None.Reads the resource named in the path; there is nothing else to select.
Body parameters
None.GET requests carry no body.
Response
Status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 404 | No such resource in this workspace. |
| 429 | Rate limited. See rate limits. |
curl
curl -X GET 'https://api.dev.oprag.ai/v1/widget/{projectId}/config' \
-H 'X-Oprag-Key: sk_live_...' SDK equivalent `mountWidget()` reads this
Platform
Health, client bootstrap configuration, and environment information.
/health Liveness check
Auth Public — no credential
Path parameters
None.
Query parameters
None.Serves a fixed document and takes no input at all.
Body parameters
None.GET requests carry no body.
Response
200 Success
{
"status": "ok",
"service": "oprag-api",
"timestamp": "2026-06-09T12:00:00.000Z"
} Status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 429 | Rate limited. See rate limits. |
curl
curl -X GET 'https://api.dev.oprag.ai/health' \
-H 'X-Oprag-Key: sk_live_...' /config Cognito pool/client IDs, API URL, Hosted UI domain prefix, SPA OAuth callback, and enabled socialProviders (Google, GitHub). Used by the dashboard and MCP clients to bootstrap auth.
Auth Public — no credential
Path parameters
None.
Query parameters
None.Serves a fixed document and takes no input at all.
Body parameters
None.GET requests carry no body.
Response
200 Success
{
"cognitoUserPoolId": "us-east-1_example",
"cognitoClientId": "exampleclientid",
"apiUrl": "https://api.dev.oprag.ai",
"cognitoRegion": "us-east-1",
"cognitoDomain": "ashutech-dev-oprag",
"oauthRedirectUri": "https://app.dev.oprag.ai/auth/callback",
"socialProviders": ["Google", "GitHub"]
} Status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 429 | Rate limited. See rate limits. |
curl
curl -X GET 'https://api.dev.oprag.ai/config' \
-H 'X-Oprag-Key: sk_live_...' /dev/info Dev testing credentials, MCP login steps, and the live API route catalog.
Auth Public — no credential
Before you call it
- Returns 404 in staging and production — it exists to bootstrap local and dev testing only.
- The response carries
mcp.authModes,mcp.notes,mcp.testProject, the fullloginStepsarray, andapis.routes— the live catalog of every main-backend route. - The dev QA password is never returned.
Path parameters
None.
Query parameters
None.Serves a fixed document and takes no input at all.
Body parameters
None.GET requests carry no body.
Response
200 Success
{
"environment": "dev",
"apiUrl": "https://api.dev.oprag.ai",
"docsUrl": "https://dev.oprag.ai/docs/",
"dashboardUrl": "https://app.dev.oprag.ai",
"mcp": {
"credentials": {
"apiUrl": "https://api.dev.oprag.ai",
"cognitoUserPoolId": "us-east-1_example",
"cognitoClientId": "exampleclientid",
"email": "dev-qa@oprag.ai"
},
"testAccount": { "email": "dev-qa@oprag.ai", "companyName": "Dev QA" },
"testProject": { "purposeId": "mcp-qa", "name": "Uolo Product Assistant" },
"authModes": [
{ "mode": "credentials", "priority": 1, "env": ["OPRAG_API_URL", "OPRAG_COGNITO_EMAIL", "OPRAG_COGNITO_PASSWORD"] },
{ "mode": "jwt", "priority": 2, "env": ["OPRAG_API_URL", "OPRAG_JWT_TOKEN"] },
{ "mode": "api-key-only", "priority": 3, "env": ["OPRAG_API_URL", "OPRAG_API_KEY"], "description": "health_check and public_chat only" }
],
"loginSteps": [
{ "step": 1, "title": "Install and build the MCP server", "commands": ["cd mcp", "npm install", "npm run build"] },
{ "step": 2, "title": "Configure credentials", "commands": ["cp mcp/.env.example mcp/.env"] }
],
"notes": ["Password self-signup is disabled; use provisioned dev QA or invite."],
"envExample": { "OPRAG_API_URL": "https://api.dev.oprag.ai", "OPRAG_COGNITO_EMAIL": "dev-qa@oprag.ai" }
},
"apis": {
"count": 74,
"routes": [{ "method": "GET", "path": "/health", "auth": "Public", "group": "health" }]
}
} Status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 429 | Rate limited. See rate limits. |
curl
curl -X GET 'https://api.dev.oprag.ai/dev/info' \
-H 'X-Oprag-Key: sk_live_...' Extract
Structured extraction takes the same integration key and is documented in its own section: Extract — 10 endpoints, covering uploads, jobs, and schemas.
Endpoints that call you
A third party calls us and signs the request — Stripe, Meta, Slack. You configure the URL in their console; you never call it yourself.
| Endpoint | Signed by | Full documentation |
|---|---|---|
POST /v1/billing/webhook | Updates the workspace's plan and billing status from Stripe's checkout and subscription events. | Workspace |
GET /v1/webhooks/whatsapp | Answers Meta's hub subscription challenge when the webhook is registered. | Channels |
POST /v1/webhooks/whatsapp | Receives inbound WhatsApp messages from Meta and answers them through the project's chat pipeline. | Channels |
POST /v1/slack/events | Slack Events API callback (url_verification, app_mention, DM) | Integrations |
Endpoints Cognito calls
Exists for Cognito to call during federated sign-in. Not a route you integrate against. They are documented on OAuth & sign-in, which explains where the authorize step actually happens.
Ready to ship?
Get started free