Skip to content
Documentation menu
HTTP APIWeb

Web: HTTP API

HTTP API for fetching ads and handling interactive actions in web apps.

Authentication

CallerAuthenticationIdentity
BrowserPlatform ID and an allowed site address. The browser supplies Origin.visitor_id
ServerAuthorization: Bearer sk_live_…stable_user_id or visitor_id

Get an API key in publisher settings. Keep it on the server. Server requests to Sidekick must omit Origin.

Send exactly one user identity. Allowed characters: A–Z, a–z, 0–9, _, ., :, -. Keep the ID across requests; do not use an email or phone number.

Platform and site address requirements →

Request an ad

POST /api/v1/web/ads

FieldTypeDescription
platform_idrequiredstringPublic platform ID.
visitor_idstringVisitor ID, 16–128 characters. Required for browser requests.
stable_user_idstringUser ID, 1–128 characters. Available for server requests instead of visitor_id.
request_idstringRequest ID, 1–128 characters. Reusing it does not prevent another ad issuance.
placementstringRegistered placement name. Defaults to chat.
language_codestringAd language. Defaults to en.
accept_formatsstring[]text, image, response, card, consent, quiz. Defaults to all formats.
contextobjectAd context. Fields depend on context.type.
testbooleanTest ads without billing. Defaults to false.
test_formatstringTest ad format when test is true.

Required fields.

Content-Type: application/json. Maximum body size: 64 KiB.

Server request

POST /api/v1/web/ads
POST /api/v1/web/ads
Authorization: Bearer sk_live_EXAMPLE
Content-Type: application/json
{
"platform_id": "plt_example",
"stable_user_id": "customer_42",
"context": {
"question": "Headphones?",
"answer": "Here are some options…"
},
"test": true,
"test_format": "card"
}

Browser request

visitorId is the persisted visitor ID. Send the request without an API key or cookies.

fetch()
const response = await fetch("https://sidekick-ads.com/api/v1/web/ads", {
method: "POST",
credentials: "omit",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
platform_id: "plt_example",
visitor_id: visitorId,
request_id: "chat-42-message-7",
test: true,
test_format: "card"
})
});
if (!response.ok) throw new Error("Ad request failed");
const payload = await response.json();

Context

context.typeFieldsLimits
conversationquestion, answerBoth fields are optional: up to 4,096 and 16,384 characters. Default type.
articletitle, contentBoth fields are required: up to 4,096 and 16,384 characters.
feedtextRequired field, up to 16,384 characters.
static—No text context.

Topic matching uses the user's question: question or title. feed and static have none, so they receive only ads without topic targeting.

Response

FieldTypeDescription
has_adbooleanWhether the response includes an ad.
adobject | nullAd object; null when no ad is available.
ad.delivery_idstringDelivery ID for interactions.
ad.expires_atstringAd expiry in ISO 8601 format.
ad.formatstringAd format.
ad.disclosurestringRequired advertising disclosure.
ad.testbooleanWhether this is a test ad.
ad.blocksobject[]text, media, gallery and buttons blocks in display order.
ad.viewstringReceipt for the view confirmation. Present on billable ads only. Views
200 OK · No fill
{
"has_ad": false,
"ad": null
}

An impression is paid once the ad is seen, not when it is issued. The browser SDK confirms the view itself; with custom rendering, send a view confirmation.

Rendering

Render every block and the disclosure. Use mountSidekickAd from the browser SDK for the standard card. In this example, payload comes from your server and /my-ad-interaction handles actions in your app.

mountSidekickAd()
const view = Sidekick.mountSidekickAd(document.querySelector("#ad-slot"), {
onAction: async (ad, action) => {
const response = await fetch("/my-ad-interaction", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ delivery_id: ad.delivery_id, action })
});
if (!response.ok) throw new Error("Interaction failed");
return (await response.json()).ad;
}
});
view.setAd(payload.has_ad ? payload.ad : null);

Interactions

POST /api/v1/web/interact

For consent and quiz, send the clicked button’s action, delivery_id and original user identity. Use the same authentication as the ad request.

POST /api/v1/web/interact
{
"platform_id": "plt_example",
"stable_user_id": "customer_42",
"delivery_id": "imp_example",
"action": "signed-action-from-button"
}

Response: {ok: true, ad}. Replace the card with the returned ad. Advancing a scene does not create another paid impression.

For buttons with a url, open it on click. Do not prefetch advertising links.

View confirmation

POST /api/v1/web/seen

An impression is paid after a view: at least half of the card on screen for at least one second. The browser SDK sends this request itself. With custom rendering, call trackView(ad) or send the request with the same authentication and user identity.

POST /api/v1/web/seen
{
"platform_id": "plt_example",
"stable_user_id": "customer_42",
"delivery_id": "imp_example",
"view": "view-receipt-from-ad"
}

Response: {ok: true}. The view receipt is valid for an hour. A request sooner than one second after issuance returns 409. A button press or a click on the ad link also counts the impression. Ads that are never seen are not paid.

Errors

StatusMeaning
400Invalid request fields or user identity.
401Missing or invalid API key.
403Platform disabled, site address not allowed or API key belongs to another publisher.
409View confirmation sent sooner than one second after issuance.
410Action or view receipt is invalid or has expired.
413Request body exceeds 64 KiB.
429Request rate limit exceeded.
503Service temporarily unavailable.

Preserve the app response on error. Do not automatically retry ad requests after network failures or 5xx: every request is a new issuance.