The hub's HTTP surface, discovery, headers, and timings.
The hub exposes two surfaces: a display surface the paired phone uses (LAN,
session-token gated), and an admin surface the MCP uses (localhost only,
write-token gated). Widgets themselves never call these — the native app does.
Display surface (LAN, session token)
| Path | Method | Purpose |
|---|
/widget/:id | GET | Widget HTML |
/widget/:id/icon | GET | Icon PNG bytes (404 if not a png icon) |
/api/data/:id | GET / POST | The widget’s JSON feed |
/api/data/:id/stream | GET | SSE push channel |
/active | GET | Active widget + version |
/widgets | GET | List of widgets |
/control | WS | Control channel |
/pair | POST | Pairing handshake |
/api/action/:widgetId/:actionId | POST | Invoke an action |
/api/pulse | POST | Side-effect-free UI echo |
/api/capability/:name/request | POST | Request a Mac capability |
/api/active/:id | POST | Phone switched the active widget |
/api/widget/:id/versions | GET | Version history |
/api/widget/:id/revert/:version | POST | Revert to a version |
/api/widget/:id/delete | POST | Delete a widget |
Admin surface (127.0.0.1, write token — MCP only)
| Path | Purpose |
|---|
/admin/publish | Publish a widget |
/admin/update | Update a widget |
/admin/set-active | Set the active widget |
/admin/list | List all widgets |
/admin/delete | Delete a widget |
/admin/data/:id | Push JSON data |
/admin/data-endpoint/:id | Get a widget’s data URL + token |
/admin/pair-status | Pairing status |
/admin/set-icon | Set/replace an icon |
/admin/versions/:id | Version history |
/admin/revert | Revert a widget |
/admin/register-action | Register an action (debug) |
Discovery (mDNS / Bonjour)
service type: _perch._tcp
domain: local.
Authorization: Bearer <token> # tokens ride in headers, never URLs
X-Perch-Schema: <version> # wire schema version
Timings
| Constant | Value |
|---|
| Default data poll interval | 1500 ms |
| Pairing token TTL | 120 s |