> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mka1.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat connectors

> Connect a saved agent to Telegram or WhatsApp.

## Before you start

Connector management is team-level. Every connector endpoint returns `403` when the request carries `X-On-Behalf-Of`, so leave the header off all connector calls. Beyond that:

* Create and activate need an API key. They reject session authentication, because the connector keeps running in the background under that key. List, retrieve, delete, and the WhatsApp setup call also accept a console session.
* The key needs `write:agents` plus the runtime scopes `write:conversations`, `write:responses`, and `read:responses`. Listing and retrieving need `read:agents`. The key's scopes at creation time are a ceiling: a scope you add to the key later does nothing until you [activate](#activate-a-connector) the connector, and each message runs with the ceiling minus anything the key has since lost.
* Optional scopes: `write:feedback` turns thumbs-up and thumbs-down reactions into response feedback. `write:files` lets the connector receive photos and documents, `read:files` lets it deliver managed files, and a generated image needs both, because it is saved as a managed file before delivery. Text-only connectors need neither file scope.

Schedules take the same API key and, unlike connectors, accept `X-On-Behalf-Of`.

Each provider needs its own credentials:

| Provider        | Fields you send                                                                                                                           | Where they come from                                                                                                                                                                                                                                       |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Telegram        | `credentials.bot_token`                                                                                                                   | BotFather                                                                                                                                                                                                                                                  |
| WhatsApp (Beta) | `credentials.access_token`, `credentials.app_secret`, `account.app_id`, `account.whatsapp_business_account_id`, `account.phone_number_id` | A Meta app with the WhatsApp product: a long-lived system-user token with `whatsapp_business_messaging` and `whatsapp_business_management`, the app ID and secret, and the IDs of the WhatsApp Business Account (WABA) and phone number the app can access |

Every connector also needs an `access` allowlist with 1 to 100 entries: Telegram chat IDs (integers) or WhatsApp sender IDs (digit strings without a leading `+`). The connector acknowledges and drops messages from anyone else, and stores nothing. There is no public mode.

To find a Telegram chat ID, message the bot before you bind it, then open `https://api.telegram.org/bot<telegram-bot-token>/getUpdates` and read `message.chat.id`. Group and supergroup IDs are negative.

