Channels

Where chat is exposed: the embeddable widget, its public configuration, and WhatsApp.

prod · https://api.oprag.ai

11 endpoints. 5 are reachable without a dashboard session — they are listed in the Integration API — and the other 6 require a Cognito JWT. The badge under each path says which.

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

Shell
curl -X GET 'https://api.oprag.ai/widget.js' \
  -H 'X-Oprag-Key: sk_live_...'
GET /v1/widget/{projectId}/config

Public display configuration for a project's chat widget. Optional fields — quickPrompts, avatarUrl, launcherIconUrl, ctaChips, proactiveTriggers, and lead-capture settings — appear only when set; visitorContextEnabled is a master consent switch.

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, and theme (primaryColor, position, and an optional mode).
  • theme.mode is auto, light, or dark. auto follows the visitor's prefers-color-scheme.
  • quickPrompts and the lead-capture fields appear only when those features are on, avatarUrl, launcherIconUrl, ctaChips, and proactiveTriggers only when set on the widget config, and escalationEnabled only when the project has an escalation webhook or email.
  • proactiveTriggers drive the widget's teaser bubbles. The widget shows at most one teaser per session, and suppresses all teasers for 7 days after a visitor dismisses one.
  • visitorContextEnabled is a project-level master switch, distinct from the widget's per-visitor consent banner (window.oprag.setConsent() / handle.setConsent()). Omitted or true (the default) leaves visitor-context capture and the consent banner on; false disables both for every visitor 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.Reads the resource named in the path; there is nothing else to select.

Body parameters

None.GET requests carry no body.

Response

200 Success

JSON
{
  "displayName": "Acme Support",
  "welcomeMessage": "Hi! Ask me anything about our product.",
  "quickPrompts": ["What is your refund policy?"],
  "avatarUrl": "https://cdn.acme.com/bot-avatar.png",
  "launcherIconUrl": "https://cdn.acme.com/launcher-icon.svg",
  "ctaChips": [
    { "label": "Book a demo", "url": "https://acme.com/demo" },
    { "label": "Email us", "url": "mailto:hello@acme.com" }
  ],
  "proactiveTriggers": [
    {
      "message": "Questions about pricing? I can help!",
      "trigger": "delay",
      "value": 30,
      "pagePattern": "/pricing*"
    }
  ],
  "feedbackEnabled": true,
  "visitorContextEnabled": true,
  "escalationEnabled": false,
  "theme": {
    "primaryColor": "#2563eb",
    "position": "bottom-right",
    "mode": "auto"
  }
}

Status codes

Status Meaning
200 Success.
404 No such resource in this workspace.
429 Rate limited. See rate limits.

curl

Shell
curl -X GET 'https://api.oprag.ai/v1/widget/{projectId}/config' \
  -H 'X-Oprag-Key: sk_live_...'

SDK equivalent `mountWidget()` reads this

GET /v1/widget/{projectId}/conversations/{conversationId}/messages

Restore a returning visitor's transcript, using the conversationId and visitorId the widget saved.

Auth Embed keyIntegration key Embed keys require a browser `Origin` on the project's allowlist

Before you call it

  • This is what powers the widget's transcript restore: the widget persists conversationId and visitorId locally and replays the thread when the visitor comes back.
  • messages is chronological (oldest first), capped at the most recent 50.
  • Each message carries role (user or assistant), text, and createdAt. sources appears only when the stored answer cited documents, and each entry carries documentTitle only — no excerpts, locations, or scores on this channel.
  • The 404 is deliberately indistinguishable: a missing conversation, a conversation from another project, and a visitorId mismatch all answer identically, so conversation ids cannot be probed.

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

Name Type Required Default Description
visitorId string Required — The visitor the widget saved alongside the conversationId. A missing or blank value is a 400; a mismatch is the same 404 as an unknown conversation.

Body parameters

None.GET requests carry no body.

Response

200 Success

JSON
{
  "messages": [
    {
      "role": "user",
      "text": "What is your refund policy?",
      "createdAt": "2026-08-27T09:14:03.000Z"
    },
    {
      "role": "assistant",
      "text": "Refunds are available within 30 days of purchase.",
      "createdAt": "2026-08-27T09:14:07.000Z",
      "sources": [{ "documentTitle": "Refund policy" }]
    }
  ]
}

Status codes

Status Meaning
200 Success.
400 visitorId is required — the query parameter is missing or blank.
401 Missing, revoked, or wrong-environment key.
403 No Origin header, an origin that is not allowlisted, or a blocked IP.
404 Conversation not found — an unknown conversation, another project's conversation, or a visitorId that does not match. All three are indistinguishable by design.
429 Rate limited. See rate limits.
503 Project is not live yet. Wait for indexing to complete before chatting.

curl

