HTTP API reference
This is a curated reference for the current public Bridge and its released clients. It covers authorized application data and public download metadata, not platform operations or the private device transport protocol.
Base origin: https://forge.readyit.dk.
Routes below are relative to that origin.
Authentication, selection and JSON
Human application requests use a valid bearer access token for Forge and the
X-Forge-Workspace-Id header selecting an authorized workspace UUID.
Use the supported login flow; do not extract credentials from a profile or
paste tokens into documentation, logs or customer messages.
GET /api/v1/tenants discovers the authenticated identity's memberships
before selection. The header selects among existing memberships; it grants
no authority. Human Admins and Technicians have ordinary workspace-wide
access under the current workspace-humans-v2 policy. Settings, accounts,
roles and invitations remain Admin-only.
Machines retain explicit test scope and are denied human directory, case, overview and generic history APIs. A human role claim does not turn a machine principal into a human.
Send request objects as application/json. Wire fields are snake_case; UUIDs
are strings and timestamps use ISO 8601 with an offset. Nullable/optional
response fields may be omitted. DTO names below identify documented wire
contracts, not URLs or assembly-download instructions.
HTTP responses contain their actual object, array or page—not the CLI
ok/data/next_actions envelope. Treat customer/history responses as private
and honor Cache-Control: no-store. After a mutation times out, its completion
may be unknown; do not assume it is safe to replay.
Public downloads
These GET routes require no login:
| Route | Result |
|---|---|
/api/v1/client-configuration |
ClientConfigurationDto: public bridge_url, auth0_issuer, auth0_client_id, auth0_audience, expected_publisher. No user credentials or memberships. |
/api/v1/cli/releases/latest?platform=win-x64 |
CliReleaseDto: schema_version, version, platform, expected_publisher, installer, archive. Each artifact contains url, size, sha256. |
/api/v2/cli/releases/latest?platform=linux-x64 |
CliReleaseV2Dto: numeric schema_version, version, platform, signed package, target_payloads. |
/api/v2/cli/releases/linux-x64/{version} |
Metadata for one verified Linux technician release. |
/download/cli/win-x64/latest/installer |
Redirect to the selected Windows setup. |
/download/cli/win-x64/latest/archive |
Redirect to the selected Windows ZIP. |
/download/cli/linux-x64/latest/installer |
Redirect to the selected Linux setup. |
/download/cli/linux-x64/latest/archive |
Redirect to the selected Linux archive. |
/download/cli/linux-x64/latest/manifest |
Redirect to version-specific Linux release metadata. |
PortableArtifactEnvelopeDto contains schema_version, algorithm, key_id,
manifest and signature. The manifest/signature encode exact signed
artifact identity, not a new trust key. Clients must verify with the approved
independently pinned key, not trust arbitrary keys supplied beside a download.
Use supported setup rather than implementing partial signature validation.
When downloading several artifacts, resolve a single release and use its immutable locations; independent latest requests can straddle a release change. Unavailable downloads fail explicitly.
Identity and enrolled devices
| Method | Route | Response |
|---|---|---|
| GET | /api/v1/tenants |
Array of TenantMembershipResponse. |
| GET | /api/v1/me |
TechnicianIdentityResponse for the selected workspace. |
| GET | /api/v1/devices |
Array of authorized DeviceSummaryResponse. |
| GET | /api/v1/devices/{id} |
Authorized DeviceDetailsResponse. |
| PUT | /api/v1/devices/{id}/metadata |
Updated device details; input UpdateDeviceMetadataRequest. |
Key fields:
TenantMembershipResponse:tenant_id,name,role,current, optional legacyauth0_organization_id. Use the Forge workspace ID for selection.TechnicianIdentityResponse:id,subject,display_name, optionalemail,tenant_id,tenant_name,role,device_access_mode.- Device summaries:
id,machine_name,device_identifier,presence,last_seen_at,host_version,is_revoked,platform, optional descriptive labels and connection/transport metadata. - Device details add revocation, current lease/technician and SSH identity information. Compatibility fields do not imply a supported legacy transport; the released path is native relay.
UpdateDeviceMetadataRequest: nullabledisplay_name,primary_user_name,organization_name. These do not update company/contact relationships.
Use forge device connect, exec, upload and download for remote work.
The CLI owns key handling, exclusive leases, grant renewal and relay
admission. There is no generic HTTP “execute a command” API in this reference.
Enrollment sharing
For authorized human device managers:
| Method | Route | Request → response |
|---|---|---|
| POST | /api/v1/enrollment-shares |
CreateEnrollmentShareRequest → CreatedEnrollmentShareResponse. |
| GET | /api/v1/enrollment-shares/{id} |
EnrollmentShareResponse. |
| DELETE | /api/v1/enrollment-shares/{id} |
Updated EnrollmentShareResponse. |
Creation input is label, platform (win-x64 or linux-x64) and optional
expires_at. Null expiry means 24 hours; the maximum is seven days.
The creation response has share and a one-time returned capability url.
Never store that URL in an ordinary request log or operational receipt.
Status includes id, label/platform/release metadata, created_at,
expires_at, state, and optional downloaded_at, consumed_at, online_at
and enrolled_device_id. Status does not return a recoverable capability or
code. Consumption and authenticated online presence are distinct.
Use enrollment guidance for delivery and installation; native code redemption and package trust belong to the signed client, not a browser script.
History and the work map
| GET route | Query and response |
|---|---|
/api/v1/access-sessions |
Optional actor, device, state, since, until, cursor, limit; returns AccessSessionPage. State is active or ended. |
/api/v1/access-sessions/{id} |
Optional cursor, limit; returns AccessSessionDetail. |
/api/v1/access-activity/uncorrelated |
Optional device, cursor, limit; returns UncorrelatedActivityPage. |
/api/v1/temporary-devices |
Optional history, cursor, limit; returns TemporaryDevicePage. history=true selects ended/promoted history. |
/api/v1/temporary-devices/{id} |
TemporaryDeviceDetail, with separately authorized promotion information. |
/api/v1/overview |
Optional customer, case, technician, activity, cursor; returns OverviewSnapshot. Activity is all, active or idle. |
Session pages use items and next_cursor. Session detail instead has
session, events, next_cursor. Session listing defaults to 25 items and
detail to 50; both accept limits 1–100. since is inclusive and until
exclusive on the access period's start.
AccessSessionSummary contains id, actor_id, actor_name, target_kind,
target_id, target_name, started_at, last_observed_at, optional
ended_at, state, end_reason, client_version, host_version.
An AuditEventResponse includes event/actor/target identifiers, outcome,
timestamps, optional version/transfer-hash metadata and provenance.
These are metadata, not commands or file contents.
TemporaryDeviceDetail contains temporary, optional access_session_id,
optional promotion, cleanup_outcome, optional cleanup_observed_at,
and cleanup_provenance. A promotion's health_confirmed_at comes from the
authenticated permanent device; a cleanup observation does not certify
remote process removal. History access does not confer Rescue control.
OverviewSnapshot contains workspace_id, observed_at, policy_version,
customer_context_available, enrolled/online counts, nodes, edges,
groups, omitted_connections, next_cursor. Nodes identify company, case,
technician, device, session or Rescue records. Groups include authorized
total and expanded counts. The bounded map describes explicit
relationships and observed access, not agent jobs or repair progress.
Customer directory
In the table, {collection} is companies or contacts.
| Method | Route | Request → response |
|---|---|---|
| GET | /api/v1/{collection} |
search, archive, cursor, limit; contacts also accept company. Returns CompanyPage or ContactPage. |
| GET | /api/v1/{collection}/{id} |
CompanyDto or ContactDto, including archived records. |
| POST | /api/v1/{collection} |
CompanyWriteRequest or ContactWriteRequest → created DTO, HTTP 201. |
| PUT | /api/v1/{collection}/{id} |
Full write request with current version → updated DTO. |
| POST | /api/v1/{collection}/{id}/archive |
DirectoryVersionRequest → updated DTO. |
| POST | /api/v1/{collection}/{id}/restore |
DirectoryVersionRequest → updated DTO. |
| GET | /api/v1/devices/{id}/customer-links |
DeviceCustomerLinksDto. |
| PUT | /api/v1/devices/{id}/customer-links |
DeviceCustomerLinksRequest → updated links. |
Write fields are display_name (1–200 characters), optional email (one
address, up to 320), optional phone (up to 64), and version for updates.
Contacts add nullable company_id. Omitted optional content fields clear
them during an update. DirectoryVersionRequest is { "version": 1 }, with
the actual current version substituted.
Company/contact DTOs include the content plus id, archived_at, version,
created_at, updated_at. Contacts also return a display-only company
reference. A reference has id, display_name, archived_at.
Device-link input must explicitly include both nullable company_id
and primary_contact_id, plus its independent version. Null unlinks.
The response includes device_id, the IDs, display-only company and
primary_contact references, and the link version.
Pages have items, next_cursor; limit is 1–100, default 25. Archive is
active (default), archived or all. Search is a literal case-insensitive
name substring. Preserve the same filters when continuing a cursor.
See customers for full examples, preserved archived references and non-idempotent create/retry behavior.
Cases and narrative
All routes below start with /api/v1/cases. {id} is the case UUID.
| Method | Suffix | Request → response |
|---|---|---|
| GET | (none) | Optional archive, one of device/session, cursor, limit → CasePage<CaseDto>. |
| POST | (none) | CaseCreateRequest → CaseDto, HTTP 201. |
| GET | /members |
cursor, limit → CasePage<CaseAuthorDto>; existing human collaborators, not account management. |
| GET / PUT | /{id} |
Read CaseDto / replace with CaseWriteRequest. |
| POST | /{id}/status |
CaseStatusRequest → CaseDto. |
| POST | /{id}/close, /reopen, /archive, /restore |
CaseVersionRequest → CaseDto. |
| GET / POST | /{id}/collaborators |
Array of CaseAssigneeDto / CaseAssigneeRequest → CaseDto. |
| DELETE | /{id}/collaborators/{member} |
Body CaseVersionRequest → CaseDto. |
| GET / POST | /{id}/links |
Array of CaseLinkDto / CaseLinkRequest → CaseDto. |
| DELETE | /{id}/links/{link} |
Body CaseVersionRequest → CaseDto. |
| GET / POST | /{id}/notes |
Paged CaseNoteDto / CaseNoteCreateRequest → CaseNoteDto, HTTP 201. |
| GET / PUT | /{id}/notes/{note} |
CaseNoteDto / CaseNoteWriteRequest → updated note. |
| GET | /{id}/notes/{note}/revisions |
Paged CaseNoteRevisionDto. |
| GET / POST | /{id}/drafts |
Paged CaseDraftDto / CaseDraftCreateRequest → CaseDraftDto, HTTP 201. |
| GET / PUT | /{id}/drafts/{draft} |
CaseDraftDto / CaseDraftWriteRequest → updated draft. |
Every lifecycle suffix above is relative to /{id}; for example, reopening
uses /api/v1/cases/{id}/reopen. Paged requests accept cursor and limit
(1–50, default 25), returning items and next_cursor. Requests are limited
to 128 KiB and reject unknown author/review claims.
Request shapes
| DTO | Fields |
|---|---|
CaseCreateRequest |
Required title; optional description, company_id, primary_contact_id, device_id, access_session_id. |
CaseWriteRequest |
Required version, title; replacement description, company_id, primary_contact_id. |
CaseVersionRequest |
Current version. |
CaseStatusRequest |
Current version, status: open, in_progress or waiting. |
CaseAssigneeRequest |
Current case version, user_id. |
CaseLinkRequest |
Current case version, kind: device or session, and target_id. |
CaseNoteCreateRequest |
Required idempotency_key, body; kind defaults to finding, basis to observation; optional source, agent_name, references. |
CaseNoteWriteRequest |
Current note version, replacement note fields; no idempotency key. |
CaseDraftCreateRequest |
recipient_address, subject, body; optional recipient_contact_id. |
CaseDraftWriteRequest |
Current draft version plus replacement draft fields. Every update clears review. |
Case titles allow 200 characters and descriptions 8,000. Note/draft bodies
allow 16,000; draft subjects 300 and recipient addresses 320.
Notes accept kinds finding, action, result, next_step and bases
observation, inference. Each of at most ten references has kind
(device, session, authorized audit) and target_id.
Response and review contracts
CaseDtoincludes metadata, customer references,creator, timestamps,status,closed_at,archived_at,version.CaseAuthorDtocontainsid,display_name,former_member.CaseLinkDtocontains its own unlinkableid,evidence,created_at. Unavailable evidence does not expose a target ID or label.CaseNoteDtocontainsid,creator,created_at,current.currentis an immutable attributed revision containingversion, content, basis/source/agent labels,author,recorded_at,references.CaseDraftDtocontains recipient/contact, subject/body, its own version, author/timestamps,state,reviewed_version,reviewer,reviewed_at. It is a draft, never a delivery receipt.
There is no V1 draft review, reviewed-export or send API. Website review uses an explicit cookie-authenticated, antiforgery-protected action bound to the exact revision. Reviewed copy/download also reauthorizes that revision. API clients cannot assert review. See the case workflow.
Errors and retries
Common status meanings:
| HTTP status | Action |
|---|---|
| 400 | Correct malformed input, unsupported selection or invalid relationship. |
| 401 / 403 | Reauthenticate or verify current membership/feature authority; do not retry under an unrelated identity. |
| 404 | The record is unavailable under current scope; it may be missing or inaccessible. |
| 409 | Reload the current version or resolve lifecycle/idempotency conflict. |
| 413 | Reduce the bounded request body. |
| 429 | Respect throttling; slow down rather than repeating immediately. |
| 503 | Service or verified release unavailable; inspect state before retrying a write. |
Many application failures return { "error": "<code>", "message": "<detail>" }.
Overview has a separate code error field; authorization/routing failures
may not return an application JSON body. Do not assume one universal error
envelope.
Important feature codes include directory_not_found, directory_conflict,
invalid_case, case_conflict, case_archived and case_storage_unavailable.
An identical note-creation retry with the same actor, workspace, key and
payload is idempotent. Other creates do not inherit that guarantee.