EDR replication protocol reference

v1 in /edr/v1/* is the EDR replication protocol’s own version. It has no relationship to InfluxDB v1. EDR sources from InfluxDB 3 Enterprise and replicates to InfluxDB 3 Enterprise, InfluxDB 3 Cloud, or AWS Timestream for InfluxDB 3.

Agent-to-agent communication is HTTP-based. The downstream facet serves the endpoints below. The upstream agent connects (/connect), then sends data batches (/data) and periodic reports (/report, default every 10 seconds). The report carries the upstream’s health and, when share_topology is enabled, the tree of upstreams behind it—this is how a central node assembles a full network picture without direct connectivity to every edge.

The HTTP response acknowledges each data batch synchronously. The upstream’s replication cursor advances only on confirmed delivery.

Replication protocol endpoints

These endpoints carry the EDR agent-to-agent replication protocol (/edr/v1/*), not an InfluxDB 3 API.

EndpointMethodPurpose
/edr/v1/connectPOSTHandshake: upstream declares identity, scope, comms expectations, topology. Sent only between agents negotiating protocol v2 or below; not sent between v3 peers.
/edr/v1/dataPOSTData batches in Line Protocol (LP) or zstd-compressed PT format.
/edr/v1/reportPOSTPeriodic status report: health, progress, upstream topology. Default interval 10 seconds.
/healthGETLiveness.

Observability API endpoints

These endpoints expose an EDR agent’s own replication metrics and status, not InfluxDB 3 data.

EndpointMethodPurpose
/metricsGETPrometheus-format metrics for both facets, including send/receive byte and row counters, per-tier queue depths (edr_upstream_tier_queue_depth{tier=...}), cursor positions, retry counts, gap and historic fill progress, and over-replication counters.
/edr/v1/metrics_jsonGETThe same data as structured JSON, including the tier_depths array, for programmatic consumption and the UI.
/edr/v1/statusGETThis node’s replication state: facets, channels, health, cursors, backlog.
/edr/v1/topologyGETThe replication network as known to this node (its upstream tree, assembled from reports, plus its downstream link).
/edr/v1/logsGETRecent structured log entries.
/edr/v1/node_infoGETNode identity, role, location, outbound health, and outbound metric snapshots.
/edr/v1/eventsGETServer-Sent Events (SSE) stream that fires when state changes, used by the UI for live updates without polling.
/uiGETEmbedded web UI.

Halt fields

GET /edr/v1/node_info returns the outbound metric snapshot under upstream_facet when the agent has one destination. For multiple destinations, read each snapshot under upstream_facet_by_destination[].

Use these values to interpret the halt fields in either snapshot:

FieldValueMeaning
replication_halted0Replication isn’t halted.
replication_haltedPositive integerThe value counts halted batches.
last_write_result0The agent hasn’t attempted a write.
last_write_result1The last write succeeded.
last_write_result2Authentication failed.
last_write_result3A schema conflict blocked the write.

edr-inspect metrics translates last_write_result into last-write=unknown, last-write=success, last-write=auth_failure, or last-write=schema_conflict. When replication_halted is greater than 0, the command also prints the REPLICATION HALTED: N batch(es) message.

The replication protocol endpoints and /health are served on the network listener (--listen, default 0.0.0.0:9090). The observability endpoints are served on the observability listener (--observability-listen, loopback 127.0.0.1:9091 by default). See CLI reference.

Logging is structured JSON (tracing) covering replication progress, connection state changes, errors and retries, configuration changes, gap advisories, and historic fill recovery decisions (including every loud over-replication warning). Significant state changes and exceptions are additionally emitted through the audit service provider interface (SPI) (stdout implementation initially).

Protocol version negotiation

Directly connected agents negotiate a protocol version and a capability set, per hop—never propagated along a relay chain (a bad hop reports at that hop; the rest of the chain is unaffected).

  • Protocol v1 is the name for the wire behavior of agents released before versioning existed (0.1.x and 0.2.x). Those agents send no version fields. EDR interprets missing version fields as protocol v1. The protocol v1 behavior hasn’t changed.
  • Protocol v2 (interim development builds; never in a released version) added explicit protocol negotiation. Protocol v2 agents negotiate at /connect. The /connect request gates /data. The /data endpoint returns HTTP 428 until the agents connect.
  • Protocol v3 (current) uses the stateless data path. Every /report includes the upstream agent’s full declaration: identity, location, communication settings, agent version, and protocol declaration. The downstream agent returns its declaration in the ReportAccept response. Both agents negotiate the protocol on every report. A response without a downstream declaration identifies a protocol v2 or earlier agent. Every /data request includes a compact declaration in the X-EDR-Name, X-EDR-Protocol: <declared>,<min>, and X-EDR-Caps headers. Protocol v3 peers never send /connect. The /data endpoint requires no prior contact. Any receiver instance can serve any request. This stateless behavior supports receiver fault tolerance and load balancing.
  • Both agents calculate the same agreement. The effective version is the lower of the two declared versions. An agent refuses the connection if the effective version is lower than either agent’s minimum. An effective version below protocol v3 selects the v2 connect-gated flow. Mixed-version fleets require no additional configuration.
Upstream \ Downstream0.1.x / 0.2.x (v1)interim dev builds (v2)1.0.0-0.rc.1+ (v3)
0.1.x / 0.2.xv1 (implicit)v1—acceptedv1—accepted
interim dev buildsv1—acceptedv2, connect-gatedv2, connect-gated
1.0.0-0.rc.1+v1—acceptedv2, connect-gatedv3, stateless

With the current minimums, no released pairing can be refused. The first possible refusal requires a future release that deliberately raises its minimum—a compatibility break that will be called out in release notes.

Refusal

Refusal is explicit and terminal. The refusing side answers HTTP 426 (on /connect, /report, or /data) with a diagnosis naming both versions and both minimums; the upstream latches a protocol halt: dispatch stops (nothing pops from any tier), health reads Halted, the reason appears in the status API, the UI, and the logs, and a PROTOCOL-HALTED WARN repeats once a minute while halted. Negotiation re-runs on every report (default 10s), so a peer upgrade clears the halt within one report interval—there’s no separate probe task. See Troubleshoot EDR.

Capabilities

Capabilities gate optional features (the version gates wire-breaking changes). Initial registry: pt-wire-1—the PT wire format (encoding: pt). A downstream that negotiates successfully but lacks a capability the local config requires produces the same protocol halt, with a message naming the config key.

Security and tokens

  • TLS is required for all upstream-downstream communication in production deployments.
  • Token-by-name model: the YAML config references tokens by name; values are resolved at runtime from the token store (file-based directory, one token per named entry, validated at startup). Config files are therefore safe to version and share.
  • Authentication: each upstream presents its auth token when connecting; the downstream maps the token to the expected upstream identity (upstreams[].auth_token).
  • Authorization by the destination: the downstream writes each upstream’s data using that upstream’s write_token against the local InfluxDB 3 instance. The token’s permissions on the destination determine what the upstream can effectively write—EDR implements no authorization layer of its own. Restricting or revoking an upstream is done by scoping or revoking its tokens.

See Manage tokens for token store operations.


Was this page helpful?

Thank you for your feedback!