Aidbox Docs

$provider-member-match

The $provider-member-match operation implements the Da Vinci PDex Provider Access API. It lets a provider submit a batch of members (patient demographics, coverage, and a treatment-relationship attestation) and receive one or more Group resources whose IDs can then be used with $davinci-data-export to pull clinical data in bulk.

The operation follows the FHIR Bulk Data async pattern: kick-off returns 202 Accepted with a Content-Location header, the client polls the status URL, and once processing is complete downloads an ndjson file containing the output Parameters resource.

$provider-member-match is always asynchronous. Clients must include the Prefer: respond-async header on the kick-off request. Requests without this header are rejected with 400 Bad Request.

How it works

Each submitted member goes through a deterministic evaluation pipeline and lands in exactly one of three output buckets:

BucketProfileCodeMeaning
MatchedMemberspdex-treatment-relationshipmatchDemographics matched a payer member, treatment attestation is valid, and the member has not opted out. The Group ID of this bucket is what the provider feeds into $davinci-data-export.
NonMatchedMemberspdex-member-no-match-groupnomatchNo match was found, the match was ambiguous, or the treatment attestation was invalid.
ConsentConstrainedMemberspdex-member-opt-outconsentconstraintDemographics matched, but the member has an active opt-out Consent on file.

Per-member failures do not fail the whole batch — problematic members are routed to NonMatchedMembers.

invalid valid no match matched opted out not opted out Input member Validate attestation NonMatchedMembers Match demographics Check opt-out ConsentConstrainedMembers MatchedMembers

Endpoint

POST [base]/fhir/Group/$provider-member-match

Workflow

1

Kick-off. POST a Parameters resource listing one or more MemberBundle entries. Include Prefer: respond-async. The server responds with 202 Accepted and a Content-Location header pointing at the status URL.

2

Poll status. GET the URL from Content-Location. While processing is running you get 202 Accepted with a Retry-After header. Once complete you get 200 OK with a Bulk Data manifest whose output[].url points to an ndjson file.

3

Download output. GET the ndjson URL from the manifest. The body is a single-line Parameters resource containing the output Group resources inline.

4

(Optional) Cancel or delete. DELETE the cancel URL to stop a running job or clean up a completed one.

Input

A FHIR Parameters resource with one or more MemberBundle parameters. Each MemberBundle contains:

PartCard.TypeProfile
MemberPatient1..1PatientHRex Patient Demographics
CoverageToMatch1..1CoverageHRex Coverage
Consent1..1ConsentProvider Treatment Relationship Consent
CoverageToLink0..1CoverageHRex Coverage

The whole Parameters body is first validated with Aidbox $validate against the provider-parameters-multi-member-match-bundle-in profile. If validation fails, the server returns 422 Unprocessable Entity with the OperationOutcome from $validate and no background job is created.

Matching algorithm

Matching is deterministic and exact. The following demographic fields are all required on the submitted Patient and must all match a payer-side Patient:

FieldLogic
Patient.name[0].familyCase-insensitive exact
Patient.name[0].given[0]Case-insensitive exact
Patient.birthDateExact
Patient.genderExact

When CoverageToMatch.subscriberId is present the matching query additionally requires _has:Coverage:beneficiary:subscriber-id=<subscriberId> so only Patients with a matching Coverage subscriber ID are considered.

A member is treated as unmatched when the demographic search returns zero entries or more than one entry (ambiguous matches are rejected conservatively).

Treatment attestation

The Consent part is the provider's attestation that a treatment relationship exists with the member. The attestation is accepted when the Consent resource is present and Consent.status = "active". There is no deeper verification of the attestation claim itself — the attestation is the declaration.

Opt-out check

After a successful demographic match, the server searches for an active opt-out Consent on the matched payer-side Patient:

GET /fhir/Consent
  ?patient=<matched-patient-id>
  &status=active
  &category=http://hl7.org/fhir/us/davinci-pdex/CodeSystem/pdex-consent-api-purpose|provider-access
  &provision-type=deny

If at least one such Consent exists, the member is placed in ConsentConstrainedMembers. Revocations (provision.type = "permit") are not returned by this query and therefore do not block the member.

All opt-out scopes (global, provider-specific, purpose-specific, payer-specific, provider-category) are currently treated the same — any active deny opts the member out. Scope-aware enforcement is not yet implemented.

Kick-off example

