Projects

API reference

All public URLs are compatible with decomp.dev's. The examples use the public instance, bytematch.dev; {owner} and {repo} are the GitHub owner and repository name.

URLReturns
/{owner}/{repo}Project page (HTML)
/{owner}/{repo}/{version}Project page for one version (HTML)
/{owner}/{repo}.jsonProject JSON
/{owner}/{repo}/{version}.jsonProject JSON for one version
/{owner}/{repo}.svgSVG badge
/{owner}/{repo}.pngPNG badge
GET /api/v1/projectsList of projects
POST /api/v1/projects/{owner}/{repo}/reportsUpload a report
GET /healthzHealth check

Project pages

/{owner}/{repo} shows the default version; /{owner}/{repo}/{version} shows one version. The page shows the measures, categories, a history chart, the list of units with their functions, and recent commits.

Project JSON

GET /{owner}/{repo}.json
GET /{owner}/{repo}/{version}.json

Query parameters:

ParameterMeaning
versionGame version. Defaults to the project's default version.
categoryReport category id. Defaults to the project's default category.
modeOutput format: omit for the project object, or shield, history, report, measures.

Default: the project object

curl https://bytematch.dev/OpenRAC/rac1-decomp.json
{
  "id": 1,
  "owner": "OpenRAC",
  "repo": "rac1-decomp",
  "repo_url": "https://github.com/OpenRAC/rac1-decomp",
  "name": "Ratchet & Clank",
  "short_name": "RAC1",
  "platform": "ps2",
  "default_version": "SCES_509.16",
  "default_category": "all",
  "commit": {
    "sha": "3f1c...",
    "message": "Match some functions",
    "timestamp": "2026-10-01T12:34:56Z"
  },
  "measures": {
    "fuzzy_match_percent": 91.2,
    "total_code": 3710000,
    "matched_code": 3191000,
    "matched_code_percent": 86.02,
    "total_data": 1200000,
    "matched_data": 900000,
    "matched_data_percent": 75.0,
    "total_functions": 5109,
    "matched_functions": 4520,
    "matched_functions_percent": 88.47,
    "complete_code": 3000000,
    "complete_code_percent": 80.86,
    "complete_data": 850000,
    "complete_data_percent": 70.83,
    "total_units": 400,
    "complete_units": 310
  },
  "report_versions": ["SCES_509.16"],
  "report_categories": [{ "id": "game", "name": "Game", "measures": { "...": "same 16 fields" } }]
}

The values above are illustrative. measures always contains the 16 objdiff measures shown.

mode=shield

A shields.io endpoint response.

curl "https://bytematch.dev/OpenRAC/rac1-decomp.json?mode=shield&label=Code&measure=matched_code_percent"
{ "schemaVersion": 1, "label": "Code", "message": "86.02%", "color": "informational" }

It accepts the same measure and label parameters as badges.

mode=history

Measures for every recorded commit of the version.

[
  {
    "timestamp": "2026-10-01T12:34:56Z",
    "commit_sha": "3f1c...",
    "commit_message": "Match some functions",
    "measures": { "...": "16 fields" }
  }
]

mode=report

