The HLA Matching API: immunogenetr’s matching as a web service

A free, public, versioned web service for HLA matching and mismatching, built on immunogenetr and py-ard, and a one-page HCT donor match report built on top of it as an example.
HLA Matching API
immunogenetr
R
HLA
Author

Nicholas K. Brown

Published

October 23, 2026

Every HLA laboratory counts mismatches, and every laboratory information system, spreadsheet, and in-house script that does so has to decide on how (often without realizing they are making decisions): Does a homozygous mismatch count once or twice? Which direction (HvG, GvH, or both) is being considered? How do null alleles count as mismatches (and matches)? Is DRB1*14:54 a mismatch for DRB1*14:01, or, since they have the same antigen recognition domain (ARD), are they considered matched? Each is a small decision, but each may be implemented differently wherever matching or mismatching is done. The immunogenetr package (Coskun and Brown, 2026) provides a framework for performing matching and mismatching reproducibly. However, an R package only helps people who use R. This post introduces the HLA Matching API, at https://api.immunogenetr.org, which puts immunogenetr’s matching engine behind a web service. I also demonstrate how this can work in practice with a one-page HCT donor match report (https://hct-report.immunogenetr.org).

What the API does

The API takes a recipient and a donor genotype, written as GL Strings, and returns per-locus matching or mismatching, or HCT match grades (X of 8 at A, B, C, and DRB1, or X of 10 with DQB1 added). Comparisons can be made host versus graft (HvG), graft versus host (GvH), or in both directions (bidirectional), as each endpoint allows; the mismatch endpoints also accept SOT, for solid organ transplant, which is the HvG calculation under an easy-to-remember name. A homozygous mismatch counts as 2 by default or as 1 on request.

For HCT, matching commonly must consider one more thing: how to handle alleles that are identical at the ARD. For that reason, the API can first reduce both genotypes with py-ard, NMDP’s reduction library. P groups are the default, and G groups, lg, lgx, W, exon, U2, S, and 1F are also available; a separate /preprocess endpoint reduces a GL String on its own. There is nothing to install, no login, and no account, so anything that can send an HTTP request can use the service. The interactive documentation lists every endpoint with its parameters and lets you try requests in the browser.

Calling it

From the command line, a mismatch count is one request:

curl -X POST https://api.immunogenetr.org/mismatch/number \
  -H 'Content-Type: application/json' \
  -d '{"gl_string_recip": "HLA-A*01:01+HLA-A*02:01^HLA-B*07:02+HLA-B*08:01",
       "gl_string_donor": "HLA-A*01:01+HLA-A*03:01^HLA-B*07:02+HLA-B*08:01",
       "loci": ["HLA-A", "HLA-B"], "direction": "GvH"}'

The answer, {"by_locus": {"HLA-A": 1, "HLA-B": 0}, "total": 1, "direction": "GvH", ...}, gives the count per locus and in total. From R, there is a ready-made client: a single file of functions, released under the MIT license in the API’s public repository, which needs only httr2. The API’s own load test uses it, so it is known to work, although writing your own is equally possible.

source("https://raw.githubusercontent.com/k96nb01/matching-api-issues/main/client/matching_api_client.R")

recipient <- "HLA-A*01:01+HLA-A*02:01^HLA-B*07:02+HLA-B*08:01^HLA-C*07:01+HLA-C*07:02^HLA-DRB1*03:01+HLA-DRB1*15:01^HLA-DQB1*02:01+HLA-DQB1*06:02"
donor     <- "HLA-A*01:01+HLA-A*02:01^HLA-B*07:02+HLA-B*08:01^HLA-C*07:01+HLA-C*07:02^HLA-DRB1*03:01+HLA-DRB1*15:01^HLA-DQB1*02:01+HLA-DQB1*06:03"

grade <- mapi_match_hct(recipient, donor, match_grade = "Xof10", preprocess = TRUE)
grade$match_summary
[1] 9

The pair is 9 of 10, since it differs only at DQB1, where HLA-DQB1*06:02 and HLA-DQB1*06:03 fall in different P groups. Of note, the response carries more than the number. It also returns the reduced GL Strings that were actually compared and the versions that produced the answer, so a result can be checked after the fact.

grade[c("redux_mode", "ipd_imgt_hla_version", "py_ard_version")]
$redux_mode
[1] "P"

$ipd_imgt_hla_version
[1] "3660"

$py_ard_version
[1] "2.4.2"

Many pairs at once

For a cohort, the batch endpoints are the right tool. Every endpoint has a batch twin under /batch/ that takes up to 1,000 pairs per request, and a pair that fails reports its own error without failing the rest of the batch. The R client’s batch functions take vectors of any length, send them in chunks, and return one data frame row per pair.

