Build slot art at production scale
One API for generating, editing, searching, approving and shipping slot-symbol art — with GLI-ready audit, multi-tenant billing and webhook integrations to your CI.
Introduction
All paths are prefixed with https://kobowlotto.com. JSON in, JSON out (PDFs and ZIPs return binary).
Production base URL https://kobowlotto.com
Auth X-API-Key header or Google SSO session cookie.
Rate limit Generations consume your monthly quota; 5xx + 429 trigger SDK auto-retry.
Versioning Endpoints are stable. Breaking changes ship behind /api/studio/v2/.
Authentication
Two parallel auth paths — both pass through the same RBAC layer.
api key X-API-Key header
Mint a key in /products/slotforge/api-keys.html . Keys are workspace-scoped and revocable. Use this from servers, CI, scripts.
curl -H "X-API-Key: sf_xxxxxxxxxxxxxxxxx" https://kobowlotto.com/api/studio/health
SSO Google OAuth
For the dashboard. Visit /products/slotforge/login.html, click Sign in with Google ; you'll get an sf_session HttpOnly cookie. The SDK uses it automatically in the browser.
Roles: viewer (read), designer (create assets), approver (sign off assets), admin (everything). Endpoints that mutate state declare their minimum role inline below.
Generate
Text-to-image, edit-image and upscale. Every generation is logged to cost_log, increments your monthly quota, and produces a hashed audit row.
Generate from prompt
POST /api/studio/generate_raw
Single-image generation from a text prompt. Counts against monthly quota.
designer · approver · admin
Param Type Required
promptstring yes
sizestring (e.g. 1024x1024) no
brand_slugstring no
providerstring no
formatstring (canonical key) no
curl
Node SDK
response
curl -X POST https://kobowlotto.com/api/studio/generate_raw \
-H "X-API-Key: $SF_KEY" \
-H "content-type: application/json" \
-d '{"prompt":"a glowing mermaid coin, polished gold","size":"1024x1024"}'
const sf = new SlotForge({ apiKey: process.env.SLOTFORGE_API_KEY });
const r = await sf.gen({
prompt: 'a glowing mermaid coin, polished gold',
size: '1024x1024',
});
console.log(r.file, r.cost_cents);
{
"ok": true,
"asset_id": 4978,
"file": "atlantis_mermaid_v1_4978.png",
"url": "/twingaming_library/atlantis_mermaid_v1_4978.png",
"size": "1024x1024",
"sha": "a1b2c3d4",
"provider": "openai_gpt_image_1",
"cost_cents": 4,
"duration_ms": 8200
}
Generate with references
POST /api/studio/generate_with_refs
Condition on existing asset(s) (style transfer, brand match).
designer · approver · admin
curl -X POST https://kobowlotto.com/api/studio/generate_with_refs \
-H "X-API-Key: $SF_KEY" -H "content-type: application/json" \
-d '{"prompt":"same character, holding crown","reference_asset_ids":[4865,4866]}'
Edit an asset
POST /api/studio/edit_image
Apply prompt-driven edit to an existing asset. Creates a new kind=edit version in the version timeline.
sf.edit({ asset_id: 4865, prompt: 'add bubbles and emerald tint' })
Upscale
POST /api/studio/upscale
2x / 4x upscale via Real-ESRGAN.
sf.upscale({ asset_id: 4865, scale: 2 })
Search
Semantic library search
POST /api/studio/search_semantic
Vector similarity over CLIP embeddings of every asset. Great for "find every mermaid I've ever generated".
const hits = await sf.search('mermaid gold coin', { limit: 20 });
hits.results.forEach(r => console.log(r.file, r.score));
Projects
List projects
GET /api/studio/projects
await sf.projects.list();
Create project
POST /api/studio/projects
designer · approver · admin
await sf.projects.create({
slug: 'atlantis_mermaid_v2',
name: 'Atlantis Mermaid v2',
theme: 'mermaid',
});
Run math simulation
POST /api/studio/projects/:id/simulate
Monte Carlo simulation: returns RTP, hit frequency, volatility class, biggest win.
await sf.projects.simulate(1, { spins: 10000 });
Brands
List brands
GET /api/studio/brands
Create brand
POST /api/studio/brands
designer · approver · admin
await sf.brands.create({
slug: 'pollard',
name: 'Pollard Banknote',
palette: { primary: '#1e3a8a', accent: '#fbbf24' },
});
Approval & versions
Change asset status
POST /api/studio/assets/:id/status
draft → review → approved → cert_submitted → production. Each transition is Ed25519-signed.
approver · admin
await sf.assets.approve(4865, 'ready for cert');
Version timeline
GET /api/studio/assets/:id/versions
GET /api/studio/assets/:id/versions/:n/diff?against=:m
POST /api/studio/assets/:id/revert/:n
Git-like history per asset: every edit/regenerate becomes a new version. Diff returns a pixel-difference PNG. Revert creates a new HEAD version cloned from version N.
const versions = await sf.assets.versions(4865);
const diff = await sf.assets.versionDiff(4865, 3, 1);
await sf.assets.revert(4865, 2);
Compliance
Generate GLI report PDF
POST /api/studio/projects/:id/compliance_report
Returns a 30+ page signed PDF: paytable, RTP, asset manifest, audit trail, jurisdiction-specific notes. Supports MN / ON / UK / MX / BR.
designer · approver · admin
const pdf = await sf.projects.complianceReport(1, { jurisdiction: 'MN' });
fs.writeFileSync('atlantis_MN.pdf', pdf);
Export
Sprite atlas
POST /api/studio/export_sprite_atlas
Packs every approved asset of a project into one PNG + JSON manifest.
await sf.exports.spriteAtlas({ project_id: 1 });
Multi-resolution ZIP
POST /api/studio/export_multires
await sf.exports.multires({ project_id: 1, sizes: ['256','512','1024'] });
Project ZIP
POST /api/studio/export_project_zip
await sf.exports.projectZip({ project_id: 1, include_audit: true });
Costs
Cost report
GET /api/studio/costs
USD aggregates by day / provider / project. Use ?since=2026-05-01.
await sf.costs.summary({ since: '2026-05-01' });
Webhooks
Create webhook
POST /api/studio/webhooks
Subscribe to events: asset.approved, project.created, cost.daily_threshold_exceeded, comment.mentioned, etc. Slack/Discord get pre-formatted payloads.
await sf.webhooks.create({
name: 'Designers Slack',
url: 'https://hooks.slack.com/services/...',
kind: 'slack',
events: ['asset.approved', 'comment.mentioned'],
});
Billing
My subscription
GET /api/billing/me
Current plan, usage vs quota, period bounds, month-to-date provider spend.
Stripe Checkout
POST /api/billing/checkout
Returns a hosted Stripe URL. Redirect the user to upgrade.
designer · approver · admin
const { url } = await sf.billing.checkout('starter');
location.href = url;