Box detail
GET /api/s2s/boxes/{boxId} returns the full detail for a single box — its
price plus the complete prize table (each prize’s value, image, and drop
odds) and the fairness snapshot link. Use it when you
drive the open from your backend
and render the box page, reel, and “show odds” list yourself.
The catalog (GET /api/s2s/boxes) lists box-level
cards (name, price, image); this endpoint adds the per-box prize detail those
cards don’t carry. Fetch it when a player opens a box page, then
POST /purchase to open.
Request
GET https://{operator}.app.lootboxsolutions.com/api/s2s/boxes/42GET https://{operator}.app.lootboxsolutions.com/api/s2s/boxes/42?currency=EUR&locale=pt-BR| Query | Notes |
|---|---|
currency | ISO-4217 code. The box price and every prize value come back in this currency; must be one of your configured currencies. Defaults to the operator default. |
locale | BCP-47-ish code (e.g. en, pt-BR). Localizes the box and prize names where a translation exists, falling back to the best-available copy. Defaults to the operator default. |
Response
{ "box": { "boxId": 42, "boxVersionId": 1201, "name": "Dragon Box", "priceMinor": 500, "currency": "EUR", "isCollectible": false, "snapshotUrl": "/fairness/box-version/1201/snapshot", "customAttributes": { "is_purchasable": true }, "prizes": [ { "itemId": 906, "name": "Golden Sword", "valueMinor": 320, "currency": "EUR", "imageUrl": "https://cdn…/items/golden-sword-card.png", "imageUrlLarge": "https://cdn…/items/golden-sword.png", "odds": 0.05, "type": "physical" }, { "itemId": 1204, "name": "Tarmogoyf — Modern Masters (NM)", "valueMinor": 15200, "currency": "EUR", "imageUrl": "https://cdn…/items/tarmogoyf-card.png", "imageUrlLarge": "https://cdn…/items/tarmogoyf.png", "odds": 0.001, "type": "physical", "isCollectible": true, "collectibleCategory": "mtg_card", "metadata": { "category": "mtg_card", "schema_version": 1, "card_name": "Tarmogoyf", "set_code": "MMA", "condition": "nm", "language": "en" } } ] }}| Field | Notes |
|---|---|
boxId | Integer id; pass to /purchase. |
boxVersionId | The current version. Pass this as the reels[].boxVersionId when you open so the player spins the exact version you showed. |
name | Display name, honouring the requested locale. |
priceMinor, currency | Open price, in the requested currency. |
isCollectible | Mirrors the catalog flag, so a detail consumer never has to re-derive it. See Collectibles. |
snapshotUrl | Path to the public fairness snapshot for this version, relative to your operator host. Prefix it with your https://{operator}.app.lootboxsolutions.com origin to link players to it. |
customAttributes | Your custom box attributes (e.g. is_purchasable), with this box’s values. Only declared attributes appear; {} when you’ve declared none. |
prizes[] | One row per item in the box, in the order configured. |
prizes[].itemId | The item id. The same id comes back on a purchase win (reels[].prize.itemId / wonItems[].itemId), so you can map the outcome to the prize tile you rendered. |
prizes[].name | Item name, honouring locale. Names are live, not snapshotted — a rename shows without republishing. |
prizes[].valueMinor, prizes[].currency | Prize value, repriced into the requested currency. The value is frozen to the box’s current version. |
prizes[].imageUrl | Card-size image URL, or null when the item has no image. |
prizes[].imageUrlLarge | The same image at its original (full) size, for an item-detail view — a dialog or zoom on the prize tile. null exactly when imageUrl is. |
prizes[].odds | Drop probability as a fraction in [0, 1] (e.g. 0.05 = 5%). The rows sum to 1. |
prizes[].type | The item’s type: physical, digital, bonus or nuggets. A Nuggets prize is worth valueMinor in Nuggets at your own rate; show that amount where you show other prizes’ value. |
Collectible prize fields
While your operator has collectibles enabled, a
prize that is a collectible carries three additional fields (the example’s
second row). The addition is strictly additive: a non-collectible prize — and
every prize while the capability is off — has none of the three keys, never a
false/null placeholder.
| Field | Notes |
|---|---|
prizes[].isCollectible | Always true when present. This marks the prize item; it is independent of the box-level isCollectible — a mixed box can contain a collectible prize. |
prizes[].collectibleCategory | The collectible family (e.g. mtg_card, coin, sports_card) — the same values as inventory. Drives which metadata keys to expect. |
prizes[].metadata | Descriptive attributes for the item, keyed per category — the same shape and semantics as the inventory item-detail metadata: read live (not snapshotted), keys vary by category plus the reserved category / schema_version pair, render whatever is present rather than hard-coding a list. null for a collectible with no attributes. Internal admin-only keys (e.g. third-party pricing cross-references) are never included. |
Use these to give the prize tiles an item-detail view — the full name, the
imageUrlLarge image, and the attributes as a spec table — so a player can
inspect a card before opening the box.
Current version — lightweight lookup
Open the exact version the player saw: pass the boxVersionId you rendered
to /purchase as reels[].boxVersionId. If the box was
republished in the meantime, that version is no longer current and the open is
refused with BOX_NOT_PLAYABLE — surface a “refresh the page and try again”
rather than opening a version whose prizes the player never saw.
To detect that before charging — e.g. to re-render the prize table when a box changed under the player — use the slim companion endpoint:
GET https://{operator}.app.lootboxsolutions.com/api/s2s/boxes/42/version{ "boxVersionId": 1201, "customAttributes": { "is_purchasable": true }}It returns the live boxVersionId plus the box’s
customAttributes — no
prices, FX repricing, or prize list. Compare the version to the one you rendered:
if they differ, your page is stale. The attributes come back here too so a
backend can apply a per-box rule (e.g. gate a purchase on is_purchasable)
against a fresh value at open time, without re-reading the full detail. Same
UNKNOWN_BOX / BOX_NOT_PLAYABLE errors as below.
Errors
| code | HTTP | when |
|---|---|---|
UNKNOWN_BOX | 404 | no box with that id for your operator |
BOX_NOT_PLAYABLE | 409 | the box is inactive or has no published version |
UNSUPPORTED_CURRENCY | 422 | currency is not one of your configured currencies |
Same data, two callers. The game app reads the equivalent in-iframe player-API box detail with a session token. This S2S endpoint is the backend-driven equivalent — same prize table, signed with your API key.