Developers

Developer API

Everything the calculator does is a REST API underneath — group ICD-10 codes to an MS-DRG (any manual version back to FY2022), price the claim with real FY2027 hospital-specific factors (FY2026 for earlier discharges), verify the result against the official Medicare pricer, and export the worksheet as PDF or Excel. JSON in, JSON out.

Base URL. Issued with your API key. The examples below call it $BASE.

On this page

Authentication & rate limits

Every call from your own server needs an issued key, sent as an X-API-Key header. Without one, or with a key we didn't issue, the endpoints on this page answer 401 (403 when the client is a script such as curl). The reply is the same for a missing and a wrong key, so it never confirms whether a guessed key exists. Usage is metered per key, not per IP, so your whole team or server fleet shares one predictable quota.

Access tiers: what each covers, its limit and how it is metered
TierCoversLimitMetered
API keyevery endpoint here, any MS-DRG, no daily cap240/min · 10,000/hour across all endpointsper key
No key (this site, in the browser)grouping and lookups; pricing for 40 common MS-DRGs (others 403), 40 priced claims a day (then 429)60/min · 500/hour per endpoint (20/min · 150/hour on the lookups below and verify), 120/min · 1,500/hour across all endpointsper client IP

Keys are issued per organization — request one here with a line about what you're building. Exceeding a limit returns 429: back off and retry after a minute. Only the across-all-endpoints limit sends a Retry-After header.

Server-side use. Browser CORS is restricted to our own origins, so call the API from your backend. Please keep /drg/verify traffic modest — each call prices the claim through the official Medicare pricer live.

Endpoints

POST/drg/group

Group a claim to an MS-DRG from ICD-10-CM diagnoses (with POA flags) and ICD-10-PCS procedures. Optional age, sex, and dischargeStatus (UB-04 code) drive the disposition-split DRG families — AMI discharged-alive vs. expired, left-AMA, the newborn MDC, and the discharged-alive-only MCC rule. Add ccn + coveredCharges + los to price the resulting DRG in the same call.

curl -X POST "$BASE/drg/group" -H "Content-Type: application/json" \
  -H "X-API-Key: $KEY" -d '{
  "diagnoses": [
    {"code": "I213",  "poa": "Y"},   // principal first (STEMI)
    {"code": "J9601", "poa": "Y"},   // acute resp failure — MCC
    {"code": "I5021", "poa": "Y"}
  ],
  "procedures": [{"code": "0271356"}, {"code": "02C03Z6"}],
  "age": 68, "sex": "M", "dischargeStatus": "01",
  "grouperVersion": "v44"          // 11 manuals, v39 (FY2022) to v44 (FY2027); omitted or unknown: the one in force today
}'
// response (trimmed)
{
  "grouper": {
    "drg": "359", "mdc": "05", "path": "surgical",
    "severity": "MCC", "severityDriver": "J9601",
    "grouperVersion": "v44", "grouperFiscalYear": "FY2027",
    "secondaryDetail": [{"dx": "J9601", "level": "MCC", "poa": "Y"}, …],
    "caveats": […]
  },
  "drgTitle": "Percutaneous Coronary Atherectomy w/ Intraluminal Device w/ MCC"
}

Also accepts FHIR R4, vendor, and Epic Tapestry claim shapes — send the payload as-is and the API detects the format. Ungroupable claims return 422 with the reason. GET /drg/grouper-versions lists the loaded manual versions.

POST/drg/calculate

Price a DRG the way Medicare does — operating + capital + IME/DSH + uncompensated care + outlier, with the hospital's real factors.

curl -X POST "$BASE/drg/calculate" -H "Content-Type: application/json" \
  -H "X-API-Key: $KEY" -d '{"drgCode": "871", "ccn": "330101", "coveredCharges": 120000, "los": 5}'
Request fields for POST /drg/calculate
FieldMeaning
drgCodeMS-DRG, e.g. 871 (required)
ccn · wageIndexa hospital CCN or a manual wage index (one required)
coveredCharges · losdrive outlier and transfer math
transferStatusnone · transfer · postacute
hmoPaidClaimMedicare Advantage claim toggle
includeIme · includeDsh · includeUcpstrip components for contract modeling (default true)

The response is the full dollar build the UI renders — component subtotals, outlier decision, grand total. Formula coefficients stay server-side.

POST/drg/verify

Price the same claim through our engine and the official Medicare pricer, live, side by side — the same check we publish on the site (typically matching to the cent).

