Get Started
From zero to your first ReelPlus API call in 5 minutes. Get a key, call the sandbox, read the funnel, handle limits, then go to production.
No store, no sales call. Everything on this page runs against the public sandbox: a demo store with 120 days of video, widget and order data. When you are done you will have pulled the store's funnel, found its best-selling videos, and seen how the API behaves when you push it too hard.
Get a key
Two ways in, both free:
| Your own key | The shared demo key | |
|---|---|---|
| How | Sign in with GitHub at the Developer Console, click Create key | Copy it from here |
| Rate limit | 60 requests per minute, yours alone | 60 per minute, shared with everyone |
| Usage page | Every call, per endpoint, with status and latency | No |
| Revoke | Any time, from the console | Never |
The demo key, if you want to skip the sign-in:
rp_653f0a33f2bbf185566e8e9a11651a4fd3cfc5fe10c1694eef4d54b830c2d2cfKeys start with rp_ and are sent as a Bearer token. The full key is shown once at creation; the console keeps only the first 12 characters and a hash.
Make your first call
The summary endpoint returns the store's whole funnel for the last 30 days. Replace the key with your own if you created one. No terminal at hand? The console playground sends the same request from the browser with your key and shows the response, the headers and the matching curl.
curl https://help.reelplus.app/api/v1/analytics/summary \
-H "Authorization: Bearer rp_653f0a33f2bbf185566e8e9a11651a4fd3cfc5fe10c1694eef4d54b830c2d2cf"const API_KEY = "rp_653f0a33f2bbf185566e8e9a11651a4fd3cfc5fe10c1694eef4d54b830c2d2cf";
const res = await fetch("https://help.reelplus.app/api/v1/analytics/summary", {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const { data, meta } = await res.json();
console.log(`${data.orders} orders, ${data.revenue} revenue since ${meta.start_date}`);import requests
API_KEY = "rp_653f0a33f2bbf185566e8e9a11651a4fd3cfc5fe10c1694eef4d54b830c2d2cf"
res = requests.get(
"https://help.reelplus.app/api/v1/analytics/summary",
headers={"Authorization": f"Bearer {API_KEY}"},
)
body = res.json()
print(body["data"]["orders"], "orders,", body["data"]["revenue"], "revenue")You get a 200 and this shape (your numbers will differ):
{
"success": true,
"data": {
"impressions": 58700,
"views": 15066,
"clicks": 2046,
"add_to_cart": 478,
"orders": 145,
"revenue": 21563.2,
"ctr": 13.58,
"cvr": 0.96
},
"meta": {
"start_date": "2026-09-29T15:11:25.778Z",
"end_date": "2026-10-29T15:11:25.778Z"
}
}Read the funnel
The eight numbers are one funnel, in order. Each step can only be reached through the one before it, so the numbers always shrink from left to right.
| Field | Meaning |
|---|---|
impressions | A widget was loaded on a page |
views | A video started playing |
clicks | A shopper clicked a product inside a video |
add_to_cart | A product was added to the cart from a video |
orders | Orders attributed to a video interaction |
revenue | The value of those orders, in the store currency |
ctr | clicks / views × 100 |
cvr | orders / views × 100 |
Narrow the window with start_date and end_date (YYYY-MM-DD). The range you actually got is echoed back in meta, so a dashboard can label the tile correctly.
Find the videos that sell
The same funnel exists per video and per widget. This is the call behind "which video did the work":
curl "https://help.reelplus.app/api/v1/analytics/videos?sort_by=revenue&sort_order=desc&limit=5" \
-H "Authorization: Bearer rp_653f0a33f2bbf185566e8e9a11651a4fd3cfc5fe10c1694eef4d54b830c2d2cf"Each item carries the video (title, thumbnail, duration, tagged products) and its own metrics object. Lists are paginated: walk page=2, page=3, … until pagination.page equals pagination.total_pages. sort_by accepts views, clicks, impressions, add_to_cart, orders, revenue, title and created_at; anything else is a 400, not a silent default.
Swap videos for widgets to compare placements instead (the home carousel against the product page player), with widget_type=carousel|story|floating|productpage as a filter.
Handle limits and errors
Every authenticated response tells you where you stand:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 41
X-RateLimit-Reset: 1793286741Past 60 requests in a minute you get 429 with Retry-After in seconds. Wait that long and retry; never retry a 401 (bad header) or 403 (unknown or revoked key), they need a fix on your side. Every error has the same envelope:
{ "success": false, "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded. Try again in 12 seconds." } }Try it: send the first call above with the key changed to rp_wrong and you get 403 INVALID_API_KEY; drop the header and you get 401 UNAUTHORIZED. The full list of codes and a retry function in JavaScript and Python are in Errors & Rate Limits.
Go to production
Production API access is enabled per store on Enterprise plans, on request. Once it is enabled, keys are generated in Settings > API Access in the ReelPlus dashboard and the base URL is provided with the access. The contract is the one you just used; only the data becomes your store's.
A complete example: the Monday digest
Twenty lines that print the five best-selling videos of the last 7 days. Save as digest.mjs and run node digest.mjs.
const API_KEY = "rp_653f0a33f2bbf185566e8e9a11651a4fd3cfc5fe10c1694eef4d54b830c2d2cf";
const BASE = "https://help.reelplus.app/api/v1";
const end = new Date();
const start = new Date(end.getTime() - 7 * 24 * 60 * 60 * 1000);
const range = `start_date=${start.toISOString().slice(0, 10)}&end_date=${end.toISOString().slice(0, 10)}`;
const res = await fetch(`${BASE}/analytics/videos?${range}&sort_by=revenue&limit=5`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${res.status} ${error.code}: ${error.message}`);
}
const { data } = await res.json();
console.log(`Top videos, last 7 days (${res.headers.get("X-RateLimit-Remaining")} requests left this minute)`);
for (const [i, v] of data.entries()) {
console.log(`${i + 1}. ${v.title}: ${v.metrics.orders} orders, ${v.metrics.revenue.toFixed(2)} revenue`);
}From here, the two things people usually do next: pipe this into a Slack message, or drop the numbers into a Google Sheet next to ad spend.
Something in these docs does not match what the API returned? That is a bug on our side. Every promise on these pages is checked against the sandbox by an automated test before a deploy; tell us which one slipped.