Developer docs
Catalog API
Pull the list of games as JSON, render them however you like, and embed any of them with one script tag. Everything below works with a single read-only API key from your publisher panel.
Quick start
Three steps: get a key, fetch the catalog, drop in the embed snippet.
# 1. Fetch the catalog (key from your publisher panel)
curl "https://zoopiagames.com/api/public/catalog?locale=en&per_page=24" \
-H "X-Api-Key: gfk_100002_xxxxxxxxxxxxxxxx"
# 2. Each game already ships with the snippet you need:
# "embed_code": "<div data-gameforge-game=\"admin/arrow\"></div>
# <script src=\"https://zoopiagames.com/gf-embed.js\"></script>"Games only run on domains you have added and verified in the publisher panel. Until then the catalog still lists them, but the game itself refuses to load.
Authentication
Every request carries your key, either as a header (preferred) or a query parameter. The key is read-only: it can list the catalog and nothing else. Rotate it from the panel if it leaks — the old key stops working immediately.
X-Api-Key: gfk_100002_xxxxxxxxxxxxxxxx # header
?key=gfk_100002_xxxxxxxxxxxxxxxx # or query parameterKeys are tied to your publisher account. A suspended or not-yet-approved account gets 401.
GET /api/public/catalog
Returns the games you are allowed to publish, newest first.
| Parameter | Default | Notes |
|---|---|---|
locale | en | en, de, fr, no, tr, pl, es — titles/descriptions in that language, falling back to English |
category | (all) | puzzle, action, arcade, platformer, sports, strategy, racing, casual |
page | 1 | 1-based page number |
per_page | 24 | max 100 |
{
"publisher": { "pub_id": "100002", "name": "Your Company" },
"locale": "en",
"category": null,
"total": 42,
"page": 1,
"per_page": 24,
"games": [
{
"owner": "admin",
"slug": "arrow-oyunu",
"title": "Arrow Master",
"description": "Aim, judge the wind, hit the target…",
"category": "arcade",
"tags": ["arrow", "aim", "arcade"],
"thumb_url": "https://zoopiagames.com/api/thumb/admin/arrow-oyunu?v=…",
"game_url": "https://cdn.example.com/gameforge-prod/admin/arrow-oyunu/live/index.html",
"embed_code": "<div data-gameforge-game=\"admin/arrow-oyunu\"></div>\n<script src=\"https://zoopiagames.com/gf-embed.js\"></script>",
"updated_at": "2026-09-18T10:12:00Z"
}
]
}thumb_url is the card image: an editor-made illustration when one exists, otherwise a real screenshot of the game. Use embed_code rather than building the iframe yourself — see below.
GET /api/public/categories
Categories that actually contain games for you, with counts — handy for building menus.
curl "https://zoopiagames.com/api/public/categories?locale=de" -H "X-Api-Key: …"
{ "locale": "de", "categories": [ { "category": "puzzle", "count": 12 }, … ] }Embedding a game
Paste the snippet where the game should appear. The script creates the iframe, handles fullscreen and mobile layout, performs the authorization handshake from your page, and re-emits gameplay events so your analytics can listen.
<div data-gameforge-game="admin/arrow-oyunu"></div>
<script src="https://zoopiagames.com/gf-embed.js"></script>
<script>
// Optional: react to what happens inside the game
window.addEventListener('gf:game_start', e => console.log('started', e.detail))
window.addEventListener('gf:game_over', e => console.log('score', e.detail.data.score))
</script>The handshake must run on your page, not inside the iframe — that is how our server sees your real domain. If you build the iframe manually the game will not load.
Caching & rate limits
- Responses carry
Cache-Control: public, max-age=300and anETag. SendIf-None-Matchand you get a cheap304. - Cache on your side too — the catalog changes rarely. A block or an unpublish takes effect on our side immediately, so a stale copy may briefly list a game that has stopped loading.
- 120 requests per minute per publisher. Over that you get
429.
Errors
| Status | code | What to do |
|---|---|---|
401 | bad_api_key | Key is wrong, or the publisher account is not approved yet. |
429 | rate_limited | Back off and reuse your cached copy. |
4xx/5xx | — | Body is always JSON with an "error" field. |
Need a key?
Register in the publisher panel, add your domain, publish our ads.txt lines and hit Verify.
Open publisher panel