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 complete audit can be scored again, for example after an answer is changed in Brellium: its status is completing briefly, then complete again, possibly with a different score and flags. When Brellium runs an audit again, the audit either goes back to in_progress with responses: [] or disappears until it completes again: GET /v2/audits/{audit_id} returns 404 and lists leave it out. audit_id and created_at never change.
  • Branch on status == "complete" and never on score. Until the audit completes, score is 0 or null, 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 details issue reads flags must be unique) and are case-sensitive, so Reviewed and reviewed are 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.

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