Get promotion details
Get a single promotion’s details, including the products it applies to.
The type field tells you how the promotion works and which product fields
to read:
discount(percentage) /fixed— a cart-level discount. There are no promotion products; rendervalueand anymin_purchase.bundle— readbundle_products: a list of{ productId, quantity, discountedPrice }.bogo— readbogo_required_products(buy these) andbogo_free_products(get these free): lists of{ productId, quantity }.
These fields contain product ids — fetch each product’s full detail with
the Products API to render it. Alternatively, pass expand=products to get the
promotion’s bundle/BOGO products resolved with their details in one call, so you
don’t need a second lookup (see the expand parameter below).
Marketplace storefronts: when a sponsored ad placement or a curated
collection gives you a promotion_id, fetch its detail here by passing
store_id (the merchant_store_id you received alongside the promotion).
A marketplace key may read a single promotion this way; it cannot list
promotions.
curl --request GET \
--url https://api.tybritelabs.com/v1/promotions/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.tybritelabs.com/v1/promotions/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.tybritelabs.com/v1/promotions/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tybritelabs.com/v1/promotions/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.tybritelabs.com/v1/promotions/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.tybritelabs.com/v1/promotions/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tybritelabs.com/v1/promotions/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"type": "discount",
"display_type": "Percentage Discount",
"name": "Spring Sale — 15% Off",
"value": "15",
"min_purchase": 50,
"start_date": "2026-06-19",
"end_date": "2026-07-20",
"status": "active",
"conditions": "Minimum spend $50",
"created_at": "2026-06-20T11:12:09.860326+00:00",
"updated_at": "2026-06-20T13:44:36.764884+00:00",
"has_time_restrictions": false,
"start_time": null,
"end_time": null,
"time_zone": "America/New_York",
"apply_to_days": null,
"id": "df290d89-0400-4b2c-aa56-11fcc486150c",
"image": "https://cdn.example.com/promotions/spring-sale.jpg",
"image_mobile": "https://cdn.example.com/promotions/spring-sale-mobile.jpg",
"video": null
}{
"error": {
"code": "invalid_request",
"message": "Invalid request parameters",
"details": "The 'email' field is required"
}
}{
"error": {
"code": "unauthorized",
"message": "Missing or invalid Authorization header"
}
}{
"error": {
"code": "forbidden",
"message": "This operation requires a secret key. Publishable keys cover catalogue reads and the actions a shopper takes for themselves."
}
}{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}{
"error": {
"code": "rate_limited",
"message": "Too many requests for this API key. Please slow down and try again shortly.",
"remaining": 0,
"reset": 1706198400
}
}{
"error": {
"code": "server_error",
"message": "An unexpected error occurred"
}
}Authorizations
API Key Authentication
Use your API key in the Authorization header:
Authorization: Bearer tybrite_sk_live_YOUR_KEY
Key Types:
Secret Keys (Server-Side Only):
- Format:
tybrite_sk_live_*(production) ortybrite_sk_test_*(sandbox) - Full read/write access to all endpoints
- ⚠️ NEVER expose in client-side code or public repositories
- Required for: every write a shopper does not make for themselves, authentication, payment verification, AI recommendations
Publishable Keys (Client-Safe):
- Format:
tybrite_pk_live_*(production) ortybrite_pk_test_*(sandbox) - Catalogue reads, plus the actions a shopper takes for themselves
- ✅ Safe for client-side JavaScript, mobile apps, and public code
- Allowed for: browsing products, search, CMS content, pricing queries, cart and wishlist, reviews, storefront events, and the Agent API's quotes, cart drafts and checkout intents
Endpoint-Specific Requirements:
- Authentication endpoints (
/v1/auth/*): Secret key required - Payment verification (
POST /v1/payments/verify): Secret key required - AI Recommendations (
POST /v1/recommendations): Secret key required - Semantic Search (
POST /v1/search): Both key types allowed (read-only operation) - Shopper actions (cart, wishlist, reviews, storefront events, Agent API quotes, cart drafts and checkout intents): Both key types allowed
- All other write operations: Secret key required
- All read operations: Both key types allowed
Using a publishable key for restricted operations returns 403 Forbidden.
Path Parameters
Query Parameters
The merchant whose promotion to read. Required for marketplace
storefronts — pass the merchant_store_id you received with the
promotion. Ignored for single-store keys.
Pass expand=products to get the promotion's bundle/BOGO products resolved
with their details, so you don't need a second lookup. The response then
additionally includes bundle_products_resolved,
bogo_required_products_resolved, and bogo_free_products_resolved — the
same entries as the corresponding id arrays, but each with an embedded
product object (product_id, name, price, image, category), or
null for any product that is unavailable.
products Comma-separated list of fields to include in the response.
Allowed Fields:
id,name,type,display_type,value,min_purchasestart_date,end_date,status,conditions,image,image_mobile,videobundle_products,bogo_required_products,bogo_free_products,free_productshas_time_restrictions,start_time,end_time,time_zone,apply_to_dayscreated_at,updated_at
Response
Success
Promotion mechanic.
fixed, discount, bundle, bogo Human-readable label derived from type (e.g. "Percentage Discount").
The discount amount or percentage for this promotion, depending on type.
Minimum order total required for the promotion to apply.
Lifecycle status. Only active promotions (within their date window) apply.
"active"
Optional human-readable conditions for the promotion.
URL of the promotion banner image. This is the default banner — used on desktop and as the fallback whenever image_mobile is not set.
Optional URL of a short video for this banner (MP4, H.264 with AAC audio). Null when none is set. image stays the poster and the fallback, so a storefront that shows only images keeps working unchanged.
Optional banner image sized for mobile viewports. When set, render this on small screens and fall back to image on larger ones (e.g. a <picture> element with a mobile <source>). When absent, use image everywhere.
Products that make up a bundle promotion (present for bundle type).
Products that must be purchased to unlock a BOGO promotion (present for bogo type).
Products given free under a BOGO promotion (present for bogo type).
Present only when the promotion is fetched with expand=products. The same
entries as bundle_products, each enriched with an embedded product object
so you can render the bundle without a second lookup.
Show child attributes
Show child attributes
Present only when the promotion is fetched with expand=products. The same
entries as bogo_required_products, each enriched with an embedded product
object.
Show child attributes
Show child attributes
Present only when the promotion is fetched with expand=products. The same
entries as bogo_free_products, each enriched with an embedded product
object.
Show child attributes
Show child attributes
ISO 3166-1 alpha-2 codes this promotion applies in. An EMPTY array means it applies everywhere, which is the default. When codes are present the promotion is only applied to shoppers in those markets, and is refused when the shopper's location cannot be determined — applying a market-limited offer to an unknown visitor would give it to everyone.
2["US", "CA"]
Region or state names this promotion applies in, matched case-insensitively. Empty means everywhere. Use alongside target_countries to narrow within a market.
["California"]
Whether the promotion only applies during specific times/days.
Daily start time (when has_time_restrictions is true).
Daily end time (when has_time_restrictions is true).
Time zone the time restrictions are evaluated in.
Days of the week the promotion applies to (when has_time_restrictions is true).
curl --request GET \
--url https://api.tybritelabs.com/v1/promotions/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.tybritelabs.com/v1/promotions/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.tybritelabs.com/v1/promotions/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tybritelabs.com/v1/promotions/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.tybritelabs.com/v1/promotions/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.tybritelabs.com/v1/promotions/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tybritelabs.com/v1/promotions/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"type": "discount",
"display_type": "Percentage Discount",
"name": "Spring Sale — 15% Off",
"value": "15",
"min_purchase": 50,
"start_date": "2026-06-19",
"end_date": "2026-07-20",
"status": "active",
"conditions": "Minimum spend $50",
"created_at": "2026-06-20T11:12:09.860326+00:00",
"updated_at": "2026-06-20T13:44:36.764884+00:00",
"has_time_restrictions": false,
"start_time": null,
"end_time": null,
"time_zone": "America/New_York",
"apply_to_days": null,
"id": "df290d89-0400-4b2c-aa56-11fcc486150c",
"image": "https://cdn.example.com/promotions/spring-sale.jpg",
"image_mobile": "https://cdn.example.com/promotions/spring-sale-mobile.jpg",
"video": null
}{
"error": {
"code": "invalid_request",
"message": "Invalid request parameters",
"details": "The 'email' field is required"
}
}{
"error": {
"code": "unauthorized",
"message": "Missing or invalid Authorization header"
}
}{
"error": {
"code": "forbidden",
"message": "This operation requires a secret key. Publishable keys cover catalogue reads and the actions a shopper takes for themselves."
}
}{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}{
"error": {
"code": "rate_limited",
"message": "Too many requests for this API key. Please slow down and try again shortly.",
"remaining": 0,
"reset": 1706198400
}
}{
"error": {
"code": "server_error",
"message": "An unexpected error occurred"
}
}