The console has the same controls under **Agents → your agent → Connectors** (`/agents/{agent_id}/connectors` on your cluster's console, for example platform.mka1.com).

## Connectors

### Connect a Telegram bot

Create a bot with BotFather, collect the chat IDs you want to allow, then bind the bot to the agent.

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  import { SDK } from '@meetkai/mka1';

  const sdk = new SDK({ bearerAuth: 'Bearer <mka1-api-key>' });

  // No xOnBehalfOf here: connector endpoints reject it with 403.
  const connector = await sdk.agentConnectors.createAgentConnector({
    id: 'agt_123',
    createAgentConnectorRequest: {
      provider: 'telegram',
      name: 'support-bot',
      credentials: { botToken: '<telegram-bot-token>' },
      access: { mode: 'allowlist', chatIds: [123456789] },
    },
  });

  console.log(connector.id, connector.status, connector.providerAccountName);
  ```

  ```python Python SDK theme={null}
  import os
  from meetkai_mka1 import SDK

  sdk = SDK(bearer_auth="Bearer <mka1-api-key>")

  # No x_on_behalf_of here: connector endpoints reject it with 403.
  connector = sdk.agent_connectors.create_agent_connector(
      id="agt_123",
      body={
          "provider": "telegram",
          "name": "support-bot",
          "credentials": {"bot_token": "<telegram-bot-token>"},
          "access": {"mode": "allowlist", "chat_ids": [123456789]},
      },
  )

  print(connector.id, connector.status, connector.provider_account_name)
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;
  using MeetKai.MKA1.Types.Requests;

  var sdk = new SDK(bearerAuth: "Bearer <mka1-api-key>");

  // No xOnBehalfOf here: connector endpoints reject it with 403.
  var created = await sdk.AgentConnectors.CreateAgentConnectorAsync(
      id: "agt_123",
      body: MeetKai.MKA1.Types.Components.CreateAgentConnectorRequest.CreateTelegram(new CreateTelegramAgentConnectorRequest()
      {
          Provider = CreateTelegramAgentConnectorRequestProvider.Telegram,
          Name = "support-bot",
          Credentials = new CreateTelegramAgentConnectorRequestCredentials()
          {
              BotToken = "<telegram-bot-token>",
          },
          Access = new CreateTelegramAgentConnectorRequestAccess()
          {
              Mode = CreateTelegramAgentConnectorRequestMode.Allowlist,
              ChatIds = new List<long> { 123456789 },
          },
      })
  );

  var connector = created.AgentConnector!;
  Console.WriteLine($"{connector.Id} {connector.Status} {connector.ProviderAccountName}");
  ```

  ```bash Bash theme={null}
  # No X-On-Behalf-Of header: connector endpoints reject it with 403.
  curl https://apigw.mka1.com/api/v1/agents/agt_123/connectors \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --data '{
      "provider": "telegram",
      "name": "support-bot",
      "credentials": {
        "bot_token": "<telegram-bot-token>"
      },
      "access": {
        "mode": "allowlist",
        "chat_ids": [123456789]
      }
    }'
  ```
</CodeGroup>

The call returns `201 Created` with a connector object (`con_...`). It does all of this before returning:

1. Validates the token with Telegram's `getMe`. A token Telegram rejects returns `400`. Telegram being unreachable returns `502` with `retryable` in the error details.
2. Stores the credentials, encrypted, and reserves the bot. Responses never include credentials; `credentials_configured` tells you they are stored. Binding the same bot a second time, from any team, returns `409`.
3. Registers the webhook with `drop_pending_updates` fixed at `true`, so messages sent to the bot before this binding are discarded.
4. Sets `status` to `active`.

If webhook registration fails, the connector is left in `status: "error"` with `last_error`, and the call returns `502`. Call [activate](#activate-a-connector) to retry once Telegram is reachable.

To check it works, send the bot a message from an allowed chat. The reply comes back in that chat, and in a private chat you see a draft that updates while the model streams. The run is scoped to the chat, not to your API key, so a plain listing of the agent's runs does not show it. Pass the chat's synthetic ID as `X-On-Behalf-Of`, using the connector's `provider_account_id` as the bot ID. The thread segment is `root` unless the message came from a forum topic, in which case it is the topic ID:

```bash theme={null}
curl https://apigw.mka1.com/api/v1/agents/agt_123/runs \
  --header 'Authorization: Bearer <mka1-api-key>' \
  --header 'X-On-Behalf-Of: telegram:<provider-account-id>:chat:123456789:thread:root'
```

### Connect a WhatsApp number (Beta)

WhatsApp needs an app-level webhook in Meta before the first phone connector exists, so this takes two calls.

First, ask for the webhook values for your Meta app:

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const setup = await sdk.agentConnectors.setupWhatsAppAppWebhook({
    id: 'agt_123',
    whatsAppWebhookSetupRequest: { appId: '300000000003' },
  });

  console.log(setup.result.callbackUrl);
  console.log(setup.result.verifyToken);
  ```

  ```python Python SDK theme={null}
  setup = sdk.agent_connectors.setup_whats_app_app_webhook(
      id="agt_123",
      app_id="300000000003",
  )

  print(setup.result.callback_url)
  print(setup.result.verify_token)
  ```

  ```csharp C# SDK theme={null}
  var setup = await sdk.AgentConnectors.SetupWhatsAppAppWebhookAsync(
      id: "agt_123",
      body: new WhatsAppWebhookSetupRequest() { AppId = "300000000003" }
  );

  Console.WriteLine(setup.WhatsAppWebhookSetup!.CallbackUrl);
  Console.WriteLine(setup.WhatsAppWebhookSetup!.VerifyToken);
  ```

  ```bash CLI theme={null}
  mka1 agent-connectors setup-whats-app-app-webhook \
    --body '{"app_id": "300000000003"}' \
    --id agt_123
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/connectors/whatsapp/setup \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --data '{"app_id": "300000000003"}'
  ```
</CodeGroup>

Copy `callback_url` and `verify_token` into the Meta app under **WhatsApp → Production setup → Configure Webhooks**, pick the WhatsApp Business Account object, and subscribe to the `messages` field. The verify token is stable: call setup again whenever you need it, since the connector object does not carry it. The response is sent with `Cache-Control: no-store`.

Then create the connector:

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const connector = await sdk.agentConnectors.createAgentConnector({
    id: 'agt_123',
    createAgentConnectorRequest: {
      provider: 'whatsapp',
      name: 'whatsapp-support',
      credentials: {
        accessToken: '<meta-system-user-token>',
        appSecret: '<meta-app-secret>',
      },
      account: {
        appId: '300000000003',
        whatsappBusinessAccountId: '123456789012345',
        phoneNumberId: '109876543210987',
      },
      access: { mode: 'allowlist', userIds: ['15551234567'] },
    },
  });

  console.log(connector.id, connector.status);
  ```

  ```python Python SDK theme={null}
  connector = sdk.agent_connectors.create_agent_connector(
      id="agt_123",
      body={
          "provider": "whatsapp",
          "name": "whatsapp-support",
          "credentials": {
              "access_token": "<meta-system-user-token>",
              "app_secret": "<meta-app-secret>",
          },
          "account": {
              "app_id": "300000000003",
              "whatsapp_business_account_id": "123456789012345",
              "phone_number_id": "109876543210987",
          },
          "access": {"mode": "allowlist", "user_ids": ["15551234567"]},
      },
  )

  print(connector.id, connector.status)
  ```

  ```csharp C# SDK theme={null}
  var created = await sdk.AgentConnectors.CreateAgentConnectorAsync(
      id: "agt_123",
      body: MeetKai.MKA1.Types.Components.CreateAgentConnectorRequest.CreateWhatsapp(new CreateWhatsAppAgentConnectorRequest()
      {
          Provider = CreateWhatsAppAgentConnectorRequestProvider.Whatsapp,
          Name = "whatsapp-support",
          Credentials = new CreateWhatsAppAgentConnectorRequestCredentials()
          {
              AccessToken = "<meta-system-user-token>",
              AppSecret = "<meta-app-secret>",
          },
          Account = new Account()
          {
              AppId = "300000000003",
              WhatsappBusinessAccountId = "123456789012345",
              PhoneNumberId = "109876543210987",
          },
          Access = new CreateWhatsAppAgentConnectorRequestAccess()
          {
              Mode = CreateWhatsAppAgentConnectorRequestMode.Allowlist,
              UserIds = new List<string> { "15551234567" },
          },
      })
  );

  Console.WriteLine(created.AgentConnector!.Status);
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/connectors \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --data '{
      "provider": "whatsapp",
      "name": "whatsapp-support",
      "credentials": {
        "access_token": "<meta-system-user-token>",
        "app_secret": "<meta-app-secret>"
      },
      "account": {
        "app_id": "300000000003",
        "whatsapp_business_account_id": "123456789012345",
        "phone_number_id": "109876543210987"
      },
      "access": {
        "mode": "allowlist",
        "user_ids": ["15551234567"]
      }
    }'
  ```
</CodeGroup>

Creation checks that the token belongs to `app_id`, carries both WhatsApp permissions, and can see `phone_number_id` under the business account. It then subscribes the app to the WABA, if it is not already subscribed, and registers a callback for this phone number. Messages that Meta still sends to the app-level webhook reach the connector too, matched by `phone_number_id`.

WhatsApp replies are session messages: Meta accepts them inside the 24-hour window that a user's message opens. The connector never sends template messages, so it cannot start a conversation on its own.

To check it works, send a message from an allowed number to the business number; the reply comes back in the same WhatsApp chat. Meta's test number is enough for this while you develop. Connector runs are scoped to the sender, so list them with `X-On-Behalf-Of: whatsapp:<phone-number-id>:user:15551234567`.

### List, retrieve, and delete connectors

List the agent's connectors, or read one to see its `status` and `last_error`:

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const connectors = await sdk.agentConnectors.listAgentConnectors({ id: 'agt_123' });
  console.log(connectors.data.map((c) => `${c.id} ${c.provider} ${c.status}`));

  const connector = await sdk.agentConnectors.getAgentConnector({
    id: 'agt_123',
    connectorId: 'con_123',
  });
  console.log(connector.lastError);
  ```

  ```python Python SDK theme={null}
  connectors = sdk.agent_connectors.list_agent_connectors(id="agt_123")
  print([(c.id, c.provider, c.status) for c in connectors.data])

  connector = sdk.agent_connectors.get_agent_connector(
      id="agt_123",
      connector_id="con_123",
  )
  print(connector.last_error)
  ```

  ```csharp C# SDK theme={null}
  var list = await sdk.AgentConnectors.ListAgentConnectorsAsync(id: "agt_123");
  foreach (var c in list.AgentConnectorList!.Data)
  {
      Console.WriteLine($"{c.Id} {c.Provider} {c.Status}");
  }

  var detail = await sdk.AgentConnectors.GetAgentConnectorAsync(
      id: "agt_123",
      connectorId: "con_123"
  );
  Console.WriteLine(detail.AgentConnector!.LastError);
  ```

  ```bash CLI theme={null}
  mka1 agent-connectors list \
    --id agt_123 \
    --limit 20 \
    --order desc

  mka1 agent-connectors get \
    --id agt_123 \
    --connector-id con_123
  ```

  ```bash Bash theme={null}
  curl 'https://apigw.mka1.com/api/v1/agents/agt_123/connectors?limit=20&order=desc' \
    --header 'Authorization: Bearer <mka1-api-key>'

  curl https://apigw.mka1.com/api/v1/agents/agt_123/connectors/con_123 \
    --header 'Authorization: Bearer <mka1-api-key>'
  ```
</CodeGroup>

To delete a connector:

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const deleted = await sdk.agentConnectors.deleteAgentConnector({
    id: 'agt_123',
    connectorId: 'con_123',
  });
  console.log(deleted.deleted); // true
  ```

  ```python Python SDK theme={null}
  deleted = sdk.agent_connectors.delete_agent_connector(
      id="agt_123",
      connector_id="con_123",
  )
  print(deleted.deleted)  # True
  ```

  ```csharp C# SDK theme={null}
  var deleted = await sdk.AgentConnectors.DeleteAgentConnectorAsync(
      id: "agt_123",
      connectorId: "con_123"
  );
  Console.WriteLine(deleted.AgentConnectorDeleted!.Deleted);
  ```

  ```bash CLI theme={null}
  mka1 agent-connectors delete \
    --id agt_123 \
    --connector-id con_123
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/connectors/con_123 \
    --request DELETE \
    --header 'Authorization: Bearer <mka1-api-key>'
  ```
</CodeGroup>

```json theme={null}
{
  "object": "agent.connector.deleted",
  "id": "con_123",
  "deleted": true
}
```

Delete unregisters the webhook, fails any events still in flight, erases the stored credentials, and marks the connector `deleted`. Telegram drops its pending updates. WhatsApp clears only this number's callback and leaves the app subscription in place for other numbers. If the provider cannot confirm the cleanup, for example because the token was already revoked, the connector moves to `error` with `last_error.operation` set to `unregister_webhook` and the call returns `502`. Repeat the `DELETE` to retry; the bot or number stays reserved until cleanup is confirmed.

There is no update call. To change the allowlist or the credentials, delete the connector and create it again.

An agent with connectors cannot be deleted. `DELETE /api/v1/agents/{agent_id}` returns `409` until every connector is gone.

### Activate a connector

Activate re-runs credential validation and webhook registration with the stored credentials, under the calling key:

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const connector = await sdk.agentConnectors.activateAgentConnector({
    id: 'agt_123',
    connectorId: 'con_123',
  });

  console.log(connector.status, connector.lastError);
  ```

  ```python Python SDK theme={null}
  connector = sdk.agent_connectors.activate_agent_connector(
      id="agt_123",
      connector_id="con_123",
  )

  print(connector.status, connector.last_error)
  ```

  ```csharp C# SDK theme={null}
  var activated = await sdk.AgentConnectors.ActivateAgentConnectorAsync(
      id: "agt_123",
      connectorId: "con_123"
  );

  Console.WriteLine(activated.AgentConnector!.Status);
  ```

  ```bash CLI theme={null}
  mka1 agent-connectors activate \
    --id agt_123 \
    --connector-id con_123
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/connectors/con_123/activate \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>'
  ```
