`GET /v1/orgs/{org}/proposals`.
const url = 'https://api.updawg.net/v1/orgs/example/proposals';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://api.updawg.net/v1/orgs/example/proposalsNewest first, ?status= repeatable, keyset-paginated on ?after=.
No status means every status
Including one this build does not recognise. The temptation is to default an inbox to the open ones — and a default that hides rows is a default that makes a proposal somebody is waiting on invisible without saying so. The portal asks for what it wants to show; the API does not decide on its behalf.
⚠️ Why the query is a list of pairs and not a struct
Query<T> deserialises with serde_urlencoded, which cannot put a
repeated key into a Vec. ?status=open&status=snoozed against a
Vec<String> field does not collect two values — it fails, and it fails
with axum’s own plain-text 400, which carries no type for a portal to
branch on and is a different shape from every other refusal this API makes.
That is DAWG-246’s problem arriving by a second route.
Vec<(String, String)> is what serde_urlencoded does support, so the
pairs are read and interpreted here. It buys one more thing worth having:
an unknown parameter can be refused. ?staus=open silently returning
everything is the same failure as an unparseable status silently returning
everything, and both are a list that is quietly not what was asked for.
Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Organization slug.
Query Parameters
Section titled “Query Parameters”Repeatable. Omitted means every status, including one this build does not recognise — a default that hides rows hides the proposal somebody is waiting on.
The prp_… id of the last proposal on the previous page.
Responses
Section titled “Responses”A page, newest first.
object
Pass as ?after= for the next page. Absent at the end, so a client
stops rather than asking for a page it has been told is empty.
object
Something it fixes is on CISA’s Known Exploited Vulnerabilities list (DAWG-72). Shown beside the severity; it never raises it.
null means nothing in this proposal was rated, which is not the
same as harmless.
The #142 people say out loud.
Zero for anything final, whatever the counts say — see
[db::inbox::Summary::outstanding].
Distinct packages, not proposal_items rows.
A status this build does not recognise is passed through as stored rather than hidden or guessed at. A portal should render an unknown status as unknown — it means this API is older than the thing that wrote the row, which is a deployment fact worth seeing.
How many match the filter, not how many are in this page.
Examplegenerated
{ "next": "example", "proposals": [ { "approvals": 1, "auto_merge": true, "closed_at": "2026-04-15T12:00:00Z", "created_at": "2026-04-15T12:00:00Z", "hosts": 1, "id": "example", "kind": "example", "known_exploited": true, "max_severity": "example", "number": 1, "outstanding": 1, "packages": 1, "required": 1, "scheduled_for": "2026-04-15T12:00:00Z", "snoozed_until": "2026-04-15T12:00:00Z", "status": "example", "title": "example", "updated_at": "2026-04-15T12:00:00Z" } ], "total": 1}An unknown status, an unknown parameter, or a cursor naming nothing.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}No session.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}No such organization, or not yours.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}Over the organization’s request limit. Retry-After says when to try again; RateLimit-Limit is the burst.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}