Build with Braes — supported builder guide Reviewed: 2026-10-05 Reference: /platform/api External REST schema: /platform/api/openapi.json Before your first build Use an agency test environment containing synthetic records, with an authorized administrator and a second staff user. Agree on the service line and the exact outcome before starting. Record unsuccessful attempts and assistance as well as successes. Public Demo is an evaluation experience; it is not a promise of an isolated integration sandbox. Ask your implementation contact for an environment appropriate for writes and event receivers. The tutorials below are executable source guidance, not evidence that your environment is deployed or configured. Confirm readiness in the product. Use only test destinations for outbound exercises; ordinary native reads and saved views do not depend on outbound delivery or a compute host. Download the curated REST schema at /platform/api/openapi.json. Human-readable reference: /platform/api. OAuth discovery: /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource/api/v1/mcp. All paths use your Braes environment's origin. The raw schema covers the external REST partition; OAuth and MCP setup are described here separately. J1: Create a referral waiting worklist in native Intake Goal: an intake leader and a second staff user can reopen the same useful worklist and revise it without changing Braes code. This tutorial uses native Intake, not personal OAuth. The agency field manager needs the existing Intake settings authority; the view author needs clinical:view and access to the selected service line. Shared adoption is decided by the native view owner. Synthetic scenario: use two existing test referrals in your agency, called Builder Example A and Builder Example B in your attempt notes. A is waiting for documents with a next-contact date tomorrow; B is waiting for a callback with a date next week. These are tutorial labels, not API identifiers or a request to create real patient records. 1. Open /intake/settings and choose Custom Fields. Add optional Waiting reason (select: Documents, Callback) and Next contact (date) fields. Select the intended service line, leave Required off, and choose Save changes. Reuse matching existing fields instead of duplicating them. Expected: both published fields appear on the Intake board; existing referrals still open without supplying new values. 2. Open /intake, find the two synthetic referrals, and enter the scenario values in their custom fields. Open Views → Create a view. Name it Builder waiting worklist, choose the waiting-reason filter and next-contact sorting offered by the published fields, include those columns, and keep Who can see this view personal initially. Preview and save using the editor. Expected: the matching synthetic referral appears and the saved view reopens from Views. 3. Make a second variation: open Views → Edit this view's layout, clear grouping and sorting, change the waiting reason, preview, and save. Close and reopen the view. Expected: the cleared coordinates remain cleared, the new filter is retained, and the original referral field values are unchanged. 4. Use the view's sharing control to request agency scope if authorized. Ask the second staff user to open Intake → Views and select it. Expected: the colleague sees only records their agency/service-line access permits. If sharing is refused, keep the personal view and use the editor's recovery action; an authorized native owner must perform the shared change. 5. Create a native Task at /tasks for the synthetic follow-up, assign its owner and due date, and retain the referral link in its description. The custom date field alone does not schedule work. If you need automatic follow-up, configure and separately test the existing Intake Automations owner against the actual trigger; do not infer automation from a saved view. 6. Recovery exercise: retire one test field in Custom Fields, then reopen the saved view. Use Edit this view or Restore the field in Intake settings beside the affected view. Restore and save the field, then verify the original values. Do not delete real data as part of this exercise. Record any denial and the successful recovery as separate attempts. J2: Authenticate an existing application and read its contract Personal MCP: copy the MCP URL from Extensions, add it to your client, and complete browser consent. Consent requires extensions:configure; the catalog page also requires extensions:read. Human scopes are mcp:tools, platform:read, no_phi, offline_access, with mcp:tools and no_phi required. The authorization-code flow uses PKCE S256, an exact registered redirect URI, and the absolute MCP resource URL for authorization, exchange, and refresh. It remains read-only and de-identified. Retain the replacement refresh token after each refresh. Revoked or expired grants require fresh consent; revoke under Personal MCP connections in Extensions. Machine setup: an agency administrator creates New machine integration in /extensions and reviews service lines, agency policy, and readiness. Save the once-shown secret in server-side secret storage. The following Node 22+ script uses BRAES_API_BASE_URL (origin only), BRAES_CLIENT_ID, BRAES_CLIENT_SECRET, and BRAES_AGENCY_ID supplied securely in the environment. It requests no_phi explicitly and prints only health/catalog data, never the bearer token. It makes no business write. Expected: the token response contains access_token, expires_in, agency_id, extension_id, and phi_mode=no_phi. Health returns data.status=ok with timestamp and version. Catalog returns data.routes, data.queries, data.capabilities, and generated_at. A successful health read proves this request works; it does not prove every operation is enabled. Keep catalog warnings and compare its scoped coverage with the public specification. Example: node --input-type=module <<'NODE' const required = name => { const value = process.env[name]; if (!value) throw new Error(name + ' is required'); return value; }; const base = new URL(required('BRAES_API_BASE_URL')); if (base.protocol !== 'https:' && !['localhost', '127.0.0.1'].includes(base.hostname)) { throw new Error('Use HTTPS for a remote Braes environment'); } async function read(response) { const body = await response.json(); if (!response.ok) throw new Error(JSON.stringify({ status: response.status, body })); return body; } const token = await read(await fetch(new URL('/api/v1/oauth/token', base), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'client_credentials', client_id: required('BRAES_CLIENT_ID'), client_secret: required('BRAES_CLIENT_SECRET'), agency_id: required('BRAES_AGENCY_ID'), phi_mode: 'no_phi' }) })); for (const path of ['/api/v1/ext/health', '/api/v1/ext/catalog']) { const result = await read(await fetch(new URL(path, base), { headers: { Authorization: 'Bearer ' + token.access_token, 'braes-contract-version': '2' } })); console.log(path, JSON.stringify(result, null, 2)); } NODE J2: Read remittances, orders, working collections, and HHVBP These read-only REST resources let a customer-built tool reconcile payments, chase signatures, reuse agency working data, and follow value-based purchasing without copying Braes screens. Each uses the same bearer token, contract-version header, data/meta envelope, and error envelope as the other external routes. The runtime catalog (GET /api/v1/ext/catalog) lists each route's required scope, whether a no_phi session can use it, and its documented query_parameters. Calls succeed only when the agency's extension policy allows the external REST read capability. Remittances (scope external:remittances:read): GET /api/v1/ext/remittances lists ERA payments with payer, amount, payment date, status, and claim count. Filters: status, era_file_id. GET /api/v1/ext/remittances/{id}/allocations lists that payment's claim-level allocations: charged, allowed, paid, adjustment, patient responsibility, variance, CARC adjustment codes such as CO-45, and match status. Totals for the whole payment are in meta.summary. An unknown remittance, or one that carries only provider-level adjustments, returns an empty page. Check and trace numbers are masked to their last four characters. In no_phi sessions they are removed, patient and claim references are pseudonymized, and dates are reduced to the year. Physician orders (scope external:physician-orders:read): GET /api/v1/ext/physician-orders lists orders newest first, with signature_status (signed, awaiting_signature, signature_not_required, rejected, superseded, cancelled), days_outstanding, aging_bucket, sla_breached, and days_to_sign. Aging is counted as of meta.as_of. Filters: status, order_type. The offset must be a multiple of limit. GET /api/v1/ext/physician-orders/{id} reads one order. Order content is never included. In a no_phi session both routes work: the list pseudonymizes patient and physician references and returns each order id as a stable OR- handle, and the single-order read takes that handle in place of the id. Working collections (scope external:working-collections:read, phi sessions only): GET /api/v1/ext/working-collections lists the collections the extension's agency identity can read: collections shared agency-wide, and collections that name that identity as an editor. Personal collections stay private. GET /api/v1/ext/working-collections/{id}/rows pages through one collection's rows. Values are keyed by stable field id, and meta.collection carries the field definitions. If a collection is refused or not found, the error names who can share it. Working values are supplemental. They never establish clinical or financial facts. Working collections are read-only from extensions. This is deliberate and not a gap you should work around. Only the collection's owner, its named editors, or an agency administrator signed in to Braes can change rows. There is no MCP proposal for row writes either: an approved proposal could not run under the extension's identity. Each collection's write block names the door. To request a change, create a task with POST /api/v1/ext/tasks that asks the collection's owner to make it, or make the change in Braes. Quality (scope external:quality:read): GET /api/v1/ext/quality/hhvbp/summary returns the agency's HHVBP cycle summary. GET /api/v1/ext/quality/hhvbp/measures returns its measure scores. Both accept performance_year and payment_year. When you omit payment_year, it is performance_year + 2. Both resources are agency-level aggregates with no patient data, so no_phi sessions can use them. Fields prefixed official_cms_ hold CMS-published results, when CMS has published them. Fields prefixed modeled_ hold Braes' projection, which is a diagnostic and not a CMS determination. If CMS has not published a result, official_cms_unavailable_reason says why. If the measure set for a year has not been imported, the request returns 404 with the reason and the recovery step. Example: // Continues the J2 script above: token and base are already defined. async function readAll(path) { const rows = []; let offset = 0; for (;;) { const url = new URL(path, base); url.searchParams.set('limit', '100'); url.searchParams.set('offset', String(offset)); const body = await read(await fetch(url, { headers: { Authorization: 'Bearer ' + token.access_token } })); rows.push(...body.data); if (body.meta?.next_offset == null) return rows; offset = body.meta.next_offset; } } const payments = await readAll('/api/v1/ext/remittances'); const overdue = (await readAll('/api/v1/ext/physician-orders')) .filter(order => order.aging_bucket === '31_plus_days'); console.log(payments.length, 'payments;', overdue.length, 'orders unsigned over 30 days'); Install the portable CLI Obtain the versioned braes-cli-0.1.0.tgz release artifact from your Braes implementation contact and use Node 22 or newer. Install that supplied file with pnpm add --global /absolute/path/braes-cli-0.1.0.tgz, then run braes --help. This is a private release artifact; no public npm registry publication is implied. Supply BRAES_API_BASE_URL, BRAES_CLIENT_ID, BRAES_CLIENT_SECRET, and BRAES_AGENCY_ID securely. Run braes auth token --phi-mode no_phi --json and securely provide its access_token as BRAES_EXTENSION_TOKEN for subsequent commands; token output is a credential and must stay out of logs. Use braes capabilities list --json to discover the current machine connection's tools. Read the listed capability input schema before preparing input.json. Never put a client secret in that file. Example: braes capabilities list --json braes propose --input-file input.json --key builder-j2-first-attempt-001 --purpose "Synthetic review exercise" --json braes proposals status --json J2: Propose a change and follow the human decision Use a machine integration whose agency policy permits the chosen capability, with a named reviewer configured as the escalation principal in Extensions. Personal browser OAuth does not gain write/proposal permission. MCP proposal tools are a separate surface from the curated REST API; do not invent a REST /proposals endpoint. From your authenticated MCP client, list tools and choose a propose_* tool actually returned for this connection. Inspect its inputSchema and _meta['braes.capabilityInputSchema']; use the latter to prepare the exact capability input with synthetic identifiers from your test agency. Check braes.availability and braes.reviewerAssigned. No hard-coded capability or invented business fields are needed. 1. Call the listed propose_* tool with arguments { input: , idempotencyKey: <8–200 character stable key>, purpose: }. For example use builder-j2-first-attempt-001 as the key; the input and tool name must come from your current catalog. Expected: a proposal receipt with approvalId, status, reviewHref, statusTool, and next, plus the owner preview. This stages review and does not execute the change. 2. Repeat the same call with the same input and key. Expected: the same approval is returned as a replay. Reusing the key with changed input is refused; use a fresh key for an intentionally changed proposal after reviewing it. 3. Have the named human reviewer open the returned reviewHref and decide through the native review surface. The external connection has no decision tool. Call braes.proposals.status with { approvalId: }. Read status, decided, executedAt, lastExecutionError, and next. An approval without executedAt is not evidence of a completed business effect. 4. If staging is refused because a reviewer or owner is unavailable, retain the input and follow the returned recovery message. The administrator fixes the reviewer/policy or the named owner restores readiness; do not repeatedly stage a substitute change. A narrowed policy must still permit tracing previously staged proposals belonging to this extension. J2: Receive an event and recover a failed delivery In the extension's native Webhook subscriptions panel, an authorized administrator creates a subscription for the selected event and a test HTTPS receiver under your control. Save its signing secret securely. Configure the necessary agreements before clinical events; those events remain held until the subscription's business associate agreement is recorded as signed. Do not use patient data for the synthetic test. For proposal decisions, subscribe to approval.decided and still use the proposal status tool for the current decision/execution truth. Receiving the event alone is not proof a business action executed. Event envelopes carry their own version and contract version; the event catalog below describes supported names and data categories. Verify the raw body before JSON parsing. Compute payloadHash = 'sha256=' + SHA256(rawBody). Verify it against x-braes-payload-sha256. Form the exact string 'v1.' + timestamp + '.' + deliveryId + '.' + payloadHash + '.' + rawBody, using x-braes-signature-timestamp and x-braes-delivery-id. Compute HMAC-SHA256 with the signing secret as a hex digest; compare 'v1=' + digest to x-braes-signature with a constant-time comparison. Reject stale timestamps (the owner verifier defaults to a 300-second tolerance). During rotation the retiring secret's signature is in x-braes-signature-previous for its overlap window. 1. Trigger the chosen synthetic event through its normal owner. Validate and durably record the event/delivery identifiers before acknowledging with a successful HTTP status. Make processing idempotent; retries and manual replay must not repeat business effects. Do not assume delivery order. 2. For the failure exercise, make only your test receiver return a temporary failure. Inspect delivery status in Extensions, restore the receiver, and use the existing replay action if needed. Expected: the retained failed attempt remains inspectable and a later delivery succeeds. If access or an agreement blocks delivery, the agency administrator repairs that specific subscription rather than bypassing verification. J3: Retain a review and hand it to the next owner Use a native Task for a synthetic operational review, assigned to the reviewer in the test agency. This is a retained-evidence exercise, not payroll approval or settlement. The task assignee, assigning user, or agency administrator can retain and interpret sources; the successor also needs task access. Native evidence features are not promised through personal OAuth. Save the CSV below as builder-review-cycle-1.csv on your device. Its example_id is a synthetic row identity, not a Braes patient or invoice UUID. The rows describe review questions only. Example: example_id,review_status,note EXAMPLE-A,Needs follow-up,Missing source confirmation EXAMPLE-B,Reviewed,Source checked in synthetic exercise 1. Open the Task's Retained evidence tab and Upload a CSV or XLSX source. Wait for verification/security scan, reload uploads, and choose Retain source. If necessary use Verify upload and reload; keep the original file when a retry is required. Expected: a retained source appears with its original filename and retained time. 2. Select the source, leave Worksheet at its default and Header row at 1, then choose Read and retain first page. Confirm two data rows. Add an Identity column mapping example_id → A and a Fact mapping note → C; set Review column to B. Map each source decision text to the appropriate offered meaning, keeping Needs follow-up unresolved. Add interpretation notes and Save interpretation proposal. Saving an interpretation does not adopt the decision or change business records. 3. Close and reopen the task, download the retained original, and load the saved mapping. Have the second authorized staff user open the same task and explain the outstanding row from the source, interpretation, and notes. Correct one interpretation and save a new proposal; verify earlier history remains available. On a revision conflict use Reload saved history and reconcile the editable draft against the current revision before saving. 4. For a second cycle, have an agency administrator use the native recurring assignment editor only when a suitable saved procedure is available: choose the accountable user, saved procedure and version, Repeat, next occurrence, timezone, and completion conditions, then Save recurring assignment. On the next occurrence use Open previous occurrence and the prior-source linking controls in Retained evidence. If no procedure fits, retain the next review in a separately named native task with a link to the earlier task; record that as manual continuation, not verified automated recurrence. 5. Where the task has Operational preparation, Start new attempt, record a Progress note, Save checkpoint, and Record interruption. Reopen under the authorized successor and continue from retained outputs and unresolved work. Verify preparation only after required owner receipts exist. An interrupted run, a prepared review, a completed task, and a confirmed downstream effect remain separate outcomes. Maintain, transfer, and remove a solution Keep an agency-owned handoff record with the solution's business owner and maintainer, native object links, package/version and publisher, current agency/service lines, local bindings, required permissions, credential locations, receiver/compute dependencies, unresolved work, and last verified receipt. Record credential locations, never secret values. The external application remains its operator's hosting and maintenance responsibility. Use Extensions for the connection's Executable readiness, Policy, usage/activity, webhook subscriptions and delivery records. Observation requires its own permissions; a missing observation grant is not proof that nothing ran. Retain object, request/correlation, proposal, delivery, and attempt identifiers when asking the responsible owner for help. Do not replay an uncertain external effect just because its receipt is missing. 1. Before installing a signed package, inspect its requested authority and dependencies and choose bindings in the receiving agency through the native owners. Do not copy another agency's UUIDs or credentials into a portable definition. The administrator can inspect the registration, immutable versions, native references, and removal behaviors with braes packages list --package using the package administration credential: an agency administrator's signed-in access token passed as --token or set in BRAES_ADMIN_BEARER. A machine extension token does not grant package administration. 2. For upgrades, open Package upgrades in the extension detail, paste the signed JSON and choose Preview package. Inspect retained agency changes and resolve each difference using Keep agency value or Use publisher value, then preview again. Install reviewed package submits the exact reviewed draft for the current scope. If someone changes a native definition, preview again and reconcile the retained choices. Workflow changes produce drafts; open the returned workflow-draft link for its owner to review and activate. 3. In a second synthetic installation, repeat with that agency's own bindings and a local edit, then preview the publisher's next version. Expected: unchanged publisher values preserve the local edit; competing edits require an explicit choice. If the agency or extension changes while reviewing, the package draft remains editable but the previous review does not authorize installation in the new scope. 4. For ownership handoff, transfer each native asset through its own owner. A working collection exposes Transfer collection ownership and New responsible owner; the current owner or agency administrator chooses an active eligible successor and checks the receipt. Rows and history remain with the collection, while sharing rules decide the former owner's remaining access. Recurring Tasks need an active accountable user. A collection transfer does not transfer a personal saved view, external application, OAuth grant, or secret. 5. Have the successor verify native access and an ordinary read before retiring the old maintainer's access. Reauthorize personal MCP through the successor's own agency-authorized consent; do not share an old refresh token. For machine integrations, an authorized lifecycle administrator rotates the secret, the application operator updates secure configuration and verifies the intended agency connection, and then the team records the new credential location. Webhook secrets have their own rotation/overlap controls. Keep outstanding task/proposal/delivery identifiers through the handoff. 6. Before removal, inspect each asset's declared behavior and affected native references. retain_with_provenance keeps records and origin metadata; detach keeps agency-owned records without package management; delete invokes the native owner's removal such as archive, withdrawal, or revocation. Package removal does not promise to retain every definition. Preserve needed agency copies through the native owner before an intentional removal, and do not change retention for operational or audit evidence. 7. Disabling or kill-switching a package retains its registration and assets; it is not removal, and existing native effects still need their owner's reconciliation and controls. A package kill switch can be cleared by its authorized administrator, followed by an explicit enable; clearing it alone does not re-enable the package. To remove, the administrator uses braes packages remove --yes only after reviewing declared effects. Registration and ledger history remain. An incomplete removal stays disabled with recorded failures; repair the named dependency and retry the existing removal to converge. 8. Have the successor run the documented recovery once and record support/implementation minutes, completed useful work, repeat usage, and observed platform costs separately. Existing agreements govern charges and support. API activity, customer-hosted AI, and managed execution have different costs; this guide creates no price, unlimited-support promise, compatibility duration, or marketplace commitment. Contract behavior, recovery, and maintaining your integration The current extension contract version is 2. Machine REST requests can pin it with braes-contract-version; responses identify the served version with braes-extension-contract-version. Within a version changes are additive. Breaking changes require a successor and deprecation before retirement; no fixed compatibility duration is promised. Keep unknown optional fields tolerable and inspect deprecation guidance. REST success is a data envelope with optional meta and warnings. Errors contain error.code, error.message, and details where available. Preserve the error and request identifier for support without retaining credentials. A list with meta.limit is a bounded result, not necessarily the full agency census. Do not invent cursor support: use only the route's documented request parameters and returned pagination fields. Governed query pagination has its own query contract. Command routes marked idempotent require Idempotency-Key. Retry an uncertain result with the same key and identical payload; a different payload must not reuse it. Read routes do not acquire write permission because a token exists. Validate required fields against the current downloaded schema and the runtime catalog before submitting. On invalid_client, verify the machine credential and agency entitlement with the extension administrator; the response deliberately does not distinguish those conditions. On PLATFORM_PHI_MODE_REQUIRED, send an explicit no_phi or permitted phi mode. On permission/policy denial, use Extensions readiness and the agency's People → Access recovery as appropriate. Renewing a token does not expand access. Respect Retry-After when supplied on rate limits. For patient-specific data or writes unavailable to personal OAuth, use the authorized native workflow or a supported machine integration whose policy grants the needed access. Native Ask Braes deep runs: when generated API authorization expires, the saved run shows Waiting for access. Open its retained run from the pause message or Activity. The person who started it, signed in to the same agency, can choose Renew access and resume or Stop this run. Renewal rechecks current authorization and resumes the original request with its trace and recorded effects. It does not create an unrelated request or grant additional access. If delivery is awaiting confirmation, use Retry saved resume; if renewal was not confirmed, recheck the run and retry access renewal after restoring the original sign-in. The open conversation observes the resumed answer while keeping unsent work. This native control does not renew an external OAuth credential; use the human or machine OAuth flow above for those connections. Renew machine tokens according to expires_in by repeating client_credentials; this grant does not return a refresh token. Secret rotation and the agency kill switch require extensions:lifecycle. Rotation is not revocation. Use the kill switch to stop agency execution, preserve work identifiers, and restore access only through the authorized owner before retrying. Documentation ownership: Braes documentation/developer experience maintains these tutorials; transport and domain owners review them whenever OAuth scopes, catalog shapes, proposal receipts, event signing, native controls, or recovery semantics change. Changes must update the shared guide and relevant contract tests in the same delivery. The download and HTML tutorials share this content. Check the reviewed date and the deployed catalog/version before each integration upgrade; the date is editorial review, not a deployment attestation.