POST /fhir/Group/$provider-member-match
Content-Type: application/fhir+json
Prefer: respond-async
{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "MemberBundle",
      "part": [
        {
          "name": "MemberPatient",
          "resource": {
            "resourceType": "Patient",
            "name": [{"family": "Johnson", "given": ["Robert"]}],
            "gender": "male",
            "birthDate": "1952-07-25",
            "identifier": [
              {"system": "http://example.org/member-id", "value": "M12345"}
            ]
          }
        },
        {
          "name": "CoverageToMatch",
          "resource": {
            "resourceType": "Coverage",
            "status": "active",
            "subscriberId": "SUB-001",
            "beneficiary": {"reference": "Patient/test-member-001"},
            "payor": [{"reference": "Organization/test-payer-001"}]
          }
        },
        {
          "name": "Consent",
          "resource": {
            "resourceType": "Consent",
            "status": "active",
            "scope": {
              "coding": [{
                "system": "http://terminology.hl7.org/CodeSystem/consentscope",
                "code": "treatment"
              }]
            },
            "category": [
              {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "IDSCL"}]},
              {"coding": [{"system": "http://loinc.org", "code": "64292-6"}]}
            ],
            "patient": {"reference": "Patient/test-member-001"},
            "dateTime": "2026-01-15T10:00:00Z",
            "performer": [
              {"identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "1982947230"}}
            ],
            "policyRule": {
              "coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "OPTIN"}]
            }
          }
        }
      ]
    }
  ]
}

Status

202 Accepted

Headers

  • Content-Location — status URL, e.g. [base]/fhir/Group/$provider-member-match-status/<task-id>

Status

422 Unprocessable Entity

Body

{
  "resourceType": "OperationOutcome",
  "id": "validationfail",
  "issue": [
    {
      "severity": "error",
      "code": "invariant",
      "diagnostics": "..."
    }
  ]
}

Status

400 Bad Request

Body

{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "processing",
      "diagnostics": "This operation requires Prefer: respond-async header"
    }
  ]
}

Status polling

GET [base]/fhir/Group/$provider-member-match-status/<task-id>

The operation tracks progress with a standard FHIR Task resource. Responses map from the Task status as follows:

Task statusHTTPHeadersBody
requested202Retry-After: 5(empty)
in-progress202Retry-After: 5, X-Progress: Processing members(empty)
completed200Content-Type: application/jsonBulk Data manifest
failed500OperationOutcome with failure diagnostics
not found404OperationOutcome

Status

202 Accepted

Headers

HeaderValue
Retry-After5
X-ProgressProcessing members

Status

200 OK

Body

{
  "transactionTime": "2026-04-20T12:34:56Z",
  "request": "[base]/fhir/Group/$provider-member-match",
  "requiresAccessToken": true,
  "output": [
    {
      "type": "Parameters",
      "url": "[base]/output/<task-id>.ndjson"
    }
  ],
  "error": []
}

Status

500 Internal Server Error

Body

{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "exception",
      "diagnostics": "<reason from Task.statusReason>"
    }
  ]
}

Output

The manifest's output[0].url points at an ndjson endpoint served by Aidbox:

GET [base]/output/<task-id>.ndjson

The body is a single line — a Parameters resource conforming to the provider-parameters-multi-member-match-bundle-out profile. Each non-empty output bucket appears as one parameter whose resource is the full inline Group. Empty buckets are omitted.

GET /output/<task-id>.ndjson

Status

200 OK

Headers

HeaderValue
Content-Typeapplication/fhir+ndjson

Body (single ndjson line, formatted for readability)

