Reference

The Matrix API

One API behind the site, the command line and the MCP server, at https://matrix.pratimana.com/api. 141 routes, listed here from the API's own routing table.

Conventions

Every route lives under https://matrix.pratimana.com/api, takes and returns JSON, and — unless marked Anyone — wants Authorization: Bearer <access token>. An access token lasts fifteen minutes; POST /api/tokens with the refresh token answers a fresh pair and retires the old refresh token. The command line does this for you; a page does it through assets/api.js.

Resources are plural nouns and the verbs carry the action: GET reads, POST creates, PATCH changes fields, PUT sets a whole value, DELETE removes. A change of state is a field, not a verb — a program is archived with PATCH /api/programs/{slug} {"status": "archived"}, an invitation is answered with PATCH /api/me/invitations/{id} {"status": "accepted"}, an upload is announced with PATCH /api/attachments/{id} {"uploaded": true}.

Lists answer {"results": [...], "count": n} and page with ?limit= and ?offset= (twenty rows by default). An error answers {"detail": "why"}, or the offending fields by name. A missing credential is 401; a refused one is 403; anything outside the caller's scope — another organization's members, a report they cannot read — is 404, deliberately, so the API does not confirm what exists.

Placeholders are ids unless named otherwise: {id} is a UUID, {slug} a program's slug, {organization_id} the caller's own organization from GET /api/me.

Sessions and tokens

A browser opens a session from its Pratimāna sign-in cookie; a terminal asks for a device code and has it approved in the browser. Both end with a token pair: an access token for the next fifteen minutes and a refresh token that mints the next pair and is spent in the process.

MethodsPathWhoWhat
POST /api/device-codes Anyone Start a terminal sign-in: a device code, and the user code to approve it with in the browser.
GETPATCH /api/device-codes/{user_code} Anyone signed in GET what a terminal is asking for; PATCH {"status": "approved" | "denied"} answers it.
POST /api/sessions Anyone Open a session from the Pratimāna sign-in cookie: a Matrix token pair.
DELETE /api/sessions/current Anyone Revoke the refresh token: the session on this device ends.
POST /api/tokens Anyone A new token pair, from a refresh token or an approved device code.

The account

Whoever holds the token. GET /api/me is the first call every client makes: it names the person, their platform tier, whether someone is viewing as them, and the organization they sit in — whose id names the organization routes below.

MethodsPathWhoWhat
GETPATCHDELETE /api/me Anyone signed in The account behind the token: GET it with its tier, viewing-as state and organization; PATCH the profile; DELETE it with {"confirm": <email>}.
GET /api/me/balance Researchers A researcher's own balance and history.
GET /api/me/dashboard Researchers The researcher's own dashboard: figures, standing, activity, bulletins.
GET /api/me/disclosure-requests Anyone signed in The requests this researcher made.
GET /api/me/invitations Anyone signed in A researcher's own private-program invitations (?status=).
PATCH /api/me/invitations/{id} Anyone signed in Answer an invitation: {"status": "accepted" | "declined"}.
GETPATCH /api/me/notifications Anyone signed in What happened, addressed to this account.
PATCHDELETE /api/me/notifications/{id} Anyone signed in PATCH {"read": true} marks one read;
GET /api/me/programs Anyone signed in Every program the caller may work on, paused ones included — the
GETPOST /api/me/publications Anyone signed in Everything the caller may edit, drafts included — the editor's list.
GET /api/me/rail Anyone signed in The side rail's summary figures and waiting counts
GETPOST /api/me/withdrawals Researchers GET the researcher's withdrawals; POST asks for one (Idempotency-Key honoured).
DELETE /api/me/withdrawals/{id} Anyone signed in Cancel one of the researcher's own pending withdrawals.

Organizations

Everything that belongs to one organization, under its id. The id has to be the caller's own (from GET /api/me); another organization's id answers 404, so the segment is an address, never a way in.

