Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.myme.so/llms.txt

Use this file to discover all available pages before exploring further.

Marfa emits live events on a per-tenant Server-Sent Events stream. Clients that need to reflect changes in real time subscribe to GET /events.

Connecting

GET /events HTTP/1.1
Host: marfa.example.com
Authorization: Bearer <token>
Accept: text/event-stream
The connection stays open. The server streams events as they occur, each on its own SSE record:
id: 019d9154-...
event: item.created
data: {"id":"019d...","type":"core.note",...}

id: 019d9155-...
event: edge.created
data: {"id":"...","edge_type":"about","source_id":"...","target_id":"..."}

: ping
Comments (lines starting with :) are heartbeats. The server sends one every ~30 seconds. Treat an idle stream longer than 60s as disconnected and reconnect.

Event types

Payloads are filtered by the subscriber’s permissions — the server won’t stream events for items or edges the credential can’t read.
EventPayload
item.createdFull item object.
item.updatedFull item object (after update).
item.state_changedFull item object (after transition).
item.deleted{ id, type }.
item.restoredFull item object (after restore).
edge.createdFull edge object.
edge.deleted{ id, edge_type, source_id, target_id }.
metadata.changed{ item_id, tags, tier, state }.

Filtering

Clients can subscribe to a subset of events:
GET /events?event=item.created,item.updated
GET /events?type=core.note                 # item events only for this type (and subtypes)
GET /events?edge_type=in-thread            # edge events only for this type
Filters apply on the server; unwanted events never leave the stream.

Reconnecting with Last-Event-ID

On reconnect, the client sends the Last-Event-ID header with the last event id it received:
GET /events HTTP/1.1
Last-Event-ID: 019d9154-...
The server replays events that occurred after that id from its event log, then transitions to live streaming. This is gapless for events within the log’s retention window (default 7 days). The EventSource API in browsers handles Last-Event-ID automatically. Non-browser clients (SDKs, server-to-server consumers) should persist the most recent event id and re-send it on reconnect.

When the event log is stale

If Last-Event-ID is older than the event log retention window, the server replies with a terminal event indicating the gap:
event: catchup_too_old
data: {"message":"Last-Event-ID predates the event log retention window","earliest_available":"..."}
Clients should recover by falling back to an incremental GET /items?updated_after=<timestamp>&limit=... sweep (paginated), then reconnect to live streaming. This path doesn’t surface deletes — items deleted during the gap aren’t returned. A subsequent SSE delete event will reconcile on receipt. Clients that need deterministic delete reconciliation after long outages should keep the SSE stream within retention or re-seed the local store.

Catch-up strategy

A typical sync engine follows this pattern:
1

First connection

Connect to GET /events without Last-Event-ID. Persist the most recent id received.
2

Live streaming

Apply events as they arrive. Persist Last-Event-ID on each event.
3

Reconnect on disconnect

Send persisted Last-Event-ID. Server replays from that point.
4

Handle `catchup_too_old`

Fall back to GET /items?updated_after=<last_sync_timestamp> with pagination. Reconnect live after catch-up completes.

Keepalive

The server sends :ping comment frames every ~30 seconds. Clients should close the connection and reconnect if no event (including pings) arrives for > 60 seconds — the connection is likely dead even if the TCP socket is open.

Scale

SSE is single-process on the emitting server. For deployments behind load balancers or multi-instance setups, configure sticky sessions or use the webhook delivery system instead — webhooks are durable and don’t require persistent connections.

SSE vs webhooks

Use caseUse
Live UI that updates as data changesSSE
Long-running server ingesting eventsSSE (or webhooks with a local queue)
Triggering workflows in external systemsWebhooks
Integrating with services that expect HTTP POSTWebhooks
Both fire on the same event surface — an item creation produces both an SSE event and a webhook delivery. Use whichever matches your consumer.