Temps réel
Recevoir les messages des conversations d'un utilisateur dès qu'ils arrivent, par une connexion SignalR ouverte en son nom — se connecter, écouter, rattraper.
Une application ouverte au nom d'un utilisateur — application mobile, poste de travail, panneau de votre logiciel — reçoit en temps réel ce qui arrive dans ses conversations, par un hub SignalR : un message reçu ou modifié, un collègue qui écrit, une conversation lue, une personne qui se connecte. Elle n'a plus à relire le fil à intervalles réguliers.
Le hub s'ouvre avec les bibliothèques clientes officielles de SignalR :
@microsoft/signalr en JavaScript, Microsoft.AspNetCore.SignalR.Client en .NET (MAUI compris), com.microsoft.signalr en Java.
Temps réel ou webhook ?
- Un webhook appelle votre serveur quand une fiche change, que quelqu'un soit connecté ou non : c'est l'outil pour tenir un autre système à jour.
- Le temps réel prévient une application ouverte de ce que son utilisateur voit dans ses conversations, tant qu'elle est connectée : rien n'est gardé pour elle quand elle ne l'est pas.
Se connecter
L'adresse du hub :
https://staging-api.docage.com/hubs/conversation- Le jeton de l'utilisateur, celui de vos autres appels (voir S'authentifier) ; la clé API n'est pas
acceptée. Confiez à la bibliothèque une fonction qui rend le jeton en cours (
accessTokenFactoryen JavaScript,AccessTokenProvideren .NET) : elle le redemande à chaque connexion et à chaque reconnexion, et le transmet seule — dans l'en-têteAuthorization, ou dans le paramètreaccess_tokenpour un WebSocket ouvert par un navigateur. - Aucun jeton demandé pour le hub seul : ce serait une seconde connexion du même type que vos autres appels, facturée quand les
deux servent dans la même minute. Prolongez le jeton en cours (
POST https://staging-api.docage.com/Account/refreshtoken) : la fonction rendra le nouveau. - Du JSON, aux conventions de l'API (voir Commencer) : noms en PascalCase (
ConversationId) — et non en camelCase, le défaut de SignalR —, dates en UTC avec leurZ, énumérations en nombres. - Depuis un navigateur, une WebView comprise, la règle d'origine (CORS) du hub n'admet que les pages de l'application elle-même : une application web ou hybride tierce l'ouvre depuis son serveur. Une application native — iOS, Android, de bureau — n'est pas concernée.
import * as signalR from "@microsoft/signalr";
const delais = [0, 2000, 5000, 10000, 30000, 60000];
const connexion = new signalR.HubConnectionBuilder()
.withUrl("https://staging-api.docage.com/hubs/conversation", { accessTokenFactory: () => jetonEnCours() })
// Reconnexion sans fin : au-delà du dernier délai, un essai par minute.
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: essai => delais[Math.min(essai.previousRetryCount, delais.length - 1)]
})
.build();
connexion.on("conversationMessageReceived", message => afficher(message.ConversationId, message));
connexion.onreconnected(() => rattraper());
await connexion.start();En .NET, la même chose : HubConnectionBuilder, WithUrl avec options.AccessTokenProvider, et WithAutomaticReconnect avec une
IRetryPolicy qui ne rend jamais null. La reconnexion automatique ne couvre pas un premier démarrage qui échoue : relancez
start() (StartAsync()) vous-même, après un délai.
Ce que vous recevez
L'utilisateur reçoit, sur chacune de ses connexions — un autre appareil, un autre onglet —, ce qui touche les conversations dont il
est participant, celles qu'il suit comprises, et seulement ce qu'il y verrait en lisant le fil. Aucun abonnement à prendre en
ouvrant une conversation : un seul hub sert toutes les siennes, et chaque événement dit laquelle (ConversationId).
Ce qui n'est pas un échange — un code de sécurité, une invitation, un envoi de campagne — n'est pas poussé : il paraît à la lecture du fil.
| Événement | Quand | Ce qu'il porte |
|---|---|---|
conversationMessageReceived |
Un message est arrivé — y compris celui de l'utilisateur, écrit depuis cette application ou une autre. | Le message, tel que le rend GET https://staging-api.docage.com/Conversations/{id}/Messages. |
conversationMessageUpdated |
Un message a changé : son texte, le statut d'un email, d'un SMS ou d'un message WhatsApp (remis, lu, en erreur), la carte d'une réponse de l'assistant IA. | Le message entier, sous le même Id. |
conversationMessageDeleted |
Un message du chat a été supprimé ; relu, il porte DeletedAtUtc et n'a plus de texte. |
ConversationId, MessageId. |
conversationMessageReactionsChanged |
Quelqu'un a posé ou retiré une réaction sur un message du chat. | ConversationId, MessageId, Reactions — toutes les réactions du message, comme dans le fil. |
conversationChanged |
La conversation a changé : relisez son état par GET https://staging-api.docage.com/Conversations/{id}/Summary. |
ConversationId, Change (ci-dessous), Status : 1 ouverte, 2 fermée. |
conversationTyping |
Quelqu'un écrit, ou a cessé d'écrire. | ConversationId, DocageUserId ou ContactId, Name, IsTyping ; IsAssistant à true quand c'est l'assistant IA. |
conversationRead |
Un participant a tout lu (« Consulté »). | ConversationId, DocageUserId ou ContactId, ReadAtUtc. |
conversationDisplayed |
Un participant a vu passer les messages sans ouvrir la conversation (« Affiché »). | ConversationId, DocageUserId ou ContactId, DisplayedAtUtc. |
conversationPresenceChanged |
Une personne s'est connectée au hub, ou l'a quitté : un utilisateur de l'organisation, ou l'invité d'une de ses conversations. | DocageUserId ou ContactId, IsOnline, LastSeenAtUtc — l'heure du départ. |
absencePresenceChanged |
L'absence d'un utilisateur de l'organisation a changé : redemandez sa présence (GetPresence). |
AbsenceId, DocageUserId. |
Change |
Ce qui a changé |
|---|---|
1 |
Les participants. |
2 |
La conversation est fermée. |
3 |
Elle est rouverte. |
4 |
Les fiches liées. |
5 |
Un message a quitté le fil — un envoi programmé annulé : relisez le fil. |
6 |
L'utilisateur l'a reportée, ou elle est revenue ; lui seul le reçoit. |
7 |
Son brouillon a été préparé par son assistant IA ; lui seul le reçoit. |
Ce que vous pouvez appeler
| Méthode | Arguments | Effet |
|---|---|---|
MarkAsRead |
L'identifiant de la conversation. | Tout est lu jusqu'à maintenant, comme par POST https://staging-api.docage.com/Conversations/{id}/Read — et les participants le savent aussitôt (conversationRead). |
MarkAsDisplayed |
La conversation ; l'instant (UTC) du dernier message montré, null pour maintenant. |
Ce que l'application a montré sans ouvrir la conversation — une notification, une liste — passe « Affiché » chez son auteur. Ce n'est pas une lecture. |
Typing |
La conversation ; true ou false. |
« … écrit » chez les autres participants. |
GetPresence |
Une liste d'identifiants d'utilisateurs, une liste d'identifiants de contacts. | Rend ceux qui sont connectés (OnlineDocageUserIds, OnlineContactIds), l'heure du départ des autres quand le serveur la connaît (LastSeen), et l'absence en cours des utilisateurs (Absences), telle que l'utilisateur a le droit de la voir. Dans son organisation seulement. |
- Une méthode refusée — une conversation que l'utilisateur ne peut pas lire, ou, pour
Typing, où il ne peut pas écrire — ne fait rien, sans erreur. - « … écrit » : envoyez
trueà la première frappe,falseà l'envoi ou après deux secondes sans frappe ; à la réception, éteignez un « … écrit » resté trente secondes sans nouvelle. - Appelez
MarkAsDisplayedquand vous montrez un message reçu sans ouvrir sa conversation : sinon son auteur reste à « Envoyé » jusqu'à la lecture.
Se reconnecter et rattraper
Le hub n'est qu'un signal : la conversation, lue par l'API, reste la référence. Rien n'est gardé pour une application déconnectée, ni rejoué à sa reconnexion.
- Reconnectez sans fin, à intervalles croissants jusqu'à une minute, et relancez la connexion au retour du réseau ou de l'application au premier plan : iOS et Android coupent les connexions d'une application en arrière-plan.
- Rattrapez à chaque reconnexion : la liste des conversations (
GET https://staging-api.docage.com/Conversations/Mine), puis, pour celle qui est à l'écran, les messages qui suivent le dernier que vous avez —GET https://staging-api.docage.com/Conversations/{id}/Messages?after=…, avec l'instant (OccurredAtUtc) de ce message. Un message déjà reçu peut revenir : dédoublonnez parId. - Le jeton n'est vérifié qu'à la connexion : une connexion ouverte survit à son expiration, la suivante exige un jeton valable — d'où la fonction qui rend le jeton en cours.
- Une application fermée ne reçoit rien, ni par le hub ni par l'API : une notification sur un téléphone verrouillé relève des services de son système (APNs, FCM), avec les clés de l'éditeur de l'application.
Avec l'assistant IA
Une demande confiée à l'assistant IA d'un utilisateur se suit sans relire la
conversation : ses réponses arrivent par conversationMessageReceived (Origin à 3, avec leur Card), une proposition décidée
revient par conversationMessageUpdated, et conversationTyping avec IsAssistant à true dit qu'il écrit. La fin d'une demande se
lit par son traitement, comme le dit Confier une demande et lire la réponse :
relisez-le quand un message de l'assistant arrive — sa dernière réponse arrive juste avant qu'il ne rende la main —, puis toutes les
deux ou trois secondes tant qu'il travaille.
Les pièges
- Les noms sont en PascalCase : en JavaScript,
message.ConversationId, jamaismessage.conversationId. - Votre propre message vous revient, parfois avant la réponse de
POST https://staging-api.docage.com/Conversations/{id}/Messages: reconnaissez-le à sonClientMessageId. - La présence suit le hub : un utilisateur est « en ligne » pour ses collègues tant qu'une de ses applications y est connectée. Fermez la connexion quand l'application ne sert plus.
- C'est le seul hub ouvert aux intégrateurs : ceux que l'application emploie pour ses propres écrans ne font pas partie de l'API, et peuvent changer sans préavis.