Skip to main content

Envelope fields

Every field on the JWE protected header, with its obligation, its type and the rule that governs it. JWE, Status and Errors in the Overview explains what the envelope is and why it is separate from the letter. This chapter is the table you check a field against while you are building one.

The authority here is the Technical Specifications page on the portal, which carries the current header table, together with the ten sheets of the NHCX Requests and Responses workbook, which state the obligation of each field per exchange. Where the older Open Protocol page differs it is noted, because it is still published and still read.

The fields

FieldTypeObligationWhat it carries
algStringMandatoryKey wrapping. RSA-OAEP-256
encStringMandatoryContent encryption. A256GCM
x-hcx-sender_codeStringMandatoryYour participant code
x-hcx-recipient_codeStringMandatoryThe recipient's. For a provider, the processor code from the policy lookup
x-hcx-api_call_idUUIDMandatoryFresh on every message, including responses
x-hcx-request_idUUIDOptionalOne per originating request. The Open Protocol page marks it Mandatory; the Technical Specifications page marks it Optional
x-hcx-correlation_idUUIDMandatoryThe thread. See the rule below
x-hcx-workflow_idStringOptionalWhich step, or which case. See the two readings below
x-hcx-timestampdatetimeMandatorySee the format note below
x-hcx-statusStringMandatoryWhere this message stands. Values below
x-hcx-ben-abha-idStringMandatoryThe beneficiary's ABHA number. Mandatory on every exchange, including those with no beneficiary in the payload
x-hcx-use_caseStringOptionalValues differ by exchange, see below
x-hcx-error_detailsJSON objectOptionalcode, message, trace. Mandatory on a protocol response
x-hcx-debug_detailsJSON objectOptionalThe same shape, for debugging
x-hcx-debug_flagEnumOptionalError, Info or Debug. A server may ignore it

The x-hcx-use_case values are not one enum. The workbook states them on three sheets and they are not the same on all three.

SheetPermitted values
PreauthNew, Enhancement, Resubmit
StatusNew, Enhancement, Resubmit
ClaimNew, Resubmit

A claim cannot be enhanced, which is why Enhancement is absent from that row. Both workbooks agree, sheet for sheet.

x-hcx-debug_flag is typed two ways. The Technical Specifications page gives the enum as Error, Info or Debug. The NHCX Requests and Responses workbook types it as Enum with the single value INFO, on its response headers, and every header table in the FHIR Reference and every sample in the API collection that carries the field sends INFO. The field is optional and a server may ignore it. Where you send it, send INFO, as the samples do. No source says whether a server checks the case of the value.

Three of those obligations are not stated anywhere else in this documentation and are worth reading twice. x-hcx-request_id is optional. x-hcx-workflow_id is optional. x-hcx-ben-abha-id is mandatory.

The correlation ID rule, in full

The rule is stated in two halves in two places, which has been read as a contradiction. It is not one. The workbook has twenty-five correlation rows: twenty-four state one half or the other, and they fit together, and the twenty-fifth gives the status enquiry its own rule.

On aSet correlation_id toRows stating it
RequestThis message's own api_call_id8
ResponseThe correlation_id of the request being answered16
Status enquiryThe api_call_id of the message whose status you are asking about1

So the initiator seeds the thread from its own call ID, and every responder echoes what it received. The Open Protocol page says the same thing in prose: the correlation ID "may be chosen as the message_id of the original sender's system. For return messages responders are expected to populate with the one in the request."

The sandbox exit checklists describe the initiator's half; the protocol pages describe the responder's. Build both and threading works.

Two further rules, and both bite on retries.

  • api_call_id and correlation_id must be different values on a response. The exit checklists check this on every answering use case.
  • A correlation ID that has failed is retired. The next attempt needs a fresh one. Reusing it earns NHCX-1006, duplicate request, or goes nowhere.

The workflow code means two different things

This is the field most likely to be misunderstood, because the sources define it twice and the definitions are not the same.

As a step code. The Workflow Status Sheet assigns a number to each step of a claim: 12 a new preauthorisation, 21 approved, 24 queried, and so on. This is the reading the Workflow Codes chapter documents and the one the reference payer validates.

As a case thread. The Open Protocol page defines it as the "unique id of workflow that may span over a series of message exchanges, e.g. an eligibility check, a preauth and then claims submission for a patient may be linked with such an id". The Technical Specifications page keeps both readings in one sentence: "Workflow id depicts the current process/state of the case. It may span over a series of message exchanges for a given transaction."