curl -X POST "$BASE/drg/verify" -H "Content-Type: application/json" -H "X-API-Key: $KEY" \
  -d '{"drgCode": "208", "ccn": "450358", "coveredCharges": 95000, "los": 4, "dischargeDate": "2026-03-15"}'

All five fields above are required; add "hmoPaidClaim": true for MA claims. Returns both totals and the delta.

POST/drg/worksheet

The same inputs as /drg/calculate, returned as a client-ready pricing worksheet with the full line-by-line formula detail. Add "fmt": "pdf" (default) or "fmt": "xlsx". Same key, DRG access and limits as /drg/calculate. An optional "providers": ["billing:NPI", "attending:NPI"] adds a provider screening section (see POST /screen).

curl -o worksheet.pdf -X POST "$BASE/drg/worksheet" -H "Content-Type: application/json" \
  -H "X-API-Key: $KEY" -d '{"drgCode": "871", "ccn": "330101", "coveredCharges": 120000, "los": 5, "fmt": "pdf"}'

POST/drg/jobs

Price a large claim file in the background: the same rows and options as POST /drg/batch, up to 20,000 rows a job. The call returns 202 with a jobId; poll its status, then fetch the results as JSON or CSV. Jobs need an API key or an approved account sign-in.

curl -X POST "$BASE/drg/jobs" -H "Content-Type: application/json" -H "X-API-Key: $KEY" \
  -d '{"rows": [{"drgCode": "871", "ccn": "330101", "coveredCharges": 120000, "los": 5}, …]}'
# 202 {"jobId": "…", "state": "queued", "rows": 18000, "done": 0, "queuePosition": 0, …}

curl "$BASE/drg/jobs/$JOB" -H "X-API-Key: $KEY"          # state: queued, running, done, cancelled or failed
curl "$BASE/drg/jobs/$JOB/results" -H "X-API-Key: $KEY"  # /drg/batch's shape: results, receipt, summary
curl "$BASE/drg/jobs/$JOB/csv" -H "X-API-Key: $KEY" -o priced.csv
curl -X POST "$BASE/drg/jobs/$JOB/cancel" -H "X-API-Key: $KEY"
Job routes
RouteReturns
POST /drg/jobs202 and the status below. Body: rows plus includeUcp, includeIme, includeDsh, includePassthrough (default true)
GET /drg/jobs/{jobId}jobId, state, rows, done, priced, errors, chunkRows, queuePosition, waitingOnRateLimit, createdAt, startedAt, finishedAt, error
GET /drg/jobs/{jobId}/resultsthe finished job: results (row = its place in your file), receipt, summary; a cancelled or failed job returns the rows it priced
GET /drg/jobs/{jobId}/csvthe same, one CSV line per submitted row
POST /drg/jobs/{jobId}/cancelstops the job; rows already priced stay in its results (rows are charged when the job is submitted)
Batch and job limits by tier
TierRows per /drg/batch callBackground jobs
No key (in the browser)10no
Approved work-email account25yes, up to 20,000 rows
API key200yes, up to 20,000 rows
API key, top tier1,000yes, up to 20,000 rows

One job runs at a time per key or account; a finished job is kept for 24 hours (the last three per caller). A job is paced in chunks at your tier’s batch rate, so a large file takes minutes, not seconds. Submitting is limited like /drg/batch (10 a minute, 50 an hour without a higher tier); status, results, CSV and cancel allow 60 a minute and 1,500 an hour.

Job errors
StatusWhen
403no API key or approved sign-in
404no such job for this key or sign-in (finished jobs are kept 24 hours)
409you already have a job running, the queue is full, or the results are asked for before the job is done
422no rows, or more than 20,000

POST/drg/remit

Reconcile an X12 835 remittance against the claims it pays. Each remitted claim is matched to its 837 claim (CLP01 = CLM01), regrouped under the manual for its discharge date, priced at the hospital (outpatient claims under OPPS) and its payment explained: paid against expected, the variance, the CARC and RARC codes and the likely cause, sorted by recoverable dollars. Patient identifiers are removed from every file before it is read.

curl -X POST "$BASE/drg/remit" -H "Content-Type: application/json" -H "X-API-Key: $KEY" \
  -d '{"remit": "ISA*00*…~", "claims": [{"content": "ISA*00*…~", "filename": "claims.837"}], "perspective": "payer"}'
