iGamingScraper REST API

Token-authenticated REST API providing structured iGaming data: slot providers, slots, news articles, jobs, and regulatory entities. OpenAPI 3.0.3, cursor-paginated, ETag-friendly, with incremental sync support.

Operations 29

GET /api/v1/demand/ Search-demand cut #
GET /api/v1/features/ List slot features #
GET /api/v1/jobs/ List vacancies #
GET /api/v1/jobs/{id}/ Get vacancy detail #
GET /api/v1/jobs/stats/ Jobs statistics (approximate) #
GET /api/v1/news/ List news articles #
GET /api/v1/news/{id}/ Get news article detail #
GET /api/v1/news/stats/ News statistics (approximate) #
GET /api/v1/providers/ List slot providers #
GET /api/v1/providers/{slug}/ Get provider detail #
GET /api/v1/providers/{slug}/demand/ Search demand for this provider #
GET /api/v1/providers/{slug}/jobs/ Job vacancies for this provider #
GET /api/v1/providers/{slug}/news/ News for this brand #
GET /api/v1/providers/{slug}/slots/ Slots for this provider #
GET /api/v1/providers/{slug}/team/ Key team members for this provider #
GET /api/v1/providers/ids/ Reconcile — all public provider slugs #
GET /api/v1/regulators/ List regulators #
GET /api/v1/regulators/{slug}/ Get regulator detail #
GET /api/v1/regulators/{slug}/news/ News for this brand #
GET /api/v1/series/ List slot series (franchises) #
GET /api/v1/series/{slug}/ Get series (franchise) family summary #
GET /api/v1/slots/ List public slots #
GET /api/v1/slots/{slug}/ Get slot detail #
GET /api/v1/slots/{slug}/demand/ Slot demand snapshot #
GET /api/v1/slots/ids/ Reconcile — all public slot slugs #
GET /api/v1/sources/ List news sources #
GET /api/v1/sources/{host}/ Get source detail #
GET /api/v1/stats/ Public aggregate statistics #
GET /api/v1/themes/ List slot themes #

Documentation

Specifications

Other Resources

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/igamingscraper-rest-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

