Thrad always records user feedback internally to power ad relevancy and guarantee a consistent user experience β regardless of whether you opt into forwarding. If you provide a feedback_url in your creative, Thrad additionally forwards the signal to your endpoint so you can close the attribution loop in your own optimisation stack.
This is a webhook Thrad sends to you, not an endpoint you call. You implement the receiver; Thrad fires the POST.
How it works
User rates ad (π or π)
β
Publisher SDK β Thrad SSP
β
Thrad records feedback internally (ad relevancy + UX guarantee)
β β only if feedback_url was in your creative
Thrad β POST {your feedback_url} (fire-and-forget, async)
Opting in
Include feedback_url inside your creative β either in ad_data (pre-rendered bid) or in the render response. The URL is per-bid, so embed whatever you need to route and attribute the signal on your side.
Pre-rendered bid:
{
"data": {
"bid": 7.50,
"bidId": "bid_abc123",
"ad_data": {
"placement": "image",
"headline": "...",
"url": "...",
"image_url": "...",
"feedback_url": "https://your-dsp.com/feedback?bid=bid_abc123"
}
}
}
Render response (two-step flow):
{
"data": {
"placement": "image",
"headline": "...",
"url": "...",
"image_url": "...",
"feedback_url": "https://your-dsp.com/feedback?bid=bid_abc123"
}
}
Request
Thrad fires a POST to your feedback_url:
| Header | Value |
|---|
Content-Type | application/json |
X-Forwarded-For | End-user IP from the publisher side |
X-User-Agent | End-user UA from the publisher side |
{
"bid_id": "bid_abc123",
"feedback_type": "positive",
"feedback_text": "",
"feedback_timestamp": "2026-05-08T15:30:00+00:00"
}
| Field | Type | Description |
|---|
bid_id | string | The bidId from your bid response |
feedback_type | "positive" | "negative" | Thumbs up or thumbs down |
feedback_text | string | Optional free-text comment from the user (usually empty) |
feedback_timestamp | ISO 8601 | When the feedback was submitted |
Response
Return any 2xx within 5 seconds. Acknowledge immediately and process async:
@app.post("/feedback")
async def receive_feedback(request: Request):
event = await request.json()
await queue.enqueue(event)
return {"ok": True}
Timeouts and retries
- Thrad times out after 5 seconds.
- No retries. If your endpoint is down the forwarded event is dropped. Thradβs internal record is always written regardless.