</CodeGroup>

Use it when a connector shows `error` (webhook registration failed, or the key behind it was revoked) and after you rotate the API key. The rules:

* Only the user who created the connector can activate it; anyone else gets `403`. Teammates can list, inspect, and delete a team connector, but to run it under another user's key, delete and recreate it.
* The stored credentials must still resolve to the same bot or phone number. If they do not, the call returns `409` and the connector moves to `error` with `last_error.operation` set to `register_webhook`.
* A connector that is being deleted, or that has no stored credentials, returns `409`.
* Success sets `status` to `active`, clears `last_error`, and replaces the stored scope ceiling with the calling key's current scopes.

### How a message becomes a run

1. The provider posts to the connector's webhook. Telegram requests must carry the secret header set at registration (`401` otherwise). WhatsApp requests must carry a valid `X-Hub-Signature-256` HMAC over the raw body. These signatures are the only authentication on the webhook paths.
2. The connector checks its status. `provisioning` or `activating` returns `503`, so the provider retries after the binding commits. Any other non-`active` status, or a deleted agent, is acknowledged and dropped.
3. The connector acknowledges and drops a message from any chat or sender outside the allowlist, and stores nothing.
4. The message is stored as an event, unique per connector and provider update ID. A redelivered update is ignored. Each chat gets one thread: a Telegram chat or forum topic, or a WhatsApp sender under the phone number.
5. Events in one thread are processed one at a time, in arrival order, so replies in one chat never overtake each other. A message that could not be queued when it arrived is picked up within 30 seconds.
6. Before running, the connector re-checks its stored API key. A revoked, disabled, or expired key, a removed team membership, a suspended organization, or a missing runtime scope moves the connector to `error` with `last_error.code` set to `connector_identity_revoked` and fails the event. If the check itself cannot complete, the event waits and is retried.
7. Photos and documents are downloaded from the provider (Telegram `getFile`, WhatsApp media IDs; 20 MiB cap for both) and uploaded to the Files API. The run input carries `input_image` and `input_file` items that reference those files. Provider URLs and tokens are never persisted.
8. Each thread gets one gateway conversation, created on its first message and reused afterwards. Sending `/start` in a private Telegram chat resets the thread before the next run, so the reply starts a fresh conversation.
9. The connector creates an agent run against the agent's current configuration, with `metadata` carrying `agent_connector_id`, `connector_event_id`, `connector_provider`, and `connector_actor_id`. The run is stamped with a synthetic end-user ID for the chat: `telegram:<bot-id>:chat:<chat-id>:thread:<topic-id>` (`root` when the chat has no topic) or `whatsapp:<phone-number-id>:user:<sender-id>`. `GET /api/v1/agents/{agent_id}/runs` filters by that scope, so a plain API key without `X-On-Behalf-Of` does not list connector runs. Org admins see them in the team-wide list, and any caller can pass the synthetic ID as `X-On-Behalf-Of` to read one chat's runs.
10. The final text is split into provider-sized parts and sent, followed by any generated images or files. Private Telegram chats also get a live draft preview while the model streams; Telegram groups and supergroups get a typing indicator instead. Delivery is at-least-once: a crash between the provider accepting a part and its message ID being committed can produce one duplicate on recovery.
11. When the key has `write:feedback`, a thumbs-up or thumbs-down reaction on any part of the reply becomes feedback on the gateway response, and removing the reaction clears it. Only the user whose message produced the reply can rate it.

