Outbound delivery
Let Tradee post each event to a URL you control, so your integration does not have to poll or hold a stream open.
How it differs from the feed
The feed is a pull surface: you hold the token and read. Outbound delivery is the push counterpart over the same fixed v1 event body. Both are per output execution, both are read-only modeled output, and neither places an order. Configure a target under Settings → Connections. You can use either mode, or both at once.
The request
Tradee sends POST with Content-Type: application/json and never follows redirects. The target must be https, must not embed credentials, and its host must resolve to a public address. Tradee re-resolves and re-checks the address immediately before every attempt, so a hostname that later points into private space stops being delivered to.
| Header | Meaning |
|---|---|
Tradee-Signature | v1={hex} HMAC-SHA256 over {timestamp}.{raw body} |
Tradee-Timestamp | RFC 3339 UTC instant included in the signed message |
Tradee-Event-Id | Stable event UUID; use it to dedupe |
Tradee-Topic | The event topic |
Tradee-Execution-Id | The originating output execution |
Tradee-Delivery-Attempt | 1-based attempt counter |
Verifying the signature
Compute the HMAC over the timestamp, a literal ., and the exact bytes you received, then compare in constant time. Signing the timestamp alongside the body means a captured request cannot be replayed later without also replaying a stale timestamp you can reject.
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
The signing secret is shown once when you set a target and once again on each rotation. Rotating issues a new secret immediately; deliveries in flight are signed with whichever secret was current when the attempt was made.
Responses and retries
Any 2xx marks the delivery accepted. 408, 429, and 5xx are retried with exponential backoff of 5, 10, 20, 40, 80, then 160 seconds, up to 6 attempts. Every other 4xx is treated as a configuration error and fails permanently without further attempts, because retrying a rejected request only delays the next signal. Respond quickly and do your work asynchronously; each attempt times out after 10 seconds.
Delivery is at-least-once. The delivery row is written in the same transaction as the event itself, so a signal cannot be silently dropped, but a slow acknowledgement can produce a duplicate. Dedupe on Tradee-Event-Id and apply position.revision monotonically, exactly as a feed receiver would.
Payload templates
By default the body is the full v1 event, byte-identical to what the feed serves. If your endpoint expects a different shape, supply a JSON object template and pull values in with ${event.path} placeholders. A value that is exactly one placeholder keeps its original type; a placeholder inside a longer string is interpolated as text. Paths that do not resolve become null, and a template can only read the event, never anything else.
{"ticker": "${event.reference.instrument}", "action": "buy", "quantity": "${event.transition.quantity_delta}"}
Templates let you point Tradee at an existing automation endpoint without writing a translation service. What that endpoint then does with the signal is entirely yours: on the Live API outputs path Tradee submits no orders and receives no fills.