Retrieve a promotion
Read one promotion: its status, images, schedule and vehicle count, plus how shoppers engaged with the promoted vehicles' photos.
Use it after a create or a status change to confirm where the promotion stands; photo updates happen in the background.
Before you call it
An id that doesn't exist, was deleted, or belongs to another rooftop gets 404 PROMOTION_NOT_FOUND.
Counts toward the 120 reads a minute per rooftop.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Required | The promotion id from Create a promotion or List promotions. |
Sample request
curl --request GET \
--url 'https://api.spyne.ai/api/pv1/promotions/351' \
--header 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.spyne.ai/api/pv1/promotions/351"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.get(url, headers=headers)
print(response.status_code, response.json())const response = await fetch("https://api.spyne.ai/api/pv1/promotions/351", {
method: "GET",
headers: {
Authorization: "Bearer YOUR_API_KEY",
},
});
console.log(response.status, await response.json());Sample response
{
"success": true,
"statusCode": 200,
"data": {
"id": 351,
"name": "Fall Clearance",
"promotionType": "custom",
"status": "active",
"assets": [{ "assetId": "1584", "position": "all_images" }],
"schedule": { "startDate": "2026-09-21T00:00:00Z", "neverEnds": true },
"priority": 1000,
"vehicleCount": 12,
"performance": {
"status": "available",
"period": { "startDate": "2026-09-21", "endDate": "2026-09-30", "days": 10 },
"vehiclesCounted": 12,
"views": 1240,
"engagedViews": 410,
"engagementRate": 33.1,
"viewsPerDay": 124,
"baseline": {
"startDate": "2026-09-07",
"endDate": "2026-09-20",
"days": 14,
"views": 980,
"engagedViews": 300,
"engagementRate": 30.6,
"viewsPerDay": 70
},
"daily": [{ "date": "2026-09-21", "views": 130, "engagedViews": 41 }]
}
}
}Response parameters (200)
The promotion fields are the same as Create a promotion returns, plus performance.
Performance is measured by Spyne's photo viewer on the rooftop's website. It counts shoppers opening a promoted vehicle's viewer, not total VDP traffic, and views on listing sites aren't included.
| Parameter | Type | Description |
|---|---|---|
performance.status | string | available; notStarted (a draft, scheduled, or not live yet); or unavailable (the numbers can't be fetched right now). Only available carries the fields below; the rest of the promotion is always returned. |
performance.period | object | The UTC days counted: startDate, endDate and days. Runs from the start day to today, or to the day it ended or was completed. A paused promotion keeps counting. |
performance.period.limitedToLastDays | integer | Only when the promotion has run longer than 365 days: the period is the last 365 days. |
performance.vehiclesCounted | integer | Vehicles whose views are included. |
performance.views | integer | Times shoppers opened a promoted vehicle's photo viewer. One visit counts once per vehicle per day. |
performance.engagedViews | integer | Visits where the shopper spun the 360, looked through the photos or played a video. |
performance.engagementRate | number | engagedViews ÷ views × 100, to 1 decimal. 0 when there are no views. |
performance.viewsPerDay | number | views ÷ period.days, to 1 decimal, so periods of different lengths compare. |
performance.baseline | object or null | The same numbers for the 14 days before the start day. Compare viewsPerDay to see the change. null when the period is limited to 365 days. |
performance.daily[] | array | { date, views, engagedViews } for every day in the period, including days with no views. |
Filter-based promotions show performance for the vehicles the promotion has been applied to.
Errors
| Status | Code | When it happens |
|---|---|---|
404 | PROMOTION_NOT_FOUND | No such promotion for this rooftop. |
400 | VALIDATION_FAILED | Spyne refused the request. |
400 | TEAM_NOT_RESOLVED | The API key isn't linked to a rooftop. |
401 | UNAUTHORIZED | The API key is missing or wrong. |
429 | RATE_LIMITED | More than 120 reads this minute. Wait the seconds in Retry-After. |
502 / 503 | SERVICE_UNAVAILABLE | A Spyne service is briefly unavailable. Retry shortly. |
A performance problem never fails the call: performance.status is unavailable instead.
What happens next
Pause, resume or end the promotion with Change status.
Updated 2 days ago
