---
{
  "title": "Construcción de un directorio de proveedores FHIR para Medicare Plan Finder",
  "description": "CMS exige que los planes Medicare Advantage publiquen un directorio de proveedores FHIR según PDex Plan-Net. Con la exportación masiva $export y _typeFilter, obtener los datos correctos requiere una sola llamada; el resto es código ordinario.",
  "date": "2026-07-06",
  "author": "Akim Khalitov, Gleb Markin",
  "tags": [
    "Compliance",
    "Integrations",
    "Payerbox"
  ],
  "reading-time": "7 min read",
  "tldr": "CMS exige ahora que cada plan Medicare Advantage publique un directorio de proveedores para Medicare Plan Finder, que lo rastrea diariamente como archivos publicados, no como una API en tiempo real. CMS permite dos formatos; aquí se utiliza el FHIR: un $export masivo extrae los recursos de la red, un paso de streaming conserva únicamente los registros que estos referencian, y una publicación atómica sirve los FHIR Bundles resultantes, junto con un manifiesto índice, a través de un endpoint compatible con el rastreador.",
  "utm-campaign": "feature",
  "utm-content": "provider-directory",
  "hide-comments": true
}
---

> For the complete documentation index, see [llms.txt](https://www.health-samurai.io/llms.txt).
> Use it to discover all available pages before guessing URLs.

---

Si gestiona usted un plan Medicare Advantage, CMS le exige ahora publicar un
[directorio de proveedores](https://www.health-samurai.io/articles/mpf-provider-directory-medicare-advantage-cms-4208-f2)
que liste qué proveedores e instalaciones forman parte de la red de cada plan, para que
[Medicare Plan Finder](https://www.medicare.gov/plan-compare/) (MPF) pueda responder a la pregunta
que los usuarios realmente formulan: ¿está cubierto mi proveedor? Esa pregunta es específica de MA:
un plan MA cubre una red contratada y, dado que MA es Medicare de financiación federal gestionado por
aseguradoras privadas, CMS tiene potestad para dictar cómo se publica el directorio. El directorio debe
ser legible por máquina, actualizarse en un plazo de 30 días tras cualquier cambio
y atestiguarse una vez al año. Forma parte de
[la apuesta más amplia de CMS por la interoperabilidad basada en FHIR](https://www.health-samurai.io/articles/understanding-the-cms-0057-f-interoperability-and-prior-authorization-final-rule).

CMS acepta dos formatos: un archivo JSON plano o FHIR; aquí se construye el formato FHIR. Este sigue
[PDex Plan-Net](https://hl7.org/fhir/us/davinci-pdex-plan-net/), el IG de Da Vinci que
estandariza la red de un plan mediante perfiles FHIR sobre
[InsurancePlan](https://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition-plannet-InsurancePlan.html),
[Organization](https://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition-plannet-Organization.html)
(tanto como red como instalación),
[Practitioner](https://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition-plannet-Practitioner.html),
[PractitionerRole](https://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition-plannet-PractitionerRole.html),
[Location](https://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition-plannet-Location.html) y
[OrganizationAffiliation](https://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition-plannet-OrganizationAffiliation.html),
así como las referencias entre ellos. CMS no consulta su servidor por cada usuario: su rastreador ingiere
los archivos publicados una vez al día y los valida, siguiendo su
[guía técnica de implementación](https://www.cms.gov/files/zip/mpf-ma-provider-directory-technical-guide-02182026-final-zip.zip).
Si falla la validación, incumple la atestación anual o supera el umbral de calidad de datos de CMS,
este suprimirá su directorio de MPF y, por lo general, lo restaurará al día siguiente de resolverse el problema.
Mientras esté suprimido, los usuarios que comparan planes no podrán ver su red, por lo que mantener el
directorio válido en cada ejecución es fundamental.

El resto de este artículo describe esa canalización, fase por fase.

## Cómo funciona

Sus datos ya residen en Payerbox. La canalización los convierte en los archivos que CMS rastrea,
según una programación. Cuatro fases:

```mermaid
flowchart LR
    A["1 · Extracción<br/>$export + _typeFilter<br/>(filtra los padres)"] --> B["2 · Filtrado<br/>resolver refs,<br/>conservar hijos"]
    B --> C["3 · Bundle<br/>FHIR + index.json"]
    C --> D["4 · Publicación<br/>almacenamiento en la nube"]
    D --> E["CMS rastrea<br/>diariamente"]
```

*La ejecución diaria, de principio a fin: extracción desde Payerbox, filtrado al subconjunto de la red,
empaquetado como FHIR y publicación de los archivos que CMS rastrea.*

Un trabajo programado ejecuta todo el proceso cada mañana, antes del rastreo diario de CMS.

Todo lo que sigue a la extracción es código ordinario sobre NDJSON, por lo que se ejecuta y prueba
sobre una exportación de muestra, sin necesidad de un servidor FHIR activo.

## Cómo extraer los datos

Existen dos formas de obtener los recursos de Payerbox. La canalización lee a través de una interfaz
de origen común, por lo que cualquiera de las dos podría alimentarla; aquí se utiliza `$export` masivo.

- **La API REST de FHIR.** Paginación mediante consultas de búsqueda ordinarias. Es una opción adecuada
  para un subconjunto pequeño y preciso, pero extraer tipos de recursos completos a escala implica
  muchas llamadas de ida y vuelta, y los datos pueden cambiar entre páginas.
- **La operación `$export` masivo de FHIR.** Esta operación se ejecuta
  [de forma asíncrona](https://www.health-samurai.io/articles/unified-fhir-async-operations-pattern)
  y transmite todo como NDJSON en un solo paso, sin la deriva entre páginas que ocasiona la paginación
  sobre la API en tiempo real. Está diseñada para esto, y es la que se utiliza aquí.

`$export` es la operación estándar [FHIR Bulk Data Access](https://hl7.org/fhir/uv/bulkdata/),
con `_typeFilter` para aplicar filtros selectivos en la exportación y `+gzip` en `_outputFormat` para
mantener el volcado en un tamaño reducido. Con `_typeFilter`, el servidor envía únicamente los recursos
que importan:

```
GET /fhir/$export
  ?_outputFormat=application/fhir+ndjson+gzip
  &_type=InsurancePlan,Organization,Practitioner,PractitionerRole,Location,OrganizationAffiliation
  &_typeFilter=InsurancePlan?status=active&_profile=.../plannet-InsurancePlan&_id=...
  &_typeFilter=PractitionerRole?active=true&_profile=.../plannet-PractitionerRole&network=...
  &_typeFilter=OrganizationAffiliation?active=true&_profile=.../plannet-OrganizationAffiliation&network=...
```

Iniciado con el encabezado de solicitud `Prefer: respond-async`, `$export` devuelve `202 Accepted`
con un encabezado de respuesta `Content-Location`: la URL de estado que se sondea hasta que los archivos
NDJSON estén listos. Los planes, los roles de profesional y las afiliaciones se devuelven ya filtrados
a los recursos activos, de la red y de Plan-Net. Los elementos hijo que estos referencian llegan
completos, de modo que un registro conservado nunca apunta a algo eliminado.

## Filtrado al subconjunto de la red

Ese `$export` fue el primer filtro: `_typeFilter` reduce los elementos padre en el servidor FHIR.
Un paso a nivel de código resuelve entonces los elementos hijo: recorre el grafo (plan → red →
organizaciones y profesionales afiliados → sus ubicaciones), conserva un elemento hijo únicamente
cuando un elemento padre conservado lo referencia, y descarta el resto. Ese grafo son las referencias
que PDex Plan-Net define entre los seis recursos:

<div class="narrow" style="display: flex; justify-content: center">

```mermaid
flowchart TD
    IP["InsurancePlan"] -->|network| NET["Organization<br/>(Red, type=ntwk)"]
    PR["PractitionerRole"] -->|network| NET
    PR -->|practitioner| PRAC["Practitioner"]
    PR -->|location| LOC["Location"]
    OA["OrganizationAffiliation"] -->|network| NET
    OA -->|organization| FAC["Organization<br/>(Instalación, type=fac)"]
    OA -->|location| LOC
```

</div>

*Las referencias entre los recursos de Plan-Net. `_typeFilter` reduce los elementos padre (InsurancePlan,
PractitionerRole, OrganizationAffiliation) en el servidor FHIR; el paso de código conserva entonces
los elementos hijo que estos referencian.*

## Empaquetado y publicación

Los recursos conservados se incluyen en [Bundles](https://hl7.org/fhir/R4/bundle.html) de FHIR
(`type: collection`), divididos por tipo de recurso en archivos numerados (`PractitionerRole-001.json`,
`-002.json`, etc.); cada recurso conserva su `meta.lastUpdated` de origen, que la guía asocia a la fecha
de última actualización de cada registro. CMS espera esa división: requiere un archivo índice por contrato,
un manifiesto con la URL de cada archivo que el rastreador lee en primer lugar:

```json
{
  "provider_urls": [
    "https://.../H9999/2026/InsurancePlan-001.json",
    "https://.../H9999/2026/PractitionerRole-001.json",
    "https://.../H9999/2026/PractitionerRole-002.json",
    "https://.../H9999/2026/Organization-001.json"
  ]
}
```

La división mantiene cada archivo en un tamaño manejable para el rastreador; la canalización pasa al
siguiente archivo numerado cuando un bundle supera un tamaño excesivo o un límite de entradas.

La publicación tiene una regla estricta: un rastreo nunca debe aterrizar en un directorio
parcialmente escrito. Un archivo como `Organization-042.json` contiene recursos distintos de una
ejecución a la siguiente, por lo que sobreescribirlo en su lugar mientras el manifiesto antiguo aún
apunta a él produce una lectura inconsistente. Por tanto, la publicación es un intercambio atómico:
se eliminan los archivos antiguos, se suben los nuevos bundles y, a continuación, se sube `index.json`
en último lugar. Esa última subida es el único paso que pone en línea la nueva versión, de modo que un
rastreador en mitad de la publicación ve el directorio de ayer, el de hoy o un breve 404 durante el
intercambio, pero nunca una mezcla parcialmente escrita. Una ejecución que falle a mitad genera una
alerta. No existe reanudación parcial: la siguiente ejecución simplemente reconstruye todo el directorio
desde cero.

## Servir al rastreador

CMS recomienda solicitudes condicionales, y el endpoint las sirve. Cada archivo lleva un `ETag`
(una huella de su contenido que cambia cuando el archivo lo hace) y una marca temporal `Last-Modified`;
el rastreador los almacena y, en su siguiente visita, vuelve a descargar un archivo solo cuando su
`ETag` ha cambiado. Los archivos sin cambios se devuelven como `304 Not Modified` sin cuerpo:

```http
GET /mpf-provider-directory/H9999/2026/Organization-042.json
If-None-Match: "a1b2c3"        # the ETag the crawler received on its last fetch
→ 304 Not Modified             # unchanged since then, so no body
```

En un directorio de miles de archivos bundle que apenas cambian de un día para otro, esa es la
diferencia entre un rastreo costoso y uno económico. También explica la publicación atómica: el `ETag`
debe cambiar exactamente cuando cambia el contenido.

Ese endpoint actúa como proxy de un bucket privado en lugar de exponer el bucket directamente, y no
requiere autenticación: el directorio Plan-Net está concebido para ser de acceso abierto, sin registro
de cliente.

## ¿Desea construir el suyo propio?

Construirlo representa una ingeniería relativamente modesta para cualquier persona que trabaje
habitualmente con servidores FHIR: un trabajo diario de exportación-filtrado-empaquetado-publicación.
Pero el cuidado reside en hacerlo correctamente en cada ejecución, y todo ello presupone que en el
servidor FHIR ya existen datos correctos de Plan-Net. Lograr esto es un proyecto en sí mismo. La calidad
de sus datos debe monitorizarse de forma continua, validando el conjunto de recursos PDex Plan-Net
frente a los criterios MPF de CMS.

Este directorio se incluye como módulo opcional de
[Payerbox](https://www.health-samurai.io/cms-0057-f), la plataforma de Health Samurai para los
requisitos de pagadores de CMS, que también proporciona las APIs de CMS-0057-F con vencimiento en 2027.

> ¿Está construyendo un directorio de proveedores para Medicare Plan Finder?
> [Hable con nuestro equipo](https://www.health-samurai.io/company#contact-form) para comenzar.

## Referencias

- [Norma final CMS-4208-F2](https://www.federalregister.gov/documents/2025/09/19/2025-18236/medicare-and-medicaid-programs-contract-year-2026-policy-and-technical-changes-to-the-medicare)
- [El requisito del directorio de proveedores de MPF, explicado](https://www.health-samurai.io/articles/mpf-provider-directory-medicare-advantage-cms-4208-f2)
- [Guía técnica de implementación del directorio de proveedores MA de CMS](https://www.cms.gov/files/zip/mpf-ma-provider-directory-technical-guide-02182026-final-zip.zip)
- [IG Da Vinci PDex Plan-Net](https://hl7.org/fhir/us/davinci-pdex-plan-net/)
- [FHIR Bulk Data Access](https://hl7.org/fhir/uv/bulkdata/)