WebSockets stellen eine kontinuierliche Verbindung zwischen Client und Server her und ermöglichen eine bidirektionale Kommunikation. Chatwoot nutzt diese Verbindung, um Echtzeit-Updates zu Plattformereignissen bereitzustellen. Um eine Verbindung zum Chatwoot WebSocket herzustellen, geben Sie einfach ein Token an und folgen Sie den Einrichtungsanweisungen in diesem Leitfaden.

**Hinweis**: Dieses Feature ist experimentell. Die Dokumentation kann sich mit jeder Version ändern. Außerdem kann keine Rückwärtskompatibilität garantiert werden, daher ist es wichtig, dass Sie stets die neueste Version der Implementierung verwenden.

## Warum sollte ich eine WebSocket-Verbindung verwenden?

Eine WebSocket-Verbindung ermöglicht Echtzeit-Datenaktualisierungen und ist daher ideal für Clients wie ein Android- oder iOS-SDK für Chatwoot. Dadurch kann das Dashboard aktualisiert werden, ohne dass die Seite neu geladen werden muss. Dies kann das Benutzererlebnis verbessern und die Produktivität eines Agents steigern.

## Wie richte ich eine WebSocket-Verbindung mit Chatwoot ein?

Um eine WebSocket-Verbindung mit Chatwoot herzustellen, müssen Sie eine Verbindung mit dem von Chatwoot bereitgestellten Authentifizierungs-PubSub-Token initiieren. Die URL für die Verbindung ist `wss://<your-installation-url>/cable`. Wenn Sie Chatwoot Cloud verwenden, können Sie `wss://app.chatwoot.com/cable` als URL verwenden.

> Ein PubSub-Token ist ein Token, das zur Authentifizierung eines Clients bei der Verbindung zu einem PubSub-(Publish-Subscribe-)Dienst verwendet wird. Der Client muss dieses Token dem Dienst vorlegen, um eine Verbindung herzustellen und mit dem Publizieren oder Abonnieren von Nachrichten zu beginnen.

In Chatwoot stehen die folgenden zwei Arten von PubSub-Tokens zur Verfügung.

