Integrating the Gamescript feed

Everything an operator's install needs to take titles from the feed. Your game server keeps the random numbers, the outcomes and the wallet. Gamescript supplies the content.

The model

A Gamescript title is a pack: the maths config, a maths document, the art set and the sound. You import the pack into your own game catalogue and your own game server plays it. Gamescript is not called during a round.

There are two hosts.

HostWhat it servesAuth
cdn.gamescript.netThe catalogue, a public manifest per title, all art and soundNone
api.gamescript.netTitle packs with reel strips, maths documents, usage reportsOperator key

1. Read the catalogue

GET https://cdn.gamescript.net/feed/v1/catalogue.json
GET https://cdn.gamescript.net/feed/v1/catalogue.sig

The catalogue lists every title with its current version, headline facts, the URL of its public manifest and the SHA-256 of its pack. catalogue.sig is a base64 Ed25519 signature over the exact bytes of catalogue.json.

Poll it on a schedule. It is cached for five minutes, so polling more often gains nothing. A title is new or changed when its version differs from the one you hold.

2. Pin the studio key

GET https://cdn.gamescript.net/feed/v1/studio-key.json

Store the public key in your own configuration once, at setup. Do not re-read it from the feed each time you verify: a key fetched from the same place as the data proves nothing. The signing key is held offline at the studio and is never present on the delivery network.

3. Fetch the pack

GET https://api.gamescript.net/v1/titles/{slug}/pack
GET https://api.gamescript.net/v1/titles/{slug}/pack?version={version}
Authorization: Bearer gs_...

The body is the pack as JSON. Three response headers carry the proof:

HeaderMeaning
x-gamescript-versionThe pack version, a 12 character content hash
x-gamescript-sha256SHA-256 of the response body
x-gamescript-signatureEd25519 signature over the response body, base64

Verify the signature over the raw body bytes with your pinned key before you parse anything. Reject the pack if it fails.

import base64, urllib.request
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

PINNED = "base64 public key from your own config"

req = urllib.request.Request(
    "https://api.gamescript.net/v1/titles/safari-reels/pack",
    headers={"Authorization": "Bearer gs_..."})
with urllib.request.urlopen(req) as r:
    body = r.read()
    signature = base64.b64decode(r.headers["x-gamescript-signature"])

key = Ed25519PublicKey.from_public_bytes(base64.b64decode(PINNED))
key.verify(signature, body)   # raises if the pack was altered

The maths document is at /v1/titles/{slug}/math with the same key.

4. What is in a pack

FieldContent
schemagamescript.pack/1
kindslot
slug, version, publishedAtIdentity. A version never changes meaning
configGrid, symbols with pays, paylines, features, RTP in basis points, volatility, bet limits, maximum win, and the reel strips
worldPresentation hints: ambience and accent colour
artEvery art and sound file with its SHA-256 and size
audioWhich of those files are the sound: music ({"file": "music.m4a"} or null), kit (cue name to file for spin, reel, tick, win, bigwin; only the cues the pack has) and voice (line name to file, {} when there are none). null when a title has no sound
mathSha256Hash of the maths document

Version 1 packs are slots on a 5 by 3 grid with 20 paylines, ten symbols (four low, four high, wild, scatter) and reel strips of 40 to 64 positions. The config object is the Spin script’s SlotTitleConfig without assetBase, which your importer sets to wherever it stores the art.

Download each art file from the artBase in the public manifest and check it against the hash in the pack. Sound files (.m4a) live beside the art under the same artBase and are in the same art list, so one loop fetches and verifies both. The public manifest carries the same audio object, and each catalogue entry has hasAudio. Versioned URLs are immutable and can be cached for good.

5. Go live your way

What happens after import is your decision and your regulator’s. A social or free play operator can activate a verified title at once. A licensed operator will usually stage it as a draft and release it with the next signed build, because outcome-affecting files belong in the release manifest.

6. Report usage

POST https://api.gamescript.net/v1/usage
Authorization: Bearer gs_...
Content-Type: application/json

{
  "day": "2026-10-01",
  "rows": [
    { "slug": "safari-reels", "rounds": 18230, "stake": "9115000", "win": "8742100", "currency": "GC" }
  ]
}

One request per day. stake and win are whole numbers sent as strings, in your own coin or currency unit. Sending a day again replaces the earlier report. No round data and no player data is accepted.

Other endpoints

EndpointReturns
GET /v1/healthService status and the number of titles
GET /v1/meYour operator record and entitlements
GET /v1/titlesThe titles you are entitled to, with version, hash and signature

Errors

Errors are JSON: { "ok": false, "error": { "code": "...", "message": "..." } }.

StatusCodeMeaning
401unauthorizedMissing, malformed or suspended key
403not_entitledYour key does not cover that title
404no_such_titleUnknown slug or version
400bad_report, bad_rowA usage report did not match the shape above