BrightshoalDocsOpen console
MenuPublishable keys

API reference

Publishable keys

Publishable keys (pk_live_...) let a browser start web chats with one assistant from the origins you allow. They are safe to ship in page source; secret API keys are not.

Make a preview link (pk_preview_…)

POST/api/preview-links

A page where anyone with the link, or only signed-in members of the org, can try the assistant's web chat; it loads from any site and while web chat is off, and its chats are tests that send nothing outside. One live link per assistant: making one turns the previous link off, with its open chats.

Secret API key, not read-only. How it works

Request body

  • assistant_idstringrequired

  • accessstringrequired

    One of public team

  • expires_atstring | nullrequiredISO 8601 timestamp

    In the future; null works until it is turned off.

Returns

201 OK

Response attributes
  • dataPreviewLinkrequired

    8 attributes
    • idstringrequired

      Also the page address: /preview/{id} on the console.

    • assistant_idstringrequired

    • project_idstringrequired

    • keystringrequired

      The preview key the page loads the widget with.

    • accessstringrequired

      One of public team

    • expires_atstring | nullrequiredISO 8601 timestamp

    • expiredbooleanrequired

    • created_atstringrequiredISO 8601 timestamp

  • 400 Validation error: usually invalid_request, with the failing fields in issues when there are any
  • 401 Missing, malformed, unknown or revoked API key (unauthorized)
  • 403 Refused, for example a read-only key on a write (read_only_key), a role too low for the route (insufficient_role), or a route that needs a console session
  • 404 Not found, or outside what the key can see
  • 429 Rate limit exceeded (rate_limited). Wait Retry-After seconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
POST /api/preview-links
curl -X POST "https://api.myleadsfactory.tech/api/preview-links" \
  -H "Authorization: Bearer $MLF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
  "access": "public",
  "expires_at": "2026-10-28T09:30:00.000Z"
}'
Response 201
{
  "data": {
    "id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "project_id": "proj_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "key": "string",
    "access": "public",
    "expires_at": "2026-10-28T09:30:00.000Z",
    "expired": true,
    "created_at": "2026-10-28T09:30:00.000Z"
  }
}

List publishable keys

GET/api/publishable-keys

Filter by project_id (covers project-scoped keys) or assistant_id (legacy pinned keys); no filter returns everything in scope. Site keys only unless kind says otherwise. Revoked keys are included, with revoked_at set.

Secret API key. How it works

Query parameters

  • project_idstring

    Only keys for this project.

  • assistant_idstring

    Only keys pinned to this assistant.

  • kindstring

    site (the default) lists the keys for live websites, test the test keys, all both.

    One of site test all

Returns

200 OK

Response attributes
  • dataarray of WidgetKeyrequired

    10 attributes
    • idstringrequired

    • org_idstringrequired

    • project_idstringrequired

    • assistant_idstring | nullrequired

      The assistant a pinned key is bound to; null for a project-scoped key.

    • keystringrequired

      Public, revocable widget key, pk_live_....

    • kindstring

      site keys go on the live website; test keys on a staging site or localhost.

      One of site test

    • allowed_originsarray of string

      Test keys: where the key loads. Site keys use the assistant's allowed_origins.

    • revoked_atstring | nullISO 8601 timestamp

    • created_atstringISO 8601 timestamp

    • updated_atstringISO 8601 timestamp

  • 400 Validation error: usually invalid_request, with the failing fields in issues when there are any
  • 401 Missing, malformed, unknown or revoked API key (unauthorized)
  • 429 Rate limit exceeded (rate_limited). Wait Retry-After seconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
GET /api/publishable-keys
curl "https://api.myleadsfactory.tech/api/publishable-keys" \
  -H "Authorization: Bearer $MLF_API_KEY"
Response 200
{
  "data": [
    {
      "id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
      "org_id": "org_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
      "project_id": "proj_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
      "assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
      "key": "string",
      "kind": "site",
      "allowed_origins": [
        "https://www.example.com"
      ],
      "revoked_at": "2026-10-28T09:30:00.000Z",
      "created_at": "2026-10-28T09:30:00.000Z",
      "updated_at": "2026-10-28T09:30:00.000Z"
    }
  ]
}

Create a publishable key

POST/api/publishable-keys

