Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Monitorização remota de pacientes com FHIR
De leituras de pressão arterial em casa a alertas: Observações de dispositivos, webhooks assinados, uma regra idempotente e o que fica fora da camada de dados. Código testado.
A monitorização remota de pacientes (RPM) recolhe medições que um paciente faz em casa — pressão arterial, peso, glicose, saturação de oxigénio — e permite que uma equipa de cuidados as veja e aja sobre elas entre consultas. A parte dos dados tem quatro passos: obter cada leitura para o registo do paciente como uma Observação codificada e atribuída ao dispositivo; reagir quando chega uma nova leitura; decidir com uma regra clara se necessita de atenção; e manter um registo do que a equipa fez. Esta página constrói esse pipeline em HL7 FHIR R4 com webhooks Anpheros e o SDK TypeScript, com código que foi executado na plataforma, e lista o que fica fora da camada de dados.
O 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
Três escolhas decidem se isto funciona na prática:
- Uma leitura, uma Observation. Cada leitura do manguito é uma Observation com LOINC 85354-9 e dois componentes (8480-6 sistólica, 8462-4 diastólica), a hora da medição e
author_type: device. Ao contrário dos resumos diários de dispositivos vestíveis, as leituras de RPM são medições individuais que um clínico pode analisar uma a uma. - Reagir a eventos, não a um temporizador. Um webhook por nova Observation permite que a regra seja executada segundos após a chegada da leitura.
- Regras sobre várias leituras. Uma única leitura elevada é frequentemente ruído; a maioria dos protocolos analisa uma série. A regra abaixo solicita três leituras consecutivas iguais ou superiores a 140/90. Esse limite é um exemplo, não um conselho clínico: a equipa de saúde define a regra para cada paciente.
Escrever leituras do dispositivo
A aplicação móvel (ou a nuvem do fornecedor do dispositivo, através do seu backend) escreve cada leitura:
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' });
Se as leituras vierem através do Apple Health ou Health Connect em vez de diretamente do dispositivo, leia-as no telemóvel conforme descrito em Dados de wearables em FHIR, mas mantenha as leituras individuais de pressão arterial como Observações individuais em vez de médias diárias.
Reagir a novas leituras
Registe um endpoint de webhook uma vez (POST /v1/webhooks com events: ["resource.created"]); a resposta contém o segredo de assinatura. Em seguida, execute um pequeno serviço que verifica cada entrega e avalia a regra:
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);
Como testámos: quatro leituras matinais (136/86, 144/92, 149/94, 152/95) foram escritas num paciente sintético numa instância local da plataforma, e a plataforma produziu um evento resource.created assinado por leitura. Esses eventos, assinados com o código de assinatura próprio da plataforma, foram enviados para o serviço acima juntamente com dois duplicados e um pedido assinado com um segredo incorreto. O resultado: a assinatura incorreta recebeu 400, os duplicados foram ignorados e o serviço levantou exatamente um alerta — 152/95, 149/94, 144/92 — não um por evento.
Em produção, mantenha seen e alerted numa base de dados em vez de na memória, para que um reinício não repita alertas.
Receber webhooks durante o desenvolvimento. Anpheros aceita e entrega apenas a endpoints HTTPS públicos: um endereço localhost ou privado é recusado quando o regista (400, campo url), mesmo na sandbox, e cada entrega verifica o endereço novamente. Para receber eventos no seu portátil, exponha o serviço através de um túnel HTTPS público e registe o endereço do túnel. Ver Webhooks.
O que o registo deve mostrar posteriormente
O alerta em si reside no seu serviço de monitorização, mas o registo deve mostrar o que resultou dele, para que o próximo clínico e o paciente vejam a história completa:
- as leituras, cada uma marcada como dados do dispositivo com o seu sistema de origem (proveniência);
- um
CarePlancom o plano de monitorização (o que é medido, com que frequência, o objetivo); - um
Encounter(classeVRpara um contacto remoto) quando a equipa contacta o paciente, e qualquer alteração de medicação como umMedicationStatement.
Anpheros armazena estes recursos; não tem um recurso de alerta ou tarefa próprio (Flag, Task e Communication não estão entre os seus tipos de recurso), pelo que as filas de alertas e o encaminhamento de chamadas pertencem ao seu serviço.
Faturação, regulamentação e segurança
Os programas de RPM dependem frequentemente de regras de reembolso — nos Estados Unidos, o Medicare paga pela monitorização fisiológica remota sob códigos CPT específicos com um número mínimo de dias com dados e tempo despendido pela equipa de saúde. Essas regras mudam e não são algo que uma plataforma de dados possa certificar; consulte as regras atuais da CMS e mantenha as evidências (as leituras e o tempo da equipa) no seu próprio sistema. Software que interpreta leituras para orientar o diagnóstico ou tratamento pode ser regulamentado como um dispositivo médico. Mantenha os limiares nas mãos dos clínicos e registe todos os alertas e respostas.
Onde o Anpheros se encaixa
O Anpheros fornece o registo (Observações FHIR R4 com proveniência, CarePlan, Encounter), webhooks assinados com retentativas, consentimento se a aplicação de outra organização precisar de ler as leituras, e um registo de acesso que o paciente pode ver. Não se conecta a fornecedores de dispositivos, não decide o que é anormal, não envia alertas nem trata de faturação.
Perguntas Frequentes
Qual recurso FHIR armazena uma leitura de pressão arterial em casa?
Uma Observation com LOINC 85354-9 (painel de pressão arterial) e dois componentes, 8480-6 (sistólica) e 8462-4 (diastólica), cada um um valueQuantity em mm[Hg], com o tempo da medição e o dispositivo como autor.
Os dados de RPM devem ser médias diárias ou leituras individuais?
Leituras individuais para medições clínicas como pressão arterial, peso ou glicose, pois os clínicos as analisam e contam. Resumos diários são adequados para dados de wearables de alta frequência, como frequência cardíaca ou passos.
Como aciono um alerta quando uma nova leitura chega?
Subscreva os webhooks resource.created, verifique a assinatura, obtenha a nova Observation e avalie a sua regra sobre a série recente. As entregas podem repetir-se, pelo que deduplique por ID de evento e torne o alerta idempotente.
O Anpheros pode enviar alertas aos clínicos?
Não. Ele notifica o seu serviço através de webhooks; quem é alertado, como e quando é decidido no seu sistema.
Relacionado
- Dados de wearables em FHIR
- Cuidados virtuais e médicos de IA: os dados de que necessitam
- Webhooks
- Proveniência de dados médicos explicada
- Integrações de saúde
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card