{
  "resourceType": "Parameters",
  "meta": {
    "profile": [
      "http://hl7.org/fhir/us/davinci-pdex/StructureDefinition/provider-parameters-multi-member-match-bundle-out"
    ]
  },
  "parameter": [
    {
      "name": "MatchedMembers",
      "resource": {
        "resourceType": "Group",
        "id": "<task-id>-matched",
        "meta": {
          "profile": [
            "http://hl7.org/fhir/us/davinci-pdex/StructureDefinition/pdex-treatment-relationship"
          ]
        },
        "active": true,
        "type": "person",
        "actual": true,
        "code": {
          "coding": [{
            "system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS",
            "code": "match"
          }]
        },
        "identifier": [
          {"system": "http://hl7.org/fhir/sid/us-npi", "value": "1982947230"}
        ],
        "managingEntity": {
          "identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "5555555555"},
          "display": "Payer Organization"
        },
        "characteristic": [{
          "code": {"coding": [{"system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS", "code": "match"}]},
          "valueReference": {
            "identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "1982947230"},
            "display": "Provider Organization"
          },
          "exclude": false,
          "period": {"start": "2026-04-20", "end": "2026-05-20"}
        }],
        "quantity": 1,
        "member": [
          {"entity": {"reference": "Patient/test-member-001", "display": "Johnson, Robert"}, "inactive": false}
        ]
      }
    },
    {
      "name": "ConsentConstrainedMembers",
      "resource": {
        "resourceType": "Group",
        "id": "<task-id>-consent",
        "meta": {
          "profile": [
            "http://hl7.org/fhir/us/davinci-pdex/StructureDefinition/pdex-member-opt-out"
          ]
        },
        "active": true,
        "type": "person",
        "actual": true,
        "code": {
          "coding": [{
            "system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS",
            "code": "consentconstraint"
          }]
        },
        "managingEntity": {
          "identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "5555555555"},
          "display": "Payer Organization"
        },
        "characteristic": [{
          "code": {"coding": [{"system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS", "code": "consentconstraint"}]},
          "valueCodeableConcept": {
            "coding": [{"system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/opt-out-scope", "code": "provider-specific"}]
          },
          "exclude": false,
          "period": {"start": "2026-04-20", "end": "2026-05-20"}
        }],
        "quantity": 1,
        "member": [
          {"entity": {"reference": "Patient/test-member-002", "display": "Williams, Sarah"}, "inactive": false}
        ]
      }
    },
    {
      "name": "NonMatchedMembers",
      "resource": {
        "resourceType": "Group",
        "id": "<task-id>-nomatch",
        "meta": {
          "profile": [
            "http://hl7.org/fhir/us/davinci-pdex/StructureDefinition/pdex-member-no-match-group"
          ]
        },
        "active": true,
        "type": "person",
        "actual": true,
        "code": {
          "coding": [{
            "system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS",
            "code": "nomatch"
          }]
        },
        "contained": [
          {
            "resourceType": "Patient",
            "id": "1",
            "name": [{"family": "Unknown", "given": ["Nobody"]}],
            "gender": "male",
            "birthDate": "2000-01-01"
          }
        ],
        "characteristic": [{
          "code": {"coding": [{"system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS", "code": "nomatch"}]},
          "valueBoolean": true,
          "exclude": false,
          "period": {"start": "2026-04-20", "end": "2026-05-20"}
        }],
        "quantity": 1,
        "member": [
          {
            "entity": {
              "reference": "#1",
              "extension": [{
                "url": "http://hl7.org/fhir/us/davinci-pdex/StructureDefinition/base-ext-match-parameters",
                "valueReference": {"reference": "#1"}
              }]
            },
            "inactive": false
          }
        ]
      }
    }
  ]
}

Output Group fields

All output Groups share type = "person", actual = true, and active = true. Additional fields depend on the bucket:

MatchedMembers and ConsentConstrainedMembers

  • managingEntity.identifier — the payer's NPI, resolved from the first submitted member's Coverage.payor[0].reference (an Organization with an identifier of system http://hl7.org/fhir/sid/us-npi). If the Organization is missing or has no NPI, this falls back to "unknown".
  • member[].entity.reference — a literal reference to the payer-side Patient that was matched.
  • characteristic[].period — 30-day validity window, period.start is today, period.end is 30 days out.

MatchedMembers only

  • identifier — array containing the provider's NPI (derived from the authenticated OAuth client's identifier entry with system http://hl7.org/fhir/sid/us-npi).
  • characteristic[0].valueReference — a logical reference by NPI to the provider Organization.

NonMatchedMembers

  • The submitted Patient demographics are not persisted as standalone Patient resources. Instead, each submitted Patient is carried in Group.contained[] with a local id ("1", "2", …).
  • member[].entity.reference is a fragment reference ("#1", "#2", …) into contained, plus a base-ext-match-parameters extension carrying the same fragment reference.
  • characteristic[0].valueBoolean = true.

Cancellation and deletion

DELETE [base]/fhir/Group/$provider-member-match-cancel/<task-id>

Cancellation is cooperative. The background worker checks the Task status before starting, after each evaluated member, and again before persisting results — so a cancelled job stops at the next checkpoint without ever writing Groups or the Binary.

Task statusActionResponse
requested / in-progressSet Task to cancelled. The background processor stops at its next checkpoint.202 Accepted
completed / failed / cancelledDelete the Task and every resource referenced from Task.output (Groups and the Binary).202 Accepted
not found404 OperationOutcome

Cancellation uses a custom $provider-member-match-cancel URL rather than DELETE on the status URL, because Aidbox operation dispatch is keyed on HTTP method and distinct method/URL combinations must be registered separately.

Group lifecycle and cleanup

Each output Group carries a 30-day validity window on Group.characteristic[0].period:

"period": {"start": "2026-04-20", "end": "2026-05-20"}

A background job inside the interop app runs hourly and:

  1. Deactivates expired Groups — Groups whose characteristic.period.end has passed and whose active = true are flipped to active = false.
  2. Hard-deletes old inactive Groups — Groups with active = false whose characteristic.period.end is more than 90 days in the past are removed along with the Task and Binary they belong to.

Cleanup only touches PDex Groups — the scan filters on _profile=<pdex-treatment-relationship,pdex-member-no-match-group,pdex-member-opt-out>. Non-PDex Groups in the same Aidbox instance are left alone.

Provider identity

The provider's NPI is extracted from the authenticated OAuth client's identifier array (entry with system http://hl7.org/fhir/sid/us-npi). The NPI is used to:

  • Populate Task.requester.identifier on the kick-off Task.
  • Populate the identifier array and the characteristic[0].valueReference on the MatchedMembers Group.

If the OAuth client has no NPI identifier, the provider NPI falls back to "unknown" in the output Groups.

Error responses

StatusCondition
202Async request accepted (kick-off) or cancellation acknowledged.
200Polling complete, manifest returned.
400Prefer: respond-async header is missing.
404Unknown task-id on status, cancel, or output.
422Input Parameters failed profile validation.
500Background processing failed; see Task.statusReason.

Individual member failures (validation issues, exceptions while evaluating one member) do not fail the whole batch — the affected members are routed to NonMatchedMembers with a reason string.

End-to-end example

The snippets below reproduce the three-bucket demo used in internal testing. They assume an Aidbox instance with the PDex STU 2.1 package loaded and an OAuth client authorized to call the interop app.

1

Seed the payer-side test data. Post this Bundle once to create the Organization, payer-side Patients, Coverages, and an opt-out Consent for member-002.

POST /fhir
Content-Type: application/fhir+json
{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "request": {"method": "PUT", "url": "/Organization/test-payer-001"},
      "resource": {
        "resourceType": "Organization", "id": "test-payer-001",
        "name": "Test Payer Organization",
        "identifier": [{"system": "http://hl7.org/fhir/sid/us-npi", "value": "5555555555"}]
      }
    },
    {
      "request": {"method": "PUT", "url": "/Patient/test-member-001"},
      "resource": {
        "resourceType": "Patient", "id": "test-member-001",
        "name": [{"family": "Johnson", "given": ["Robert"]}],
        "gender": "male", "birthDate": "1952-07-25"
      }
    },
    {
      "request": {"method": "PUT", "url": "/Patient/test-member-002"},
      "resource": {
        "resourceType": "Patient", "id": "test-member-002",
        "name": [{"family": "Williams", "given": ["Sarah"]}],
        "gender": "female", "birthDate": "1985-03-12"
      }
    },
    {
      "request": {"method": "PUT", "url": "/Coverage/test-coverage-001"},
      "resource": {
        "resourceType": "Coverage", "id": "test-coverage-001", "status": "active",
        "subscriberId": "SUB-001",
        "beneficiary": {"reference": "Patient/test-member-001"},
        "payor": [{"reference": "Organization/test-payer-001"}]
      }
    },
    {
      "request": {"method": "PUT", "url": "/Coverage/test-coverage-002"},
      "resource": {
        "resourceType": "Coverage", "id": "test-coverage-002", "status": "active",
        "subscriberId": "SUB-002",
        "beneficiary": {"reference": "Patient/test-member-002"},
        "payor": [{"reference": "Organization/test-payer-001"}]
      }
    },
    {
      "request": {"method": "PUT", "url": "/Consent/test-optout-member-002"},
      "resource": {
        "resourceType": "Consent", "id": "test-optout-member-002", "status": "active",
        "scope": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/consentscope", "code": "patient-privacy"}]},
        "patient": {"reference": "Patient/test-member-002"},
        "category": [{"coding": [{"system": "http://hl7.org/fhir/us/davinci-pdex/CodeSystem/pdex-consent-api-purpose", "code": "provider-access"}]}],
        "provision": {"type": "deny"},
        "policyRule": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "OPTIN"}]}
      }
    }
  ]
}
2