Returns the key in data.key: pk_live_... for a site key, pk_test_... for a test key. project_id (or, with a project API key, nothing at all) mints a project-scoped key, usable with any assistant in the project: the embed names the assistant with data-mlf-assistant and public chat requests send assistant. assistant_id mints a key pinned to that assistant. An org-wide API key must send one of the two (400 otherwise). Publishable keys are safe in page source; which sites may use a site key is the assistant's channels.web_chat.allowed_origins. kind: test mints a test key for a staging site or localhost: it loads only on its own allowed_origins, and its chats run the assistant's draft, search the test knowledge publication and reach test webhooks only.

Secret API key, not read-only. How it works

Request body

  • project_idstringnot empty

    Mint a project-scoped key.

  • assistant_idstringnot empty

    Mint a key pinned to this assistant.

  • kindstring

    site for your live site, test for a staging site or localhost.

    One of site test

    Default "site"

  • allowed_originsarray of stringup to 20 items

    Test keys only, and required for them: the HTTP(S) origins the key loads on.

Returns

201 OK

Response attributes
  • dataWidgetKeyrequired

    10 attributes
    • idstringrequired

    • org_idstringrequired

    • project_idstringrequired

    • assistant_idstring | nullrequired

      The assistant a pinned key is bound to; null for a project-scoped key.

    • keystringrequired

      Public, revocable widget key, pk_live_....

    • kindstring

      site keys go on the live website; test keys on a staging site or localhost.

      One of site test

    • allowed_originsarray of string

      Test keys: where the key loads. Site keys use the assistant's allowed_origins.

    • revoked_atstring | nullISO 8601 timestamp

    • created_atstringISO 8601 timestamp

    • updated_atstringISO 8601 timestamp

  • 400 Validation error: usually invalid_request, with the failing fields in issues when there are any
  • 401 Missing, malformed, unknown or revoked API key (unauthorized)
  • 403 Refused, for example a read-only key on a write (read_only_key), a role too low for the route (insufficient_role), or a route that needs a console session
  • 404 assistant_not_found or project_not_found: not in this key's scope
  • 429 Rate limit exceeded (rate_limited). Wait Retry-After seconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
POST /api/publishable-keys
curl -X POST "https://api.myleadsfactory.tech/api/publishable-keys" \
  -H "Authorization: Bearer $MLF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "assistant_id": "asst_7d2e9b14c6a04f3e8b5d1a9c0e7f6b23"
}'
Response 201
{
  "data": {
    "id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "org_id": "org_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "project_id": "proj_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "key": "string",
    "kind": "site",
    "allowed_origins": [
      "https://www.example.com"
    ],
    "revoked_at": "2026-10-28T09:30:00.000Z",
    "created_at": "2026-10-28T09:30:00.000Z",
    "updated_at": "2026-10-28T09:30:00.000Z"
  }
}

Revoke a publishable key

DELETE/api/publishable-keys/{id}

Revocation, not deletion: the row stays and gains a revoked_at, so an embed that still carries the key gets a clean refusal rather than a missing record.

Secret API key, not read-only. How it works

Path parameters

  • idstringrequired

    Key record id, wkey_... (not the pk_live_ key itself).

Returns

200 OK

Response attributes
  • dataWidgetKeyrequired

    10 attributes
    • idstringrequired

    • org_idstringrequired

    • project_idstringrequired

    • assistant_idstring | nullrequired

      The assistant a pinned key is bound to; null for a project-scoped key.

    • keystringrequired

      Public, revocable widget key, pk_live_....

    • kindstring

      site keys go on the live website; test keys on a staging site or localhost.

      One of site test

    • allowed_originsarray of string

      Test keys: where the key loads. Site keys use the assistant's allowed_origins.

    • revoked_atstring | nullISO 8601 timestamp

    • created_atstringISO 8601 timestamp

    • updated_atstringISO 8601 timestamp

  • 401 Missing, malformed, unknown or revoked API key (unauthorized)
  • 403 Refused, for example a read-only key on a write (read_only_key), a role too low for the route (insufficient_role), or a route that needs a console session
  • 404 Not found, or outside what the key can see
  • 429 Rate limit exceeded (rate_limited). Wait Retry-After seconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
DELETE /api/publishable-keys/{id}
curl -X DELETE "https://api.myleadsfactory.tech/api/publishable-keys/PUBLISHABLE_KEY_ID" \
  -H "Authorization: Bearer $MLF_API_KEY"
Response 200
{
  "data": {
    "id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "org_id": "org_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "project_id": "proj_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
    "key": "string",
    "kind": "site",
    "allowed_origins": [
      "https://www.example.com"
    ],
    "revoked_at": "2026-10-28T09:30:00.000Z",
    "created_at": "2026-10-28T09:30:00.000Z",
    "updated_at": "2026-10-28T09:30:00.000Z"
  }
}