Retrieve an audit by id

GET /v2/audits/{audit_id} returns one audit with its current status, score, flags and responses. Call it when you have an audit_id from a list call or a stored record. To find audits, see Page through and filter lists.

Prerequisites

  • An access token in $BRELLIUM_ACCESS_TOKEN, cached and reused (Authenticate with OAuth2 client credentials).
  • An audit_id, for example from GET /v2/audits?status=complete&limit=1 (Make your first request). This page uses the sample audit a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d.
  • With a live key the response contains protected health information (PHI); a sandbox key returns the sample audit.

Steps

Fetch the audit

Put the audit_id in the path. Authorization is the only header you need.

curl "https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
  --header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
  --write-out "HTTP %{http_code}\n"
const res = await fetch(
  "https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  {
    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 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())

The full programs below make the same call and return no audit on a 404. They raise any other error with its code, message and request_id, and print score, flags and each answer only when status is complete.

// 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 AuditPerson = {
  person_id: string | null;
  role: string;
  role_title: string;
  name: string;
};
type AuditResponse = {
  response_id: string;
  question_id: string | null;
  question: string;
  answer: string;
  evidence: string;
  remediation: string | null;
  affirmation: string | null;
};
type Audit = {
  audit_id: string;
  object: "audit";
  status: string;
  score: number | null;
  set_id: string;
  flags: string[];
  created_at: string;
  updated_at: string;
  reviewed_at: string | null;
  display_info: { key: string; title: string; value: string; format: string }[];
  documents: string[];
  people: AuditPerson[];
  responses: AuditResponse[];
};
type ApiError = {
  error: { type: string; code: string; message: string; request_id?: string };
};

// Returns null for a 404: no audit with this id that your token can read.
async function getAudit(auditId: string): Promise<Audit | null> {
  const res = await fetch(`https://api.brellium.com/v2/audits/${auditId}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (res.status === 404) return null;
  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})`,
    );
  }
  return (await res.json()) as Audit;
}

async function main() {
  const audit = await getAudit("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d");
  if (!audit) {
    console.log("No audit with that id in this organization");
    return;
  }
  if (audit.status !== "complete") {
    console.log(`Audit is ${audit.status}; score and flags are not final yet`);
    return;
  }
  console.log(`score ${audit.score}, flags ${audit.flags.join(", ")}`);
  for (const r of audit.responses) {
    console.log(`${r.answer}: ${r.question}`);
  }
}

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 get_audit(audit_id: str) -> dict | None:
    """Returns None for a 404: no audit with this id that your token can read."""
    res = requests.get(
        f"{BASE_URL}/v2/audits/{audit_id}",
        headers={"Authorization": f"Bearer {TOKEN}"},
        timeout=30,
    )
    if res.status_code == 404:
        return None
    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')})"
        )
    return res.json()


audit = get_audit("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d")
if audit is None:
    print("No audit with that id in this organization")
elif audit["status"] != "complete":
    print(f"Audit is {audit['status']}; score and flags are not final yet")
else:
    print(f"score {audit['score']}, flags {', '.join(audit['flags'])}")
    for r in audit["responses"]:
        print(f"{r['answer']}: {r['question']}")

A 200 carries the full audit. Every field is always present, and an array with no items is [].

{
  "audit_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "object": "audit",
  // read this first
  "status": "complete",
  // meaningful only when status is "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",
  // changes on completion, re-scoring and flag updates
  "updated_at": "2026-09-24T02:37:12.105Z",
  // set when someone marks the audit reviewed in Brellium
  "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"
    }
  ],
  "documents": ["0f8e7d6c-5b4a-4938-8271-605f4e3d2c1b"],
  "people": [
    {
      "person_id": null,
      "role": "client",
      "role_title": "Client",
      "name": "Sample Client"
    },
    // a linked person; also their email recipient's person_id when they have one
    {
      "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
    }
  ]
}
Read status before score and flags

An unfinished audit has the same shape as a finished one, so check status to learn whether score, flags and responses are final. The call below fetches the audit and prints status, score, flags and the number of responses.

