BBISS
IndustriesPricingHazard librarySample brief
Sign inStart with BISS
ContactPaper vs BriefwrightSafety software vs BriefwrightAudit trailHistorySupervisor mobileEmployee sign inPrivacyTermsConstructionWorking at heightExcavationCrane liftTransportationForklift operationManufacturingWarehousingOil & gasHot workConfined spaceUtilitiesLockout tagout

© 2026 BISS. All rights reserved.

API reference

The Briefwright API, in one page.

Read the future v1 surface for meetings: the three endpoints, the headers we will require once the API-key program opens, and the lifecycle states each meeting walks through. Every example below is a curl-against-the-stub and the response is parsed by the same shared contract the handler returns.

Base URL

/api/v1
A small public surface for the future meeting workflow. The endpoints below are documented ahead of the v1 launch; each example request on this page resolves against a live stub so you can copy and try.

Required headers

authentication placeholder
Future v1 will gate every request under an API-key program. The stub accepts the header (and ignores it) so example curl flows already work end to end.
HeaderValueNote
AuthorizationBearer <api-key>Placeholder for the upcoming API-key program. The stub serves unauthenticated requests regardless of this header; production v1 will reject requests without a valid key.
Content-Typeapplication/jsonRequired on POST endpoints; the stub will echo it back, document the v1 contract.
POST
/api/v1/meetings
live now
Create a meeting
POST creates a meeting in PLANNED state. The v1 server persists hazards + controls under `briefJson.sections` so a brief can be generated later without re-asking the supervisor, and returns the created row including the lifecycle status, server-assigned id, and the timestamp the row was persisted.

Auth

Required. Signed-in callers only. The stub uses the deployed session cookie; future v1 will additionally require an API-key in `Authorization: Bearer <key>`.

Scheme: session

Request body

{
  "title": "Tower 3 — tower crane pick",
  "industry": "construction",
  "job": "crane-lift",
  "location": "Site B, Bay 4",
  "crew": "Tower-3",
  "hazards": ["fall from height", "suspended load"],
  "controls": ["harness + tie-off", "tag-line on every pick"]
}

Request fields

FieldTypeNote
titlestring (1..140)Free-text headline.
industrystring (1..80)e.g. 'construction'.
jobstring (1..80)e.g. 'crane-lift' — the day's work.
locationstring (1..160)On-site location label.
crewstring (1..160)Crew identifier.
hazardsstring[] (≥1)Staged into briefJson.sections.hazards.
controlsstring[] (≥1)Staged into briefJson.sections.controls.

Response shape

{
  "id": "cm123abc...",
  "title": "Tower 3 — tower crane pick",
  "industry": "construction",
  "job": "crane-lift",
  "createdAt": "2026-08-15T08:30:00.000Z",
  "status": "PLANNED",
  "meta": {
    "apiVersion": "v1",
    "documentationUrl": "/docs/api"
  }
}
FieldTypeNote
idstringServer-assigned meeting id (cuid).
titlestring | nullFree-text headline; null when the meeting has no title yet.
industrystring | nulloptional
jobstring | nulloptional
createdAtISO-8601 stringrequired
status'PLANNED' | 'IN_PROGRESS' | 'COMPLETE'required
meta.apiVersion'v1'required
meta.documentationUrl'/docs/api'Canonical link to the API reference for the current API version.
GET
/api/v1/meetings
live now
List meetings
GET returns the meetings the caller owns, ordered newest first. The stub returns an empty data array on every request — the production endpoint will hydrate the array with the rows the API-key is scoped to.

Auth

Required. Signed-in callers only; the v1 surface is not the public history feed at /api/meetings (which the dashboard already consumes).

Scheme: session

Response shape

{
  "data": [],
  "meta": {
    "apiVersion": "v1",
    "documentationUrl": "/docs/api"
  }
}
FieldTypeNote
dataMeetingItem[]Hydrated meeting rows; the stub returns an empty array.
meta.apiVersion'v1'required
meta.documentationUrl'/docs/api'Canonical link to the API reference for the current API version.
POST
/api/v1/meetings/<meeting-id>/sign-in
live now
Record a meeting sign-in
POST appends a sign-in row to the meeting whose id is in the path. The v1 server stamps `attendanceRecorded: true` on the parent meeting and flips the Job to IN_PROGRESS on the first row.

Auth

Required. Signed-in callers only. The parent meeting must already exist (typically produced by POST /meetings earlier in the workflow).

Scheme: session

Request body

