List a document's audits
Filter GET /v2/audits by documents or external_id to list the audits that cover one document, whether you know it by its document_id or by the external_id you gave it. Use the list to show a result next to the document in your own system, or to check whether a complete audit exists. Coding evaluations take a document_id filter on GET /v2/coding_evaluations instead. An audit carries only the ids of its documents, in documents[]; to fetch a document itself, use Retrieve a document.
Prerequisites
- An access token in
$BRELLIUM_ACCESS_TOKEN, cached and reused (Authenticate with OAuth2 client credentials). - A
document_id, for example any id indocuments[]on an audit. This page uses the sample audit's document0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b. - With a live key the response contains protected health information (PHI); a sandbox key returns sample audits.
Steps
List the audits that cover one document
documents is a query parameter of GET /v2/audits, so the response is a normal list page. It holds full audits, newest first, and has_more is true when more audits follow.
curl \
"https://api.brellium.com/v2/audits?documents=0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
--write-out "HTTP %{http_code}\n"
const params = new URLSearchParams({
documents: "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
});
const res = await fetch(`https://api.brellium.com/v2/audits?${params}`, {
headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
});
if (!res.ok)
throw new Error(
`HTTP ${res.status}: ${JSON.stringify((await res.json()).error)}`,
);
console.log(`HTTP ${res.status}`, await res.json());
import BrelliumClient from "@brellium/api-client";
const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });
const audits = await client.audits.list({
documents: "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
});
console.log(audits);
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
audits = client.audits.list(documents="0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b")
print(audits.to_json())
To collect every audit for one or more documents, page with starting_after until has_more is false. The TypeScript and Python programs below do that for the complete audits of the sample document and print each audit's id, score and flags.
// Keep credentials on the server; never in a browser or mobile app.
const token = process.env.BRELLIUM_ACCESS_TOKEN;
if (!token) throw new Error("BRELLIUM_ACCESS_TOKEN is not set");
type Audit = {
audit_id: string;
object: "audit";
status: string;
score: number | null;
set_id: string;
flags: string[];
documents: string[];
created_at: string;
updated_at: string;
};
type AuditList = { object: "list"; data: Audit[]; has_more: boolean };
type ApiError = {
error: { type: string; code: string; message: string; request_id?: string };
};
// Every audit covering ANY of the given document_ids, newest first, across pages.
async function auditsForDocuments(
documentIds: string[],
status?: string,
): Promise<Audit[]> {
const audits: Audit[] = [];
let startingAfter: string | undefined;
do {
const params = new URLSearchParams({ limit: "100" });
// Repeat the parameter once per id. One comma-separated value (documents=a,b)
// works too.
for (const documentId of documentIds) params.append("documents", documentId);
if (status) params.set("status", status);
if (startingAfter) params.set("starting_after", startingAfter);
const res = await fetch(`https://api.brellium.com/v2/audits?${params}`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
const body = (await res.json()) as ApiError;
throw new Error(
`${res.status} ${body.error.code}: ${body.error.message} (request_id ` +
`${body.error.request_id})`,
);
}
const page = (await res.json()) as AuditList;
audits.push(...page.data);
startingAfter = page.has_more
? page.data[page.data.length - 1]?.audit_id
: undefined;
} while (startingAfter);
return audits;
}
async function main() {
const audits = await auditsForDocuments(
["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"],
"complete",
);
if (audits.length === 0) {
console.log("No complete audit covers this document yet");
return;
}
for (const a of audits) {
console.log(`${a.audit_id} score ${a.score} flags ${a.flags.join(", ")}`);
}
}
main();
# Keep credentials on the server; never in a browser or mobile app.
import os
import requests
TOKEN = os.environ["BRELLIUM_ACCESS_TOKEN"]
BASE_URL = "https://api.brellium.com"
def audits_for_documents(
document_ids: list[str], status: str | None = None
) -> list[dict]:
"""Every audit covering ANY of the given document_ids, newest first, across
pages.
"""
audits: list[dict] = []
starting_after = None
while True:
# A list value repeats the parameter: ?documents=<id>&documents=<id>.
# Comma-separated ids (documents=<id>,<id>) work too.
params: dict = {"documents": document_ids, "limit": 100}
if status:
params["status"] = status
if starting_after:
params["starting_after"] = starting_after
res = requests.get(
f"{BASE_URL}/v2/audits",
params=params,
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30,
)
if not res.ok:
err = res.json()["error"]
raise RuntimeError(
f"{res.status_code} {err['code']}: {err['message']} "
f"(request_id {err.get('request_id')})"
)
page = res.json()
audits.extend(page["data"])
if not page["has_more"]:
return audits
starting_after = page["data"][-1]["audit_id"]
audits = audits_for_documents(
["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"], status="complete"
)
if not audits:
print("No complete audit covers this document yet")
for a in audits:
print(f"{a['audit_id']} score {a['score']} flags {', '.join(a['flags'])}")
The response is 200 with a page that holds the sample audit, shortened below to leave out reviewed_at, display_info, people and responses. For the full audit, see Retrieve an audit by id. For every parameter of the list, see List audits.
{
"object": "list",
"data": [
{
// the id to store
"audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "audit",
// read this before score and flags
"status": "complete",
"score": 0.6666666666666666,
// the question set it is scored against
"set_id": "3c2b1a09-8f7e-4d6c-b5a4-938271605f4e",
"flags": ["Failed", "Missing Signature"],
"created_at": "2026-09-24T02:34:54.489Z",
"updated_at": "2026-09-24T02:37:12.105Z",
// the document_id of every document the audit covers
"documents": ["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"]
// reviewed_at, display_info, people and responses are omitted; see
// Retrieve an audit by id
}
],
"has_more": false
}
Narrow by status and question set
Filters combine, so an audit must match all of them. status=complete leaves out unfinished audits, and set_id keeps the audits scored against one question set. A document can have one audit per question set it is scored against.
When Brellium scores or runs an audit again, the list shows the same audit_id with a new updated_at, so watch updated_at to catch the new score. Until the audit completes again, it can show an unfinished status or be missing from lists.
curl --get "https://api.brellium.com/v2/audits" \
--data-urlencode "documents=0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b" \
--data-urlencode "status=complete" \
--data-urlencode "set_id=3c2b1a09-8f7e-4d6c-b5a4-938271605f4e" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
| jq '.data[] | {audit_id, status, score, set_id, documents, updated_at}'
const params = new URLSearchParams({
documents: "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
status: "complete",
set_id: "3c2b1a09-8f7e-4d6c-b5a4-938271605f4e",
});
const res = await fetch(`https://api.brellium.com/v2/audits?${params}`, {
headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
});
if (!res.ok)
throw new Error(
`HTTP ${res.status}: ${JSON.stringify((await res.json()).error)}`,
);
const { data } = await res.json();
for (const { audit_id, status, score, set_id, documents, updated_at } of data) {
console.log({ audit_id, status, score, set_id, documents, updated_at });
}
import BrelliumClient from "@brellium/api-client";
const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });
const { data } = await client.audits.list({
documents: "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
status: "complete",
set_id: "3c2b1a09-8f7e-4d6c-b5a4-938271605f4e",
});
for (const { audit_id, status, score, set_id, documents, updated_at } of data) {
console.log({ audit_id, status, score, set_id, documents, updated_at });
}
import json
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
page = client.audits.list(
documents="0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
status="complete",
set_id="3c2b1a09-8f7e-4d6c-b5a4-938271605f4e",
)
for a in page.data:
data = a.model_dump(mode="json")
keys = ["audit_id", "status", "score", "set_id", "documents", "updated_at"]
print(json.dumps({key: data[key] for key in keys}, indent=2))
{
"audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"status": "complete",
"score": 0.6666666666666666,
"set_id": "3c2b1a09-8f7e-4d6c-b5a4-938271605f4e",
"documents": ["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"],
"updated_at": "2026-09-24T02:37:12.105Z"
}
status and set_id each take one value. For several question sets, send one request per set. Before complete, score is null or 0 and flags is not final. For the statuses, see Understand an audit.
Look up by your own reference id
When your system knows the document by the external_id you set on it, filter by external_id. The match is exact, and an external_id belongs to at most one document in your organization.
curl "https://api.brellium.com/v2/audits?external_id=EHR-NOTE-48213&status=complete" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
| jq '{count: (.data | length), has_more, audit_ids: [.data[].audit_id]}'
const params = new URLSearchParams({
external_id: "EHR-NOTE-48213",
status: "complete",
});
const res = await fetch(`https://api.brellium.com/v2/audits?${params}`, {
headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
});
if (!res.ok)
throw new Error(
`HTTP ${res.status}: ${JSON.stringify((await res.json()).error)}`,
);
const { data, has_more } = await res.json();
console.log({
count: data.length,
has_more,
audit_ids: data.map((a: { audit_id: string }) => a.audit_id),
});
import BrelliumClient from "@brellium/api-client";
const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });
const { data, has_more } = await client.audits.list({
external_id: "EHR-NOTE-48213",
status: "complete",
});
console.log({
count: data.length,
has_more,
audit_ids: data.map((a) => a.audit_id),
});
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
page = client.audits.list(external_id="EHR-NOTE-48213", status="complete")
print(
{
"count": len(page.data),
"has_more": page.has_more,
"audit_ids": [a.audit_id for a in page.data],
}
)
{
"count": 1,
"has_more": false,
"audit_ids": ["a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"]
}
When no document has that external_id, the API returns 200 with an empty page:
{ "object": "list", "data": [], "has_more": false }
The external_id filter takes a value of 1 to 255 characters; an empty value returns 400 VALIDATION_ERROR with path: ["external_id"]. When you send external_id with documents, both filters apply: the audit must cover one of the document_id values and a document with that external_id. A batch with a file still missing 24 hours after it was created expires whole, and its external_id values are released, so this filter no longer finds its documents (Upload documents).
Query several documents at once
Repeat documents once per document_id, or send the ids in one value separated by commas. An audit matches when it covers any of them, and an audit that covers several appears once, with every document it covers in documents[]. The second id below is made up.
curl --get "https://api.brellium.com/v2/audits" \
--data-urlencode "documents=0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b" \
--data-urlencode "documents=11111111-1111-4111-8111-111111111111" \
--data-urlencode "limit=100" \
--data-urlencode "include_total=true" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
| jq '{total_count, has_more, audits: [.data[] | {audit_id, documents}]}'
const params = new URLSearchParams();
params.append("documents", "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b");
params.append("documents", "11111111-1111-4111-8111-111111111111");
params.append("limit", "100");
params.append("include_total", "true");
const res = await fetch(`https://api.brellium.com/v2/audits?${params}`, {
headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
});
if (!res.ok)
throw new Error(
`HTTP ${res.status}: ${JSON.stringify((await res.json()).error)}`,
);
const { total_count, has_more, data } = await res.json();
const audits = data.map(
({ audit_id, documents }: { audit_id: string; documents: string[] }) => ({
audit_id,
documents,
}),
);
console.log({ total_count, has_more, audits });
import BrelliumClient from "@brellium/api-client";
const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });
const { total_count, has_more, data } = await client.audits.list({
documents: [
"0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
"11111111-1111-4111-8111-111111111111",
],
limit: 100,
include_total: "true",
});
const audits = data.map(({ audit_id, documents }) => ({ audit_id, documents }));
console.log({ total_count, has_more, audits });
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
page = client.audits.list(
documents=[
"0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
"11111111-1111-4111-8111-111111111111",
],
limit=100,
include_total="true",
)
audits = [{"audit_id": a.audit_id, "documents": a.documents} for a in page.data]
print(
{"total_count": page.total_count, "has_more": page.has_more, "audits": audits}
)
{
"total_count": 1,
"has_more": false,
"audits": [
{
"audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"documents": ["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"]
}
]
}
To group the result by document, or to keep only audits that cover all of the ids, loop over each audit's documents[] in your code. documents accepts up to 100 ids, but a query string over 2,048 bytes is rejected with a bare 403 and no JSON body. Each documents=<uuid>& takes 47 bytes and each comma-separated id 37, so one request fits about 43 repeated ids or about 50 comma-separated ids, fewer with status or a cursor. Split a longer list of ids across requests, and page each one with starting_after while has_more is true (Page through and filter lists).
List a document's coding evaluations
To filter coding evaluations by document, send document_id to GET /v2/coding_evaluations. It takes exactly one id. status and the created_* and updated_* windows work as on audits.
On this endpoint, audit_id also takes one id and keeps only that audit's coding evaluations. For every parameter, see List coding evaluations.
curl --get "https://api.brellium.com/v2/coding_evaluations" \
--data-urlencode "document_id=0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b" \
--data-urlencode "status=complete" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
| jq '.data[] | {coding_eval_id, status, audit_id, documents}'
const params = new URLSearchParams({
document_id: "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
status: "complete",
});
const res = await fetch(
`https://api.brellium.com/v2/coding_evaluations?${params}`,
{
headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
},
);
if (!res.ok)
throw new Error(
`HTTP ${res.status}: ${JSON.stringify((await res.json()).error)}`,
);
const { data } = await res.json();
for (const { coding_eval_id, status, audit_id, documents } of data) {
console.log({ coding_eval_id, status, audit_id, documents });
}
import BrelliumClient from "@brellium/api-client";
const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });
const { data } = await client.codingEvaluations.list({
document_id: "0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b",
status: "complete",
});
for (const { coding_eval_id, status, audit_id, documents } of data) {
console.log({ coding_eval_id, status, audit_id, documents });
}
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
page = client.coding_evaluations.list(
document_id="0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b", status="complete"
)
for e in page.data:
print(
{
"coding_eval_id": e.coding_eval_id,
"status": e.status,
"audit_id": e.audit_id,
"documents": e.documents,
}
)
{
// the sample coding evaluation; your ids differ
"coding_eval_id": "6f1c2b3a-4d5e-4f60-8a71-92b3c4d5e6f7",
"status": "complete",
// the linked audit, or null
"audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"documents": ["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"]
}
Sending document_id twice returns 400 VALIDATION_ERROR (Invalid input: expected string, received array), so send one request per document. To read a coding evaluation's results, see List and retrieve coding evaluations.
Expected response
A document with no audit and an unknown document_id return the same empty page, { "object": "list", "data": [], "has_more": false }, so an empty page doesn't tell you whether the document exists. To check, fetch the document with GET /v2/documents/{document_id}.
Lists can take a few seconds to include a new or changed audit, so a newly completed audit can be missing from the list or still show its earlier status. For the same few seconds, GET /v2/audits/{audit_id} can return the previous version (Retrieve an audit by id).
Common mistakes
| Mistake | What you see | Fix |
|---|---|---|
Passing your own reference as documents= |
400 VALIDATION_ERROR, Invalid UUID, path: ["documents"] |
documents takes only document_id values, repeated (?documents=a&documents=b) or comma-separated (?documents=a,b). Use external_id= for your own references. |
Using document_id on audits |
200 with every audit in your organization, as if you sent no filter |
The API ignores unknown parameters. Audits take documents; document_id is the filter on coding evaluations. |
Next
Page through and filter lists
Cursor pagination, batch get by id, and each resource's filters.
Retrieve an audit by id
Retrieve one audit, check status before trusting score and flags, handle 404 and 400.
List and retrieve coding evaluations
List and retrieve coding evaluations and read their E/M and ICD results.