MethodsPathWhoWhat
GET /api/organizations/{organization_id} The organization's members The caller's organization, their role in it, and the permissions
GET /api/organizations/{organization_id}/audit-events The organization's members The organization's audit trail, newest first; ?action= narrows.
GET /api/organizations/{organization_id}/disclosure-requests The organization's members The
GETPOST /api/organizations/{organization_id}/groups The organization's members Groups: named bundles of permissions over some or all of the organization's programs.
GETPUTPATCHDELETE /api/organizations/{organization_id}/groups/{id} The organization's members One group: read, edit, remove.
GETPOST /api/organizations/{organization_id}/members The organization's members GET the organization's seats; POST adds an existing organization account by email.
PATCHDELETE /api/organizations/{organization_id}/members/{id} The organization's members PATCH a seat's role or title; DELETE removes the seat.
PUT /api/organizations/{organization_id}/owner The organization's members Hand the organization to another member. The new owner becomes an
GET /api/organizations/{organization_id}/scope The organization's members Every scope asset across the organization's programs: the attack
GET /api/organizations/{organization_id}/sla-breaches The organization's members Open (unacknowledged) breaches across the organization, newest
PATCH /api/organizations/{organization_id}/sla-breaches/{id} The organization's members Acknowledge a response-time breach: {"acknowledged": true}.
GETPATCH /api/organizations/{organization_id}/sso The organization's members GET the settings; PATCH domains, the toggle, the default role, or
PUT /api/organizations/{organization_id}/sso/metadata The organization's members Import the identity provider's SAML metadata XML.
POST /api/organizations/{organization_id}/sso/scim-tokens The organization's members Rotate the SCIM bearer token. The plaintext is in this one response.
GET /api/organizations/{organization_id}/summary The organization's members The executive summary the command hub opens with.
GET /api/organizations/{organization_id}/wallet The organization's members The caller's organization wallet: balance, what is held in escrow,
POST /api/organizations/{organization_id}/wallet/deposits The organization's members Record money arriving. Admin or finance of the organization.
POST /api/organizations/{organization_id}/webhook-deliveries/{id}/attempts The organization's members Try a delivery again.
GETPOST /api/organizations/{organization_id}/webhooks The organization's members GET the organization's webhooks; POST registers one.
PATCHDELETE /api/organizations/{organization_id}/webhooks/{id} The organization's members Edit (url, events, active) or remove a webhook.
GET /api/organizations/{organization_id}/webhooks/{id}/deliveries The organization's members Recent deliveries of one webhook and how they went.
POST /api/organizations/{organization_id}/webhooks/{id}/tests The organization's members Queue a ping so the receiver can be checked end to end.

Programs

Bounty programs, public and private. Reading is open to anyone who can see the program; the sub-resources are the program team's. Archiving is an edit of status and is the organization owner's alone.

MethodsPathWhoWhat
GETPOST /api/programs Depends on the method GET the programs the caller may see (?search=, ?type=, ?asset=, ?sort=); POST creates one for the caller's organization.
GETPATCH /api/programs/{slug} Depends on the method GET one program with its scope, tiers and rules; PATCH edits it — {"status": "archived"} archives, the owner alone.
GETPOST /api/programs/{slug}/invitations The program's team Invitations to a private program, from the company side.
GET /api/programs/{slug}/policy-versions Anyone Every published policy text with its changelog note. Readable by
PUT /api/programs/{slug}/reward-tiers The program's team Replace the reward table in one write. There are at most four rows
GET /api/programs/{slug}/safe-harbor Anyone The terms in force for one program, and whether the caller has
POST /api/programs/{slug}/scope-assets The program's team Add an asset to the program's scope.
PATCHDELETE /api/programs/{slug}/scope-assets/{id} The program's team Edit or remove one scope asset.
GETPOST /api/programs/{slug}/scope-rules Anyone signed in GET: the program's scope rules, every one, resolved. POST: a new
PATCHDELETE /api/programs/{slug}/scope-rules/{id} Anyone signed in Edit (active, note) or remove one scope rule.
POST /api/programs/{slug}/simulations The program's team What a mix of findings would cost, from the program's reward tiers.
GET /api/programs/{slug}/thanks Anyone Security acknowledgments: the researchers a programme has resolved
GETPUT /api/programs/{slug}/vrt Anyone signed in GET: the taxonomy as this program applies it — every leaf with the
GET /api/programs/teasers Anyone Private programs that chose to be known about. Name, icon, one

Grid Radar

The directory of programs that are not on Matrix: bounty and disclosure programs hosted on HackerOne, Bugcrowd, Intigriti, YesWeHack, Immunefi or a company's own site, curated by Pratimāna's staff. Read-only, for any signed-in account: a visitor is asked to sign in first. A target is a record and a link out; it never takes a report — the curation routes sit under Platform administration.

MethodsPathWhoWhat
GET /api/radar Anyone signed in The Grid Radar directory: every active target, filtered and sorted.
GET /api/radar/{slug} Anyone signed in One target's record card, by slug, for any signed-in account. A deactivated target is 404.

Reports

A researcher's findings and what the program does with them. A draft is the researcher's alone until it is sent — POST /api/reports with {"draft": id}. Attachments are uploaded straight to storage against a signed grant and announced when the upload is done.

