Understand an audit
An audit is one or more documents scored against a question set: Brellium answers each question from the documents, scores the result and sets flags. The audit carries only the ids of its related records (set_id, documents[], people[].person_id); fetch each from its own endpoint (Related records). Read status before score or flags, and watch updated_at for changes.
The audit object
GET /v2/audits/{audit_id} returns the sample audit below; your audits have the same shape.
curl "https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN"
const res = await fetch(
"https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
{ headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` } },
);
const body = await res.json();
if (!res.ok) throw new Error(`HTTP ${res.status}: ${JSON.stringify(body.error)}`);
console.log(body);
import BrelliumClient from "@brellium/api-client";
const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });
const audit = await client.audits.retrieve("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d");
console.log(audit);
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
audit = client.audits.retrieve("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d")
print(audit.to_json())
{
"audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "audit",
"status": "complete",
"score": 0.6666666666666666,
// the question set: GET /v2/question_sets/{set_id}
"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",
"reviewed_at": null,
"display_info": [
{
"key": "provider",
"title": "Provider",
"value": "Jordan Rivera",
"format": "text"
},
{
"key": "date_of_service",
"title": "Date of service",
"value": "2026-09-24T02:34:54.489Z",
"format": "date"
}
],
// document ids only
"documents": ["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"],
"people": [
{
"person_id": null,
"role": "client",
"role_title": "Client",
"name": "Sample Client"
},
{
// the email recipient's person_id
"person_id": "2a1b0c9d-8e7f-4a6b-9c5d-4e3f2a1b0c9d",
"role": "provider",
"role_title": "Provider",
"name": "Jordan Rivera"
}
],
"responses": [
{
"response_id": "e1d2c3b4-a596-4877-9867-5a4b3c2d1e0f",
"question_id": "7d6c5b4a-3928-4170-a695-847362514f3e",
"question": "Is the session note signed by the rendering provider?",
"answer": "No",
"evidence": "The signature block at the end of the note is empty.",
"remediation": "Ask the rendering provider to sign the note.",
"affirmation": null
},
{
"response_id": "d0c1b2a3-9485-4766-8756-4a3b2c1d0e9f",
"question_id": "6c5b4a39-2817-4069-9584-736251403f2e",
"question": "Does the note document the service start and end times?",
"answer": "Yes",
"evidence": "Start 09:00, end 10:00 are recorded in the header.",
"remediation": null,
"affirmation": "Service times are documented."
},
{
"response_id": "c9b0a192-8374-4655-8645-3a2b1c0d9e8f",
"question_id": "5b4a3928-1706-4f58-8473-625140392e1d",
"question": "Which program does this note belong to?",
"answer": "N/A",
"evidence": "Informational question; no answer is scored.",
"remediation": null,
"affirmation": null
}
]
}
Every field is always present, in this order, whatever the status. evidence can quote a document and name is a person's name, so treat the whole object as protected health information (PHI).
Fields
| Field | Type | Meaning |
|---|---|---|
audit_id |
UUID | The id of the audit, used as the path parameter, the cursor value and the batch get value. |
object |
"audit" |
Always "audit". |
status |
string | Where the audit is in its status lifecycle. |
score |
number or null | The share of scored questions answered as expected, from 0 to 1. Meaningful only when status is complete; before that it is 0 or null. |
set_id |
UUID | The question set the audit is scored against. |
flags |
string[] | Free-text labels; [] until the audit completes. Brellium sets them at every completion, and a PATCH replaces them until the next completion. |
created_at |
string, RFC 3339 in UTC | When the audit was created; it never changes. |
updated_at |
string, RFC 3339 in UTC | When the audit last changed, by Brellium or by you. |
reviewed_at |
string, RFC 3339 in UTC, or null | When the audit was last marked reviewed in Brellium; null when it is not marked reviewed. Audits marked reviewed before November 26, 2024 also have null, because the time was not recorded then. Marking an audit reviewed or unreviewed also sets a new updated_at. |
display_info |
AuditDisplayInfoItem[] |
The audit header fields shown in Brellium, in display order. [] when there are none. |
documents |
UUID[] | The documents the audit covers, by document_id, in the audit's order. The list has more than one id when Brellium reviews a batch uploaded with "grouping": "group" as one audit, which depends on your organization's setup. [] when there are none. |
people |
AuditPerson[] |
The people named on the audit, such as the client and provider, in display order. [] when there are none. |
responses |
AuditResponse[] |
One answer per question, informational questions included, in question order. [] until the audit has responses. |
An AuditDisplayInfoItem has four string fields: key (such as provider), title (such as Provider), value and format. value is the value as text, with dates and times as RFC 3339 in UTC, and "" when the field has no value. format says how to show the value, such as "text", "date" or "time".
An AuditPerson has person_id (UUID or null), role (string), role_title (string) and name (string). person_id is the id shared by the email recipient and user for that person; it is null when the name is not linked to a person, as for the sample's client. role is the identifier of the person's role, such as client, and role_title is its label, such as Client. name is the person's name as it appears on the audit; the audit carries no email address.
An AuditResponse has response_id (UUID), question_id (UUID or null; null when the response is not linked to a question), question (string) and answer ("Yes", "No" or "N/A"). evidence (string) is the text supporting the answer, "" when there is none. remediation and affirmation (string or null) both come from the question.
Status lifecycle
Brellium uses these status values, in order:
| Value | Meaning |
|---|---|
todo |
The audit is created; processing has not started. |
processing |
Brellium is preparing the audit; no question is answered yet. |
in_progress |
Brellium is answering the questions; responses grows as answers arrive. |
completing |
Every question is answered; Brellium is scoring the audit. |
complete |
The audit is scored; score, flags and responses are final for this completion. |
error |
Processing failed; the audit can still complete later. |
- No status is final. A
completeaudit can be scored again, for example after an answer is changed in Brellium: itsstatusiscompletingbriefly, thencompleteagain, possibly with a differentscoreandflags. When Brellium runs an audit again, the audit either goes back toin_progresswithresponses: []or disappears until it completes again:GET /v2/audits/{audit_id}returns404and lists leave it out.audit_idandcreated_atnever change. - Branch on
status == "complete"and never onscore. Until the audit completes,scoreis0ornull, and both mean the audit is not scored yet. - Treat any other value as not complete, including values added later.
Flags
flags is the only writable field. PATCH /v2/audits/{audit_id} takes { "flags": [...] } and replaces the whole list. To add a flag, fetch the audit, add your flag to its flags and send the full list. The API rejects a list that breaks one of these rules with 400 VALIDATION_ERROR:
- An audit holds at most 50 flags of 1 to 100 characters each;
{ "flags": [] }removes every flag. - Flags must be unique (the
detailsissue readsflags must be unique) and are case-sensitive, soReviewedandreviewedare different flags.
curl --request PATCH \
"https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
--header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data '{"flags": ["Failed", "Missing Signature", "Reviewed"]}'
const res = await fetch(
"https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
{
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ flags: ["Failed", "Missing Signature", "Reviewed"] }),
},
);
const body = await res.json();
if (!res.ok) throw new Error(`HTTP ${res.status}: ${JSON.stringify(body.error)}`);
console.log(body);
import os
from brellium_api_client import BrelliumClient
client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])
audit = client.audits.update(
"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
flags=["Failed", "Missing Signature", "Reviewed"],
)
print(audit.to_json())
{
"audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "audit",
"flags": ["Failed", "Missing Signature", "Reviewed"],
"updated_at": "2026-10-21T15:00:00.000Z"
/* ... every other key of the audit object above, unchanged */
}
The update response is the current audit, so use it instead of fetching the audit again. When two requests change the same audit, the last to arrive wins. A new completion recomputes flags from the answers and drops the flags you set through the API. When status returns to complete with a newer updated_at, set the flags you need again.
POST /v2/audits/batch_update applies the same rules to 1 to 100 items of the form { "audit_id": ..., "flags": [...] }. The response has one result per item, in request order: the updated audit, or { "audit_id": ..., "error": {...} } for an item that failed. A failed item does not stop the others, so one unknown audit_id fails only its own item (its error.code is NOT_FOUND). When any item breaks a validation rule, the whole request returns 400 VALIDATION_ERROR and no audit changes. For single and batch updates with code, see Update audit flags.
updated_at is the change signal
Every change sets a new updated_at: a completion, a new score, your flag updates and marking the audit reviewed or unreviewed in Brellium. The audit object has no completion timestamp, so sync on updated_after and updated_before. Make consecutive windows overlap, because lists can take a few seconds to include a new or changed audit. For the loop, see Keep audits in sync with updated_after.
Related records
| On the audit | Points at | Fetch with |
|---|---|---|
set_id |
The question set. A non-null responses[].question_id matches one of its questions[].question_id values, unless the question was deleted or removed from the set after the audit ran. |
GET /v2/question_sets/{set_id} (Retrieve a question set). For the steps, see Retrieve an audit's question set. |
documents[] |
The documents the audit covers, by document_id. |
GET /v2/documents/{document_id} (Retrieve a document). |
people[].person_id |
The person's email recipient and user, which share this person_id. |
GET /v2/email_recipients/{person_id} (Retrieve an email recipient). For the steps, see Link an audit's people to recipients and users. |
GET /v2/audits filters by set_id, documents and flags, but has no person filter. For every audit filter, see Page through and filter lists.
Retrieve an audit by id
For a few seconds after an audit is created or changed, GET /v2/audits/{audit_id} can return 404 or the previous version, so confirm your own update from your PATCH or batch_update response body.
An id that is not a UUID returns 400 VALIDATION_ERROR. The API returns 404 NOT_FOUND with the message Audit not found when your organization has no audit with this id. Another organization's id returns 404 too.
Next
Retrieve an audit by id
Retrieve one audit, check status before trusting score and flags, handle 404 and 400.
Update audit flags
Set the flags of one audit or of many in a batch update, without dropping the flags each audit already has.
Keep audits in sync with updated_after
Backfill once, then poll updated_after windows that overlap and upsert by id.
Retrieve an audit's question set
Follow set_id to the question set and join responses to questions.