Request fields for POST /drg/remit
FieldMeaning
remitthe 835 text (required, up to 6 MB)
claimsup to 50 claim files, each {content, filename} (837I text, up to 6 MB each)
ccnprice every claim at this hospital instead of the CCN on each claim
perspectivepayer (recoverable = overpayments, the default) or provider (underpayments)

Every matched claim that is priced counts as one priced claim of your day, charged up front, and a call prices at most as many claims as your tier’s batch row limit above. It is rate-limited like /drg/batch. 422: no 835 text, a file that cannot be read, or more priceable claims than your row limit; 429: the day’s priced claims are spent.

POST/screen

Provider screening: compare a claim’s provider NPIs with the OIG List of Excluded Individuals/Entities (LEIE), the file OIG publishes each month. A hit is reported as matches an LEIE entry, with the list’s date and the entry as published, never as a finding that a provider is excluded: OIG says a match must be confirmed in its online search (exclusions.oig.hhs.gov) with the person’s SSN or the entity’s EIN. Screening changes no price, receipt or export amount, and it is not a payment determination.

curl -X POST "$BASE/screen" -H "Content-Type: application/json" -H "X-API-Key: $KEY" \
  -d '{"claims": [{"claimRef": "TEST-1", "serviceFrom": "2026-07-10", "serviceThrough": "2026-07-16", "providerState": "TX",
       "providers": [{"role": "rendering", "npi": "1234567893", "last": "ZZTESTPERSON", "first": "ALPHA"}]}]}'
# 200 {"results": [{"claimRef": "TEST-1", "screening": {"status": "noMatch", "lists": [...], "screened": [...], "flags": [], ...}}],
#      "lists": [{"list": "LEIE", "asOf": "2026-10-09", "fileLabel": "09-2026", ...}]}
Request fields for POST /screen
FieldMeaning
claimsthe claims to screen: exactly 1 without an API key or approved sign-in; with one, up to your tier’s batch row limit
claimRefyour own reference, up to 40 characters, returned as given
serviceFrom, serviceThroughthe claim’s service dates (ISO); an entry is compared with them, or with today’s date when there are none
providerStatethe provider’s 2-letter state; name checks need one
providersup to 24, each {role, npi, last, first, middle, org}. npi (10 digits) is required on every provider; role is one of billing, attending, operating, otherOperating, rendering, referring, primaryCare, ordering, supervising, purchasedService, serviceFacility, other

Limits. Without a key a call screens one claim and spends one of the day’s free lookups; more than one claim without a key or approved sign-in is a 401. Names are compared only when a call holds one claim, and only on providers that carry an NPI: a bulk call ignores names and says so in notes. There is no name search. A provider without an NPI, an unknown role or a malformed date is a 422. Screening never spends a priced claim. Inputs and results are not stored or logged.

The screening block. status is flags, noMatch, unavailable (the list could not be loaded: never read it as a no match) or notRun. lists names the LEIE file screened against (asOf, fileLabel, daysOld, stale past 45 days). screened lists each provider with npiResult (match, noMatch, notScreened with a reason) and nameResult. Each of flags carries code (LEIE_NPI, LEIE_REIN, LEIE_AFTER, LEIE_NAME, LEIE_NAME_REIN), severity (check, possible, info), basis, the roles and lines, the entry as published (name, state, general and specialty, exclusion authority and date, waiver), the service dates compared, and an evidence line for a case note. It never holds a birth date or address. notChecked says what was not screened: SAM.gov exclusions, state Medicaid exclusion lists, Medicare enrollment, and ordering and referring eligibility.

Elsewhere. POST /drg/import returns the same block as screening (a keyless call with andGroup: false gets status: notRun). POST /drg/batch/x12 returns rowScreening, one block per row in rows, and screeningLists. POST /drg/worksheet takes an optional providers list of "role:npi" strings (up to 6) and providerState, and adds a Provider screening section to the worksheet; without them the worksheet is unchanged. GET /meta reports the list on hand as screening.leie (asOf, fileLabel, rows, status, daysOld).

Arranging or contracting with an excluded person can bring civil money penalties (42 CFR 1003.200(b)(4)). OIG recommends screening monthly.

Claim fields go in the body

Every pricing endpoint takes its fields as one JSON object in a POST body: /drg/calculate, /drg/verify, /drg/worksheet, and the outpatient, post-acute and state Medicaid pricing routes. The field names and limits are the route’s own parameters, listed on this page for each route, and a field may hold a list where a route repeats a parameter. A query string is written to every access log between you and us, and charges and dates of service tied to a hospital are claim content.

