The second-screen flow lets a viewer pick up on their phone exactly where they are on the TV.
Your app describes the screen it is showing, Diddo returns a QR code, and scanning it opens the Diddo-hosted second-screen app on the viewer's phone at that same place: a filtered product list, one product, their cart or the checkout.
💡Unlike QR Code Payments, which hands off a cart that is already built, a second-screen code can hand off any point in the journey, so viewers can browse and build their cart on their phone.
This section covers:
- How the hand-off works
- Generating a code for a product list, a product, the cart or the checkout
- Choosing the image format
- Size limits and what happens when a payload is too long
🌀 How It Works
-
Describe the screen
Your TV app calls the QR endpoint with the view it is showing and the values that view needs, for example the game on screen.
-
Show the code
Diddo returns the QR image. Everything the phone needs is encoded in the URL inside it; nothing is stored on our side for the scan.
-
Customer scan
The phone opens the second-screen app on your branded Diddo host, already on the right page. A game code opens the game's catalogue, with a switch between the two teams and a link out to the full catalogue.
-
Shop and pay
From there the viewer browses, builds a cart and pays on their phone with Apple Pay, Google Pay or a card.
📘 Entity and mode never travel in the request body. Both come from your API key, so a test key always produces a test-mode code.
📱 Sample Second-Screen Flow
A viewer scans a game code, filters to one team, adds a hoodie to their cart and checks out with Google Pay, all in test mode.
Video demo:
🔌 Endpoint
Endpoint:
bashPOST /second-screen/qr
Required Headers:
textAuthorization: Bearer <your_api_key> Content-Type: application/json
Request Body:
| Field | Required | Notes |
|---|---|---|
view | ✅ | list, product, cart or checkout |
template_cart_id | For cart and checkout | The TV's template cart. Optional for list and product. Must be a template cart owned by your entity in your key's mode. checkout also requires it to hold products. |
list | — | Filters for view=list. Optional back-navigation context for view=product. |
product | For product | product_id (required) and variant_id (optional) |
screen | — | A name for the TV screen the code was drawn on, used for scan attribution, e.g. game-shop |
qr.size | — | PNG edge in pixels, 128–2048, default 512. SVG is vector and ignores it. |
The list object takes the same names as the Products API: game_id, league, teams, players, category, color, gender, age, brand, tags, sort, min_price, max_price, limit and curated.
🏀 Example: The Game on Screen
The most common code. Name the game and the phone opens that game's catalogue.
json{ "view": "list", "list": { "game_id": "0022500123", "league": "nba", "teams": ["knicks", "spurs"] }, "screen": "game-shop" }
cURL Example:
bashcurl --request POST \ --url 'https://sandbox.api.shopdiddo.com/second-screen/qr.svg' \ --header 'Authorization: Bearer <your_api_key>' \ --header 'Content-Type: application/json' \ --data '{"view":"list","list":{"game_id":"0022500123","league":"nba","teams":["knicks","spurs"]},"screen":"game-shop"}' \ > qr.svg
💡Send
leagueand bothteamsalongsidegame_id. The teams drive the team switch at the top of the game catalogue.
🛍️ Other Views
A filtered list (no game). Any Products API filter works:
json{ "view": "list", "list": { "league": "nba", "teams": ["lakers"], "category": ["tops"], "sort": "price_asc" } }
One product, with the list the viewer came from as the way back:
json{ "view": "product", "product": { "product_id": "202412345678", "variant_id": "20241234567801" }, "list": { "league": "nba", "teams": ["lakers"] } }
The cart or the checkout, once the TV has a template cart:
json{ "view": "checkout", "template_cart_id": "3b2f89de-c485-4d83-a395-69078186583a" }
🖼️ Choosing the Format
Suffix the path, or send an Accept header:
| You want | Request |
|---|---|
| SVG (recommended, scales cleanly) | POST /second-screen/qr.svg or Accept: image/svg+xml |
| PNG | POST /second-screen/qr.png or Accept: image/png |
| Just the URL, to render your own code | POST /second-screen/qr.json or Accept: application/json |
With no Accept header the response is JSON. The .json body carries the encoded url, its size in bytes, the qr_version it needs, and dropped_keys / truncated_keys describing any trimming (see below).
📘Image responses are sent with
Cache-Control: no-store. Request a fresh code each time the TV screen changes.
📏 Size Limits
A code has to stay scannable, so the encoded URL must fit QR version 10 (213 bytes). If your payload is longer, Diddo trims it before refusing it:
- A
productcode drops its back-navigationlistin one step. - A
listcode dropstags, thencurated, then shortensplayers,teams,category,color,genderandagefrom the end, one item at a time, until the URL fits. sort,min_price,max_price,limit,modeandscreenare never dropped.
Use the .json variant during development to see what, if anything, was trimmed.
A payload still over budget after trimming returns 400 with the untrimmed size, trimmed size and the budget in its details. Error responses follow the same structured format as the Error Handling guide.