Shell
curl -X GET 'https://api.oprag.ai/v1/widget/{projectId}/conversations/{conversationId}/messages' \
  -H 'X-Oprag-Key: sk_live_...'
GET /v1/webhooks/whatsapp

Answers Meta's hub subscription challenge when the webhook is registered.

Auth Integration key

Before you call it

  • Meta calls this when you register the webhook; your code never does.
  • hub.verify_token is compared against the global WHATSAPP_VERIFY_TOKEN, never a per-project value.

Path parameters

None.

Query parameters

Name Type Required Default Description
hub.mode "subscribe" Required — Meta sends subscribe. Any other value is rejected with 403.
hub.verify_token string Required — Compared in constant time against the configured verify token. A mismatch is a 403.
hub.challenge string Required — Echoed back verbatim as the plain-text 200 body when verification passes.

Body parameters

None.GET requests carry no body.

Response

200 Success

JSON
1234567890

Status codes

Status Meaning
200 Verified. The body is hub.challenge verbatim, as plain text.
401 Missing, revoked, or wrong-environment key.
403 Invalid verification request when a parameter is missing or hub.mode is not subscribe; Verification token mismatch when the token does not match.
429 Rate limited. See rate limits.

curl

Shell
curl -X GET 'https://api.oprag.ai/v1/webhooks/whatsapp' \
  -H 'X-Oprag-Key: sk_live_...'
POST /v1/webhooks/whatsapp

Receives inbound WhatsApp messages from Meta and answers them through the project's chat pipeline.

Auth Integration key

Before you call it

  • Meta calls this, not your code. It needs an X-Hub-Signature-256 header — sha256= followed by an HMAC-SHA256 of the raw body under the app secret — and the raw JSON body.
  • Text messages only. Deliveries are de-duplicated on Meta's message id, and phone_number_id selects which project answers.
  • Answers run through the shared chat pipeline with channel: "whatsapp".
  • An unmapped or disabled connection is acknowledged without running chat at all, so Meta stops retrying.

Path parameters

None.

Query parameters

None.The provider signs and posts the whole payload; nothing is read from the URL.

Body parameters

Defined by the caller.Inbound message payload from WhatsApp.

Response

Status codes

Status Meaning
200 Acknowledged, as plain-text OK. Meta retries anything else, so this is the answer whenever the signature is valid.
401 Invalid webhook signature — the HMAC did not match.
403 Origin or IP not allowed for this project.
429 Rate limited. See rate limits.
503 WHATSAPP_APP_SECRET is not configured.

curl

Shell
curl -X POST 'https://api.oprag.ai/v1/webhooks/whatsapp' \
  -H 'X-Oprag-Key: sk_live_...'
GET /v1/projects/{projectId}/widget-config

Widget settings (dashboard)

Auth Cognito JWT member

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.
401 Missing or expired JWT.
403 The signed-in user's role does not allow this.
404 No such resource in this workspace.
429 Rate limited. See rate limits.

curl

Shell
curl -X GET 'https://api.oprag.ai/v1/projects/{projectId}/widget-config' \
  -H 'Authorization: Bearer <Cognito JWT>'
PATCH /v1/projects/{projectId}/widget-config

Update the widget's display, branding (avatar, launcher icon, CTA chips), proactive triggers, lead capture, and theme settings.

Auth Cognito JWT admin

Before you call it

  • Branding URLs — avatarUrl, launcherIconUrl, and each chip's url — must be https://, up to 2048 characters; chip URLs may also be mailto:. URLs carrying credentials, a raw IP address, or a localhost host are rejected with 400.
  • ctaChips labels are limited to 40 characters. At most 3 chips are kept, at most 3 proactiveTriggers, and at most 6 quickPrompts; overflow is dropped silently, not rejected.
  • Each proactive trigger fires its message as a teaser on the visitor's page. trigger: "delay" needs value in whole seconds (5–600), trigger: "scroll" needs value in whole percent (10–90), and trigger: "exit" (exit intent) must omit value. An optional pagePattern — starting with /, up to 200 characters, with one optional trailing * wildcard — limits which pages it fires on.
  • An empty string clears avatarUrl or launcherIconUrl; an empty array clears ctaChips, quickPrompts, or proactiveTriggers.
  • feedbackEnabled and visitorContextEnabled both default to true when omitted. visitorContextEnabled: false is a project-level kill switch: it turns off visitor-context capture (referrer, landing page, UTM) and the widget's per-visitor consent banner for every visitor, overriding any visitor's own consent choice — see GET /v1/widget/{projectId}/config.

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
enabled boolean Optional Whether the feature is active.
displayName string Optional See the request example below.
welcomeMessage string Optional See the request example below.
quickPrompts string[] Optional Starter questions shown before the first message.
avatarUrl string Optional Assistant avatar image. https:// URL, up to 2048 characters. An empty string clears it.
launcherIconUrl string Optional Custom launcher-bubble icon image. https:// URL, up to 2048 characters. An empty string clears it.
ctaChips object[] Optional Call-to-action chips: { label, url } each, at most 3 kept. Labels up to 40 characters; URLs https:// or mailto:. An empty array clears them.
proactiveTriggers object[] Optional Proactive teasers: { message, trigger, value?, pagePattern? } each, at most 3 kept. message is 1–200 characters. trigger is delay (value required: whole seconds, 5–600), scroll (value required: whole percent, 10–90), or exit (value must be omitted). pagePattern starts with /, up to 200 characters, with one optional trailing * wildcard. An empty array clears them.
leadCaptureEnabled boolean Optional Offer the lead form when the documents cannot answer.
leadCaptureTitle string Optional Heading above the lead form.
leadCaptureFields "name" | "email"[] Optional Which built-in inputs to show.
feedbackEnabled boolean Optional Show thumbs up/down on answers. Defaults to on.
visitorContextEnabled boolean Optional Capture visitor context (referrer, landing page, UTM) and show the consent banner. false is a project-level kill switch — it turns off both for every visitor, overriding any visitor's own consent choice. Defaults to on.
leadFormFields object[] Optional Additional custom fields. Growth and above.
theme object Optional Widget theme: primaryColor, position, mode.

