Pulse
How collectors stay in sync with Mend delivery state through the Spanly-Pulse response header.
Pulse is the sync mechanism between the Spanly ingest API and the collectors (TypeScript SDK, Python SDK, and CLI). It tells a running collector when the Mend delivery state for its environment has changed, without adding any request, latency, or failure mode to data ingestion.
The Spanly-Pulse header
Every ingest API response for an authenticated environment carries:
Spanly-Pulse: <digest>The digest is a content hash of the environment's current delivery state (the active patches being served). It changes if and only if the delivery state changes.
Collectors read the header on every flush and compare it to the digest of the state they currently hold:
- Same digest: nothing to do.
- Different digest: fetch the new state in the background with
GET /mend/state/:digest. - Header absent: keep the current state. The server omits the header when the digest is not cached yet or the cache is unreachable; it recomputes in the background and the header returns on a later response.
The header is set on all responses where the API key resolved to an
environment, including error responses such as 400 and 503, so a
failed flush can still deliver a fresh digest. Responses rejected
before authentication (401, or 503 while key validation is
unavailable) carry no header.
Fetching delivery state
Both endpoints live on the same base URL as /collect and use the
same Authorization: Bearer <api key> header.
GET /mend/state/:digest
Returns the delivery-state document when :digest is the
environment's current digest. The response is content-addressed and
immutable (Cache-Control: immutable, max-age=31536000), so it can be
cached forever.
If the digest is no longer current, the endpoint returns 404 with
{ "error": "unknown_digest" }. The collector keeps its current state
and picks up the fresh digest from the Spanly-Pulse header on its
next flush, or resyncs through /mend/state/current.
GET /mend/state/current
Returns { "digest": "<digest>" }, the environment's current digest.
Use it to resync after a 404, or at startup before any flush has
observed a Pulse header.
Digest computation
The digest is the lowercase hex SHA-256 of the delivery-state document serialized as canonical JSON: object keys sorted ascending by UTF-16 code units, no whitespace, arrays kept in order, members with undefined values dropped. Every producer and consumer derives the same digest from the same document, which is what makes the fetch URL content-addressed.
Fail-open rules
Pulse never interferes with monitoring or with your MCP traffic:
- A missing header means keep the current state; it is never an error.
- State fetches run in the background and never delay a flush.
- A failed state fetch leaves the current state in place; the collector retries on a later flush.
- If the collector cannot obtain any delivery state, it serves your server's manifest untouched.