Claims Service — API Contracts
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: SERVICE_OVERVIEW · Service Template · 02 DDD
Base URL
/api/v1/claims-service
All routes require:
Authorization: Bearer <JWT>(Keycloak tenant realm)X-Tenant-ID: <tenantId>header (validated against JWTtenant_idclaim)- Module entitlement
ehr.claims— write operations return403 MODULE_NOT_LICENSEDif absent
Claims
POST /api/v1/claims
Assemble and submit a new claim from encounter charges.
Request body:
{
"encounterId": "enc_01HXY...",
"coverageId": "cov_01HXY...",
"chargeIds": ["chg_01HXY...", "chg_01HXY2..."],
"billProviderId": "prov_01HXY...",
"renderingProviderId": "prov_01HXY2...",
"serviceDate": { "from": "2026-03-01", "to": "2026-03-01" },
"diagnosisCodes": ["J06.9"],
"autoSubmit": true
}
Response 201:
{
"claimId": "clm_01HXY...",
"status": "submitted",
"clearinghouseRef": "CHX-2026-00123",
"totalBilled": { "amount": 275.00, "currency": "USD" }
}
GET /api/v1/claims
List claims with filtering.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
patientId | string | Filter by patient |
encounterId | string | Filter by encounter |
status | string | Claim status filter |
fromDate | date | Service date range start |
toDate | date | Service date range end |
page | number | Page number (default 1) |
pageSize | number | Max 100 (default 20) |
Response 200:
{
"data": [{ "claimId": "clm_...", "status": "paid", "totalBilled": {...}, "serviceDate": {...} }],
"meta": { "total": 142, "page": 1, "pageSize": 20 }
}
GET /api/v1/claims/:claimId
Retrieve full claim detail.
Response 200:
{
"claimId": "clm_01HXY...",
"patientId": "pat_...",
"encounterId": "enc_...",
"coverageId": "cov_...",
"status": "accepted",
"payerClaimNumber": "PAY-2026-99999",
"diagnosisCodes": ["J06.9"],
"lineItems": [...],
"totalBilled": { "amount": 275.00, "currency": "USD" },
"denial": null,
"createdAt": "2026-03-01T10:00:00Z",
"updatedAt": "2026-03-02T14:30:00Z"
}
POST /api/v1/claims/:claimId/submit
Manually trigger submission for a ready claim (if autoSubmit: false).
Response 200: { "status": "submitted", "clearinghouseRef": "..." }
POST /api/v1/claims/:claimId/appeal
File an appeal for a denied claim.
Request body:
{
"denialId": "dnl_01HXY...",
"appealNotes": "Medical necessity documentation attached."
}
Response 200: { "appealStatus": "filed", "appealDeadline": "2026-05-01" }
POST /api/v1/claims/:claimId/resubmit
Create a corrected replacement claim.
Request body: (same shape as POST /api/v1/claims, with corrected fields)
Response 201: { "claimId": "clm_NEW...", "status": "submitted", "replacesClaimId": "clm_OLD..." }
Coverages
POST /api/v1/coverages
Add an insurance coverage record for a patient.
Request body:
{
"patientId": "pat_01HXY...",
"payerId": "pyr_01HXY...",
"subscriberId": "MBR-123456",
"groupNumber": "GRP-789",
"planName": "Blue Shield PPO",
"priority": "primary",
"relationship": "self",
"effectiveFrom": "2026-01-01",
"effectiveTo": null
}
Response 201: { "coverageId": "cov_01HXY...", "status": "active" }
GET /api/v1/coverages
Query: patientId (required), priority, status
Response 200: Paginated list of coverage records ordered by priority.
GET /api/v1/coverages/:coverageId
Full coverage detail.
PATCH /api/v1/coverages/:coverageId
Update coverage fields (effectiveTo, planName, copay, etc.).
POST /api/v1/coverages/:coverageId/eligibility-checks
Trigger real-time eligibility verification.
Response 201:
{
"eligibilityId": "elig_01HXY...",
"status": "active",
"deductibleMet": { "amount": 250.00, "currency": "USD" },
"oopMet": { "amount": 500.00, "currency": "USD" },
"coinsurance": 20,
"expiresAt": "2026-04-19T00:00:00Z"
}
GET /api/v1/coverages/:coverageId/eligibility-checks
List eligibility check history for a coverage.
Prior Authorizations
POST /api/v1/authorizations
Request a prior authorization.
Request body:
{
"coverageId": "cov_01HXY...",
"patientId": "pat_01HXY...",
"procedureCode": { "system": "CPT", "code": "27447" },
"diagnosisCodes": ["M17.11"],
"requestedUnits": 1
}
Response 201: { "authorizationId": "auth_01HXY...", "status": "pending" }
GET /api/v1/authorizations/:authorizationId
Authorization detail including decision.
PATCH /api/v1/authorizations/:authorizationId
Update authorization (record external decision, extend validity).
Remittances
POST /api/v1/remittances/ingest
Ingest an ERA payload (called by the EDI ingest worker).
Request body: { "channel": "x12_835", "rawPayload": "<X12 835 content>" }
Response 202: { "remittanceId": "rem_01HXY...", "processingStatus": "queued" }
GET /api/v1/remittances/:remittanceId
Remittance summary with per-claim allocation detail.
FHIR R4 Read Surface
The following FHIR R4 endpoints are available for read/search. Write operations use the REST API above.
| FHIR Resource | Endpoint | Notes |
|---|---|---|
Coverage | GET /fhir/R4/Coverage/{id} | Single record |
Coverage | GET /fhir/R4/Coverage?patient={patientId} | Patient coverages |
Claim | GET /fhir/R4/Claim/{id} | Single claim |
Claim | GET /fhir/R4/Claim?patient={patientId}&status={status} | Filtered claims |
ClaimResponse | GET /fhir/R4/ClaimResponse/{id} | Claim response/acknowledgement |
ClaimResponse | GET /fhir/R4/ClaimResponse?request={claimId} | Response for specific claim |
CoverageEligibilityRequest | GET /fhir/R4/CoverageEligibilityRequest/{id} | Eligibility request |
CoverageEligibilityResponse | GET /fhir/R4/CoverageEligibilityResponse/{id} | Eligibility response |
ExplanationOfBenefit | GET /fhir/R4/ExplanationOfBenefit/{id} | Single EOB |
ExplanationOfBenefit | GET /fhir/R4/ExplanationOfBenefit?patient={patientId} | Patient EOBs |
Common Error Codes
| Code | HTTP | Meaning |
|---|---|---|
CLAIM_NOT_FOUND | 404 | Claim does not exist for this tenant |
CLAIM_INVALID_STATE | 409 | Transition not permitted in current state |
CLAIM_VALIDATION_FAILED | 422 | Pre-submission scrub errors |
COVERAGE_NOT_FOUND | 404 | Coverage not found |
COVERAGE_INACTIVE | 422 | Coverage expired or cancelled |
CODING_INVALID | 422 | ICD-10/CPT code invalid per terminology-service |
SUBMISSION_FAILED | 502 | Payer/clearinghouse unavailable |
MODULE_NOT_LICENSED | 403 | Tenant missing ehr.claims entitlement |
UNAUTHORIZED | 401 | Missing or invalid JWT |
FORBIDDEN | 403 | Insufficient RBAC role |