The full objdiff report of the latest commit, as JSON (objdiff's report.json format).

mode=measures

Only the measures object.

Badges

GET /{owner}/{repo}.svg
GET /{owner}/{repo}.png

ByteMatch renders badges itself; there is no shields.io dependency.

ParameterDefaultMeaning
measurematched_code_percentWhich measure to show. See the table below.
labelproject name, or the category name when category is setLeft-hand text.
colorinformational (#007ec6)Right-hand color: a shields.io name (brightgreen, informational, ...) or hex.
labelColor#555Left-hand color, same formats. label_color also works.
styleflatflat, flat-square, plastic, for-the-badge.
categoryproject defaultReport category id.
versionproject defaultGame version.
modeshieldAccepted for compatibility with decomp.dev badge URLs.

Measures:

measureShown as
fuzzy_match_percent91.20%
matched_code, matched_code_percent86.02%
matched_data, matched_data_percentpercentage
complete_code, complete_code_percentpercentage
complete_data, complete_data_percentpercentage
matched_functions_percentpercentage
matched_functions4,520 / 5,109
complete_units310 / 400

Byte measures (matched_code, matched_data, complete_code, complete_data) show the corresponding percentage, not a byte count.

Style spellings decomp.dev accepted also work: FlatSquare, ForTheBadge, and Social (rendered as flat).

Examples:

![Code](https://bytematch.dev/OpenRAC/rac1-decomp.svg?mode=shield&label=Code&measure=matched_code_percent)
![Functions](https://bytematch.dev/OpenRAC/rac1-decomp.svg?label=Functions&measure=matched_functions&style=for-the-badge)
![Game](https://bytematch.dev/OpenRAC/rac1-decomp.png?category=game&measure=matched_code_percent&color=brightgreen)

Project list

GET /api/v1/projects

Lists the projects on the instance, each with its default version's latest measures.

Each entry has owner, repo, name, short_name, platform, url, icon_url, cover_url, version (the default version), timestamp (its latest commit), gain_30d (matched-code percentage points gained over the last 30 days) and measures.

Query parameters, the same as the project list page:

ParameterMeaning
qSearch words; every word must appear in the name or owner/repo.
platformPlatform id, e.g. ps2.
sortupdated (default), progress, functions, gain, size, newest or name.
pagePage number, from 1.
per_pageResults per page: default 100, at most 500.

Paging is reported in the X-Total-Count and X-Total-Pages headers and a Link header with first, last, prev and next.

Upload API

POST /api/v1/projects/{owner}/{repo}/reports

For projects that are not on GitHub or whose CI is private. Most GitHub projects do not need it; see Getting started.

Authentication. Authorization: Bearer bm_..., using a per-project token created on the project's manage page. The token is shown once; only its hash is stored. Revoke it on the same page.

Query parameters:

ParameterRequiredMeaning
versionyes, unless the project splits versionsGame version this report is for.
commityesCommit SHA.
commit_messagenoCommit message.
commit_timestampnoISO-8601 time of the commit. Defaults to now.

Body. The raw report: objdiff JSON or binary protobuf. It may be gzip-compressed if sent with Content-Encoding: gzip. Reports larger than the instance's MAX_REPORT_BYTES (256 MiB by default) are rejected.

Response. JSON listing the versions stored and the project page:

{ "stored": ["GALE01"], "url": "https://bytematch.dev/<owner>/<repo>" }

For a split-versions project, stored lists every version found in the report.

curl

curl --fail -X POST \
  -H "Authorization: Bearer $BYTEMATCH_TOKEN" \
  --data-binary @build/GALE01/report.json \
  "https://bytematch.dev/api/v1/projects/<owner>/<repo>/reports?version=GALE01&commit=$GITHUB_SHA"

Compressed:

gzip -c build/GALE01/report.json | curl --fail -X POST \
  -H "Authorization: Bearer $BYTEMATCH_TOKEN" \
  -H "Content-Encoding: gzip" \
  --data-binary @- \
  "https://bytematch.dev/api/v1/projects/<owner>/<repo>/reports?version=GALE01&commit=$GITHUB_SHA"

GitHub Actions step

Store the token as a repository secret named BYTEMATCH_TOKEN:

- name: Upload progress to ByteMatch
  if: github.event_name == 'push' && github.ref == 'refs/heads/main'
  env:
    BYTEMATCH_TOKEN: ${{ secrets.BYTEMATCH_TOKEN }}
  run: |
    curl --fail -X POST \
      -H "Authorization: Bearer $BYTEMATCH_TOKEN" \
      --data-binary @build/GALE01/report.json \
      "https://bytematch.dev/api/v1/projects/${{ github.repository }}/reports?version=GALE01&commit=$GITHUB_SHA"

To record the commit message, URL-encode it into the query string, for example with jq:

MSG=$(printf %s "$(git log -1 --format=%s)" | jq -sRr @uri)
curl --fail -X POST \
  -H "Authorization: Bearer $BYTEMATCH_TOKEN" \
  --data-binary @build/GALE01/report.json \
  "https://bytematch.dev/api/v1/projects/<owner>/<repo>/reports?version=GALE01&commit=$GITHUB_SHA&commit_message=$MSG"

Health check

GET /healthz

For load balancers and uptime monitors.

Next
Self-hosting