API reference

The Relayfile v1 HTTP API: Bearer auth, the workspace filesystem endpoints (tree, file, bulk, events), and the sync and writeback surfaces.

The Relayfile data plane is a plain HTTP API. Every workspace operation — reading the tree, reading and writing files, ingesting webhooks, checking sync status — is a request against /v1/workspaces/{workspaceId}/.... The full machine-readable contract is the OpenAPI spec in the repo at openapi/relayfile-v1.openapi.yaml; this page is the runnable summary.

Authentication

Authenticated requests carry a Bearer token and a correlation ID:

export RELAYFILE_BASE_URL=http://127.0.0.1:8080
export RELAYFILE_WORKSPACE=ws_live
export RELAYFILE_TOKEN="$(./scripts/generate-dev-token.sh ${RELAYFILE_WORKSPACE})"
export RELAYFILE_CORRELATION_ID="corr_$(date +%s)"

Every authenticated call includes:

-H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
-H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}"

X-Correlation-Id is required on authenticated HTTP requests — it's used for traceability and auditability across requests. Tokens are scope-aware: the OpenAPI contract defines fs:read and fs:write scopes, and the data plane enforces them. Do not send X-Workspace-Id; the routing layer sets it internally.

Use the rw_… workspace ID returned by mount-session / join for every data-plane call — never the request-side app UUID. Passing an app UUID returns 404 workspace_not_found. The SDK resolves this for you; raw-HTTP callers must resolve it first.

Health

GET /health returns a liveness response and requires no auth:

curl -sS "${RELAYFILE_BASE_URL}/health" | jq .

Filesystem

The filesystem endpoints are the core surface. All are scoped to a workspace.

List a tree

GET /v1/workspaces/{workspaceId}/fs/tree lists files and directories under a path.

curl -sS \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/fs/tree?path=/&depth=2" | jq .

Read a file

GET /v1/workspaces/{workspaceId}/fs/file reads one file.

curl -sS \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/fs/file?path=/README.md" | jq .

Write a file

PUT /v1/workspaces/{workspaceId}/fs/file creates or updates one file.

curl -sS -X PUT \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}" \
  -H "Content-Type: application/json" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/fs/file" \
  -d '{ "path": "/docs/guide.md", "content": "# agent guide", "contentType": "text/markdown" }' | jq .

Delete a file

DELETE /v1/workspaces/{workspaceId}/fs/file deletes one file.

curl -sS -X DELETE \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/fs/file?path=/docs/guide.md" | jq .

Bulk write

POST /v1/workspaces/{workspaceId}/fs/bulk writes many files in one request.

curl -sS -X POST \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}" \
  -H "Content-Type: application/json" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/fs/bulk" \
  -d '{ "files": [ { "path": "/src/app.js", "content": "console.log(1);", "contentType": "application/javascript" } ] }' | jq .

Other filesystem endpoints

EndpointPurpose
GET .../fs/events?path=/&limit=20Read the filesystem event feed
GET .../fs/query?path=/documents&...Structured metadata query (filters synced metadata, not path)
GET .../fs/export?format=json|tar|patchExport visible files, optionally scoped with path=
GET .../fs/ws?token=...Upgrade to a WebSocket stream of real-time changes

fs/query matches against each file's synced provider/semantics metadata, not the path prefix — a provider's content is only queryable if its sync tags that metadata. For reads over un-tagged providers, prefer fs/tree + fs/file. The SDK wraps all of these as listTree, readFile, writeFile, bulkWrite, deleteFile, queryFiles, and subscribe.

Sync

Inspect and drive provider sync for a workspace:

EndpointPurpose
GET .../sync/statusWorkspace sync status (per-provider readiness)
GET .../sync/ingressIngress queue and reliability counters
GET .../sync/dead-letterList dead-letter envelopes
POST .../sync/dead-letter/{id}/replayReplay one dead-letter envelope
POST .../sync/dead-letter/{id}/ackAcknowledge a dead-letter envelope
POST .../sync/refreshTrigger a sync refresh
curl -sS \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: ${RELAYFILE_CORRELATION_ID}" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/sync/status" | jq .

Webhooks and writeback

Push normalized provider events in, and drive outbound writeback work:

EndpointPurpose
POST .../webhooks/ingestSubmit a provider-agnostic webhook into a workspace
POST /v1/internal/webhook-envelopesInternal envelope ingest (trusted callers; may require HMAC in prod)
GET .../writeback/pendingList outbound writeback items awaiting a provider
POST .../writeback/{itemId}/ackAcknowledge a processed writeback item
curl -sS -X POST \
  -H "Authorization: Bearer ${RELAYFILE_TOKEN}" \
  -H "X-Correlation-Id: webhook_test_1" \
  -H "Content-Type: application/json" \
  "${RELAYFILE_BASE_URL}/v1/workspaces/${RELAYFILE_WORKSPACE}/webhooks/ingest" \
  -d '{ "provider": "salesforce", "event_type": "file.updated", "path": "/salesforce/Account_123", "data": { "content": "Account details", "contentType": "text/plain" }, "delivery_id": "sf_evt_123" }' | jq .

Operations and admin

GET .../ops, GET .../ops/{opId}, and POST .../ops/{opId}/replay list, fetch, and replay workspace operations. The admin plane (/v1/admin/...) exposes backend config, cross-workspace ingress and sync health, and envelope/op replay. Most workspace and admin endpoints use Bearer auth; internal ingress may use service-to-service signing in production.