curl "https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
  --header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
  | jq '{status, score, flags, responses: (.responses | length)}'
const res = await fetch(
  "https://api.brellium.com/v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  {
    headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
  },
);
if (!res.ok)
  throw new Error(
    `HTTP ${res.status}: ${JSON.stringify((await res.json()).error)}`,
  );
const { status, score, flags, responses } = await res.json();
console.log({ status, score, flags, responses: responses.length });
import BrelliumClient from "@brellium/api-client";

const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });

const { status, score, flags, responses } = await client.audits.retrieve(
  "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
);
console.log({ status, score, flags, responses: responses.length });
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(
    {
        "status": audit.status,
        "score": audit.score,
        "flags": audit.flags,
        "responses": len(audit.responses),
    }
)
{
  "status": "complete",
  "score": 0.6666666666666666,
  "flags": ["Failed", "Missing Signature"],
  "responses": 3
}

The current status values, in processing order, are todo, processing, in_progress, completing, complete and error. New values can appear, so branch on complete and treat anything else as not finished. Before complete, flags is not final, score is null or 0 and responses can be empty or partial.

A complete audit can change again. When it is recalculated in Brellium, it moves through completing back to complete with a new score, flags and updated_at. Compare updated_at with your stored value to spot this.

Handle 404 and 400

The API returns 404 NOT_FOUND when your organization has no audit with this audit_id; another organization's id returns 404 too. The call below uses an id that matches no audit.

curl "https://api.brellium.com/v2/audits/11111111-1111-4111-8111-111111111111" \
  --header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
  --write-out "HTTP %{http_code}\n"
const res = await fetch(
  "https://api.brellium.com/v2/audits/11111111-1111-4111-8111-111111111111",
  {
    headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
  },
);
// A 404 is the expected result here, so print the envelope instead of throwing.
console.log(`HTTP ${res.status}`, await res.json());
import BrelliumClient, { APIError } from "@brellium/api-client";

const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });

try {
  console.log(await client.audits.retrieve("11111111-1111-4111-8111-111111111111"));
} catch (err) {
  if (!(err instanceof APIError)) throw err;
  console.log(`HTTP ${err.status}`, err.error);
}
import os

from brellium_api_client import APIStatusError, BrelliumClient

client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])

try:
    print(client.audits.retrieve("11111111-1111-4111-8111-111111111111").to_json())
except APIStatusError as err:
    print(f"HTTP {err.status_code}", err.body)
{
  "error": {
    "type": "not_found_error",
    "code": "NOT_FOUND",
    "message": "Audit not found",
    "request_id": "9c1f0a7e-4b2d-4e3a-8f6b-2d1c0b9a8e7f"
  }
}

An audit_id that isn't a UUID, such as not-a-uuid, returns 400 VALIDATION_ERROR. A 400 never means the audit wasn't found.

curl "https://api.brellium.com/v2/audits/not-a-uuid" \
  --header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN" \
  --write-out "HTTP %{http_code}\n"
const res = await fetch("https://api.brellium.com/v2/audits/not-a-uuid", {
  headers: { Authorization: `Bearer ${process.env.BRELLIUM_ACCESS_TOKEN}` },
});
// A 400 is the expected result here, so print the envelope instead of throwing.
console.log(`HTTP ${res.status}`, await res.json());
import BrelliumClient, { APIError } from "@brellium/api-client";

const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });

try {
  console.log(await client.audits.retrieve("not-a-uuid"));
} catch (err) {
  if (!(err instanceof APIError)) throw err;
  console.log(`HTTP ${err.status}`, err.error);
}
import os

from brellium_api_client import APIStatusError, BrelliumClient

client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])

try:
    print(client.audits.retrieve("not-a-uuid").to_json())
