Reference
Integrations (FHIR API)
For developers and clinic IT. Your own system can check whether a patient is covered, and send the claim, without anyone using the portal. The same rules apply as in the portal, because both use the same engine.
How it fits together
The API follows FHIR R4, a common standard for health data, so most electronic medical record (EMR) systems already speak it. You do four things, in this order:
1. Token
Sign in with your client ID and secret.
POST /oauth/token2. Find
Look up the member by Member ID.
GET /Patient3. Verify
Ask if they are a member with cover in force.
$submit4. Claim
Send the claim for the member's program.
POST /Claim
Base URL: https://intrifund-staging.evimerointeractive.net/api/fhir. Send and expect application/fhir+json. A clinic can reach only its own data and only members it has checked.
Get a token
IntriFund issues your clinic a client ID and a client secret, and only to a verified clinic. The secret is shown once and is stored only as a hash, so keep it safe. If it is lost, ask for a new one. Tokens use the OAuth 2.0 client credentials grant and last one hour.
POST /api/fhir/oauth/token Content-Type: application/x-www-form-urlencoded Authorization: Basic base64(client_id:client_secret) grant_type=client_credentials
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "system/Patient.read system/CoverageEligibilityRequest.write system/Claim.write"
}Send Authorization: Bearer <access_token> on every other call. Ask for a new token a few minutes before the old one ends. A token is limited to its scopes, written like system/Claim.write. A call outside your scopes is refused with HTTP 403.
Discovery documents are public: /.well-known/smart-configuration and /api/fhir/metadata.
Find the patient
Lookups are keyed on the Member ID. These are the only allowed forms:
- The IntriFund Member ID (
identifier), optionally with the date of birth to confirm the card - A Patient id alone (
_id: the Member ID, or the EMR UUID for an integrated EMR)
Searching by name, phone, email or date of birth is refused with HTTP 400: a name can match several people, an identifier matches one. This also stops anyone from browsing the member list.
GET /api/fhir/Patient?identifier=https://intrifund-staging.evimerointeractive.net/api/terminology/member-id|BEN-7K9M2P&birthdate=1991-02-01
{
"resourceType": "Bundle", "type": "searchset", "total": 1,
"entry": [{
"resource": {
"resourceType": "Patient",
"identifier": [{ "system": "https://intrifund-staging.evimerointeractive.net/api/terminology/member-id", "value": "BEN-7K9M2P" }],
"active": true,
"name": [{ "family": "Doe", "given": ["Jane"] }],
"birthDate": "1991-02-01"
}
}]
}active means verified. Contact details, address and photo are returned only to the system that registered the patient; any other clinic gets the minimal view above. The Member ID identifier carries the standard HL7 type MB (Member Number).
Verify a member (eligibility check)
Post a CoverageEligibilityRequest to /api/fhir/CoverageEligibilityRequest/$submit. This is the verification call to make before treating someone. Name the patient one of three ways, the same three the clinic portal offers: by reference (Patient/{id}, the EMR UUID or the Member ID); by Member ID in patient.identifier plus the patient-birth-date extension; or by name and date of birth in a contained Patient (patient.reference: "#p1"). A Member ID is a convenience, never a requirement. Two factors are always needed, so a card number or a surname alone cannot be used to look someone up.
{
"resourceType": "CoverageEligibilityRequest",
"status": "active",
"purpose": ["validation"],
"created": "2026-10-20T08:00:00Z",
"insurer": { "reference": "Organization/IntriFUND" },
"patient": {
"identifier": { "system": "https://intrifund-staging.evimerointeractive.net/api/terminology/member-id", "value": "BEN-7K9M2P" }
},
"extension": [{
"url": "https://intrifund-staging.evimerointeractive.net/fhir/StructureDefinition/patient-birth-date",
"valueDate": "1991-02-01"
}],
"item": [{
"category": { "coding": [{ "system": "https://intrifund-staging.evimerointeractive.net/api/terminology/program", "code": "MM" }] },
"productOrService": { "coding": [{ "code": "00010" }] }
}]
}{
"resourceType": "CoverageEligibilityResponse",
"outcome": "complete",
"disposition": "Active: 1 coverage(s) in force.",
"patient": {
"reference": "Patient/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"identifier": { "system": "https://intrifund-staging.evimerointeractive.net/api/terminology/member-id", "value": "BEN-7K9M2P" }
},
"insurance": [{
"coverage": {
"reference": "Coverage/12",
"identifier": { "type": { "text": "Policy Number" }, "system": "https://intrifund-staging.evimerointeractive.net/api/terminology/policy-number", "value": "IFP-00000015-MM" },
"display": "Medical Mission"
},
"inforce": true,
"benefitPeriod": { "start": "2026-10-01", "end": "2027-09-30" },
"item": [{ "category": { "coding": [{ "system": "https://intrifund-staging.evimerointeractive.net/api/terminology/program", "code": "MM", "display": "Medical Mission" }] } }],
"extension": [
{ "url": "https://intrifund-staging.evimerointeractive.net/fhir/StructureDefinition/coverage-status", "valueCode": "active" },
{ "url": "https://intrifund-staging.evimerointeractive.net/fhir/StructureDefinition/coverage-percent", "valueString": "80.00%" }
]
}],
"extension": [{
"url": "https://intrifund-staging.evimerointeractive.net/fhir/StructureDefinition/beneficiary-status",
"valueCoding": { "system": "https://intrifund-staging.evimerointeractive.net/fhir/CodeSystem/beneficiary-status", "code": "active", "display": "Active" }
}]
}Read two things. The beneficiary status extension tells you the state of the member. insurance lists every cover the member has, each with its Policy Number, program, period, percent, its own status (coverage-status: active, cancelled or draft) and the standard FHIR inforce flag, which is true only when the member is verified and the cover is active with today inside its period. Treat on inforce, nothing else.
| Status | Meaning | insurance |
|---|---|---|
| active | Verified by both managers, with at least one cover in force today. | all covers, inforce true on the live ones |
| pending | Registered and awaiting approval. Not a member yet. | all covers as draft, inforce false |
| expired | Verified, but every cover has passed its end date. | all covers, inforce false |
| inactive | Rejected, or verified with no cover (none, or all cancelled). | whatever exists, inforce false |
There is no fraudulent status. An unknown patient returns HTTP 404 with an OperationOutcome. The codes, the value set and the extension definitions are published at /api/fhir/CodeSystem/beneficiary-status, /api/fhir/ValueSet/beneficiary-status and /api/fhir/StructureDefinition/beneficiary-status, with no token needed, so a FHIR validator can resolve them.
Read cover
GET /api/fhir/Coverage?beneficiary=Patient/{id} lists a member's cover, and GET /api/fhir/Coverage/{id} reads one. Each Coverage carries the Member ID in subscriberId, the program in class, the coverage percent and the beneficiary status extension. Cover on a member who is not yet verified has status draft, so it can never be mistaken for live cover.
Send a claim
Post a Claim with use set to preauthorization to /api/fhir/Claim. It becomes a service request in IntriFund, which a manager reviews. Diagnoses are ICD-10 codes and line items are CPT-4 codes.
The rules a claim must pass
The member is verified.
A pending or rejected beneficiary cannot be claimed for, whatever cover rows exist.
The cover is the member’s cover in the claimed program, and it is in force today.
Started, not ended, not cancelled. There is no fallback to cover in a different program.
Every line item is a service the program covers.
The totals add up.
Errors
Claim errors return HTTP 400 and a JSON body with a plain reason:
{ "error": "This member has no coverage in force for program DG today." }| HTTP | When | What to do |
|---|---|---|
| 400 | A search was not allowed, the body is malformed, or a claim rule failed. The message says which. | Fix the request. Do not retry the same one. |
| 401 | The token is missing, expired or invalid. | Get a new token. |
| 403 | Your scopes do not allow this. | Ask for the right scope. |
| 404 | No such patient or cover. | Check the id. Verify the member first. |
Identifiers in the API
| What | Format | System |
|---|---|---|
| Member ID | BEN-XXXXXX | https://intrifund-staging.evimerointeractive.net/api/terminology/member-id |
| Patient id | EMR UUID, or the Member ID | - |
| Policy Number | IFP-00000050-MM | https://intrifund-staging.evimerointeractive.net/api/terminology/policy-number |
| Program code | MM, DG | https://intrifund-staging.evimerointeractive.net/api/terminology/program |
| Beneficiary status | active, pending, expired, inactive | https://intrifund-staging.evimerointeractive.net/fhir/CodeSystem/beneficiary-status |
One Member ID per person, one Policy Number per program the member is enrolled in (the member number plus the program code), and one Coverage ID per term of cover under that policy. A renewal is a new Coverage ID under the same Policy Number. The claim quotes the Policy Number; the bare member number is still accepted for older integrations.
The six characters of a Member ID use the Crockford base32 alphabet: digits and capitals, without I, L, O or U, so they survive being read over the phone.