1. **User PubSub Token**: Dieses Token hat die Berechtigungen eines Agenten/Admins und erhält alle nachfolgend auf der Seite aufgelisteten Ereignisse. Sie erhalten das PubSub-Token, indem Sie die [Profile API](https://www.chatwoot.com/developers/api/#operation/fetchProfile) aufrufen.

2. **Contact PubSub Token**: Chatwoot generiert für jede Sitzung einer Kontaktperson ein eindeutiges PubSub-Token. Dieses Token kann verwendet werden, um sich mit dem WebSocket zu verbinden und Echtzeit-Updates für dieselbe Sitzung zu empfangen. Wenn ein Kontakt über die öffentlichen APIs erstellt wird, ist das `pubsub_token` im Antwort-Payload enthalten. Dieses Token gewährt nur Zugriff auf Ereignisse, die sich auf die aktuelle Sitzung beziehen, wie z. B. `conversation.created`,  `conversation.status_changed`, `message.created`, `message.updated`, `conversation_typing_on`, `conversation_typing_off` und `presence.update`.

Bitte beachten Sie die [Client APIs](https://www.chatwoot.com/hc/user-guide/articles/1784681463-wie-erstellt-man-einen-api_kanaleingang), um Echtzeit-Integrationen für Kunden mit Chatwoot zu erstellen.

**Hinweis**: Dieses Token kann je nach Typ der Installation regelmäßig rotiert werden. Bitte stellen Sie sicher, dass Sie das aktuellste Token verwenden.

### Wie verbinde ich mich mit dem Chatwoot WebSocket?

Um sich mit dem Chatwoot WebSocket zu verbinden, verwenden Sie den Befehl `subscribe` und fügen Sie Ihr `pubSubToken`, `accountId` und `userId` (bei Verwendung eines User-Tokens) in die Verbindungsanfrage ein. Hier sehen Sie ein Beispiel, wie Sie die Verbindung zu Chatwoot herstellen können.

```
// Hilfsmethode hinzufügen, um JSON in einen String zu konvertieren
const stringify = (payload = {}) => JSON.stringify(payload);

const pubSubToken = "<contact/user-pub-sub-token>";
const accountId = "<your-account-id-in-integer>";
const userId = "<user-id-in-integer-if-using-user-token>";
const connection = new WebSocket(
  "wss://app.chatwoot.com/cable"
);

connection.send(
  stringify({
    command: "subscribe",
    identifier: stringify({
      channel: "RoomChannel",
      pubsub_token: pubSubToken,
      account_id: accountId,
      user_id: userId,
    }),
  })
);

// Der erwartete String in connection.send hat folgendes Format:
// {"command":"subscribe","identifier":"{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"your-pubsub-token\\",\\"account_id\\": account_id_integer,\\"user_id\\":user_id_integer }"}
```

### Anwesenheitsstatus an den WebSocket-Server senden

Um den Online-Status Ihrer Benutzer in Chatwoot aufrechtzuerhalten, können Sie alle 30 Sekunden ein Anwesenheits-Update an Chatwoot senden. Diese Aktion hält den Status des Agenten/Kontakts online.

**Wie aktualisiere ich den Anwesenheitsstatus eines Agenten/Admins?**

Um die Anwesenheit eines Agenten oder Admins zu aktualisieren, senden Sie folgenden Payload an den Server:

```
const userPayload = stringify({
  command: "message",
  identifier: stringify({
    channel: "RoomChannel",
    pubsub_token: "<user-pubsub-token>",
    account_id: accountId,
    user_id: userId,
  }),
  data: stringify({ action: "update_presence" }),
});

connection.send(userPayload);
// Der erwartete String in connection.send hat folgendes Format:
// {"command":"message","identifier":"{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"your-pubsub-token\\",\\"account_id\\": account_id_integer,\\"user_id\\":user_id_integer ","data":"{\\"action\\":\\"update_presence\\"}"}
```

**Wie aktualisiere ich den Anwesenheitsstatus eines Kontakts?**

Um die Anwesenheit eines Kontakts zu aktualisieren, senden Sie folgenden Payload an den Server:

```
const agentPayload = stringify({
  command: "message",
  identifier: stringify({
    channel: "RoomChannel",
    pubsub_token: "<user-pubsub-token>",
  }),
  data: stringify({ action: "update_presence" }),
});

connection.send(agentPayload);
// Der erwartete String in connection.send hat folgendes Format:
// {"command":"message","identifier":"{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"your-pubsub-token\\","data":"{\\"action\\":\\"update_presence\\"}"}
```

## WebSocket-Payload

### Objekte

Ein Ereignis kann eines der folgenden Objekte als Payload enthalten. Die verschiedenen von Chatwoot unterstützten Objekttypen sind wie folgt.

**Conversation**

Für eine Konversation wird folgendes Payload zurückgegeben.

```
{
  "additional_attributes": {
    "browser": {
      "device_name": "string",
      "browser_name": "string",
      "platform_name": "string",
      "browser_version": "string",
      "platform_version": "string"
    },
    "referer": "string",
    "initiated_at": {
      "timestamp": "iso-datetime"
    }
  },
  "can_reply": "boolean",
  "channel": "string",
  "id": "integer",
  "inbox_id": "integer",
  "contact_inbox": {
    "id": "integer",
    "contact_id": "integer",
    "inbox_id": "integer",
    "source_id": "string",
    "created_at": "datetime",
    "updated_at": "datetime",
    "hmac_verified": "boolean"
  },
  "messages": ["Array of message objects"],
  "meta": {
    "sender": {
      // Contact Object
    },
    "assignee": {
      // User Object
    }
  },
  "status": "string",
  "unread_count": "integer",
  "agent_last_seen_at": "unix-timestamp",
  "contact_last_seen_at": "unix-timestamp",
  "timestamp": "unix-timestamp",
  "account_id": "integer"
}
```

**Contact**

Für einen Kontakt wird folgendes Payload zurückgegeben.

```
{
  "additional_attributes": "object",
  "custom_attributes": "object",
  "email": "string",
  "id": "integer",
  "identifier": "string or null",
  "name": "string",
  "phone_number": "string or null",
  "thumbnail": "string"
}
```

**User**

Für einen Agent/Admin wird folgendes Payload zurückgegeben.

```
{
  "id": "integer",
  "name": "string",
  "available_name": "string",
  "avatar_url": "string",
  "availability_status": "string",
  "thumbnail": "string"
}
```

**Message**

Für eine Nachricht wird folgendes Payload zurückgegeben.

```
{
  "id": "integer",
  "content": "string",
  "account_id": "integer",
  "inbox_id": "integer",
  "message_type": "integer",
  "created_at": "unix-timestamp",
  "updated_at": "datetime",
  "private": "boolean",
  "status": "string",
  "source_id": "string / null",
  "content_type": "string",
  "content_attributes": "object",
  "sender_type": "string",
  "sender_id": "integer",
  "external_source_ids": "object",
  "sender": {
    "type": "string - contact/user"
    // User oder Contact Object
  }
}
```

**Notification**

Für eine Benachrichtigung wird folgendes Payload zurückgegeben.

```
{
  "id": "integer",
  "notification_type": "string",
  "primary_actor_type": "string",
  "primary_actor_id": "integer",
  "primary_actor": {
    "can_reply": "boolean",
    "channel": "string",
    "id": "integer",
    "inbox_id": "integer",
    "meta": {
      "assignee": {
        "id": "integer",
        "name": "string",
        "available_name": "string",
        "avatar_url": "string",
        "type": "user",
        "availability_status": "string",
        "thumbnail": "string"
      },
      "hmac_verified": "boolean"
    },
    "agent_last_seen_at": "unix-timestamp",
    "contact_last_seen_at": "unix-timestamp",
    "timestamp": "unix-timestamp",
  },
  "read_at": "unix-timestamp",
  "secondary_actor": "object/null",
  "created_at":"unix-timestamp",
  "account_id": "integer",
  "push_message_title": "string"
}
```

### Identifier

Jedes Ereignis hat ein `identifier`-Attribut im folgenden Format.

```
{
  "identifier": "{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"token\\",\\"account_id\\":id,\\"user_id\\":user_id}"
}
```

### Message

Jedes Ereignis enthält ein `message`-Attribut, in dem der Ereignisname sowie die zugehörigen Daten zurückgegeben werden. Um die Liste der Ereignisse zu sehen, finden Sie die Dokumentation unten.

## Ereignistypen

### conversation.created

Dieses Ereignis wird ausgelöst, wenn eine neue Konversation initiiert wird. Beim Abonnieren des PubSub-Tokens eines Kontakts enthält dieses Ereignis nur Daten zur spezifischen Sitzung, die mit dem PubSub-Token verknüpft ist.

**Verfügbar für**: Agent/Admin, Kontakt

```
{
  "message": {
    "event": "conversation.created",
    "data": {
      // Hier steht das Konversationsobjekt zur Verfügung
    }
  }
}
```

### conversation.read

Dieses Ereignis wird ausgelöst und an die Agents/Admins gesendet, die Zugriff auf die Inbox haben, wenn ein Kontakt eine Nachricht gelesen hat.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "conversation.read",
    "data": {
      // Hier steht das Konversationsobjekt zur Verfügung
    }
  }
}
```

### message.created

Dieses Ereignis wird an die Agents, Admins, Kontakte gesendet, wenn eine neue Nachricht in einer Konversation erstellt wird, auf die sie Zugriff haben.

**Verfügbar für**: Agent/Admin, Kontakt

```
{
  "message": {
    "event": "message.created",
    "data": {
      // Hier steht das Nachrichtenobjekt zur Verfügung
    }
  }
}
```

### message.updated

Dieses Ereignis wird an die Agents, Admins, Kontakte gesendet, wenn eine Nachricht in einer Konversation aktualisiert wird, auf die sie Zugriff haben.

**Verfügbar für**: Agent/Admin, Kontakt

```
{
  "message": {
    "event": "message.updated",
    "data": {
      // Hier steht das Nachrichtenobjekt zur Verfügung
    }
  }
}
```

### conversation.status_changed

Dieses Ereignis wird an die Agents, Admins, Kontakte gesendet, wenn sich der Status einer Konversation ändert.

**Verfügbar für**: Agent/Admin, Kontakt

```
{
  "message": {
    "event": "conversation.status_changed",
    "data": {
      // Hier steht das Konversationsobjekt zur Verfügung
    }
  }
}
```

### conversation.typing_on

Dieses Ereignis wird an die Agents, Admins, Kontakte gesendet, wenn ein Kontakt oder ein Agent beginnt, eine Antwort zu schreiben.

**Verfügbar für**: Agent/Admin, Kontakt

```
{
  "message": {
    "event": "conversation.typing_on",
    "data": {
      "conversation": {
        // Hier steht das Konversationsobjekt zur Verfügung
      },
      "user": {
        // Hier steht das Kontakt-/Agent- bzw. Admin-Benutzerobjekt zur Verfügung.
      },
      "is_private": "boolean", // Zeigt, ob der Agent eine private Notiz tippt oder nicht.
      "account_id": "integer"
    }
  }
}
```

### conversation.typing_off

Dieses Ereignis wird an die Agents, Admins, Kontakte gesendet, wenn ein Kontakt oder ein Agent das Schreiben einer Antwort beendet.

**Verfügbar für**: Agent/Admin, Kontakt

```
{
  "message": {
    "event": "conversation.typing_off",
    "data": {
      "conversation": {
        // Hier steht das Konversationsobjekt zur Verfügung
      },
      "user": {
        // Hier steht das Kontakt- oder Benutzerobjekt zur Verfügung.
      },
      "account_id": "integer"
    }
  }
}
```

### assignee.changed

Dieses Ereignis wird an die Agents/Admins mit Zugriff auf eine Inbox gesendet, wenn der zugewiesene Agent geändert wird.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "assignee.changed",
    "data": {
      // Hier steht das Konversationsobjekt zur Verfügung
    }
  }
}
```

### team.changed

Dieses Ereignis wird an die Agents/Admins mit Zugriff auf eine Inbox gesendet, wenn das zugewiesene Team geändert wird.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "team.changed",
    "data": {
      // Hier steht das Konversationsobjekt zur Verfügung
    }
  }
}
```

### conversation.contact_changed

Dieses Ereignis wird an die Agents/Admins gesendet, wenn zwei Kontakte zusammengeführt und deren Konversationen unter einem Kontakt konsolidiert werden.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "conversation.contact_changed",
    "data": {
      // Hier steht das Konversationsobjekt zur Verfügung
    }
  }
}
```

### contact.created

Dieses Ereignis wird an die Agents/Admins gesendet, wenn ein Kontakt erstellt wird.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "contact.created",
    "data": {
      // Hier steht das Kontaktobjekt zur Verfügung
    }
  }
}
```

### contact.updated

Dieses Ereignis wird an die Agents/Admins gesendet, wenn ein Kontakt aktualisiert wird.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "contact.updated",
    "data": {
      // Hier steht das Kontaktobjekt zur Verfügung
    }
  }
}
```

### presence.update

Dieses Ereignis steht sowohl für Agenten als auch Kontakte zur Verfügung und bietet Echtzeit-Updates über den Verfügbarkeitsstatus der Benutzer im System. Das an Kontakte gesendete Ereignis enthält keine Informationen über den Verfügbarkeitsstatus anderer Kontakte.

**Verfügbar für**: Agent/Admin

```
{
  "message": {
    "event": "presence.update",
    "data": {
      "account_id": "integer",
      "users": {
        "user-id": "string"
      },
      "contacts": {
        "contact-id": "string"
      }
    }
  }
}
```

### notification_created

Dieses Ereignis wird an die Agents/Admins gesendet, wenn eine Benachrichtigung erstellt wird.

**Verfügbar für**: Agent/Admin