Provider limits:

| Limit                      | Telegram                                                                 | WhatsApp                                                   |
| -------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------- |
| Inbound media download cap | 20 MiB                                                                   | 20 MiB                                                     |
| Outbound photo             | 10 MiB; larger photos, or photos Telegram rejects, are sent as documents | JPEG or PNG, 5 MiB                                         |
| Outbound document          | 50 MiB                                                                   | 50 MiB; plain text, PDF, Word, PowerPoint, and Excel types |
| Text per message           | 32,768 code points                                                       | 4,096 code points                                          |
| Feedback                   | Native reactions in private chats, groups, and supergroups               | Native thumbs reactions                                    |

Telegram albums are not merged: each item in a media group is its own update and therefore its own run. Managed files created for connector input and output are kept so retries and conversation history keep working; the connector does not delete them.

### Connector reference

Connector object fields:

| Field                                    | Description                                                                                                                                                                                                                                                                                                          |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                     | `con_...`                                                                                                                                                                                                                                                                                                            |
| `agent_id`                               | The agent the connector belongs to.                                                                                                                                                                                                                                                                                  |
| `provider`                               | `telegram` or `whatsapp`.                                                                                                                                                                                                                                                                                            |
| `name`                                   | Optional label, 1 to 120 characters.                                                                                                                                                                                                                                                                                 |
| `status`                                 | See the status table below.                                                                                                                                                                                                                                                                                          |
| `provider_account_id`                    | Telegram bot user ID, or WhatsApp phone number ID.                                                                                                                                                                                                                                                                   |
| `provider_account_name`                  | Bot username or display phone number, when the provider returned one.                                                                                                                                                                                                                                                |
| `config`                                 | `webhook_path` and the stored `access` allowlist. Telegram connectors also record `allowed_updates` (`message`, `message_reaction`, `callback_query`).                                                                                                                                                               |
| `credentials_configured`                 | `true` while encrypted credentials are stored.                                                                                                                                                                                                                                                                       |
| `last_error`                             | `null`, or an object with `provider`, `operation` (`register_webhook`, `unregister_webhook`, or `resolve_identity`), `message`, and, depending on the failure, `code` (`connector_identity_revoked` when the stored key no longer passes), `http_status`, `error_code`, `error_subcode` (WhatsApp), and `retryable`. |
| `created_at`, `updated_at`, `deleted_at` | ISO 8601 timestamps.                                                                                                                                                                                                                                                                                                 |

Connector statuses:

| Status         | Meaning                                                                                                 |
| -------------- | ------------------------------------------------------------------------------------------------------- |
| `provisioning` | Credentials validated and stored; the webhook is not registered yet. Webhook traffic is asked to retry. |
| `activating`   | Webhook registration in progress, at creation or after activate.                                        |
| `active`       | Receiving messages and running the agent.                                                               |
| `error`        | Registration, cleanup, or the key check failed. Read `last_error`, fix the cause, then activate.        |
| `deleting`     | Provider cleanup in progress. No new work starts.                                                       |
| `deleted`      | Gone. Deleted connectors are not listed.                                                                |

## Troubleshooting

