Documentation Index
Fetch the complete documentation index at: https://docs.open.cx/llms.txt
Use this file to discover all available pages before exploring further.
Authentication
All Partner API requests require a Bearer token in the Authorization header. Partner API keys are provisioned by the OpenCX team — they are separate from org-level API keys.
Authorization: Bearer YOUR_PARTNER_API_KEY
Base URL: https://api.open.cx
IP allow list
Partner API endpoints support IP-level access control. When an allow list is configured on your partner account, requests from IPs not in the list are rejected with 403 Forbidden — even with a valid API key.
All traffic passes through Cloudflare, which forwards the real client IP in the X-Forwarded-For header. The backend extracts and validates this IP on every request.
IP allow lists are configured by the OpenCX team during onboarding. Contact us to add, update, or remove IPs. When no allow list is set, requests are accepted from any IP (token-only authentication).
Security layers
| Layer | What it does |
|---|
| Bearer token | Every request must include a valid partner API JWT. Revoked or missing keys return 401. |
| IP allow list | When configured, only requests from whitelisted IPs are accepted. Others get 403. |
| Partner active check | Inactive partner accounts are blocked at the auth layer (401). |
| Rate limiting | 100 req/min per partner globally, plus per-endpoint limits. |
| Org ownership | All org-scoped endpoints verify the org belongs to the calling partner (403 otherwise). |
Create Org
Create a new organization for one of your customers.
Request body
| Field | Type | Required | Description |
|---|
name | string | Yes | Display name for the org. |
external_id | string | No | Your internal ID for this customer. Must be unique per partner — duplicates return 409. |
website | string | No | Customer’s website URL. |
language | string | No | Default language code (e.g. "en", "es", "de"). Defaults to "en". |
ai_instructions | string | No | The AI profile — system prompt that defines the agent’s personality, knowledge scope, and behavior. Overrides your partner-level default if set. |
integrations | object | No | Auto-connect integrations during creation. See below. |
Integrations
Pass credentials in the integrations object to auto-connect supported third-party integrations during org creation. Credentials are validated against the live third-party API — invalid credentials cause the request to fail with a 400.
Each integration has its own shape under its own key. Some integrations accept either a single object (for one connection) or an array (for multiple connections — different locations, brands, or currencies). When passing an array, each entry should include a name that the AI uses in conversations to disambiguate between connections.
Single connection (object form):
{
"integrations": {
"example_integration": {
"name": "Primary",
"app_key": "...",
"user_key": "..."
}
}
}
Multiple connections (array form):
{
"integrations": {
"example_integration": [
{ "name": "Account A", "app_key": "...", "user_key": "..." },
{ "name": "Account B", "app_key": "...", "user_key": "..." }
]
}
}
Supported integration keys and their per-integration field shapes are documented on each integration’s page. This section will expand as more integrations become available via the provisioning API. For integrations not yet supported here, use the org-level dashboard or API after creation.
Response
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Acme Tours",
"widget_token": "f8e7d6c5b4a39281...",
"external_id": "customer-12345"
}
| Field | Type | Description |
|---|
id | string | The org UUID. Use this to manage the org via other OpenCX APIs. |
name | string | The org name as provided. |
widget_token | string | Widget embed token. Pass this to the chat widget. |
external_id | string | null | Your external ID, echoed back. |
Error responses
| Status | Condition | Body |
|---|
400 | Invalid request body, or integration credentials failed validation. | { "statusCode": 400, "message": "..." } |
401 | Missing, invalid, or revoked API key. | { "statusCode": 401, "message": "..." } |
409 | An org with this external_id already exists for your partner. | { "statusCode": 409, "message": "Org with external_id \"...\" already exists" } |
Examples
curl -X POST https://api.open.cx/partner/v1/orgs \
-H "Authorization: Bearer YOUR_PARTNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Tours",
"external_id": "customer-12345",
"language": "en",
"ai_instructions": "You are a support agent for Acme Tours. Help customers with bookings and questions."
}'
List Orgs
List all organizations created by your partner account.
Query parameters
| Parameter | Type | Default | Description |
|---|
limit | number | 50 | Number of orgs to return (1–100). |
offset | number | 0 | Number of orgs to skip (for pagination). |
Response
{
"data": [
{
"id": "a1b2c3d4-...",
"name": "Acme Tours",
"widget_token": "f8e7d6c5b4a3...",
"external_id": "customer-12345",
"created_at": "2026-03-15T10:30:00.000Z"
}
],
"total": 142
}
Examples
curl "https://api.open.cx/partner/v1/orgs?limit=10&offset=0" \
-H "Authorization: Bearer YOUR_PARTNER_API_KEY"
Get Org by external_id
Look up a single org by the external_id you supplied at creation. Use this when you need to reverse-resolve from your internal identifier to the OpenCX org — for example, before creating an API key or generating a login link — without paginating through /orgs.
GET /partner/v1/orgs/by-external-id/:externalId
Path parameters
| Parameter | Type | Description |
|---|
externalId | string | The external_id you set when calling POST /partner/v1/orgs. URL-encode it if it contains reserved characters. |
Response
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Acme Tours",
"widget_token": "f8e7d6c5b4a39281...",
"external_id": "customer-12345",
"created_at": "2026-03-15T10:30:00.000Z"
}
Error responses
| Status | Condition |
|---|
401 | Invalid or revoked partner API key. |
404 | No org with this external_id exists for your partner account. |
Lookups are scoped to your partner account. If a different partner has an org with the same external_id, you will not see it — you only ever resolve orgs you created.
Examples
curl "https://api.open.cx/partner/v1/orgs/by-external-id/customer-12345" \
-H "Authorization: Bearer YOUR_PARTNER_API_KEY"
Create Org API Key
Create an API key for a specific org. The returned key authenticates requests to the OpenCX Public API (crawling, training, contacts, etc).
POST /partner/v1/orgs/:orgId/api-keys
Request body
| Field | Type | Required | Description |
|---|
name | string | No | A label for the key (e.g. "Production"). Defaults to "Default". |
Response
{
"api_key_id": "key-uuid-here",
"api_key": "eyJhbGciOi..."
}
| Field | Type | Description |
|---|
api_key_id | string | The key’s UUID. |
api_key | string | The JWT API key. Use this as Bearer token for org-level API calls. |
The full API key is only returned once — store it securely. If lost, create a new one.
Examples
curl -X POST https://api.open.cx/partner/v1/orgs/ORG_ID/api-keys \
-H "Authorization: Bearer YOUR_PARTNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Production" }'
Error responses
| Status | Condition |
|---|
401 | Invalid or revoked partner API key. |
403 | Org does not belong to this partner. |
Create Login Link
Generate a short-lived, single-use URL that logs a user directly into the dashboard with the correct org context. No email, no forms, no org picker — the user lands in the dashboard immediately.
Use this instead of invitations when you want frictionless access — for example, embedding a “Manage support” button in your own platform that takes the user straight into their dashboard.
POST /partner/v1/orgs/:orgId/login-links
Request body
| Field | Type | Required | Description |
|---|
email | string | Yes | Email address of the user. If no account exists, one is created automatically. |
name | string | No | Display name for the user (used only when creating a new account). Defaults to the email prefix. |
role_ids | string[] | No | Array of role UUIDs to assign when creating org membership. Ignored if user is already a member. |
Response
{
"url": "https://platform.open.cx/partner-login?token=a1b2c3...",
"expires_at": "2026-04-12T12:15:00.000Z"
}
| Field | Type | Description |
|---|
url | string | The login URL. Redirect the user’s browser here. |
expires_at | string | ISO 8601 timestamp. The link expires 15 minutes after creation. |
Login links are single-use — once a user visits the URL, it is consumed and cannot be reused. Generate a new link for each login session.
Security properties
| Property | Value |
|---|
| Token entropy | 256 bits (cryptographically random) |
| TTL | 15 minutes |
| Single-use | Token deleted on first use |
| Rate limit | 30 links/min per partner |
Error responses
| Status | Condition |
|---|
401 | Invalid or revoked partner API key. |
403 | Org does not belong to this partner. |
Examples
curl -X POST https://api.open.cx/partner/v1/orgs/ORG_ID/login-links \
-H "Authorization: Bearer YOUR_PARTNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "owner@acmetours.com", "name": "Jane Smith" }'
Idempotency
Use external_id to prevent duplicate orgs. If you call POST /partner/v1/orgs twice with the same external_id, the second call returns 409 Conflict. This makes it safe to retry org creation without risk of duplicates. Use GET /partner/v1/orgs/by-external-id/:externalId to resolve the existing org directly — no pagination required.
The external_id uniqueness constraint is scoped to your partner account. Different partners can use the same external_id values.