Verify the signature
Every attempt has aFluent-Signature header:
v1 value is:
Node.js and TypeScript
This example uses only Node.js built-ins. Pass it the original body bytes, not a parsed object.Language-independent procedure
- Split the header on commas.
- Extract
tand everyv1value. - Parse
tas Unix seconds and reject timestamps more than five minutes from your current time. - Construct the signed bytes as UTF-8
t, then., then the unmodified request-body bytes. - Calculate HMAC-SHA256 using the signing secret as UTF-8 bytes.
- Encode the result as lowercase hexadecimal.
- Compare it with each
v1value using a constant-time function. Accept if any match.
v1 values makes the parser compatible with future signing transitions even though Fluent currently sends one.
Idempotency
Automatic retries send the sameFluent-Event-Id and Fluent-Delivery-Id with a higher Fluent-Attempt. Store the event ID in a table with a unique constraint before performing side effects.
If the event ID already exists, return 2xx without repeating the work. Do not treat a duplicate as an error; an error response causes more retries.
Manual retry starts the completed delivery again. Business idempotency must therefore remain keyed by event ID, even after the automatic retry window ends.
Ordering
Delivery order is not guaranteed. Retries, multiple workers, and concurrent transactions can make a newer state arrive before an older one. Treat each payload as a snapshot. For each document or run, store the greatest appliedsequence and ignore an event with a lower sequence. Sequence values are global and gappy, so do not use missing numbers to detect lost events.
Before an irreversible action, fetch current state from GET /api/v1/documents/{id} or GET /api/v1/runs/{id}. This protects against both stale delivery and a state transition that occurred after the event was created.
Response and retry behavior
Fluent gives each request 10 seconds and accepts any2xx response as success.
Fluent stores at most the first 2,048 bytes of the response body for endpoint diagnostics.
Return
2xx after durably recording the event, then do expensive work asynchronously. A slow synchronous receiver can complete its own operation but still exceed Fluent’s timeout and receive the same event again.
Attempts and endpoint health
Each delivery can make up to six automatic attempts. Fluent records the current attempt, response status, response snippet, error, and duration in the endpoint’s delivery log. A terminal delivery failure increments the endpoint’s consecutive-failure count when the failure came from the customer endpoint. A successful delivery resets the count to zero. Fluent-side preparation errors are retried but do not count against endpoint health. After 20 consecutive terminal failures, Fluent:- Disables the endpoint.
- Marks pending deliveries as failed.
- Stops recording and delivering new events for that endpoint.
- Records the disable reason.
- Emails team administrators once.
Manual retries
Team administrators can open a completed delivery and select Retry. Both succeeded and failed deliveries can be retried while the endpoint is enabled. This resets delivery-attempt diagnostics and places the same event back in the delivery queue. Your event-ID idempotency remains authoritative: retrying a succeeded delivery should not repeat a business side effect unless you intentionally remove or override your deduplication record.Secret rotation
Rotating a signing secret is an immediate cutover. The next delivery uses the new secret, and the previous secret stops verifying without an overlap window. Use this sequence:- Prepare the receiver to read the new secret from your secret manager.
- Rotate the secret in Fluent and copy the newly displayed value.
- Save the value in your secret manager.
- Restart or refresh the receiver so it reads the new value.
- Send a test event.
Network requirements
Webhook destinations must:- Use HTTPS.
- Have no username or password in the URL.
- Resolve to public IPv4 or IPv6 addresses only.
- Accept the request without an HTTP redirect.
- Respond within 10 seconds.
Receiver checklist
- Preserve the raw body and verify
Fluent-Signaturefirst. - Keep clocks synchronized so the five-minute replay window is reliable.
- Enforce a unique constraint on
Fluent-Event-Id. - Persist first, acknowledge with
2xx, and process asynchronously. - Apply only snapshots newer than the resource’s stored sequence.
- Ignore unknown fields and event types.
- Reconcile current API state before irreversible work.
- Alert on terminal failures and disabled endpoints.
- Avoid logging signing secrets or sensitive fetched
document_data.