CMS ACCESS Model API
0.9.8 - draft
US
This page is part of the ACCESS Model IG v0.9.8 DRAFT (v0.9.8: Releases Draft) based on FHIR (HL7® FHIR® Standard) R4. No current official version has been published yet. For a full list of available versions, see the Directory of published versions
This Operations Manual provides general implementation guidance applicable to all ACCESS Model APIs.
All ACCESS Model APIs follow consistent asynchronous processing and parameter patterns for ease of implementation. The Alignment API uses an asynchronous request-response pattern to accommodate the processing time required for backend logic. This pattern allows clients to submit requests and subsequently poll for results without maintaining a persistent connection. The pattern uses two sets of operations to support a submit-and-poll workflow:
ACCESS operations can take some time to complete making a synchronous request-response pattern impractical for real-world implementations.
Processing these operations may require:
The typical workflow consists of the following steps:
$check-eligibility, $align, $unalign, $report-data operationHTTP 202 Accepted with a Content-Location header containing the URL for retrieving submission status$submission-status operation through the submission status URL providedHTTP 200 OK with the final resultInteraction Pattern:
The following sequence diagram illustrates the general asynchronous pattern used by all ACCESS APIs:
sequenceDiagram
participant Client as ACCESS Participant System
participant API as ACCESS API
participant Backend as Backend Processing
Client->>API: POST [base]/access/Patient/$operation
Note over Client,API: Submit request with required parameters
API->>Backend: Queue request for processing
Backend-->>API: Request queued
alt Still Processing
API-->>Client: 202 Accepted
Note over API,Client: Content-Location header with status URL<br/>(no response body)
else Processing Complete - Error
API-->>Client: 4xx or 5xx
Note over API,Client: OperationOutcome<br/>with error details
end
loop Status Polling
Client->>API: GET [base]/access/Patient/$submission-status/<submissionID>
alt Still Processing
API-->>Client: 202 Accepted
Note over API,Client: No response body<br/>Continue polling
Note over Client: Wait 5-30 seconds
else Processing Complete - Success
API->>Backend: Retrieve result
Backend-->>API: Operation result
API-->>Client: 200 OK
Note over API,Client: Parameters resource<br/>with result code
Note over API,Client: optional OperationOutcome<br/>with issue details
else Processing Complete - Error
API-->>Client: 4xx or 5xx
Note over API,Client: OperationOutcome<br/>with error details
end
end
All primary operations ($check-eligibility, $align, $unalign, $report-data) require an entityId query parameter:
entityId (required): ACCESS participant identifier. Must follow the pattern ACCES#####.All primary operations ($check-eligibility, $align, $unalign, $report-data) require these common parameters:
urn:oid:2.16.840.1.113883.3.221.5) with CARIN Blue Button identifier typing. EDI Payer IDs are 5-character alphanumeric codes widely used in healthcare transactions (e.g., eligibility checks, claims, remittance).Some operations may require additional parameters. Please consult the documentation in this guide for information about each specific API.
The $submission-status operation retrieves the current status of a previously submitted request. This is a read-only operation that uses the HTTP GET method. The URL used to retrieve the submission status is returned by the primary operation (extracted from the Content-Location URL).
Submission Status URL: GET <submission status URL>
Output Parameters (when complete):
result (CodeableConcept, required): Result code with descriptive text indicating the status. Actual values depend on the API in use.issues (OperationOutcome, optional): This parameter MAY be included to provide more detail about the context of the result code.Example Response from a Primary Operation:
HTTP/1.1 202 Accepted
Content-Location: https://[base]/access/Patient/$submission-status/sub-123456
(No response body - processing asynchronously)
All primary operations are invoked at the resource level:
POST https://[base]/access/[resource]/[$operation]?entityId=[participantID]
Where [base] is the FHIR server base URL provided during participant registration
Where [resource] is Patient
Where [$operation] is the primary dollar sign operation (e.g., $check-eligibility, $align, $unalign, $report-data)
Where [entityId] is the participant ID (e.g., of the form ACCES#####)
application/fhir+jsonapplication/fhir+jsonAll APIs require a patientID. Each API requires the patient's member ID (e.g., for CMS's ACCESS Model, the patient's MBI) in the Patient resource, whether it is a separate parameter or part of the Data Reporting bundle. FOR CMS's ACCESS Model only, a patient must be a Medicare beneficiary to be eligible and align to a CMS ACCESS participant:
{
"resourceType": "Patient",
"identifier": [
{
"type": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MC"
}
]
},
"system": "http://terminology.hl7.org/NamingSystem/cmsMBI",
"value": "1EG4TE5MK73"
}
],
"name": [
{
"family": "Doe",
"given": ["John"]
},
"gender" : "male"
],
}
NOTE: The IG will accept any patient identifier and payer identifier so that this IG can be used by other payers looking to align with the ACCESS Model.
ACCESS operations return a Content-Location HTTP header containing the URL to check the status of the submission. Clients should:
Content-Location header value from the HTTP response$submission-status callsExample:
Content-Location: https://[base]/access/Patient/$submission-status/sub-123456
Clients should implement an appropriate polling strategy to balance responsiveness with server load:
Polling Logic:
1. Initiate the ACCESS operation (POST $<operation> with required parameters)
2. Receive HTTP 202 with Content-Location
3. Wait initial delay (5-10 seconds)
4. While (timeout not exceeded):
a. Poll status (GET $submission-status)
b. If HTTP 202: wait and continue loop
c. If HTTP 200: process result and exit
d. If HTTP 4xx/5xx: handle error and exit
5. If timeout exceeded: handle as error
HTTP 202 Accepted: The request is being processed. No result is available yet. Continue polling.
HTTP 200 OK: Processing is complete. The response body contains a Parameters resource with the result. For example, here is a sample response from a successful request:
{
"resourceType": "Parameters",
"parameter": [{
"name": "result",
"valueCodeableConcept": {
"coding": [{
"system": "https://dsacms.github.io/cmmi-access-model/CodeSystem/ACCESSAlignmentResultCS",
"code": "aligned",
"display": "Aligned"
}],
"text": "Patient is eligible and has been aligned so the ACCESS participant can now begin providing services to the patient under the model."
}
}]
}
Clients should:
parameter[0].valueCodeableConcept from the Parameters resourcecoding[0].code against known alignment result codestext element for user-friendly messagingClients should be prepared to handle the following conditions:
HTTP Status Code Errors:
Client-Side Errors:
Best Practice: Always check HTTP status codes before attempting to parse the response body. Only HTTP 200 responses contain the result from the original request.
Content-Location HTTP header URL may contain sensitive identifiers and should be handled securelyErrors are returned using FHIR OperationOutcome resources:
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "invalid",
"details": {
"text": "Missing required parameter: participantID"
}
}
]
}
The following diagram illustrates the complete error handling flow for ACCESS API interactions:
flowchart TD
Start([Submit Request]) --> Auth{Valid<br/>Token?}
Auth -->|No| Err401[Return 401 Unauthorized]
Auth -->|Yes| Validate{Valid<br/>Parameters?}
Validate -->|No| CheckError{Error Type?}
CheckError -->|Missing Parameter| Err400A[Return 400 Bad Request<br/>Missing required parameter]
CheckError -->|Invalid Format| Err400B[Return 400 Bad Request<br/>Invalid format]
CheckError -->|Invalid Value| Err400C[Return 400 Bad Request<br/>Invalid value]
Validate -->|Yes| Queue[Queue for Processing]
Queue --> Return202[Return 202 Accepted<br/>with Content-Location]
Return202 --> Poll([Client Polls Status])
Poll --> CheckStatus{Processing<br/>Status?}
CheckStatus -->|Still Processing| Return202Poll[Return 202 Accepted<br/>No body]
Return202Poll --> Wait[Client Waits]
Wait --> Poll
CheckStatus -->|Complete - Success| Return200[Return 200 OK<br/>with result]
CheckStatus -->|Complete - Business Logic Error| Return200Error[Return 200 OK<br/>with error result code]
CheckStatus -->|System Error| Err500[Return 500 Internal Error]
CheckStatus -->|Not Found| Err404[Return 404 Not Found]
Key Decision Points:
Missing Required Parameter:
POST https://[base]/access/Patient/$check-eligibility?entityId=ACCES12345
HTTP/1.1 400 Bad Request
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "required",
"details": { "text": "Missing required parameter: patient" }
}
]
}
Invalid MBI Format:
HTTP/1.1 400 Bad Request
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "invalid",
"details": { "text": "Invalid Medicare Beneficiary Identifier (MBI) format" }
}
]
}
Invalid Track Code:
HTTP/1.1 400 Bad Request
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "code-invalid",
"details": {
"text": "Invalid track code. Must be one of: eCKM, CKM, MSK, BH"
}
}
]
}
Malformed Parameters Resource:
HTTP/1.1 400 Bad Request
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "structure",
"details": {
"text": "Parameters resource structure is invalid"
},
"diagnostics": "Expected Parameters.parameter array but received malformed JSON"
}
]
}
Invalid Participant ID (400):
HTTP/1.1 400 Bad Request
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "invalid",
"details": {
"text": "Participant ID is not valid"
}
}
]
}
FHIR Validation Failure:
HTTP/1.1 400 Bad Request
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "invalid",
"details": {
"text": "FHIR validation failed: Patient.identifier.system is required when Patient.identifier.value is present"
},
"diagnostics": "The Patient resource does not conform to the US Core Patient profile. MBI identifier must include both 'system' (http://terminology.hl7.org/NamingSystem/cmsMBI) and 'value' elements."
}
]
}
Submission ID Not Found (404):
GET https://[base]/access/Patient/$submission-status/invalid-sub-id
HTTP/1.1 404 Not Found
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": { "text": "Submission ID 'invalid-sub-id' not found" }
}
]
}
Missing or Invalid Token (401):
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token"
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "security",
"details": {
"text": "Invalid or expired access token"
}
}
]
}
Insufficient Scope (403):
HTTP/1.1 403 Forbidden
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "forbidden",
"details": {
"text": "Insufficient scope for requested operation."
}
}
]
}
Service Temporarily Unavailable (503):
HTTP/1.1 503 Service Unavailable
Retry-After: 60
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "transient",
"details": {
"text": "Service temporarily unavailable. Please retry after 60 seconds."
}
}
]
}
Internal Server Error (500):
HTTP/1.1 500 Internal Server Error
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "exception",
"details": {
"text": "An unexpected error occurred processing your request. Please contact support with submission ID if this persists."
}
}
]
}
Example Status Check Request (Processing Complete - Aligned and Switch Approved):
GET https://[base]/access/Patient/$submission-status/sub-123456
Response:
HTTP/1.1 200 OK
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{
"name": "result",
"valueCodeableConcept": {
"coding": [
{
"system": "https://dsacms.github.io/cmmi-access-model/CodeSystem/ACCESSAlignmentResultCS",
"code": "aligned-switch-approved",
"display": "Aligned and switch approved"
}
],
"text": "The request to switch the patient's alignment from a different participant after the 90-day lock in period is accepted and the patient is considered switched and now re-aligned."
}
}
]
}
There are other types of errors specific to each API that may be returned. Please see the API Guidance menu in this manual to get more information and examples for those errors.
This asynchronous pattern aligns with:
For additional information about FHIR patterns, see:
Scenario: Network failure occurs during polling
Implementation Guidance:
Scenario: User clicks submit button multiple times or system retries unnecessarily
Implementation Guidance:
Scenario: OAuth token expires while waiting for async operation to complete
Implementation Guidance:
Scenario: Patient has conditions qualifying for multiple tracks
Implementation Guidance:
Patient can be aligned to different participants or the same participant in different tracks