cohort <- data.frame(
  recip_gl = c("HLA-A*01:01+HLA-A*02:01^HLA-B*07:02+HLA-B*08:01",
               "HLA-A*02:01^HLA-B*07:02+HLA-B*44:02"),
  donor_gl = c("HLA-A*01:01+HLA-A*03:01^HLA-B*07:02+HLA-B*08:01",
               "HLA-A*02:01+HLA-A*24:02^HLA-B*07:02+HLA-B*44:03")
)

mapi_batch_mismatch_number(
  recip = cohort$recip_gl, donor = cohort$donor_gl,
  loci = c("HLA-A", "HLA-B"), direction = "GvH"
) |>
  subset(select = c(row, `HLA-A`, `HLA-B`, total))
  row HLA-A HLA-B total
1   1     1     0     1
2   2     0     1     1

In testing, 27,000 pairs went through in 28 sequential requests, at about 2 to 3 seconds per 1,000-pair request. Importantly, the server sits behind a web application firewall that answers sustained high-rate traffic with a bot challenge, an HTML page that no API client can pass. Sending requests one at a time rather than in parallel, and using the batch endpoints for anything more than a handful of pairs, keeps clear of it. The R client raises an error if it is ever challenged, and the repository README has the details.

The same answer next quarter

A match result depends on three moving parts: the IPD-IMGT/HLA Database release, the immunogenetr matching engine, and the py-ard reducer. The /health endpoint reports all three, alongside the API’s own version.

mapi_health()[c("api_version", "immunogenetr_version", "ipd_imgt_hla_version", "py_ard_version")]
$api_version
[1] "1.3.0"

$immunogenetr_version
[1] "1.5.0"

$ipd_imgt_hla_version
[1] "3660"

$py_ard_version
[1] "2.4.2"

Versions are pinned per release and updated each quarter with the IPD-IMGT/HLA releases. Consequently, the same input gives the same answer until the next deliberate update, and it is always possible to say which versions produced a given result.

An example built on it: the HCT donor match report

To show what can be built on the API, I wrote a small app, hct-report.immunogenetr.org. Given a recipient’s and a donor’s high-resolution typing, it returns a one-page PDF match report.

A one-page HCT donor match report. A typing table shows recipient and donor alleles at A, B, C, DRB1, DQA1, DQB1, DPA1, and DPB1, with a Mismatches row showing 1 at B, 1 at DPA1, and NP at DPB1. The match grade at the P group level is 9/10 and 7/8. Below are the P group genotypes that were matched, comments, and a footer listing every software and database version used.

A report for one of the app’s built-in synthetic example pairs; no real person’s typing.

The report gives the mismatch count at A, B, C, DRB1, DQA1, DQB1, and DPA1 after both typings are reduced to P groups, and the X/10 and X/8 grades at the P group level, in whichever direction is chosen. DPB1 permissiveness comes from the IPD-IMGT/HLA DPB1 T-cell epitope service and is shown as P (permissive) or NP (non-permissive). The genotypes that were actually matched are printed as GL Strings, so the input to the matching is always visible, and the comments call out every locus where P group reduction changed the match grade. In the example above, HLA-DRB1*14:01 and HLA-DRB1*14:54 differ by name but share a P group, so the pair is 9/10 at the P group level and 7/10 by two-field allele name. A footer records every software and database version behind the result.

Notably, the app does no matching of its own. Every count and grade on the report comes from the matching API, in up to 21 calls per report, including the two-field comparison used in the comments. The app’s source is on GitHub under the MIT license, so a laboratory that wants a report in a different shape has a reasonable starting point. Only typing leaves the browser: the report has no field for a name or any other identifier.

Who it is for

Researchers come first: anyone who needs consistent mismatch counts across a cohort without writing the matching logic again. The larger goal, however, is laboratory information systems. If LIS vendors build the API into their products, HLA laboratories get well-defined, versioned matching calculations without each vendor implementing them separately, and each laboratory validates the result in its own setting. If you develop laboratory software and would like to discuss that, please get in touch.

The API and the report are for research use only, and any clinical application requires independent validation according to local regulations. The service is hosted by the Perelman School of Medicine at the University of Pennsylvania.

Take-homes

  1. The API is at https://api.immunogenetr.org, free, with no login. Start with the interactive documentation.
  2. From R, source() the client from the public repository, and use the mapi_batch_*() functions for anything more than a few pairs, one request at a time.
  3. Results are versioned: /health reports the IPD-IMGT/HLA, immunogenetr, and py-ard versions behind every answer.
  4. For a ready-made HCT report, try hct-report.immunogenetr.org, or adapt its source.

Questions, bug reports, and feature requests are welcome in the API’s issue tracker. If you publish results that rely on the API, please cite the IPD-IMGT/HLA database, Barker DJ, et al. The IPD-IMGT/HLA Database: recent developments in sequence submission. Nucleic Acids Res. 2026;54(D1):D1152-D1158, and the engine, Coskun and Brown, 2026.