Skip to main content

API: release tracking

Optional plugin. Enable per application in Settings → Plugins; every route below 404s while disabled. See Release tracking for how attribution works and — importantly — the real limitations of the code-host link before you rely on it.

Deploys — /?api=deploys

MethodPurpose
GET{data:[…], markers:[…]} — deploys newest-first, each with issue_count; markers is a lighter shape for chart overlays.
POSTRecord a deploy: {version, environment?, ref?, notes?, deployed_at?}. version+environment must be unique together. 201.
DELETERemove a deploy by id.
POST /?api=deploys
{"version":"v2.4.1","environment":"production","ref":"a1b2c3d","notes":"checkout fixes"}

Nothing calls this for you — there's no CI/CD integration. Add the curl call to your own deploy script if you want it populated automatically.

GET /?api=issue-releases&id={id}

Releases one issue has appeared in, grouped from its occurrences' release values:

{
"releases": [{"release": "v2.4.0", "occurrences": 3, "first_seen": "…", "last_seen": "…"}],
"first_release": "v2.3.0",
"last_release": "v2.4.0",
"source_link": "https://github.com/org/repo/blob/main/app/Services/Checkout.php#L42"
}

source_link is null unless release-settings has a repo_url_template configured. Read Release tracking before assuming this link is correct for your deploy layout.

GET{repo_url_template, default_ref, configured}. PUT {repo_url_template, default_ref} saves them.

Placeholders substituted into the template: {ref} (always default_ref, never the specific release's own recorded ref), {path} (the issue's source frame, only lightly trimmed — see the caveat above), {line}.

GitHub https://github.com/org/repo/blob/{ref}/{path}#L{line}
GitLab https://gitlab.com/org/repo/-/blob/{ref}/{path}#L{line}
Bitbucket https://bitbucket.org/org/repo/src/{ref}/{path}#lines-{line}

Source maps — /?api=source-maps

De-minifies browser stack traces from the capture SDKs by matching an uploaded Source Map v3 file against (release, file). Unlike ingest, this is a normal authenticated dashboard route, not guard-exempt — uploads come from CI or the dashboard, never the public ingest key.

MethodPurpose
GETList stored maps: release, file, size — never the content.
POSTUpload {release, file, map}. file may be a full URL; only its basename is kept. 201.
DELETERemove by id.
for map in dist/assets/*.js.map; do
curl -X POST "$LOG_LENS_URL/?api=source-maps&app=web" \
-H "X-Log-Lens-Token: $LOG_LENS_TOKEN" -H "Content-Type: application/json" \
-d "$(jq -c --arg r "$VERSION" --arg f "$(basename "${map%.map}")" --rawfile m "$map" \
-n '{release:$r, file:$f, map:$m}')"
done

A browser event with a matching release gets each frame resolved against the stored map at ingest time — the issue is stored with the original file/line/function, not the minified location. A frame with no matching map is left as-is.

  • Release tracking — the full mechanics, including the two real gaps in the code-host link.
  • HTTP ingest — the release field on a pushed event is how occurrences.release gets populated at all.