Aller au contenu
Documentation

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.

7 min de lecture Mise à jour le 12 novembre 2026

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 (accessTokenFactory en JavaScript, AccessTokenProvider en .NET) : elle le redemande à chaque connexion et à chaque reconnexion, et le transmet seule — dans l'en-tête Authorization, ou dans le paramètre access_token pour 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 leur Z, é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.
JavaScript
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 MarkAsDisplayed quand 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 par Id.
  • 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, jamais message.conversationId.
  • Votre propre message vous revient, parfois avant la réponse de POST https://staging-api.docage.com/Conversations/{id}/Messages : reconnaissez-le à son ClientMessageId.
  • 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.