except APIStatusError as err:
    print(f"HTTP {err.status_code}", err.body)
{
  "error": {
    "type": "invalid_request_error",
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "origin": "string",
        "code": "invalid_format",
        "format": "uuid",
        "path": ["audit_id"],
        // also carries a regex "pattern"; read code and path, which are stable
        "message": "Invalid UUID"
      }
    ],
    "request_id": "38174c7d-a1fc-489b-a3fd-4f010c7ba1e7"
  }
}

Branch on type and code, which are stable; message and details can change. For every code, see Rate limits and errors. Send Brellium support the request_id (also the x-request-id response header) and the time of the request. Leave response bodies out of the report: they can contain PHI.

Fetch the related records you need

An audit carries only the ids of its related records (set_id, documents[], people[].person_id); fetch each from its own endpoint. The call below fetches the email recipient of the sample audit's provider.

# The provider's email recipient (people[].person_id). Skip entries whose
# person_id is null.
curl "https://api.brellium.com/v2/email_recipients/2a1b0c9d-8e7f-4a6b-9c5d-4e3f2a1b0c9d" \
  --header "Authorization: Bearer $BRELLIUM_ACCESS_TOKEN"
// The provider's email recipient (people[].person_id). Skip entries whose
// person_id is null.
const res = await fetch(
  "https://api.brellium.com/v2/email_recipients/2a1b0c9d-8e7f-4a6b-9c5d-4e3f2a1b0c9d",
  {
    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(await res.json());
import BrelliumClient from "@brellium/api-client";

const client = new BrelliumClient({ oAuth2: process.env.BRELLIUM_ACCESS_TOKEN });

// The provider's email recipient (people[].person_id). Skip entries whose
// person_id is null.
const recipient = await client.emailRecipients.retrieve(
  "2a1b0c9d-8e7f-4a6b-9c5d-4e3f2a1b0c9d",
);
console.log(recipient);
import os

from brellium_api_client import BrelliumClient

client = BrelliumClient(o_auth2=os.environ["BRELLIUM_ACCESS_TOKEN"])

# The provider's email recipient (people[].person_id). Skip entries whose
# person_id is null.
recipient = client.email_recipients.retrieve("2a1b0c9d-8e7f-4a6b-9c5d-4e3f2a1b0c9d")
print(recipient.to_json())
{
  "person_id": "2a1b0c9d-8e7f-4a6b-9c5d-4e3f2a1b0c9d",
  "object": "email_recipient",
  // illustrative; the full recipient is in Link an audit's people
  "email": "jordan.rivera@clinic.example"
  // ...
}

Each field below points at one kind of related record:

The audit is still valid when one of these calls returns 404. A question set or email recipient can be deleted after the audit ran, and a person with a person_id isn't always an email recipient.

Expected response

The response in step 1 has all 13 fields of an audit (Retrieve an audit). Two of them need extra handling:

Field What to do with it
responses[] The audit has one response per question, in question order, including informational questions. answer is "Yes", "No" or "N/A". evidence can quote the document. question_id is null when the response isn't linked to a question.
reviewed_at It holds the time the audit was last marked reviewed in Brellium, or null when the audit isn't marked reviewed. Audits marked reviewed before November 26, 2024 also have null, because the time wasn't recorded then. Marking the audit reviewed or unreviewed also changes updated_at.

For a few seconds after an audit is created, GET /v2/audits/{audit_id} can return 404. After a change, such as the audit's completion or a flag update, the same call can still return the previous version for a few seconds, so check status and compare updated_at. After your own PATCH /v2/audits/{audit_id}, the response is the current audit, so use it instead of fetching the audit again.

Common mistakes

Mistake What you see Fix
Treating a 404 as "deleted" 404 NOT_FOUND "Audit not found" for an audit you see in Brellium Check your token's organization. The API can't delete audits.
Fetching every known audit in a loop to find changes 429 RATE_LIMITED once your organization has used its burst of 100 requests and sends more than 5 per second Pull changes with GET /v2/audits?updated_after=... (Keep audits in sync with updated_after), and fetch by audit_id only the audits you haven't stored.
A trailing slash on the path 404 NOT_FOUND "Route not found: GET /v2/audits/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/" Build the path exactly.

Next