Heartbeat presence and maintain the advisory editing lock
workflow:readOne poll that does three things: records that you have this workflow open, maintains or acquires the ADVISORY editing lock, and carries the take-over handshake — all in a single round trip.
The lock is advisory. It does not refuse writes; the real guards are expectedRev (optimistic locking) and the per-flow write lock the server takes around every mutation. Its purpose is to let a client show "someone else is editing" and go read-only.
Presence evaporates on its own: stop beating and you disappear within about 30 seconds, so a closed tab needs no cleanup. Beat at beatEverySeconds from the response — the server owns the interval, do not hard-code one.
mine is computed server-side. Never compare user ids yourself: sessions and machine principals make that comparison wrong.
The takeover handshake:
"request"— ask the current holder to hand over. The holder sees it in their next beat'stakeover. If they do not respond, the requester can claim the lock after a ~30-second grace, so an away holder can never strand a workflow."grant"— sent by the HOLDER to hand the lock over now. There is deliberately no "decline": the service has none, and offering one would be a lie."force"— the admin override. It is checked HERE against the caller'sworkspace:managepermission, never trusted from the client; without it the call is 403 (note: 403 for this operation is a permission check on thetakeovervalue, not onworkflow:read).""or omitted — an ordinary beat.
editing: true means "I am an editor surface" and asks for the lock when it is free. editing: false is a passive viewer that only registers presence.
Authorization
bearerAuth An API token: Authorization: Bearer grt_…. Mint one in the app under Settings → Workspace → API tokens; the raw value is shown once. Scopes confine the token — see x-permission on each operation.
In: header
Path Parameters
Workflow id (UUID). A malformed id answers 404 here, not 400 — presence never discloses whether a flow exists.
uuidRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/workflows/497f6eca-6276-4993-bfeb-53cbbbba6f08/presence" \ -H "Content-Type: application/json" \ -d '{}'{ "data": { "editors": [ { "userId": "string", "name": "string", "since": "2019-08-24T14:15:22Z", "keel": true } ], "lock": { "userId": "string", "name": "string", "since": "2019-08-24T14:15:22Z", "keel": true }, "mine": true, "takeover": { "userId": "string", "name": "string", "since": "2019-08-24T14:15:22Z" }, "beatEverySeconds": 0 }}