Request

JSON
{
  "displayName": "Acme Support",
  "avatarUrl": "https://cdn.acme.com/bot-avatar.png",
  "launcherIconUrl": "https://cdn.acme.com/launcher-icon.svg",
  "ctaChips": [
    { "label": "Book a demo", "url": "https://acme.com/demo" },
    { "label": "Email us", "url": "mailto:hello@acme.com" }
  ],
  "proactiveTriggers": [
    {
      "message": "Questions about pricing? I can help!",
      "trigger": "delay",
      "value": 30,
      "pagePattern": "/pricing*"
    }
  ]
}

Response

200 Success

JSON
{
  "companyId": "co_abc123",
  "projectId": "proj_abc123",
  "enabled": true,
  "displayName": "Acme Support",
  "welcomeMessage": "How can I help?",
  "avatarUrl": "https://cdn.acme.com/bot-avatar.png",
  "launcherIconUrl": "https://cdn.acme.com/launcher-icon.svg",
  "ctaChips": [
    { "label": "Book a demo", "url": "https://acme.com/demo" },
    { "label": "Email us", "url": "mailto:hello@acme.com" }
  ],
  "proactiveTriggers": [
    {
      "message": "Questions about pricing? I can help!",
      "trigger": "delay",
      "value": 30,
      "pagePattern": "/pricing*"
    }
  ],
  "theme": {
    "primaryColor": "#5046e5",
    "position": "bottom-right"
  },
  "createdAt": "2026-08-11T12:00:00.000Z",
  "updatedAt": "2026-08-28T12:00:00.000Z",
  "scriptTag": "<script src=\"https://api.dev.oprag.ai/widget.js\" data-project=\"proj_abc123\" data-embed-key=\"YOUR_EMBED_KEY\"></script>"
}

Status codes

Status Meaning
200 Success.
400 The request body failed validation.
401 Missing or expired JWT.
403 The signed-in user's role does not allow this.
404 No such resource in this workspace.
429 Rate limited. See rate limits.

curl

Shell
curl -X PATCH 'https://api.oprag.ai/v1/projects/{projectId}/widget-config' \
  -H 'Authorization: Bearer <Cognito JWT>' \
  -H 'Content-Type: application/json' \
  -d '{"displayName": "Acme Support","avatarUrl": "https://cdn.acme.com/bot-avatar.png","launcherIconUrl": "https://cdn.acme.com/launcher-icon.svg","ctaChips": [{ "label": "Book a demo", "url": "https://acme.com/demo" },{ "label": "Email us", "url": "mailto:hello@acme.com" }],"proactiveTriggers": [{"message": "Questions about pricing? I can help!","trigger": "delay","value": 30,"pagePattern": "/pricing*"}]}'
GET /v1/projects/{projectId}/channels/whatsapp

WhatsApp Business channel status for a project, with no secrets in it.

Auth Cognito JWT admin

Before you call it

  • status is disconnected, connected, or error. Before the first connection, connected and enabled are both false and status is disconnected.
  • No secrets are returned — this is a WhatsAppChannelStatus, in which tokenConfigured and webhookVerifyConfigured report only whether they exist.

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

200 Success

JSON
{
  "connected": true,
  "enabled": true,
  "phoneNumberId": "123456789",
  "displayPhoneNumber": "+15551234567",
  "wabaId": "987654321",
  "tokenConfigured": true,
  "webhookVerifyConfigured": true,
  "lastInboundAt": "2026-08-11T12:00:00.000Z",
  "status": "connected"
}

