Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.thrads.ai/llms.txt

Use this file to discover all available pages before exploring further.

Requesting an Ad Format

Use the ad_formats field in your bid request to specify which formats your integration can render. The server picks the best match and the response includes an ad_format field confirming what was returned. When ad_formats is omitted, it defaults to ["sponsored_message"] for contextual requests and ["sponsored_prompt"] for opener requests. Sponsored polls are contextual-only. Request them only with request_type: "contextual" and never on opener placements.

Available Formats

Formatad_formats valueStatus
Sponsored Messagesponsored_messageLive
Sponsored Promptsponsored_promptLive
CarouselcarouselComing soon
Sponsored Pollsponsored_pollLive for contextual placements
Use the ad_format field in the response to determine which format was returned and render accordingly. A native ad card displayed inline in the conversation. Includes a headline, description, brand visuals, and a call-to-action. The card has two render modes, declared by the server in the placement field:
  • text — compact card with the advertiser logo only. The response includes logo_url; image_url is absent. Forced when config.image_enabled=false, when no product photo is available, or when the DSP chooses text mode.
  • image — full card with a hero product photo. The response includes image_url; logo_url may also be present alongside.
When placement is missing, treat it as "text".
Sponsored message in text mode (logo only)
Sponsored message in image mode (full product photo)
Response fields: ad_format, advertiser, domain, headline, description, cta_text, url, placement, logo_url, image_url, view_url
{
  "ad_format": "sponsored_message",
  "price": 5.50,
  "advertiser": "Nike",
  "domain": "nike.com",
  "headline": "Premium Running Shoes",
  "description": "Perfect for marathon training. Lightweight and comfortable.",
  "cta_text": "Shop Now",
  "url": "https://ssp.thrads.ai/api/v1/tracking/redirect?token=abc123",
  "placement": "image",
  "logo_url": "https://cdn.example.com/nike-logo.png",
  "image_url": "https://cdn.example.com/nike-shoes.jpg",
  "view_url": "https://ssp.thrads.ai/api/v1/tracking/view?token=v1",
  "dsp": "thrad_dsp",
  "bidId": "bid_abc123"
}
FieldDescription
ad_formatAlways "sponsored_message" for this format.
priceClearing price (CPM) in dollars — what the publisher earns.
advertiserBrand name of the advertiser (e.g. "Nike"). In rare cases this may return a domain (e.g. "nike.com") as a fallback when the brand name is not available. Your UI should handle both gracefully.
domainAdvertiser website domain (e.g. "nike.com").
headlineAd headline. Respects config.max_headline_chars when set.
descriptionAd body text. May be null.
cta_textCall-to-action text. May be absent — default to “Learn More” in your UI.
urlClick tracking URL. Always use this for clicks — it tracks the click and redirects to the landing page.
placementRender mode: "text" (logo only) or "image" (full product photo). When missing, treat as "text".
logo_urlAdvertiser brand/logo URL. Required when placement="text". May also be present alongside image_url when placement="image".
image_urlProduct/hero photo URL. Present when placement="image", absent when placement="text". Setting config.image_enabled=false forces text mode, so image_url will never be returned.
view_urlOptional impression tracking pixel URL. Fire it when the ad becomes visible to the user (see Billing & Viewability).
dspWinning DSP identifier.
bidIdBid identifier for tracking and debugging.
A set of sponsored follow-up questions displayed as clickable prompts before or during a conversation.
Sponsored prompt example
Response fields: ad_format, advertiser, sponsored_prompt, url, logo_url The response returns an array of bids, each containing a sponsored prompt:
{
  "bids": [
    {
      "ad_format": "sponsored_prompt",
      "bidId": "bid_sp_001",
      "advertiser": "Nike",
      "sponsored_prompt": "What are the best running shoes for marathon training?",
      "url": "https://ssp.thrads.ai/api/v1/tracking/redirect?token=sp1",
      "logo_url": "https://cdn.example.com/nike-logo.png",
      "view_url": "https://ssp.thrads.ai/api/v1/tracking/view?token=v1"
    }
  ]
}
Coming soon — contact us at contact@thrad.ai for early access.
A scrollable set of ad cards, each with its own headline, image, and link. Useful for showcasing multiple products in a single slot.
Sponsored carousel example
An interactive poll sponsored by an advertiser. Sponsored polls are contextual-only and appear in the same mid-conversation inventory path as sponsored messages. They are not opener or pre-chat inventory.
Sponsored poll example
Request poll inventory by sending ad_formats on a contextual bid request:
Poll-only contextual request
{
  "request_type": "contextual",
  "ad_formats": ["sponsored_poll"]
}
Mixed contextual request
{
  "request_type": "contextual",
  "ad_formats": ["sponsored_message", "sponsored_poll"]
}
When you request both sponsored_message and sponsored_poll, Thrad first selects the winning campaign through the normal contextual auction. After a campaign wins, campaign delivery settings determine whether the returned creative is a message or poll. Response fields: ad_format, sponsored_poll_id, advertiser, domain, question, options, vote_url, results_url, cta_text, cta_url, view_url, results
{
  "ad_format": "sponsored_poll",
  "price": 5.50,
  "sponsored_poll_id": 123,
  "advertiser": "Warner Music Group",
  "domain": "warnermusic.com",
  "question": "What kind of playlist are you making?",
  "options": [
    { "id": "0", "text": "Wedding" },
    { "id": "1", "text": "Study" },
    { "id": "2", "text": "Workout" }
  ],
  "vote_url": "https://ssp.thrads.ai/api/v1/tracking/sponsored-polls/vote?token=vote123",
  "results_url": "https://ssp.thrads.ai/api/v1/tracking/sponsored-polls/results?token=results123",
  "cta_text": "Listen now",
  "cta_url": "https://ssp.thrads.ai/api/v1/tracking/redirect?token=cta123",
  "view_url": "https://ssp.thrads.ai/api/v1/tracking/view?token=v1",
  "results": {
    "total_votes": 0,
    "options": [
      { "id": "0", "text": "Wedding", "votes": 0, "percentage": 0 },
      { "id": "1", "text": "Study", "votes": 0, "percentage": 0 },
      { "id": "2", "text": "Workout", "votes": 0, "percentage": 0 }
    ]
  },
  "dsp": "thrad_dsp",
  "bidId": "bid_poll_abc123"
}
FieldDescription
ad_formatAlways "sponsored_poll" for this format.
sponsored_poll_idPoll identifier.
advertiserBrand name of the advertiser.
domainAdvertiser website domain.
questionPoll question text.
optionsAnswer options. Each option has id and text; submit the selected id when voting.
vote_urlSigned vote URL. Option buttons submit to this URL; they do not use normal click tracking.
results_urlSigned results URL. Fetch it to refresh aggregate results without recording a vote.
cta_textOptional post-vote advertiser CTA text.
cta_urlOptional post-vote advertiser click tracking URL. Show it after voting; voting itself does not redirect.
view_urlOptional impression tracking pixel URL. Fire it when the poll becomes visible to the user.
resultsOptional aggregate results object with total_votes and per-option votes/percentage.
dspWinning DSP identifier.
bidIdBid identifier for tracking and debugging.