The field is Optional on all twenty-five rows of the workbook, across all ten sheets, including CoverageEligibility and Insurance Plan. So the exchanges for which the Workflow Status Sheet assigns no code are exchanges on which the header may simply be omitted. There is nothing to negotiate.

In practice: send the step code where the sheet gives one, because that is what the payer keys on. Send nothing where it does not. Agree the case-thread reading with a payer only if one asks for it.

Status words

The Technical Specifications page defines all seven.

ValueSent byMeaning
request.initiatedThe initiatorStarting the request cycle
request.queuedThe exchangeQueued at NHCX, waiting to be processed
request.dispatchedThe exchangeSuccessfully reached the recipient's system
request.stoppedThe exchangeStopped completely after failed attempts to reach the recipient
response.partialThe responderA partial response, or an acknowledgement of the request
response.completeThe responderThe final response, closing the cycle
response.errorThe responderThe request was rejected, or an error was met

request.stopped is the one nothing else explains. It is what the exchange records when redelivery has been exhausted, and it is the state behind a retired correlation ID.

The Open Protocol page carries a different set entirely: request.initiate, request.retry, response.success, response.fail, response.sender_not_supported, response.unhandled, response.request_retry. None of those seven appears in the workflow sheet, in any sample, or in the gateway's own validation messages. It is a superseded draft. Do not build against it, and be ready to meet it in older material.

Timestamp

Contested in format and in zone, and the chapter on JWE, Status and Errors sets out the disagreement. Two facts settle part of it.

  • The workbook types the field as a Unix timestamp and gives 1706308383 as its example on every sheet. The handbook and the FAQ use ISO 8601. Every sample bundle uses ISO 8601 with +05:30.
  • There is one numeric tolerance. The reference payer refuses a message whose timestamp is more than 24 hours behind the current time, with PAYR-1005. That is the only bound any source states.

Send ISO 8601 with +05:30, because that is what the samples carry. Accept a Unix epoch on the way in. Note that the ABDM sessions call is a different matter: its TIMESTAMP header is UTC with a trailing Z and milliseconds, and a drifted clock is refused.

Domain headers

The Overview says a few facts may be written on the outside of the envelope for the exchange's records. There is a naming convention for them and there are named examples, which is more than this documentation has said before.

The convention, from both the Open Protocol and Technical Specifications pages:

x-hcx-<use_case_name>-<parameter_name>

where use_case_name is under sixteen characters and ideally matches the API path segment, and parameter_name is under thirty-two characters. Both pages print the prefix as x-NHCX-. Send x-hcx-, for the reason given under The header prefix below.

The named examples. The Notification Integration document carries four in its domain_values table, which is what the exchange passes to a beneficiary's app so it can render a message without opening anything:

HeaderWhat it carries
x-hcx-amount_submittedThe amount submitted by the provider
x-hcx-benefit-category_typeThe benefit category, meaning the specialty
x-hcx-benefit_codeAn array of the benefits or services submitted
x-hcx-actionThe event type, such as preauth_response

The eObjects page adds a Usage domain header on the Claim Request and Claim Response, carrying preauthorization or claim.

And the access-control policy makes one of them load-bearing: an insurance marketplace must "submit the acquired consent as part of the domain header" before it may be given individual claim data. Access Control and Roles has the rest.

Send none of these to a payer that has not asked for one. But they are named, they have a convention, and the earlier statement in this documentation that no source names any of them was wrong.

The header prefix

The Open Protocol page writes every field as x-NHCX-. The Technical Specifications page, the workbook, the FAQ, the Postman collections and every sample write x-hcx-. Send x-hcx-.

What the receipt carries

Not a protected header, but the shape every participant must return within thirty seconds of a delivery.

{
"timestamp": "04/09/2026 11:46:41:305",
"api_call_id": "<from the incoming header>",
"correlation_id": "<from the incoming header>",
"result": {
"sender_code": "…",
"recipient_code": "…",
"entity_type": "preauth",
"protocol_status": "request.queued"
},
"error": { "code": "", "message": "" }
}

HTTP 202. Not 200, not an empty body. entity_type is derived from the path: the second-to-last segment, or the last where that is v1, with on_ stripped.