| Symptom                                                                                                   | Cause                                                                                                                                                                                                                                     | Fix                                                                                                                                                   |
| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| The bot never replies                                                                                     | `status` is not `active`. Anything else is acknowledged and dropped.                                                                                                                                                                      | Read the connector; `last_error` says why. Fix the cause, then activate.                                                                              |
| The bot never replies                                                                                     | The chat or sender is not in `config.access`. Unlisted chats are dropped silently. Telegram group and supergroup IDs are negative numbers.                                                                                                | Delete the connector and create it again with the right allowlist; there is no update call.                                                           |
| Telegram stopped delivering after a token change                                                          | The stored token is the old one; credentials cannot be edited.                                                                                                                                                                            | Delete the connector and create it again with the new token. Creation drops updates queued under the old binding.                                     |
| WhatsApp messages never reach the agent                                                                   | The app-level webhook is missing in Meta, or its values differ from setup.                                                                                                                                                                | Configure **WhatsApp → Production setup → Configure Webhooks** with the exact `callback_url` and `verify_token` from setup, subscribed to `messages`. |
| WhatsApp replies are not sent                                                                             | The 24-hour customer-service window is closed.                                                                                                                                                                                            | Wait for the user to message again; the connector never sends template messages.                                                                      |
| `403` on a connector endpoint                                                                             | The request carried `X-On-Behalf-Of`; create or activate was called with a session; the key lacks `read:agents` or `write:agents`, or the runtime scopes on create and activate; or someone other than the creating user called activate. | Drop the header. Use an API key with the scopes listed under [Before you start](#before-you-start). Activate with the creating user's key.            |
| `400` at creation: "Telegram rejected the bot credentials" or "WhatsApp rejected the account credentials" | The token or app credentials are wrong.                                                                                                                                                                                                   | Check them and create again. A `502` instead means the provider was unreachable; retry.                                                               |
| `409` at creation                                                                                         | The bot or phone number is already bound to another connector, possibly in another team.                                                                                                                                                  | Delete that connector first.                                                                                                                          |
| `status: "error"` with `last_error.code` = `connector_identity_revoked`                                   | The API key behind the connector was revoked, disabled, or lost a runtime scope, or the creating user left the team.                                                                                                                      | Fix the key, then activate from the creating user's key. If that user is gone, delete the connector and create it again under another key.            |
| `status: "error"` with `last_error.operation` = `register_webhook` or `unregister_webhook`                | The provider call failed; `http_status` and `error_code` are the provider's. After activate, it can also mean the stored credentials no longer match the bot or phone number.                                                             | Activate, or repeat the delete, once the provider is healthy. If the credentials no longer match, delete and recreate.                                |
| A schedule never runs                                                                                     | `status` is `paused` or `completed`.                                                                                                                                                                                                      | Resume a paused schedule. A `completed` one has fired; create a new schedule.                                                                         |
| A `once` schedule never runs                                                                              | `run_at` was already in the past.                                                                                                                                                                                                         | Create a new schedule with a future `run_at`.                                                                                                         |
| A cron schedule fires at the wrong hour                                                                   | `timezone` is `UTC` by default. `0 9 * * 1-5` in `UTC` is early morning on the US west coast.                                                                                                                                             | Set `timezone`.                                                                                                                                       |
| `400` on create with an interval                                                                          | `interval_seconds` is below 60.                                                                                                                                                                                                           | Raise it.                                                                                                                                             |
| Ticks are missing from `run_count`                                                                        | The previous run was still executing when the next tick fired, so the tick was skipped.                                                                                                                                                   | Compare `last_run_at` with the run's duration and lengthen the interval.                                                                              |
| `run_count` never increases                                                                               | The agent was deleted; a tick for a deleted agent creates no run.                                                                                                                                                                         | Nothing to do; the schedule cannot be reached without its agent. Delete schedules before their agent.                                                 |
| `502` on create                                                                                           | The scheduler refused the schedule. Nothing was kept.                                                                                                                                                                                     | Retry the create.                                                                                                                                     |
| `502` on update                                                                                           | The new spec was saved, but the timer may not have been replaced.                                                                                                                                                                         | Repeat the update until it returns `200`.                                                                                                             |

For timed runs, see [Schedules](/docs/agent-schedules).