Poll Rendering

Render poll options as buttons or equivalent controls. Do not wrap the whole poll card in an advertiser click link; option clicks must call the signed vote_url.
function renderSponsoredPoll(poll) {
  const container = document.createElement("div");
  container.className = "thrad-sponsored-poll";
  container.innerHTML = `
    <div class="thrad-sponsored-label">Sponsored · ${poll.advertiser || "Advertiser"}</div>
    <h3>${poll.question}</h3>
    <div class="poll-options"></div>
    <div class="poll-results" hidden></div>
    <a class="poll-cta" target="_blank" rel="noopener" hidden>
      ${poll.cta_text || "Learn More"}
    </a>
  `;

  const optionsEl = container.querySelector(".poll-options");
  const resultsEl = container.querySelector(".poll-results");
  const ctaEl = container.querySelector(".poll-cta");

  for (const option of poll.options) {
    const button = document.createElement("button");
    button.type = "button";
    button.textContent = option.text;
    button.addEventListener("click", async () => {
      const results = await submitPollVote(poll.vote_url, option.id);
      renderPollResults(resultsEl, results);
      optionsEl.hidden = true;
      resultsEl.hidden = false;

      if (poll.cta_url) {
        ctaEl.href = poll.cta_url;
        ctaEl.hidden = false;
      }
    });
    optionsEl.appendChild(button);
  }

  return container;
}

async function submitPollVote(voteUrl, optionId) {
  const response = await fetch(voteUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ option_id: optionId })
  });

  if (!response.ok) {
    throw new Error("Poll vote failed");
  }

  return response.json();
}

function renderPollResults(resultsEl, results) {
  resultsEl.replaceChildren(
    ...results.options.map((option) => {
      const row = document.createElement("div");
      row.textContent = `${option.text}: ${option.percentage}%`;
      return row;
    })
  );
}
See Sponsored Poll Tracking for vote, duplicate vote, and results endpoint behavior.

Response Handling

No Bid Response

{
  "requestId": "api_req_124",
  "timestamp": "2025-11-24T21:51:52.240297Z",
  "totalTime": 0.095,
  "status": "success",
  "message": "No bids",
  "data": {
    "bid": null
  },
  "error": null
}
A 200 OK response with "bid": null is not an error. It means the auction ran successfully but no DSP submitted a winning bid. This is normal behavior and should be handled gracefully in your UI.