Skip to main content

Edge API

The Edge web app is a plain client of a REST API under /api/v1. Everything the app does, you can do with the API. The full endpoint reference is the Edge API reference, rendered from entrosity-edge.backend/api/openapi.yaml, the spec the server's router and request validation (and the app's TypeScript types) are generated from.

Conventions​

  • Base URL: https://hub.entrosity.com/edge/api/v1 (the proxy strips /edge). The connector API is under /edge/api/connector/v1 (Edge connector protocol).
  • Authentication: Authorization: Bearer <product token>, a five-minute token from Entrosity Hub for the product edge (POST /api/platform/v1/auth/product-token {"product":"edge"} with the Hub's session, Hub API). Edge has no sign-in of its own; users, tenants and roles come from the Hub.
  • Access rules: every route has a rule in entrosity-edge.backend/internal/http/portal/access.go: public, signed in, global admin, or a tenant permission (Roles and permissions). Tenant users may only call /tenants/{their tenant id}/…; any other tenant answers 404. A missing permission answers 403.
  • JSON bodies with snake_case keys, at most 1 MB. Request schemas refuse unknown fields (422).
  • Lists: cardholders, cards, the audit logs and the admin tenant list take ?page=&page_size= (default 50, maximum 200) and return items, page, page_size and total. Other lists return all items.
  • Access log: GET /tenants/{tenantID}/events is newest first with keyset pagination: limit (1–500, default 100), filters from, to, door_id, controller_id, cardholder_id and type (repeat for several). The answer has items, has_more and, when there is more, next_before_at and next_before_id to pass as before_at and before_id.
  • Rate limit: 20 requests per second per client IP, burst 60 (EDGE_API_RATE_PER_SECOND, EDGE_API_RATE_BURST); 429 beyond.
  • Every response carries X-Request-ID.

Errors​

Errors are RFC 7807 application/problem+json with a stable code:

{
"type": "/problems/card_already_registered",
"title": "Conflict",
"status": 409,
"code": "card_already_registered",
"detail": "a card with this number is already registered",
"request_id": "…"
}

Validation errors have code: "validation" and fields with a message per field. All codes: Error codes.

Asynchronous operations​

Some calls start a job on the connector and return the job at once:

CallJobResult
POST /tenants/{tenantID}/connectors/{connectorID}/discover {driver, transport?, addresses?}edge.discover{controllers: [{driver, target, model, serial, firmware, door_mode}]}
POST /tenants/{tenantID}/controllers/{controllerID}/testedge.controller.test{driver, target, model, serial, firmware}
POST /tenants/{tenantID}/doors/{doorID}/openedge.door.opennone; the event door_opened_remote follows

Poll GET /tenants/{tenantID}/jobs/{jobID} until status is succeeded, failed, timeout or cancelled; result, error_code and error carry the outcome. Discovery and door opening need an online connector (409 connector_offline).

Configuration syncs are not started by the API: every change that affects a controller schedules one (Configuration sync). POST /tenants/{tenantID}/controllers/{controllerID}/sync forces a full resend.

Controller PINs​

A TrackBase002 controller's PIN is write-only:

  • POST /tenants/{tenantID}/controllers and PATCH /tenants/{tenantID}/controllers/{controllerID} take pin (integer, 1–4294967294). Only the driver trackbase002 has a PIN: for any other driver pin is a 422 validation error on the field pin.
  • The update also takes clear_pin: true, which removes the PIN; pin and clear_pin together are a 422.
  • Controllers are returned with pin_set (boolean); the PIN itself is never returned, and the audit log records only whether one is set.
  • Edge stores the PIN encrypted with EDGE_MASTER_KEY. Without it, setting or clearing a PIN answers 409 master_key_missing.
  • A new or cleared PIN, like a new address, transport or unit id, sends the controller's configuration again (Edge connector protocol).

Connector updates​

  • Connectors carry update_channel (stable or beta), the capabilities of their last hello (edge_update: the connector updates itself), and update_version and update_offered_at: the release last offered to it. Tenant admins change the channel with PATCH /tenants/{tenantID}/connectors/{connectorID} {"update_channel": "beta"}.
  • GET /admin/connector-releases (global admins) lists the stored releases, newest version first, with signing_enabled and the public_key connector builds must embed.
  • CI publishes releases with POST /admin/connector-releases?version=&channel=stable|beta&notes=, Authorization: Bearer <EDGE_RELEASE_TOKEN> (not a Hub token) and the raw MSI as the body (application/octet-stream, at most 64 MiB). This call is not in the API reference; see Running Entrosity Edge.

Live updates​

The app receives live updates as server-sent events:

  1. POST /auth/sse-token {"tenant_id": …} returns a token valid for 60 seconds, bound to the tenant and the session.
  2. GET /tenants/{tenantID}/stream?sse_token=<token> (or with the bearer token) streams text/event-stream, with a keep-alive comment every 25 seconds.
EventData
access.eventsAn array of new access log entries (as in the list API).
controller.status{controller_id, status, error?}
controller.sync{controller_id, sync_status, error?}
door.state{door_id, controller_id, open, locked}
connector.status{connector_id, status} (online, offline, deleted)
job.updateA connector job changed state.

Sensitive actions​

Deleting an enrollment token permanently (POST /tenants/{tenantID}/enrollment-tokens/{tokenID}/delete) is for global admins and needs a step_up_token: the Hub issues it for the admin's password (POST /api/platform/v1/auth/step-up, product edge, Hub API).