{
  "name": "Alex Rivera",
  "employeeNumber": "B-0042",
  "signatureSvg": "<svg viewBox=\"0 0 480 180\"><path d=\"M10 90 L470 90\"/></path></svg>",
  "supervisorAckName": "Pat Chen"
}

Response shape

{
  "id": "cm123abc...",
  "meetingId": "cm456def...",
  "name": "Alex Rivera",
  "employeeNumber": "B-0042",
  "signatureSvg": "<svg viewBox=\"0 0 480 180\"><path d=\"M10 90 L470 90\"/></path></svg>",
  "supervisorAckName": "Pat Chen",
  "supervisorAckAt": "2026-08-15T08:42:00.000Z",
  "createdAt": "2026-08-15T08:42:00.000Z",
  "meta": {
    "apiVersion": "v1",
    "documentationUrl": "/docs/api"
  }
}
FieldTypeNote
idstringrequired
meetingIdstringrequired
namestringFree text; v1 will not enforce roster membership.
employeeNumberstringUnique per meeting — duplicates return 409.
signatureSvgstringCaptured signature; an empty string is treated as unsigned.
supervisorAckNamestring | nulloptional
supervisorAckAtISO-8601 string | nullSentinel for whether the supervisor has acknowledged the row.
createdAtISO-8601 stringrequired
meta.apiVersion'v1'required
meta.documentationUrl'/docs/api'required
POST
/api/meetings/<meeting-id>/attend
live now
Record quick attendance
POST appends an attendance row to the meeting whose id is in the path. This is a public stub distinct from the v1 surface above: it accepts `{ name, trade/role }` and persists through the same `MeetingSignIn` model the public web sign-in form writes through (the `trade` body field is stored as `employeeNumber`). The server also stamps `attendanceRecorded: true` on the parent meeting, matching the v1 sign-in side effect.

Auth

Not required. Public endpoint. No API-key or session is enforced; submitter-side POST curls resolve unauthenticated. The seed rows used by the Try-it demo can be missing — a 404 is fire-once when the parent meeting id does not exist.

Scheme: public

Request body

{
  "name": "Alex Rivera",
  "trade": "Ironworker / CW-2871"
}

Request fields

FieldTypeNote
namestring (1..120)required
tradestring (1..80)Trade or role, e.g. 'Ironworker / CW-2871'.

Response shape

{
  "id": "cm123abc...",
  "meetingId": "cm456def...",
  "name": "Alex Rivera",
  "trade": "Ironworker / CW-2871",
  "createdAt": "2026-08-15T08:42:00.000Z",
  "meta": {
    "documentationUrl": "/docs/api"
  }
}
FieldTypeNote
idstringrequired
meetingIdstringrequired
namestringrequired
tradestringStored under the existing `MeetingSignIn.employeeNumber` column. Duplicates per meeting return 409.
createdAtISO-8601 stringrequired
meta.documentationUrl'/docs/api'Canonical link to the API reference for the current publication.

Live probe

Try the endpoints
Four curl-equivalent requests — three against the v1 stub plus the public/api/meetings/<id>/attend stub. The response for each renders in the panel below; nothing on this page initial-loads, the probes only fire when you press a Try button. The three v1 probes require sign-in (the v1 stubs are auth-gated); an anonymous caller receives a 401 on each. The attend probe is public and accepts any caller.

GET /meetings

curl /api/v1/meetings
// press Try it to capture a live response

POST /meetings

curl -X POST /api/v1/meetings
// press Try it to capture a live response

POST /meetings/<meeting-id>/sign-in

curl -X POST /api/v1/meetings/<meeting-id>/sign-in
// press Try it — POSTs to a deterministic placeholder id (cm123placeholderdocs000000); a not-found error is expected when no such row exists yet

POST /meetings/<meeting-id>/attend

curl -X POST /api/meetings/<meeting-id>/attend
// press Try it — POSTs the sample { name, trade } body to a deterministic placeholder id (cm123placeholderdocs000000); a 404 is expected when no such row exists yet

Lifecycle states

Meeting status values
The three stages every meeting walks through. The full state graph is documented in the same contract shared with the production sign-in / job handlers.
ValueLabelDescription
PLANNEDPlannedThe meeting row exists but no Job has opened the brief; supervisors can still edit the title, industry, and crew before the lift.
IN_PROGRESSIn progressA Job is open against the meeting; the brief is locked, and the sign-in sheet is collecting signatures.
COMPLETECompleteThe Job has closed (with an optional note from the supervisor); the brief and sign-in PDF can both be exported from this state.