Use this option to create a link for one specific campaign.
Select Single campaign.
Choose the campaign from the list.
Shareable Campaign API Links let an operator generate a stable, revocable link that returns campaign data from Unibo's public API — without handing out backoffice credentials and without exposing the internal backend host. A link can point to a single campaign or to a group of campaigns sharing one or more labels.
Typical use: give an affiliate, an on-site integration, or a partner a URL they can call to read live campaign/tournament data (name, image, dates, terms, prizes, leaderboard, …).
In the back office, select Shareable Links from the sidebar.
Click Create link.
Provide a descriptive name for the link.
Note: The name is only visible in the back office and helps you identify the link later.
Use this option to create a link for one specific campaign.
Select Single campaign.
Choose the campaign from the list.
Use this option to include multiple campaigns.
Select By labels.
Enter one or more labels.
The link will return every campaign that contains any of the selected labels.
You can set campaign labels in Advanced Settings under the General tab of the campaign.
If required, choose an expiry date and time.
After this date, the link will no longer be valid.
By default, every available response field is included.
If you don't need certain fields, untick them before creating the link.
For example, you may want to exclude:
game_ids For tournament campaigns, it can significantly increase the response size.
Only the selected fields will be returned by the API.
Click Create.
The generated link will display:
URL
Token
Click Copy to copy the complete URL for use in your application or integration.
From Shareable Links, you can:
View all existing shareable links.
Revoke links that should no longer be accessible.
A link is just a URL you open or call:
GET https://<tenant>-public-api.unibo.io/public/api/v1/shared/campaigns?token=<TOKEN>Auth — the token can be passed as the ?token= query parameter (for a link you just open) or as an Authorization: Bearer <TOKEN> header (for API clients).
Response — a paginated list of campaigns. Tournament/race campaigns include the tournament payload (leaderboard, prizes) merged in at the top level. Optional query params: ?currency= and ?language= .
Only publicly visible campaigns are returned — Active, Scheduled, or Finished, and not hidden from public APIs. Draft/Cancelled campaigns are never exposed (a link to one returns an empty list, not an error).
Field selection — any fields excluded on the link are omitted; excluding heavy fields like leaderboard also skips computing them.
Optional query params supported: currency, language, and exclude_fields (a subset of the link's own selection).
Responses are always paginated (count / next / previous / results). There are two payload shapes:
Base shape — returned for every campaign type (Missions, Jackpot, Prize Drop, Raffle, …): the common campaign fields only.
Tournament & Race — the base fields plus tournament_prizes , total_prizes , and leaderboard , merged in at the top level.
Keys are stable; the values below are illustrative.
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1510,
"custom_id": "WELCOME-MISSIONS",
"name": "Welcome Missions",
"image": "https://cdn.unibo.io/media/campaign-backgrounds/welcome.jpg",
"start": "2026-07-01T00:00:00Z",
"end": null,
"status": "AC",
"status_for_display": "Active",
"terms": {
"content": "Complete the missions to earn rewards. Full terms apply.",
"campaign_type": "MI",
"campaign_type_for_display": "Missions",
"tournament_type": null,
"tournament_type_for_display": null
},
"game_ids": ["softswiss:GonzosQuest", "softswiss:BookOfDead"],
"campaign_info": "Three missions, three rewards."
}
]
}Jackpot, Prize Drop and Raffle campaigns return this same set of fields — only the terms.campaign_type / campaign_type_for_display differ. No jackpot/prize-drop/raffle-specific data is included in the shared payload.
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1423,
"custom_id": "SUMMER-SLOTS-TT",
"name": "Summer Slots Tournament",
"image": "https://cdn.unibo.io/media/campaign-backgrounds/summer.jpg",
"start": "2026-07-01T00:00:00Z",
"end": "2026-07-07T23:59:59Z",
"status": "AC",
"status_for_display": "Active",
"terms": {
"content": "Wager on eligible slots to climb the leaderboard. Full terms apply.",
"campaign_type": "TO",
"campaign_type_for_display": "Tournaments",
"tournament_type": "PT",
"tournament_type_for_display": "Point tournament"
},
"game_ids": ["softswiss:StarburstXXX"],
"campaign_info": "Compete for a €2,000 prize pool!",
"tournament_prizes": [
{ "title": "€1,000 cash", "place_from": 1, "place_to": 1 },
{ "title": "€500 cash", "place_from": 2, "place_to": 2 },
{ "title": "€50 cash", "place_from": 3, "place_to": 12 }
],
"total_prizes": {
"cash": "€2,000",
"free_spins": null,
"bonus": null,
"deposit_bonus": null,
"catalog_item": []
},
"leaderboard": [
{ "player_id": "a1b2c3d4", "player_username": "luckystar", "score": 184520, "prizes": ["€1,000 cash"] },
{ "player_id": "e5f6g7h8", "player_username": "reelqueen", "score": 173110, "prizes": ["€500 cash"] }
]
}
]
}Identical structure to a Tournament — the same tournament_prizes, total_prizes, and leaderboard Fields are merged in. Only terms.campaign_type_for_display reads Races (with the relevant tournament_type, e.g. Race or Speed race).
A by-label link returns every matching campaign inresults, each using the shape for its own type. count reflects the total:
{
"count": 3,
"next": null,
"previous": null,
"results": [
{ "id": 1423, "name": "Summer Slots Tournament", "status": "AC", "tournament_prizes": [], "leaderboard": [] },
{ "id": 1510, "name": "Welcome Missions", "status": "AC" },
{ "id": 1544, "name": "Weekend Prize Drop", "status": "SC" }
]
}If the link excludes leaderboard, That key is simply absent from each tournament/race entry (and the leaderboard query is skipped entirely) — everything else is unchanged.
Each tenant gets a dedicated host: https://<tenant>-public-api.unibo.io. It is deliberately locked to the shareable-links endpoint only — any other path on that host is rejected (HTTP 403). This hides the internal backoffice/backend host and limits the surface to exactly the shared-campaigns endpoint. It's provisioned per tenant via infrastructure and requires no application change.
Tokens are revokeable (instant) and can be given an expiry .
Each token is scoped to one tenant and only ever returns publicly-visible campaign data — never player data or admin data.
The endpoint is rate-limited .
Tokens travel in the URL, so treat a link like a shared secret: revoke and reissue if one leaks.
App: backend/src/shareable_links/ — ShareableLink model, services, public view + permission, and the backoffice management viewset ( /api/v1/shareable-links/ ).
Response serializer mirrors the bridge campaign API (type-aware merge) and honours per-link field exclusion.
PUBLIC_API_BASE_URL setting renders the link on the vanity host; it's wired per tenant from the infra alb_public_api_host .
Delivery: unibo-services MR !4017 (backend + frontend + LaunchDarkly gate); infrastructure MR !342 (subdomain + ALB routing + PUBLIC_API_BASE_URL ). Epic: unibo-engineering&73 .