MethodsPathWhoWhat
GETPOST /api/attachments Researchers Step one: a signed URL for one file.
GETPATCHDELETE /api/attachments/{id} Anyone signed in GET an attachment's status; PATCH {"uploaded": true} announces the upload; DELETE removes it.
GET /api/attachments/{id}/download Anyone signed in A five-minute signed URL for a clean file, to someone who may read
GETPOST /api/drafts Researchers A researcher's unsent reports. Theirs alone: no programme, and no
GETPATCHDELETE /api/drafts/{id} Researchers One draft: read, edit, discard.
GET /api/drafts/{id}/collaboration Researchers Everything about the people on one draft.
POST /api/drafts/{id}/collaborators Researchers
PATCHDELETE /api/drafts/{id}/collaborators/{cid} Researchers
POST /api/drafts/{id}/comments Researchers
POST /api/drafts/{id}/comments/{cid}/resolve Researchers
POST /api/drafts/{id}/presence Researchers The composer's heartbeat, answered with the same state.
POST /api/drafts/{id}/suggestions Researchers
POST /api/drafts/{id}/suggestions/{sid}/{decision} Researchers
GET /api/drafts/shared Researchers Drafts other researchers have shared with the caller.
GETPOST /api/reports Depends on the method GET the reports in the caller's scope (?program=, ?status=, ?bucket=, ?assigned=, ?open=true, ?sla=open, ?disclosure=, ?search=); POST submits one, or sends a draft ({"draft": id}).
GETPATCH /api/reports/{id} Anyone signed in GET one report as the caller may see it; PATCH is the reporter revising it while it is still theirs.
PATCH /api/reports/{id}/assessment Anyone signed in The programme's assessment of a report: severity (by level or by a CVSS vector the server scores), the asset and weakness, and the internal severity and notes the reporter never sees.
PUT /api/reports/{id}/assignee Anyone signed in Set or clear the report's assignee.
GETPOST /api/reports/{id}/comments Anyone signed in The conversation on one report.
PATCH /api/reports/{id}/content Anyone signed in The programme editing the report's text: the title and the five
GET /api/reports/{id}/desk Anyone signed in The triage desk's facts around one report: the queue either side
PUT /api/reports/{id}/disclosure Anyone signed in Ask to publish a resolved report, or agree to the other side's ask.
POST /api/reports/{id}/disputes Researchers The reporter challenging a rejection.
GETPOST /api/reports/{id}/publications Anyone signed in Drafting an advisory or a writeup from a report.
GETPOSTDELETE /api/reports/{id}/redactions Anyone signed in The spans a program has masked for the public copy of a report.
GET /api/reports/{id}/similar Anyone signed in Candidates for "is this a duplicate", ranked for the triager.
PATCH /api/reports/{id}/triage Anyone signed in Move a report through triage: status, severity, bounty, note.
GET /api/reports/similar Anyone signed in Reports resembling one that is still being written, for the wizard.

Advisories and writeups

What the two sides write about a finding once it is public: the organization's advisory and the researcher's writeup. Reading is open to anyone. A piece drafted against a disclosed report is numbered PMA-2026-0042 or PMW-2026-0012 and is addressed under whoever published it — /acme/advisories/PMA-2026-0042, /@alex/writeups/PMW-2026-0012-oauth-takeover. Writing one is the author's alone: an advisory the program's, a writeup the reporter's, subject to the embargo the two agreed at disclosure.

MethodsPathWhoWhat
GET /api/advisories Anyone Published advisories or writeups.
GET /api/advisories/{space}/{ref} Anyone One published piece, addressed the way its URL addresses it.
GET /api/advisories/facets Anyone What the archive's dropdowns may offer, with counts.
GET /api/disclosure-requests/{id} Anyone signed in One request by its own id — what the inbox and a notification link to.
PUT /api/disclosure-requests/{id}/decision Anyone signed in PUT {"decision": "approve"|"decline", "agreed_publish_at"?, "note"?}
POST /api/disclosure-requests/{id}/notes Anyone signed in POST {"kind": "comment"|"change_request", "body"} — a word on the
POST /api/disclosure-requests/{id}/resubmit Anyone signed in POST {"message"?} — after the changes, the request asks about the new text.
GET /api/publications Anyone Published advisories or writeups.
GETPUTPATCHDELETE /api/publications/{id} Anyone signed in One piece, as its author works on it.
GETPOSTDELETE /api/publications/{id}/disclosure-request Anyone signed in A researcher's request to publish a writeup about a private report.
GETPOST /api/votes Anyone signed in A signed-in reader's word on a public thing.
GET /api/writeups Anyone Published advisories or writeups.
GET /api/writeups/{space}/{ref} Anyone One published piece, addressed the way its URL addresses it.
GET /api/writeups/facets Anyone What the archive's dropdowns may offer, with counts.

Public and reference data

What a visitor sees without signing in: disclosed reports, the activity feed, the standings, a researcher's profile, the blog, the vulnerability taxonomy, CVSS scoring and the platform's safe-harbor terms.