Deprecated: the same routes still answer GET with the fields as query parameters, with the same results, rate limits and daily caps, and mark the reply with a Deprecation: true header. Move to POST: the GET form will be retired. Lookups (/drg/search, /drg/codes, hospital search) stay GET.

Outpatient, post-acute and Medicaid

These routes take their fields as one JSON object in a POST body (the field names below), and answer the deprecated GET with the same fields as query parameters.

Outpatient, post-acute and state Medicaid pricing routes
RouteFields
/outpatient/comparehcpcs; ccn or wageIndex (0.1 to 3.0); serviceDate (YYYY-MM-DD). Hospital outpatient (APC) and ASC rates side by side
/outpatient/apgMedicaid EAPG line pricing
POST /outpatient/ocean outpatient claim’s HCPCS lines through the OCE and NCCI edits (packaging, MUE units, PTP pairs)
/ltch/calculatedrgCode; wageIndex (default 1.0); lengthOfStay (0 to 730)
/irf/calculatecmg; tier; wageIndex; rural; or ccn with dischargeDate to price on the facility’s record; charges
/ipf/calculate · /hospice/calculate · /snf/calculate · /hh/calculate · /esrd/calculatethe inpatient psychiatric, hospice, SNF, home health and dialysis pricers
POST /snf/claima SNF claim by its bill type: 21x as the PDPM per diem from each 0022 line’s HIPPS code and covered days
/nymedicaid/priceaprDrg; severity (1 to 4); opcert (NY operating certificate, TX TPI, CO CCN or VA NPI); state (NY, TX, CO, VA or WA); alcDays; drugs
/mdmedicaid/pricehospital; lines as CENTER:units pairs, for example MSG:4,OR:120; payer (ffs or mco)
POST /mdmedicaid/batchup to 1,000 Maryland claims a call (25 without a key or sign-in), each {claimId, hospital, lines: [{center, units}]}
/vamedicaid/eapg/price · fee/rate · nf/price · hospice/price · homehealth/price · transplant/priceVirginia Medicaid outpatient EAPG, fee schedules, nursing facility, hospice, home health and transplant rates
curl -X POST "$BASE/outpatient/compare" -H "Content-Type: application/json" -H "X-API-Key: $KEY" \
  -d '{"hcpcs": "45385", "ccn": "330101"}'
curl -X POST "$BASE/nymedicaid/price" -H "Content-Type: application/json" -H "X-API-Key: $KEY" \
  -d '{"aprDrg": "720", "severity": 3, "opcert": "…", "state": "NY"}'

Without a key, priced calls on these routes count against a daily allowance of their own, separate from the inpatient one, and lookups against another; an API key or an approved account lifts both. They are rate-limited per endpoint like the routes above. 400 or 422: a field outside its range or a code the tables do not hold, with the reason in detail; 429: a limit or the day’s allowance is spent; 503: that pricer’s tables are not loaded.

Lookups

Lookup endpoints and what each returns
EndpointWhat it returns
GET /drg/search?q=sepsisMS-DRGs by code or title (code, title, MDC, type, weight)
GET /drg/codes?q=J96&kind=dxICD-10-CM / PCS codes with descriptions and CC/MCC severity (kind=dx|proc)
GET /drg/hospitals/search?q=houstonIPPS hospitals by name, or filter by state/city/zip
GET /drg/hospitals/{ccn}one hospital's profile (name, location, wage index, CMI, teaching)
GET /drg/grouper-versionsloaded MS-DRG manual versions; isDefault marks the one in force today

Search endpoints require ≥2 characters and cap at 25 rows per response.

Errors

Error status codes and what they mean
StatusMeaning
400 / 404bad filter, or unknown DRG / CCN — {"detail": "…"} says which
422claim couldn't be grouped, or invalid body — the detail carries the grouper's reason
401 / 403no valid X-API-Key (403 for a script client such as curl)
429rate limit hit; back off and retry after a minute, or after the Retry-After seconds when sent
502 / 503an upstream dependency (official pricer, registry) is unavailable — retry later

Estimates, not adjudication. Results are payment estimates from published factors — final payment is determined by the payer at claim adjudication. Grouping notes its approximations in the caveats field of every response.

© 2026 PayerParity · info@payerparity.com · Request an API key