igaming-tools-openapi.json Raw ↑
{"openapi": "3.0.3", "info": {"title": "iGaming Tools API", "version": "1.0.0", "description": "Public REST API for iGaming data: slot providers, slots, news, jobs, sources.\n\n## Authentication\n\nEvery endpoint documented in this schema requires an `Authorization: Token <your-token>` header. Create a free account and issue your own key at /account/.\n\n## Response Codes\n\n- **200** OK. Quota is decremented, unless this specific operation is documented as exempt.\n- **304** Not Modified — ETag match (If-None-Match). Quota is not decremented.\n- **400** Bad Request — invalid filter or parameter. Quota is not decremented.\n- **401** Unauthorized — missing or invalid token. Quota is not decremented.\n- **402** Payment Required — billing quota exhausted (monthly free tier or paid balance depleted). Retry after quota reset or top-up. Distinct from rate limiting. Quota is not decremented.\n- **404** Not Found — resource does not exist or is not yet public. Quota is not decremented.\n- **429** Too Many Requests — technical per-user rate limit exceeded (requests/min). Back off and retry. Distinct from quota (402). Quota is not decremented.\n\n## Sync Protocol\n\nUse `?updated_since=<ISO-8601>` for incremental sync. Store `X-Sync-Timestamp` response header and pass as `updated_since` next call. Use `/ids/` endpoints for tombstone reconcile (unpublished items do not appear in deltas).", "termsOfService": "https://i-gaming.tools/terms/", "contact": {"name": "iGaming Tools support", "email": "support@i-gaming.tools", "url": "https://i-gaming.tools/docs/"}, "license": {"name": "Terms of Service", "url": "https://i-gaming.tools/terms/"}}, "paths": {"/api/v1/demand/": {"get": {"operationId": "demand_list", "description": "Single parametrized endpoint over the market-demand cut (slot × country search-volume aggregate). The volume_12m figure is a SUM over a rolling 12-month window shared by every row in the response (not the latest month) — see meta.window and meta.coverage.pairs_at_frontier_pct for how complete the current month's collection is. coverage=our own catalogue, not the wider market (meta.coverage.basis). The response schema is a oneOf over four envelopes, one per axis family, and meta.by tells you which one you received: by='slot' carries per-market detail, by='slot_global' aggregates a slot across markets, by='country' is one market per row, and the remaining axes share a keyed shape. See the examples for each.", "summary": "Search-demand cut", "parameters": [{"in": "query", "name": "by", "schema": {"type": "string", "enum": ["country", "feature", "game_category", "mechanic", "provider", "slot", "slot_global", "theme"], "default": "slot"}, "description": "Cut axis; the shape of each result item is decided by this parameter alone. 'slot' (default) is one slot in ONE market and requires ?country=; 'slot_global' is one slot aggregated across every tracked market and does not require one; passing ?country= there simply narrows the aggregate. 'country' is one market; 'provider', 'theme', 'feature', 'mechanic' and 'game_category' share one shape keyed by the axis value. Any other value → 400. 'theme'/'feature' are overlapping axes (a slot with multiple themes counts in each) — see response meta.overlapping."}, {"in": "query", "name": "country", "schema": {"type": "string"}, "description": "2-letter ISO country code (case-insensitive, normalized to upper-case). REQUIRED when by='slot', because that axis reports one slot in one market and its per-market fields are undefined without one — use by='slot_global' for a worldwide ranking instead. Optional for every other axis, where omitting it aggregates across all tracked markets. Invalid format → 400."}, {"in": "query", "name": "coverage", "schema": {"type": "boolean", "default": true}, "description": "false suppresses meta.coverage entirely — the coverage aggregates are not computed at all, rather than computed and discarded. Omitted or true follows the default rule: meta.coverage is populated on the first page of a cursor traversal (previous == null) and null on subsequent pages. Any other value returns 400."}, {"in": "query", "name": "cursor", "schema": {"type": "string"}, "description": "Opaque pagination cursor from a previous response's next/previous link."}, {"in": "query", "name": "feature", "schema": {"type": "string"}, "description": "Feature slug (exact match). Non-existent slug → empty results, not 400."}, {"in": "query", "name": "game_category", "schema": {"type": "string", "enum": ["crash", "instant_win", "live", "other", "scratch", "table", "unknown", "video_slot"]}, "description": "Game category filter (catalogue). One of: unknown, video_slot, crash, instant_win, scratch, live, table, other. Not to be confused with ?by=game_category (cut axis) — both can be combined."}, {"in": "query", "name": "has_bonus_buy", "schema": {"type": "string"}, "description": "'true' or 'false'. Any other value returns 400."}, {"in": "query", "name": "jackpot_type", "schema": {"type": "string", "enum": ["fixed", "none", "pooled", "progressive", "unknown"]}, "description": "Jackpot type (none/fixed/progressive/pooled/unknown)"}, {"in": "query", "name": "max_win_max", "schema": {"type": "integer"}, "description": "max_win <= this value (multiplier of stake, positive integer). Also filters GET /api/v1/demand/ — same catalogue filter."}, {"in": "query", "name": "max_win_min", "schema": {"type": "integer"}, "description": "max_win >= this value (multiplier of stake, positive integer). Also filters GET /api/v1/demand/ — same catalogue filter."}, {"in": "query", "name": "mechanic", "schema": {"type": "string", "enum": ["cluster", "lines", "megaways", "scatter_pays", "variable_ways", "ways"]}, "description": "Bet mechanic (catalogue filter). One of: lines, ways, cluster, megaways, scatter_pays. Not to be confused with ?by=mechanic (cut axis) — both can be combined."}, {"in": "query", "name": "ordering", "schema": {"type": "string", "enum": ["-volume_12m", "volume_12m"], "default": "-volume_12m"}, "description": "Whitelist: '-volume_12m' (default, highest demand first) or 'volume_12m' (lowest first). Any other value → 400."}, {"in": "query", "name": "page_size", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 20}, "description": "Number of results per page. Default 20, maximum 100 — same limits as the rest of the public API. An operator-configured limit may lower the maximum."}, {"in": "query", "name": "provider", "schema": {"type": "string"}, "description": "Provider slug (exact match). Non-existent slug → empty results, not 400. Not to be confused with ?by=provider (cut axis) — both can be combined."}, {"in": "query", "name": "released_after", "schema": {"type": "string", "format": "date"}, "description": "ISO date (YYYY-MM-DD). release_date >= this value. Slots with release_date IS NULL are excluded. 400 on invalid format."}, {"in": "query", "name": "released_before", "schema": {"type": "string", "format": "date"}, "description": "ISO date (YYYY-MM-DD). release_date <= this value — INCLUSIVE, the named day is part of the range. Note that ?published_before, ?posted_before and ?established_before on other endpoints are EXCLUSIVE. Slots with release_date IS NULL are excluded. 400 on invalid format."}, {"in": "query", "name": "rtp_max", "schema": {"type": "number", "format": "double"}, "description": "rtp_default <= this value (percent, decimal, e.g. 96.5). Also filters GET /api/v1/demand/ — same catalogue filter."}, {"in": "query", "name": "rtp_min", "schema": {"type": "number", "format": "double"}, "description": "rtp_default >= this value (percent, decimal, e.g. 96.5). Also filters GET /api/v1/demand/ — same catalogue filter."}, {"in": "query", "name": "search", "schema": {"type": "string"}, "description": "Case-insensitive substring search over slot name + aliases. Empty/whitespace-only value is a no-op (does not narrow results). Soft-clipped to 100 characters (not a 400)."}, {"in": "query", "name": "series", "schema": {"type": "string"}, "description": "Series slug (exact match). A slot belongs to at most one series."}, {"in": "query", "name": "theme", "schema": {"type": "string"}, "description": "Theme slug (exact match). Non-existent slug → empty results, not 400."}, {"in": "query", "name": "volatility", "schema": {"type": "string", "enum": ["high", "low", "med_high", "med_low", "medium", "very_high"]}, "description": "Volatility (low/med_low/medium/med_high/high/very_high)"}], "tags": ["demand"], "security": [{"TokenAuth": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DemandCutEnvelope"}, "examples": {"CutBySlot(default,Requires?country=)": {"value": {"meta": {"by": "slot", "country": "BR", "window": {"start": "2025-07", "end": "2026-06"}, "window_mixed": false, "metric": "volume_12m", "total_volume_12m": 4820100, "overlapping": false, "coverage": {"basis": "our_catalogue", "markets_tracked": 81, "slots_total": 509, "providers": [{"slug": "pragmatic-play", "name": "Pragmatic Play", "slots": 509}], "pairs_at_frontier_pct": 70, "computed_at": "2026-07-29T03:30:00Z"}}, "next": null, "previous": null, "results": [{"slot": {"slug": "example-slot-title", "name": "Example Slot Title", "provider": {"slug": "pragmatic-play", "name": "Pragmatic Play"}, "demo_url": "https://demo.i-gaming.tools/iframe/example-slot-title/"}, "volume_12m": 12000, "months_covered": 12, "last_seen": {"month": "2026-06", "volume": 1100}, "prev_volume": 950}]}, "summary": "Cut by slot (default, requires ?country=)"}, "CutBySlotGlobal(worldwideRanking,No?country=Needed)": {"value": {"meta": {"by": "slot_global", "country": null, "window": {"start": "2025-08", "end": "2026-07"}, "window_mixed": false, "metric": "volume_12m", "total_volume_12m": 1200000, "overlapping": false, "coverage": null}, "next": "https://i-gaming.tools/api/v1/demand/?by=slot_global&cursor=abc", "previous": null, "results": [{"slot": {"slug": "example-slot-title", "name": "Example Slot Title", "provider": {"slug": "example-provider", "name": "Example Provider"}, "demo_url": null}, "volume_12m": 48000, "markets_with_data": 17}]}, "summary": "Cut by slot_global (worldwide ranking, no ?country= needed)"}, "CutByCountry(marketMap,OneCall—No?country=Filter)": {"value": {"meta": {"by": "country", "country": null, "window": {"start": "2025-07", "end": "2026-06"}, "window_mixed": false, "metric": "volume_12m", "total_volume_12m": 4820100, "overlapping": false, "coverage": null}, "next": "https://i-gaming.tools/api/v1/demand/?by=country&cursor=abc", "previous": null, "results": [{"country": {"iso": "BR", "name": "Brazil"}, "volume_12m": 812000, "slots_with_data": 509, "pairs_at_frontier_pct": 70}]}, "summary": "Cut by country (market map, one call — no ?country= filter)"}, "CutByProvider|theme|feature|mechanic|gameCategory": {"value": {"meta": {"by": "game_category", "country": null, "window": {"start": "2025-07", "end": "2026-06"}, "window_mixed": false, "metric": "volume_12m", "total_volume_12m": 4820100, "overlapping": false, "coverage": null}, "next": null, "previous": null, "results": [{"key": {"slug": "video_slot", "name": "Video Slot"}, "volume_12m": 4400000, "slots_with_data": 480}]}, "summary": "Cut by provider|theme|feature|mechanic|game_category"}}}}, "description": "Success.", "headers": {"X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "400": {"$ref": "#/components/responses/Err400"}}}}, "/api/v1/features/": {"get": {"operationId": "features_list", "description": "Cursor-paginated directory of slot features (game mechanics) that have at least one public slot. Use ?feature=<slug> on GET /api/v1/slots/ to filter by feature. aliases are alternative spellings for matching a user's query to this slug (e.g. 'egypt' -> 'egyptian'). Filter by slug only — aliases are not a second filter key. If next is not null, the directory does not fit in one response — keep paging until next is null before treating the set as complete.", "summary": "List slot features", "parameters": [{"in": "query", "name": "cursor", "schema": {"type": "string"}, "description": "Opaque pagination cursor from a previous response's next/previous link."}, {"in": "query", "name": "page_size", "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 200}, "description": "Number of results per page. Default 200, maximum 500. The default is large enough to return the whole directory in one response; if next is not null, keep paginating with cursor until it is."}], "tags": ["features"], "security": [{"TokenAuth": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TaxonomyDirectoryPage"}, "examples": {"BonusGameDirectoryEntry": {"value": {"count": 64, "next": null, "previous": null, "results": [{"slug": "bonus-game", "name": "Bonus Game", "slots_count": 27, "aliases": ["bonus round", "mini game"]}]}, "summary": "Bonus Game directory entry"}}}}, "description": "Success.", "headers": {"X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "400": {"$ref": "#/components/responses/Err400"}}}}, "/api/v1/jobs/": {"get": {"operationId": "jobs_list", "description": "Public iGaming vacancy catalog. Cursor-pagination. No count. Field source_url — original vacancy page. Field url is absent: use source_url instead. With ?updated_since the order switches to (updated_at, id) ASC for forward sync, and only vacancies CHANGED since that moment are returned. Combine it with ?include_closed=true when replicating: without that, a vacancy that closed since your last run is simply absent from the delta, and your copy keeps showing it as open. Store the X-Sync-Timestamp header and pass it back on the next run.", "summary": "List vacancies", "parameters": [{"in": "query", "name": "brand_slug", "schema": {"type": "string"}, "description": "Brand slug (exact). The provider or operator this vacancy is attributed to."}, {"in": "query", "name": "city", "schema": {"type": "string"}, "description": "City slug"}, {"in": "query", "name": "company", "schema": {"type": "string"}, "description": "Company slug"}, {"in": "query", "name": "country", "schema": {"type": "string"}, "description": "Location country ISO-2 (→ location_country)"}, {"name": "cursor", "required": false, "in": "query", "description": "Opaque pagination cursor from a previous response's next/previous link.", "schema": {"type": "string"}}, {"in": "query", "name": "employment_type", "schema": {"type": "string", "enum": ["contract", "freelance", "full_time", "internship", "part_time"]}, "description": "Employment type."}, {"in": "query", "name": "igaming_segment", "schema": {"type": "string", "enum": ["affiliate", "casino", "esports", "game_studio", "lottery", "payment_provider", "platform_provider", "poker", "regulator", "sportsbook"]}, "description": "iGaming segment."}, {"in": "query", "name": "include_closed", "schema": {"type": "boolean"}, "description": "false (default) = ACTIVE only; true = + CLOSED within window"}, {"in": "query", "name": "ordering", "schema": {"type": "string", "enum": ["-posted_at", "posted_at"]}, "description": "Ordering (whitelist: posted_at, -posted_at; default -posted_at)"}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results per page. Default 20, maximum 100 — same limits as the rest of the public API. An operator-configured limit may lower the maximum.", "schema": {"type": "integer"}}, {"in": "query", "name": "posted_after", "schema": {"type": "string", "format": "date-time"}, "description": "Posted at >= this value (ISO 8601, inclusive)."}, {"in": "query", "name": "posted_before", "schema": {"type": "string", "format": "date-time"}, "description": "Posted at < this value (ISO 8601, EXCLUSIVE — the named moment is not included)."}, {"in": "query", "name": "q", "schema": {"type": "string"}, "description": "Text search by title (case-insensitive substring)"}, {"in": "query", "name": "remote_mode", "schema": {"type": "string", "enum": ["hybrid", "on_site", "remote"]}, "description": "Remote mode."}, {"in": "query", "name": "seniority", "schema": {"type": "string", "enum": ["c_level", "head", "junior", "lead", "mid", "senior"]}, "description": "Seniority level."}, {"in": "query", "name": "skills", "schema": {"type": "array", "items": {"type": "string"}}, "description": "Skill slugs (OR semantics; repeatable parameter)"}, {"in": "query", "name": "source", "schema": {"type": "string", "enum": ["careers", "linkedin"]}, "description": "Source."}, {"in": "query", "name": "updated_since", "schema": {"type": "string", "format": "date-time"}, "description": "ISO-8601 datetime. Returns only records updated at or after this moment."}], "tags": ["jobs"], "security": [{"TokenAuth": []}], "responses": {"200": {"headers": {"X-Sync-Timestamp": {"$ref": "#/components/headers/XSyncTimestamp"}, "X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedJobsListList"}}}, "description": "Success."}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "400": {"$ref": "#/components/responses/Err400"}}}}, "/api/v1/jobs/{id}/": {"get": {"operationId": "jobs_retrieve", "description": "Full vacancy card by UUID. CLOSED older than window or hidden → 404.", "summary": "Get vacancy detail", "parameters": [{"in": "path", "name": "id", "schema": {"type": "string", "format": "uuid"}, "description": "Stable identifier of the vacancy, safe to store and reuse.", "required": true}], "tags": ["jobs"], "security": [{"TokenAuth": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobsDetail"}}}, "description": "Success.", "headers": {"X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "404": {"$ref": "#/components/responses/Err404"}}}}, "/api/v1/jobs/stats/": {"get": {"operationId": "jobs_stats_retrieve", "description": "Approximate counts for landing total-badge. total_approx — approximate row count (±5%; not an exact count). Free — this endpoint does not count against your quota.", "summary": "Jobs statistics (approximate)", "tags": ["jobs"], "security": [{"TokenAuth": []}], "responses": {"200": {"content": {"application/json": {"schema": {"type": "object", "properties": {"total_approx": {"type": "integer", "description": "Approximate count (±5%; not an exact count)."}, "by_status_public": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "Count per public status code."}, "by_segment": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "Count per iGaming segment code."}, "last_posted_at": {"type": "string", "format": "date-time", "nullable": true}, "computed_at": {"type": "string", "format": "date-time"}}}, "examples": {"ExampleResponse": {"value": {"total_approx": 4210, "by_status_public": {"live": 3900, "closed_recent": 310}, "by_segment": {"casino": 1200, "sportsbook": 800}, "last_posted_at": "2026-06-08T10:00:00Z", "computed_at": "2026-06-09T12:00:00Z"}, "summary": "Example response"}}}}, "description": "Success.", "headers": {"X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429WithQuota"}}}}, "/api/v1/news/": {"get": {"operationId": "news_list", "description": "Cursor-paginated list of iGaming news articles ordered by published_at DESC. Does not include body_en — body is only available in the detail endpoint. Filterable by brand, language, host, and date range. With ?updated_since the order switches to (updated_at, id) ASC for forward sync, and only articles CHANGED since that moment are returned — including ones published long ago but ingested or corrected recently. Store the X-Sync-Timestamp header and pass it back on the next run.", "summary": "List news articles", "parameters": [{"in": "query", "name": "brand_kind", "schema": {"type": "string"}, "description": "Brand kind code. Currently one of slot_provider, casino_brand, regulator, other. The set is data-driven, so treat it as open."}, {"in": "query", "name": "brand_slug", "schema": {"type": "string"}, "description": "Brand slug"}, {"name": "cursor", "required": false, "in": "query", "description": "Opaque pagination cursor from a previous response's next/previous link.", "schema": {"type": "string"}}, {"in": "query", "name": "host", "schema": {"type": "string"}, "description": "Host FQDN"}, {"in": "query", "name": "language", "schema": {"type": "string"}, "description": "Language code (ISO 639-1)"}, {"name": "ordering", "required": false, "in": "query", "description": "Which field to use when ordering the results.", "schema": {"type": "string"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results per page. Default 20, maximum 100 — same limits as the rest of the public API. An operator-configured limit may lower the maximum.", "schema": {"type": "integer"}}, {"in": "query", "name": "published_after", "schema": {"type": "string", "format": "date-time"}, "description": "Published at >= this value (ISO 8601, inclusive)."}, {"in": "query", "name": "published_before", "schema": {"type": "string", "format": "date-time"}, "description": "Published at < this value (ISO 8601, EXCLUSIVE — the named moment is not included)."}, {"in": "query", "name": "updated_since", "schema": {"type": "string", "format": "date-time"}, "description": "ISO-8601 datetime. Returns only records updated at or after this moment."}], "tags": ["news"], "security": [{"TokenAuth": []}], "responses": {"200": {"headers": {"X-Sync-Timestamp": {"$ref": "#/components/headers/XSyncTimestamp"}, "X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedNewsArticleShortList"}}}, "description": "Success."}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "400": {"$ref": "#/components/responses/Err400"}}}}, "/api/v1/news/{id}/": {"get": {"operationId": "news_retrieve", "description": "Full news article by UUID including body_en from content storage. If content storage is unavailable: body_en=\"\", body_unavailable_reason=\"content_storage_unavailable\". If body was not extracted: body_unavailable_reason=\"extraction_failed\".", "summary": "Get news article detail", "parameters": [{"in": "path", "name": "id", "schema": {"type": "string", "format": "uuid"}, "description": "Stable UUID identifier of the article.", "required": true}], "tags": ["news"], "security": [{"TokenAuth": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/NewsArticleFull"}}}, "description": "Success.", "headers": {"X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "404": {"$ref": "#/components/responses/Err404"}}}}, "/api/v1/news/stats/": {"get": {"operationId": "news_stats_retrieve", "description": "Approximate counts for total-badge display. Returns total_approx, by_status_done, by_language, last_published_at. Free — this endpoint does not count against your quota. Same as /jobs/stats/ and /stats/.", "summary": "News statistics (approximate)", "tags": ["news"], "security": [{"TokenAuth": []}], "responses": {"200": {"content": {"application/json": {"schema": {"type": "object", "properties": {"total_approx": {"type": "integer", "description": "±5% approximate total."}, "by_status_done": {"type": "integer"}, "by_language": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "Count per language code."}, "last_published_at": {"type": "string", "format": "date-time", "nullable": true}, "computed_at": {"type": "string", "format": "date-time"}}}}}, "description": "Success.", "headers": {"X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429WithQuota"}}}}, "/api/v1/providers/": {"get": {"operationId": "providers_list", "description": "Cursor-paginated list of public slot providers. Supports ?updated_since for incremental sync and ETag/304. X-Sync-Timestamp response header for next-sync cursor. Use /providers/ids/ for tombstone reconcile.", "summary": "List slot providers", "parameters": [{"in": "header", "name": "If-None-Match", "schema": {"type": "string"}, "description": "Opaque ETag value from a previous response to this same endpoint. When it matches the current ETag, the server returns 304 Not Modified with no body instead of re-sending the full payload."}, {"in": "query", "name": "country", "schema": {"type": "string"}, "description": "Country (exact, free-text)"}, {"name": "cursor", "required": false, "in": "query", "description": "Opaque pagination cursor from a previous response's next/previous link.", "schema": {"type": "string"}}, {"in": "query", "name": "established_after", "schema": {"type": "integer"}, "description": "Established in this year or later (inclusive)."}, {"in": "query", "name": "established_before", "schema": {"type": "integer"}, "description": "Established strictly before this year (EXCLUSIVE — the named year is not included)."}, {"in": "query", "name": "has_news", "schema": {"type": "boolean"}, "description": "Brands with news only"}, {"name": "ordering", "required": false, "in": "query", "description": "Which field to use when ordering the results.", "schema": {"type": "string"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results per page. Default 20, maximum 100 — same limits as the rest of the public API. An operator-configured limit may lower the maximum.", "schema": {"type": "integer"}}, {"in": "query", "name": "search", "schema": {"type": "string"}, "description": "Search by name and aliases"}, {"in": "query", "name": "updated_since", "schema": {"type": "string", "format": "date-time"}, "description": "ISO-8601 datetime. Returns only records updated at or after this moment."}], "tags": ["providers"], "security": [{"TokenAuth": []}], "responses": {"200": {"headers": {"X-Sync-Timestamp": {"$ref": "#/components/headers/XSyncTimestamp"}, "ETag": {"$ref": "#/components/headers/ETag"}, "X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedBrandShortList"}, "examples": {"ListProviders": {"value": {"next": "https://i-gaming.tools/api/v1/providers/?cursor=cD00ODY%3D", "previous": "https://i-gaming.tools/api/v1/providers/?cursor=cj0xJnA9NDg3", "results": [{"slug": "example-provider", "kind": "slot_provider", "name": "Example Provider", "aliases": ["Example"], "hosts_count": 3, "news_count": 42}]}, "summary": "List providers"}}}}, "description": "Success."}, "304": {"headers": {"X-Sync-Timestamp": {"$ref": "#/components/headers/XSyncTimestamp"}, "ETag": {"$ref": "#/components/headers/ETag"}}, "description": "Not Modified — the ETag in If-None-Match matched the current value. No body."}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "400": {"$ref": "#/components/responses/Err400"}}}}, "/api/v1/providers/{slug}/": {"get": {"operationId": "providers_retrieve", "description": "Full provider profile: firmographics, assets (logo), company block (hq/offices/licenses/contacts), counts (slots/jobs/news/team/has_demand), HATEOAS links to sub-resources. ETag/304 via If-None-Match.", "summary": "Get provider detail", "parameters": [{"in": "header", "name": "If-None-Match", "schema": {"type": "string"}, "description": "Opaque ETag value from a previous response to this same endpoint. When it matches the current ETag, the server returns 304 Not Modified with no body instead of re-sending the full payload."}, {"in": "path", "name": "slug", "schema": {"type": "string"}, "required": true}], "tags": ["providers"], "security": [{"TokenAuth": []}], "responses": {"200": {"headers": {"ETag": {"$ref": "#/components/headers/ETag"}, "X-Quota-Free-Remaining": {"$ref": "#/components/headers/XQuotaFreeRemaining"}, "X-Quota-Paid-Balance": {"$ref": "#/components/headers/XQuotaPaidBalance"}, "X-Quota-Resets-At": {"$ref": "#/components/headers/XQuotaResetsAt"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProviderDetail"}, "examples": {"ProviderDetail": {"value": {"slug": "example-provider", "kind": "slot_provider", "name": "Example Provider", "aliases": ["Example"], "about_html": "<p>Example Provider builds video slots.</p>", "firmographics": {"country": "MT", "jurisdiction": "Malta", "established": 2015, "authority_for": "", "statutory_authority": ""}, "assets": {"logo": {"url": "https://cdn.i-gaming.tools/brands/example-provider.png", "key": "brands/example-provider.png", "version": "brands/example-provider.png"}}, "company": {"hq": {"label": "Head office", "city": "Sliema", "country": "MT"}, "offices": [{"label": "Studio", "city": "Kyiv", "country": "UA", "sort_order": 1}], "licenses": [{"authority": "MGA", "license_ref": "MGA/B2B/000/0000", "jurisdiction": "Malta", "status": "active", "sort_order": 0}], "contacts": [{"kind": "email", "label": "Sales", "value": "mailto:sales@example.com"}]}, "counts": {"slots": 128, "jobs": 4, "news": 42, "team": 11, "has_demand": true}, "links": {"slots": "/api/v1/providers/example-provider/slots/", "demand": "/api/v1/providers/example-provider/demand/", "jobs": "/api/v1/providers/example-provider/jobs/", "news": "/api/v1/providers/example-provider/news/", "team": "/api/v1/providers/example-provider/team/"}, "hosts": [{"host": "example-provider.com", "display_name": "Example Provider"}], "verified_at": "2026-07-01T10:00:00Z", "updated_at": "2026-08-01T09:30:00Z"}, "summary": "Provider detail"}}}}, "description": "Success."}, "304": {"headers": {"ETag": {"$ref": "#/components/headers/ETag"}}, "description": "Not Modified — the ETag in If-None-Match matched the current value. No body."}, "401": {"$ref": "#/components/responses/Err401"}, "429": {"$ref": "#/components/responses/Err429"}, "402": {"$ref": "#/components/responses/Err402"}, "404": {"$ref": "#/components/responses/Err404"}}}}, "/api/v1/providers/{slug}/demand/": {"get": {"operationId": "providers_demand_retrieve", "description": "Provider demand snapshot: computed_at, provider-level metrics, top_slots. Empt

# --- truncated at 32 KB (144 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/igaming-tools/refs/heads/main/openapi/igaming-tools-openapi.json