MethodsPathWhoWhat
GET /api/activity Anyone OffGrid: what happened to reports on public programmes, newest first,
GET /api/cvss Anyone GET the score and band of a CVSS vector (?vector=CVSS:3.1/… or CVSS:4.0/…).
GET /api/disclosures Anyone Disclosed reports, newest first, narrowed by the archive's filters.
GET /api/disclosures/{id} Anyone One disclosed report, in full, with the program's redactions applied.
GET /api/disclosures/facets Anyone What the archive's filters can usefully offer: the programs and the
GET /api/leaderboard Anyone The global standings (?window=, ?category=, ?program_type=, ?country=, ?handle=, ?limit=, ?offset=).
GET /api/posts Anyone Published posts, for the blog and the dashboard bulletins.
GET /api/posts/{slug} Anyone One published post, by slug.
GET /api/researchers/{handle} Anyone A researcher's public profile and standing.
GETPUT /api/safe-harbor Depends on the method GET the platform's terms in force; PUT publishes a new version.
GET /api/safe-harbor/versions Platform staff Every published version of the platform's terms.
GET /api/stats Anyone signed in Figures for one program's dashboard (?program=).
GET /api/vrt Anyone The vulnerability taxonomy: categories, items and their priorities.

Platform administration

Pratimāna's own staff, in three tiers: a member reads, an admin acts, and a superadmin alone changes what an account is, deletes accounts, settles money and views as someone else.

MethodsPathWhoWhat
GET /api/admin/abuse Platform staff Three signals, none of them a verdict. Rejection rate over ninety
GET /api/admin/audit-events Platform staff The platform-wide record, including the rows no organization owns —
GET /api/admin/disputes Platform staff Disputes for platform staff to rule on (?status=).
PATCH /api/admin/disputes/{id} Platform staff Rule on a dispute: {"outcome": …, "note": …}.
POST /api/admin/impersonations Platform superadmins "View as": a short-lived token that authenticates as somebody else.
GET /api/admin/ledger Platform staff The books at a glance: what is held, what is owed, what is waiting.
PATCHDELETE /api/admin/memberships/{id} Platform staff Change or end one membership, under the same last-admin rule the
GET /api/admin/organizations Platform staff Every organization, for the membership picker. ?search= narrows by name.
GETPATCH /api/admin/organizations/{id} Platform staff One organization. PATCH {"slug"} changes the first segment of its
GET /api/admin/organizations/{id}/wallet Platform staff One organization's wallet, as the platform sees it.
POST /api/admin/organizations/{id}/wallet/deposits Platform staff Record a deposit into an organization's wallet.
GETPOST /api/admin/posts Platform staff Every post, drafts included. Platform staff only.
GETPATCHDELETE /api/admin/posts/{id} Platform staff One post: read, edit, publish or unpublish, remove.
GETPOST /api/admin/programs Platform staff Every program on the platform, with the numbers a platform operator actually wants; POST makes one for an organization, or for the person who will own it.
GETPOST /api/admin/radar Platform staff Every target, deactivated ones included. Platform staff read; a
GETPOST /api/admin/radar-syncs Platform staff Grid Radar's HackerOne sync runs: the recent ones, and a request for
GETPATCHDELETE /api/admin/radar/{slug} Platform staff One target: read, edit, verify or unverify, deactivate, remove.
GET /api/admin/stats Platform staff Platform-wide figures for the panel.
GETPOST /api/admin/users Platform staff Everyone on the platform, filterable by role, with their standing; POST adds a researcher account ahead of their first sign-in.
GETPATCHDELETE /api/admin/users/{id} Platform staff GET one account; PATCH its profile, or (superadmin) its role and standing; DELETE it.
POST /api/admin/users/{id}/memberships Platform staff Put a company account into an organization, with a role. The team
GET /api/admin/withdrawals Platform staff Every withdrawal request (?status=).
PATCHDELETE /api/admin/withdrawals/{id} Depends on the method PATCH {"status": "paid", "reference"} settles a withdrawal (superadmin); DELETE cancels it (platform admin).

Other services

Not for people. The accounts service asks about addresses and single sign-on with the shared internal token; the scanner pushes its verdicts with a Google OIDC token; the scheduler ticks the jobs; the load balancer reads the health check.

MethodsPathWhoWhat
GETDELETE /api/internal/accounts The accounts service (internal token) GET whether Matrix knows an address and as what; DELETE removes the Matrix side of an account.
GET /api/internal/downloads/{token} Holder of a signed download link What a bucket does for a signed GET, when the bucket is a folder.
POST /api/internal/jobs The scheduler (internal or OIDC token) Run the due scheduled jobs once: the scheduler's tick.
POST /api/internal/scan-results The scanner (OIDC token) Pub/Sub push from the scanner. Authenticated by the OIDC token the
GET /api/internal/sso The accounts service (internal token) The identity provider for an email domain, for the accounts service's SAML sign-in.
PUT /api/internal/uploads/{token} Holder of a signed upload grant What a bucket does for a signed PUT, when the bucket is a folder.
GET /healthz Anyone Up, and able to reach the database. A process that answers 200