Streaming flag changes
Instead of polling for changes, open a Server-Sent Events stream and let Flagonic tell you the moment a flag in your project is created, updated, toggled, or deleted. OFREP does not define streaming yet, so this endpoint is a Flagonic extension — your evaluation calls stay pure OFREP.
The endpoint
With an SDK key (fgn_sdk_…), open a long-lived GET request.
The stream is scoped like every SDK-key call: you hear about changes to your key's project,
nothing else.
curl -N https://flags.example.com/api/v1/stream \
-H "Authorization: Bearer $FLAGONIC_SDK_KEY"
# retry: 3000
#
# event: change
# data: {"version":"3a5b9c…"}
What you receive
event: change | The project's flag configuration changed. data is a JSON object with a single version field. |
version | An opaque identifier for the current flag configuration. Equal versions mean nothing changed; you never need to parse it. |
retry: 3000 | Standard SSE reconnect hint, sent once on connect. |
: ping | Heartbeat comment every 25 seconds so idle connections survive proxies and load balancers. Ignore it. |
One change event arrives immediately on connect carrying the
current version. Remember the last version you acted on: if the connect event matches it,
you missed nothing while disconnected and can skip the refetch.
Reacting to a change
The event deliberately carries no flag data — your evaluation results depend on your own context, so the stream just tells you when to re-evaluate. On each new version, re-run bulk evaluation:
POST /ofrep/v1/evaluate/flags
A minimal Go consumer (any language with an SSE or line-reading HTTP client works the same way):
req, _ := http.NewRequest("GET", base+"/api/v1/stream", nil)
req.Header.Set("Authorization", "Bearer "+sdkKey)
resp, err := http.DefaultClient.Do(req)
if err != nil { /* back off and reconnect */ }
defer resp.Body.Close()
sc := bufio.NewScanner(resp.Body)
var last string
for sc.Scan() {
data, ok := strings.CutPrefix(sc.Text(), "data: ")
if !ok {
continue // event name, heartbeat, or blank separator
}
var ev struct{ Version string }
if json.Unmarshal([]byte(data), &ev) == nil && ev.Version != last {
last = ev.Version
refreshFlags() // re-run bulk evaluation
}
}
EventSource cannot send headers. The stream
authenticates with a bearer token, which the browser EventSource API cannot
attach — and an SDK key does not belong in frontend code anyway. Consume the stream from
your backend (or an edge proxy) and fan changes out to browsers yourself.
Reliability notes
- Reconnect with backoff. Honor the
retryhint, then compare the version in the connect event against the last one you processed to decide whether to refetch. - Bursts coalesce. Several rapid changes may arrive as a single event with the final version — you always converge on the latest configuration.
- Every instance hears every change. With the Postgres backend, a change made through any Flagonic instance reaches streams held by all instances, so streaming works behind a load balancer.
- Polling still works. Bulk evaluation keeps its ETag / If-None-Match support; streaming is an optimization, not a replacement. If the stream drops, fall back to polling until it is re-established.