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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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.
| Methods | Path | Who | What |
|---|---|---|---|
| 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 |