Kick off. Submit three members: one will match, one will hit the opt-out, one has no match.

POST /fhir/Group/$provider-member-match
Content-Type: application/fhir+json
Prefer: respond-async
{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "MemberBundle",
      "part": [
        {"name": "MemberPatient", "resource": {"resourceType": "Patient", "name": [{"family": "Johnson", "given": ["Robert"]}], "gender": "male", "birthDate": "1952-07-25"}},
        {"name": "CoverageToMatch", "resource": {"resourceType": "Coverage", "status": "active", "subscriberId": "SUB-001", "beneficiary": {"reference": "Patient/test-member-001"}, "payor": [{"reference": "Organization/test-payer-001"}]}},
        {"name": "Consent", "resource": {"resourceType": "Consent", "status": "active", "scope": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/consentscope", "code": "treatment"}]}, "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "IDSCL"}]}, {"coding": [{"system": "http://loinc.org", "code": "64292-6"}]}], "patient": {"reference": "Patient/test-member-001"}, "dateTime": "2026-01-15T10:00:00Z", "performer": [{"identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "1982947230"}}], "policyRule": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "OPTIN"}]}}}
      ]
    },
    {
      "name": "MemberBundle",
      "part": [
        {"name": "MemberPatient", "resource": {"resourceType": "Patient", "name": [{"family": "Williams", "given": ["Sarah"]}], "gender": "female", "birthDate": "1985-03-12"}},
        {"name": "CoverageToMatch", "resource": {"resourceType": "Coverage", "status": "active", "subscriberId": "SUB-002", "beneficiary": {"reference": "Patient/test-member-002"}, "payor": [{"reference": "Organization/test-payer-001"}]}},
        {"name": "Consent", "resource": {"resourceType": "Consent", "status": "active", "scope": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/consentscope", "code": "treatment"}]}, "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "IDSCL"}]}, {"coding": [{"system": "http://loinc.org", "code": "64292-6"}]}], "patient": {"reference": "Patient/test-member-002"}, "dateTime": "2026-01-15T10:00:00Z", "performer": [{"identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "1982947230"}}], "policyRule": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "OPTIN"}]}}}
      ]
    },
    {
      "name": "MemberBundle",
      "part": [
        {"name": "MemberPatient", "resource": {"resourceType": "Patient", "name": [{"family": "Unknown", "given": ["Nobody"]}], "gender": "male", "birthDate": "2000-01-01"}},
        {"name": "CoverageToMatch", "resource": {"resourceType": "Coverage", "status": "active", "subscriberId": "SUB-999", "beneficiary": {"reference": "Patient/test-member-001"}, "payor": [{"reference": "Organization/test-payer-001"}]}},
        {"name": "Consent", "resource": {"resourceType": "Consent", "status": "active", "scope": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/consentscope", "code": "treatment"}]}, "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "IDSCL"}]}, {"coding": [{"system": "http://loinc.org", "code": "64292-6"}]}], "patient": {"reference": "Patient/test-member-001"}, "dateTime": "2026-01-15T10:00:00Z", "performer": [{"identifier": {"system": "http://hl7.org/fhir/sid/us-npi", "value": "1982947230"}}], "policyRule": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "OPTIN"}]}}}
      ]
    }
  ]
}

Response: 202 Accepted, Content-Location: [base]/fhir/Group/$provider-member-match-status/<task-id>.

3

Poll. Call the status URL until it returns 200 OK.

GET /fhir/Group/$provider-member-match-status/<task-id>
4

Download. Use the output[0].url from the manifest to fetch the ndjson.

GET /output/<task-id>.ndjson

Expected result distribution:

MemberMatchOpt-outBucket
Johnson, RobertYes (test-member-001)NoMatchedMembers
Williams, SarahYes (test-member-002)YesConsentConstrainedMembers
Unknown, NobodyNoNonMatchedMembers

Last updated: