Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Surveillance à distance des patients avec FHIR
Des relevés de tension artérielle à domicile aux alertes : Observations de l'appareil, webhooks signés, règle idempotente et ce qui reste en dehors de la couche de données. Code testé.
La surveillance à distance des patients (RPM) collecte les mesures qu'un patient prend à domicile — tension artérielle, poids, glycémie, saturation en oxygène — et permet à une équipe de soins de les visualiser et d'agir en conséquence entre les visites. La partie données comprend quatre étapes : intégrer chaque lecture dans le dossier du patient en tant qu'Observation codée et attribuée au périphérique ; réagir à l'arrivée d'une nouvelle lecture ; décider avec une règle claire si elle nécessite une attention ; et conserver un enregistrement de ce que l'équipe a fait. Cette page construit ce pipeline sur HL7 FHIR R4 avec les webhooks Anpheros et le SDK TypeScript, avec du code qui a été exécuté sur la plateforme, et liste ce qui reste en dehors de la couche de données.
Le pipeline
cuff, scale, glucose meter, pulse oximeter
│ (Bluetooth / vendor app / Apple Health / Health Connect)
▼
patient's phone app ──► your backend ──► FHIR Observation (author: device) in the patient's record
│ webhook: resource.created (signed)
▼
your monitoring service: rule → alert → care team
│
note, call, CarePlan change, next appointment
Trois choix déterminent si cela fonctionne en pratique :
- Une lecture, une Observation. Chaque mesure du brassard est une Observation avec LOINC 85354-9 et deux composantes (8480-6 systolique, 8462-4 diastolique), l'heure de la mesure et
author_type: device. Contrairement aux résumés des dispositifs portables quotidiens, les lectures RPM sont des mesures individuelles qu'un clinicien peut examiner une par une. - Réagir aux événements, pas à un minuteur. Un webhook par nouvelle Observation permet à la règle de s'exécuter quelques secondes après l'arrivée de la lecture.
- Règles sur plusieurs lectures. Une seule lecture élevée est souvent du bruit ; la plupart des protocoles examinent une série. La règle ci-dessous demande trois lectures consécutives à ou au-dessus de 140/90. Ce seuil est un exemple, pas un avis clinique : l'équipe de soins définit la règle pour chaque patient.
Écriture des lectures depuis l'appareil
L'application mobile (ou le cloud du fournisseur de l'appareil, via votre backend) écrit chaque lecture :
await anpheros.observations.create(patientId, {
code: '85354-9', category: 'vital-signs', effective_at: '2026-10-13T07:15:00-04:00', author_type: 'device',
components: [{ code: '8480-6', value: 152, unit: 'mm[Hg]' }, { code: '8462-4', value: 95, unit: 'mm[Hg]' }],
}, { source_system: 'bp-cuff-app' });
Si les lectures proviennent d'Apple Health ou de Health Connect plutôt que directement de l'appareil, lisez-les sur le téléphone comme décrit dans Données portables en FHIR, mais conservez les lectures individuelles de tension artérielle comme des Observations individuelles au lieu de moyennes quotidiennes.
Réagir aux nouvelles lectures
Enregistrez un point de terminaison de webhook une fois (POST /v1/webhooks avec events: ["resource.created"]) ; la réponse contient le secret de signature. Ensuite, exécutez un petit service qui vérifie chaque livraison et évalue la règle :
import { createServer } from 'node:http';
import { Anpheros, apiKey, verifyWebhookSignature } from '@anpheros/sdk';
const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) });
const SECRET = process.env.WEBHOOK_SECRET!;
const seen = new Set<string>(); // deliveries are at-least-once: de-duplicate by event id
const alerted = new Set<string>(); // one alert per newest reading, however many events arrive
// Rule: the three most recent home readings all at or above 140/90 → tell the care team once
async function checkBloodPressure(patientId: string, observationId: string) {
const obs = await anpheros.observations.get(observationId);
if (obs.code !== '85354-9') return; // only blood pressure readings trigger the rule
const { data } = await anpheros.observations.list(patientId, { code: '85354-9', limit: 3 }); // newest first
const value = (o: typeof obs, code: string) => o.components.find(c => c.code === code)?.value ?? 0;
const allHigh = data.length === 3 && data.every(o => value(o, '8480-6') >= 140 || value(o, '8462-4') >= 90);
if (!allHigh || alerted.has(data[0].id)) return;
alerted.add(data[0].id);
console.log(`ALERT patient ${patientId}: last 3 readings ≥ 140/90 →`,
data.map(o => `${value(o, '8480-6')}/${value(o, '8462-4')}`).join(', ')); // in production: notify the care team
}
createServer(async (req, res) => {
const chunks: Buffer[] = [];
for await (const c of req) chunks.push(c as Buffer);
const body = Buffer.concat(chunks).toString('utf8');
const ok = await verifyWebhookSignature({ secret: SECRET, header: req.headers['anpheros-signature'] as string, body });
if (!ok) { res.writeHead(400).end(); return; } // not from Anpheros, or too old
res.writeHead(204).end(); // answer fast; do the work after
const event = JSON.parse(body);
if (seen.has(event.id)) return;
seen.add(event.id);
const d = event.data;
if (event.type === 'resource.created' && d.resource_type === 'Observation') await checkBloodPressure(d.patient, d.id);
}).listen(8799);
Comment nous l'avons testé : quatre lectures matinales (136/86, 144/92, 149/94, 152/95) ont été écrites sur un patient synthétique sur une instance locale de la plateforme, et la plateforme a produit un événement resource.created signé par lecture. Ces événements, signés avec le code de signature propre à la plateforme, ont été envoyés au service ci-dessus avec deux doublons et une requête signée avec un mauvais secret. Le résultat : la mauvaise signature a obtenu 400, les doublons ont été ignorés, et le service a déclenché exactement une alerte — 152/95, 149/94, 144/92 — pas une par événement.
En production, conservez seen et alerted dans une base de données plutôt qu'en mémoire, afin qu'un redémarrage ne répète pas les alertes.
Réception des webhooks pendant le développement. Anpheros accepte et ne livre qu'à des points de terminaison HTTPS publics : une adresse localhost ou privée est refusée lors de son enregistrement (400, champ url), même dans le bac à sable, et chaque livraison vérifie à nouveau l'adresse. Pour recevoir des événements sur votre ordinateur portable, exposez le service via un tunnel HTTPS public et enregistrez l'adresse du tunnel. Voir Webhooks.
Ce que l'enregistrement doit montrer par la suite
L'alerte elle-même réside dans votre service de surveillance, mais l'enregistrement doit montrer ce qu'il en est résulté, afin que le prochain clinicien et le patient voient l'histoire complète :
- les relevés, chacun marqué comme données de l'appareil avec son système source (provenance) ;
- un
CarePlanavec le plan de surveillance (ce qui est mesuré, à quelle fréquence, l'objectif) ; - un
Encounter(classeVRpour un contact à distance) lorsque l'équipe appelle le patient, et tout changement de médication comme unMedicationStatement.
Anpheros stocke ces ressources ; il n'a pas de ressource d'alerte ou de tâche propre (Flag, Task et Communication ne font pas partie de ses types de ressources), donc les files d'attente d'alertes et le routage des gardes appartiennent à votre service.
Facturation, réglementation et sécurité
Les programmes de RPM dépendent souvent des règles de remboursement — aux États-Unis, Medicare paie pour la surveillance physiologique à distance sous des codes CPT spécifiques avec un nombre minimum de jours de données et de temps passé par l'équipe de soins. Ces règles changent et ne sont pas quelque chose qu'une plateforme de données peut certifier ; vérifiez les règles actuelles du CMS et conservez les preuves (les relevés et le temps de l'équipe) dans votre propre système. Les logiciels qui interprètent les relevés pour orienter le diagnostic ou le traitement peuvent être réglementés en tant que dispositif médical. Gardez les seuils entre les mains des cliniciens et enregistrez chaque alerte et réponse.
Où Anpheros s'intègre
Anpheros fournit l'enregistrement (Observations FHIR R4 avec provenance, CarePlan, Encounter), des webhooks signés avec tentatives de relance, le consentement si l'application d'une autre organisation a besoin de lire les relevés, et un journal d'accès consultable par le patient. Il ne se connecte pas aux fournisseurs d'appareils, ne décide pas de ce qui est anormal, n'envoie pas d'alertes et ne gère pas la facturation.
Foire aux questions
Quelle ressource FHIR stocke une mesure de tension artérielle à domicile ?
Une Observation avec LOINC 85354-9 (panel de tension artérielle) et deux composantes, 8480-6 (systolique) et 8462-4 (diastolique), chacune étant une valueQuantity dans mm[Hg], avec l'heure de la mesure et l'appareil comme auteur.
Les données RPM doivent-elles être des moyennes journalières ou des lectures individuelles ?
Lectures individuelles pour les mesures cliniques telles que la tension artérielle, le poids ou la glycémie, car les cliniciens les examinent et les comptent. Les résumés journaliers conviennent aux données de haute fréquence des wearables telles que la fréquence cardiaque ou les pas.
Comment déclencher une alerte lorsqu'une nouvelle lecture arrive ?
Abonnez-vous aux webhooks resource.created, vérifiez la signature, récupérez la nouvelle Observation et évaluez votre règle sur la série récente. Les livraisons peuvent se répéter, alors dédupliquez par identifiant d'événement et rendez l'alerte idempotente.
Anpheros peut-il envoyer des alertes aux cliniciens ?
Non. Il notifie votre service via des webhooks ; qui est alerté, comment et quand est décidé dans votre système.
Liens Utiles
- Données des appareils portables en FHIR
- Soins virtuels et médecins IA : les données dont ils ont besoin
- Webhooks
- Provenance des données médicales expliquée
- Intégrations de soins de santé
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card