CMS-0057-F and your API gateway: governing the four payer FHIR APIs before January 2027
CMS-0057-F gives payers until January 2027 to run four FHIR APIs. How an API gateway enforces access, attribution, and audit evidence across all four.
- healthcare
- fhir
- compliance
- cms-0057-f
- workflow-builder
Health plans have three months left. By January 1, 2027, Medicare Advantage organizations, Medicaid and CHIP programs and their managed care plans, and qualified health plans on the federal exchanges must have the CMS Interoperability and Prior Authorization final rule (CMS-0057-F) APIs running in production. Most payer IT teams we talk to have the FHIR servers sorted. Their open question is the CMS-0057-F API gateway layer: who decides which caller can reach which API, how a provider's treatment relationship is checked before claims data leaves the building, and what evidence the plan can produce when someone asks.
The rule describes four APIs with four very different audiences. The Patient Access API serves third-party apps the member chose. The Provider Access API serves in-network providers who have a treatment relationship with the member, and the member can opt out. The Payer-to-Payer API serves other health plans, and the member has to opt in. The Prior Authorization API serves provider systems that submit and track authorization requests. Each of these needs a different trust model, but all four usually sit in front of the same FHIR data store.
That combination is the hard part. If every FHIR backend team builds its own authorization logic for its own consumer type, the plan ends up with four access models, four log formats, and no single answer to the question "who accessed this member's data, and why were they allowed to?"
Why bolting payer APIs onto existing gateways falls short
Most payers already run some API management, often Azure API Management or Apigee in front of claims and eligibility services, or AWS API Gateway in front of a vendor FHIR server. These products handle token validation well. Where they struggle is the policy CMS-0057-F actually describes. A Provider Access request is only legitimate if the provider is attributed to that member and the member has not opted out. That is a data lookup, not a scope check. In Apigee it becomes a JavaScript policy plus a service callout. In Azure APIM it becomes a policy expression calling a separate attribution service. In AWS it becomes a Lambda authorizer that someone has to deploy, monitor, and keep in step with the attribution data.
The second problem is evidence. CMS asks payers to report Patient Access API usage, including how many unique members had data sent to an app they designated. A plan that runs API traffic through a vendor-managed control plane often finds that the logs live in the vendor's analytics tier, retained for a fixed window, in a format the compliance team cannot query directly. Pulling an annual count of unique members per app turns into a data engineering project every reporting cycle.
The third problem is the boundary itself. Member claims, encounter, and prior authorization data is PHI. Sending request metadata, and in some configurations payloads, through a SaaS control plane adds a business associate relationship and a data flow that your HIPAA risk assessment has to cover. Many plans would rather keep the whole API path, including logs, inside the infrastructure they already assess.
How Zerq structures a CMS-0057-F API gateway
Zerq treats the four payer APIs as four collections behind one gateway, each with its own consumers and its own controls, sharing one request log in your own MongoDB. The model maps onto the rule directly.
Each API is a collection. You create patient-access, provider-access, payer-to-payer, and prior-authorization collections that proxy to your FHIR server's base URL. Collections are where workflows attach, so the Provider Access attribution check lives on that collection and nowhere else.
Each consumer is a client. A member-facing app, a provider organization, a peer health plan, or an EHR vendor's prior authorization integration is a named client. That name appears on every request log entry, which is what makes per-consumer reporting possible later.
Each client gets one or more profiles. A profile is the runtime access contract: auth type (token, JWT, OIDC, mTLS, or none), allowed HTTP methods, IP or CIDR restrictions, and active state. Callers identify themselves with X-Client-ID and X-Profile-ID headers alongside their credential, and the gateway rejects a request from the wrong IP with 403 before it even checks the token.
Each client gets a policy. Policies carry a short-term rate limit (1m, 5m, or 1h windows) and a long-term quota (1d, 7d, or 30d). Over-limit callers receive 429. A bulk export from a peer payer and a member app polling for claim updates need very different limits, and this is where you set them.
The profile design for each API
The table below is the profile layout we recommend as a starting point. Every setting is a field on the profile or policy in the management UI.
| Collection | Typical client | Auth type | Allowed methods | Network restriction |
|---|---|---|---|---|
patient-access | Member-designated app | oidc (your SMART authorization server) | GET | None (public apps) |
provider-access | In-network provider org | oidc | GET | Provider's egress CIDRs |
payer-to-payer | Peer health plan | oidc with certificate-bound tokens, or mtls | GET, POST | Peer's egress CIDRs |
prior-authorization | EHR or provider PA system | oidc | GET, POST | Vendor egress CIDRs |
For the payer-to-payer exchange, an OIDC profile can also require RFC 8705 certificate-bound tokens. Set requireCertificateBoundToken: true on the profile through the management API or the Management MCP update_profile tool (there is no dashboard toggle for this yet). A token copied out of a peer's logs is then useless without the matching client certificate. CMS-0057-F does not mandate this, but for a bulk channel between two organizations it is cheap insurance.
Building the Provider Access attribution check
The Provider Access API is the one most likely to need custom logic, because the rule ties access to attribution and to the member's opt-out choice. The profile's OIDC validation proves who the provider is. The workflow decides whether that provider may see this member. The steps below build it in the workflow builder on the provider-access collection.
-
In the management UI, open Collections, select
provider-access, and open its Workflow. A proxied collection starts with anhttp_triggerconnected to aproxy_node. You will insert three nodes between them. -
Add a JWT node in
decodemode. The profile has already verified the token's issuer, audience, and signature, so the workflow only needs the claims. The node strips theBearerprefix itself.
{
"id": "provider_token",
"type": "jwt_node",
"config": {
"operation": "decode"
},
"inputs": {
"token": "{{ $json['http_trigger'].request.headers.Authorization[0] }}"
}
}
The decoded claims are available at $json['provider_token'].payload. Which claim carries the provider's NPI or organization identifier depends on your authorization server; this example assumes a custom npi claim.
- Add a MongoDB node that looks up the attribution record. Point
credentials_idat a MongoDB credential stored in the gateway, so the connection string never appears in workflow config.
{
"id": "attribution",
"type": "mongodb_node",
"config": {
"credentials_id": "mongo-attribution", // gateway-stored MongoDB credential
"database": "member_services", // database holding attribution data
"collection": "provider_attribution", // one document per provider-member link
"operation": "findOne" // return a single matching record or null
},
"inputs": {
"filter": {
"npi": "{{ $json['provider_token'].payload.npi }}",
"member_id": "{{ $json['http_trigger'].request.query.patient }}",
"status": "active"
}
}
}
The node returns its match at $json['attribution'].result.document, or null when no active attribution exists. Strip the // annotations before pasting; they are here to explain each field.
- Add a condition node that requires both an attribution record and no opt-out flag on it.
{
"id": "attribution_gate",
"type": "condition_node",
"config": {
"conditions": [
{
"condition": "$json['attribution'].result.document != null && $json['attribution'].result.document.opted_out !== true",
"output": "attributed"
}
],
"default_output": "not_attributed"
}
}
- Wire
attributedto the existingproxy_node. Wirenot_attributedand the MongoDB node'serrorbranch to a response node that returns a FHIROperationOutcome, so conformant clients parse the denial correctly.
{
"id": "deny_unattributed",
"type": "response_node",
"config": {
"status": 403,
"headers": { "Content-Type": "application/fhir+json" },
"body": {
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "forbidden",
"details": { "text": "No active attribution between requesting provider and member" }
}]
}
}
}
- Test the flow with the workflow test tools before enabling it, using one attributed member, one unattributed member, and one opted-out member. Then Save and Enable. Both actions are recorded in the audit log with your identity, so the change that introduced the control is itself evidence.
The same pattern covers Payer-to-Payer opt-in: look up the member's consent record, and route to the proxy only when it exists. For the Prior Authorization API, a validate_node with a JSON Schema in front of the POST path rejects malformed submissions at the gateway with a clear error, before they reach the authorization engine.
The audit evidence CMS-0057-F reporting needs
Every request through the gateway produces a request log entry in your own MongoDB. These are the fields stored for a denied Provider Access call:
{
"request_id": "7f1c2a9e-4b0d-4c55-9a51-2e8d0c3f6b17",
"created_at": "2026-10-01T14:02:11.408Z",
"method": "GET",
"path": "/fhir/r4/ExplanationOfBenefit",
"status": 403,
"latency": 9,
"client_id": "c-riverside-medical-group",
"profile_id": "p-riverside-prod",
"collection": "provider-access",
"client_ip": "198.51.100.24",
"response_body": "{\"resourceType\":\"OperationOutcome\",...}"
}
client_id and profile_id tie the event to a named provider organization and the specific credential it used. collection tells you which of the four APIs was involved. status separates allowed access (200) from attribution denials (403), throttling (429), and authentication failures (401). request_id is also returned to the caller in the X-Request-ID header, so a provider's support ticket can be traced back to one exact entry.
For the Patient Access API usage metrics, filter Logs by collection patient-access, status 200, and a custom date range covering the reporting year. Narrow by Client ID to see one app's volume, or use the Metrics dashboard for request volumes per client, then query the log collection directly, or your SIEM if you forward logs there, to count distinct member identifiers per app. Payload search across request and response bodies lets an investigator find every request that touched one member ID without knowing which API it came through. Request logs contain PHI, so restrict log viewing to approved roles and set retention in gateway settings to match your record retention policy. The observability pages cover the filters in detail.
Configuration changes have their own trail. Audit logs record actor ID, action, resource type, resource ID, IP address, request body, and response status for every create, update, and delete. They are visible only to users with the Auditor role, so your compliance team can review who changed the Provider Access workflow or loosened a payer's policy without holding edit rights on the platform.
A readiness checklist for the next 90 days
Use these questions to check where your plan stands before January:
- Is each of the four APIs its own collection, so access rules and log filters do not mix audiences?
- Does every external consumer have a named client and a profile, rather than a shared key?
- Is the Provider Access attribution and opt-out check enforced at a single point, and can you show the test cases that prove it?
- Is Payer-to-Payer gated on the member's opt-in record, with peer payers restricted by network and, ideally, certificate-bound tokens?
- Can you produce per-app Patient Access usage from logs you control, without a vendor export?
- Do your logs and configuration live inside the boundary your HIPAA risk assessment already covers?
What this looks like for a regional health plan
A regional plan with Medicare Advantage and Medicaid managed care lines had a vendor FHIR server in production for the 2021 Patient Access requirements, fronted by a cloud API gateway with one shared OAuth client per consumer category. Provider Access was in development, with the attribution check written inside the FHIR facade by a contractor. Nobody could say how the plan would count unique members per app for CMS reporting.
They deployed Zerq on their existing Kubernetes cluster, next to the FHIR server, with the request log in a MongoDB instance their security team already monitored. Each provider group and app vendor became its own client. The attribution check moved out of the FHIR facade into a six-node workflow on the provider-access collection, reading the same attribution collection the care management team maintains. Peer payers were onboarded on OIDC profiles with certificate-bound tokens and CIDR restrictions.
The change their compliance lead noticed most was in the questions they could now answer. Which provider groups were denied for missing attribution last month is now a two-filter query. The annual Patient Access metrics come from the same log store as every other access record. When the plan's auditor asks who changed the attribution rule and when, the Auditor role answers it without an engineer in the room. The deployment details are on the architecture page.
Closing
A CMS-0057-F API gateway built on Zerq gives payers four things the current patchwork does not. Each of the four APIs gets its own consumers, auth model, and limits, all managed in one place. The attribution and opt-in rules the regulation actually describes are enforced as visible, versioned workflows instead of code hidden in a FHIR facade. The member-level usage evidence for CMS reporting comes from request logs you own and can query. And the whole path, including PHI-bearing logs, stays inside your own infrastructure.
Zerq is an enterprise API gateway built for regulated industries — one platform for API management, AI agent access, compliance audit, and developer portal, running entirely in your own infrastructure. See how it works or request a demo to walk through your specific requirements.