Status codes

Status Meaning
200 Success.
401 Missing or expired JWT.
403 The signed-in user's role does not allow this.
404 No such resource in this workspace.
429 Rate limited. See rate limits.

curl

Shell
curl -X GET 'https://api.oprag.ai/v1/projects/{projectId}/channels/whatsapp' \
  -H 'Authorization: Bearer <Cognito JWT>'
POST /v1/projects/{projectId}/channels/whatsapp/connect

Attach a WhatsApp Business phone number to the project.

Auth Cognito JWT admin

Before you call it

  • Ownership of the number is verified against the Meta Graph API with the supplied token before anything is stored.
  • accessToken is encrypted at rest, which requires CHANNEL_TOKEN_ENCRYPTION_KEY to be configured.
  • Hub webhook verification always uses the global WHATSAPP_VERIFY_TOKEN, never a per-project one.
  • A successful connect returns the project's WhatsAppChannelStatus, exactly as GET …/channels/whatsapp would.

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
phoneNumberId string Required WhatsApp Business phone number id.
wabaId string Required WhatsApp Business account id.
accessToken string Required Long-lived access token. Encrypted at rest.
displayPhoneNumber string Optional Human-readable number to show in the dashboard. Defaults to the one Meta reports for phoneNumberId.

Request

JSON
{
  "phoneNumberId": "123456789",
  "wabaId": "987654321",
  "accessToken": "EAA...",
  "displayPhoneNumber": "+15551234567"
}

Response

200 Success

JSON
{
  "connected": true,
  "enabled": true,
  "phoneNumberId": "123456789",
  "displayPhoneNumber": "+15551234567",
  "wabaId": "987654321",
  "tokenConfigured": true,
  "webhookVerifyConfigured": true,
  "status": "connected"
}

Status codes

Status Meaning
200 Success.
400 A required field is missing, or Meta's ownership check for the number failed.
401 Missing or expired JWT.
403 The signed-in user's role does not allow this.
404 No such resource in this workspace.
409 That phone number is already connected somewhere else.
429 Rate limited. See rate limits.
503 Channel token encryption is not configured.

curl

Shell
curl -X POST 'https://api.oprag.ai/v1/projects/{projectId}/channels/whatsapp/connect' \
  -H 'Authorization: Bearer <Cognito JWT>' \
  -H 'Content-Type: application/json' \
  -d '{"phoneNumberId": "123456789","wabaId": "987654321","accessToken": "EAA...","displayPhoneNumber": "+15551234567"}'
PATCH /v1/projects/{projectId}/channels/whatsapp

Pause or resume an existing WhatsApp connection without deleting its credentials.

Auth Cognito JWT admin

Before you call it

  • Returns the project's WhatsAppChannelStatus with the new enabled value.

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
enabled boolean Optional Pause or resume the channel without disconnecting it.

Request

JSON
{ "enabled": false }

Response

200 Success

JSON
{
  "connected": true,
  "enabled": false,
  "phoneNumberId": "123456789",
  "displayPhoneNumber": "+15551234567",
  "wabaId": "987654321",
  "tokenConfigured": true,
  "webhookVerifyConfigured": true,
  "status": "connected"
}

Status codes

Status Meaning
200 Success.
400 enabled is missing or is not a boolean.
401 Missing or expired JWT.
403 The signed-in user's role does not allow this.
404 WhatsApp channel is not connected — it was never connected.
429 Rate limited. See rate limits.

curl

Shell
curl -X PATCH 'https://api.oprag.ai/v1/projects/{projectId}/channels/whatsapp' \
  -H 'Authorization: Bearer <Cognito JWT>' \
  -H 'Content-Type: application/json' \
  -d '{ "enabled": false }'
DELETE /v1/projects/{projectId}/channels/whatsapp

Disconnect WhatsApp from the project.

Auth Cognito JWT admin

Before you call it

  • Deletes both the connection row and the global phone_number_id lookup.

Path parameters

Name Type Required Description
projectId string Required Project the request applies to. Must belong to the calling workspace.

Query parameters

None.Acts on the resource named in the path; there is nothing to choose.

Body parameters

None.DELETE requests carry no body.

Response

Status codes

Status Meaning
204 Disconnected. The body is empty.
400 The request body failed validation.
401 Missing or expired JWT.
403 The signed-in user's role does not allow this.
404 WhatsApp channel is not connected — it was never connected.
429 Rate limited. See rate limits.

curl

Shell
curl -X DELETE 'https://api.oprag.ai/v1/projects/{projectId}/channels/whatsapp' \
  -H 'Authorization: Bearer <Cognito JWT>'

Ready to ship?

Get started free