Returns a 300-pixel-wide PNG image, not a JSON body. Save the response to a .png file. url is required.
Authentication: Unauthenticated; no caller credentials are required.
Parameters
url · query · required
Text/URL to encode; no navigation or upstream fetch is performed.
{
"name": "url",
"in": "query",
"description": "Text/URL to encode; no navigation or upstream fetch is performed.",
"schema": {
"type": "string"
},
"example": "https://example.com/stats/DEMO2345",
"required": true
}
Responses
200 — PNG image bytes (synthetic example is a PNG signature representation, not JSON).
{
"description": "PNG image bytes (synthetic example is a PNG signature representation, not JSON).",
"content": {
"image/png": {
"schema": {
"type": "string",
"format": "binary"
},
"examples": {
"synthetic": {
"summary": "Binary PNG response",
"value": "\\x89PNG\\r\\n\\x1a\\n…"
}
}
}
}
}
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/qrcode?url=https%3A%2F%2Fexample.com%2Fstats%2FDEMO2345"
GET /api/remote/{command}
Dispatch a remote command (legacy GET; modifies data)
Dispatches a command to an active remote_control host. Success confirms dispatch, not that the host applied it. Prefer POST: GET also changes state and must not be prefetched. Query deviceId takes precedence over JSON, but conflicting selectors are rejected. score_left/right aliases resolve to score_home/away. zone is accepted only by score-up commands and sends a one-shot goal, not a prepared confirmation. Only deviceId and zone are forwarded from request fields; arbitrary payload, scores or match IDs in JSON are not forwarded by this HTTP handler.
Authentication: Requires an issued API key via X-API-Key (recommended) or legacy apiKey query. Missing/invalid keys return 401; revoked/expired keys and devices outside a scoped key’s grants return 403. Unrestricted keys can target any device. Alias resolution precedes authorization. Headers keep keys out of query URLs.
Parameters
command · path · required
Command to dispatch. Left/right scoring aliases map to home/away.
Target device; POST may provide it in JSON instead.
{
"name": "deviceId",
"in": "query",
"description": "Target device; POST may provide it in JSON instead.",
"schema": {
"type": "string"
},
"example": "demo-table-01",
"required": true
}
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/remote/score_home_up?deviceId=demo-table-01&zone=3" \
--header "X-API-Key: $IREF_API_KEY"
Dispatches a command to an active remote_control host. Success confirms dispatch, not that the host applied it. Prefer POST: GET also changes state and must not be prefetched. Query deviceId takes precedence over JSON, but conflicting selectors are rejected. score_left/right aliases resolve to score_home/away. zone is accepted only by score-up commands and sends a one-shot goal, not a prepared confirmation. Only deviceId and zone are forwarded from request fields; arbitrary payload, scores or match IDs in JSON are not forwarded by this HTTP handler.
Authentication: Requires an issued API key via X-API-Key (recommended) or legacy apiKey query. Missing/invalid keys return 401; revoked/expired keys and devices outside a scoped key’s grants return 403. Unrestricted keys can target any device. Alias resolution precedes authorization. Headers keep keys out of query URLs.
Parameters
command · path · required
Command to dispatch. Left/right scoring aliases map to home/away.
Target device; POST may provide it in JSON instead.
{
"name": "deviceId",
"in": "query",
"description": "Target device; POST may provide it in JSON instead.",
"schema": {
"type": "string"
},
"example": "demo-table-01",
"required": false
}
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request POST "$BASE_URL/api/remote/score_home_up?deviceId=demo-table-01&zone=3" \
--header "X-API-Key: $IREF_API_KEY" \
--header "Content-Type: application/json" \
--data '{"deviceId":"demo-table-01","zone":"3"}'
Send a one-shot goal command to a connected host. Query values take precedence over POST body values, including invalid values. At least deviceId and side must be supplied in the query or JSON body. This changes match data. A successful response means dispatch only; it is not a delivery or scoring guarantee. Prefer POST; the legacy GET variant also modifies data and must not be prefetched.
Authentication: Requires an issued API key. Send X-API-Key (recommended), or the legacy apiKey query parameter. Missing/invalid keys return 401; revoked/expired keys return 403. Unrestricted keys can target any device. Device-scoped keys require an explicit grant for the canonical target device; an empty list denies all targets. Aliases resolve before authorization; conflicting query/body targets are rejected. Prefer headers to keep credentials out of URLs.
Parameters
deviceId · query · required
Target device. POST may supply this in JSON instead.
{
"name": "deviceId",
"in": "query",
"description": "Target device. POST may supply this in JSON instead.",
"required": true,
"schema": {
"type": "string",
"description": "Target device with an active remote_control session."
},
"example": "demo-table-01"
}
side · query · required
Scoring side. POST may supply this in JSON instead.
{
"name": "side",
"in": "query",
"description": "Scoring side. POST may supply this in JSON instead.",
"required": true,
"schema": {
"type": "string",
"enum": [
"home",
"away",
"left",
"right",
"guest",
"visitor"
],
"description": "Case-insensitive; surrounding whitespace is trimmed."
},
"example": "home"
}
zone · query · optional
Optional scoring rod. POST may supply this in JSON instead.
{
"name": "zone",
"in": "query",
"description": "Optional scoring rod. POST may supply this in JSON instead.",
"required": false,
"schema": {
"type": "string",
"enum": [
"2",
"3",
"5"
]
},
"example": "3"
}
Responses
200 — Command dispatched to the host, not confirmation that the host applied it.
403 — API key revoked, expired, or not authorized for the resolved device.
{
"description": "API key revoked, expired, or not authorized for the resolved device.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"examples": {
"synthetic": {
"value": {
"error": "API key is not authorized for this device"
}
}
}
}
}
}
404 — No active remote_control session exists for the device.
{
"description": "No active remote_control session exists for the device.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"examples": {
"synthetic": {
"value": {
"error": "No active remote_control session for this device"
}
}
}
}
}
}
410 — The session exists but its host is disconnected.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/remote/goal?deviceId=demo-table-01&side=home&zone=3" \
--header "X-API-Key: $IREF_API_KEY"
Send a one-shot goal command to a connected host. Query values take precedence over POST body values, including invalid values. At least deviceId and side must be supplied in the query or JSON body. This changes match data. A successful response means dispatch only; it is not a delivery or scoring guarantee. Prefer POST; the legacy GET variant also modifies data and must not be prefetched.
Authentication: Requires an issued API key. Send X-API-Key (recommended), or the legacy apiKey query parameter. Missing/invalid keys return 401; revoked/expired keys return 403. Unrestricted keys can target any device. Device-scoped keys require an explicit grant for the canonical target device; an empty list denies all targets. Aliases resolve before authorization; conflicting query/body targets are rejected. Prefer headers to keep credentials out of URLs.
Parameters
deviceId · query · optional
Target device. POST may supply this in JSON instead.
{
"name": "deviceId",
"in": "query",
"description": "Target device. POST may supply this in JSON instead.",
"required": false,
"schema": {
"type": "string",
"description": "Target device with an active remote_control session."
},
"example": "demo-table-01"
}
side · query · optional
Scoring side. POST may supply this in JSON instead.
{
"name": "side",
"in": "query",
"description": "Scoring side. POST may supply this in JSON instead.",
"required": false,
"schema": {
"type": "string",
"enum": [
"home",
"away",
"left",
"right",
"guest",
"visitor"
],
"description": "Case-insensitive; surrounding whitespace is trimmed."
},
"example": "home"
}
zone · query · optional
Optional scoring rod. POST may supply this in JSON instead.
{
"name": "zone",
"in": "query",
"description": "Optional scoring rod. POST may supply this in JSON instead.",
"required": false,
"schema": {
"type": "string",
"enum": [
"2",
"3",
"5"
]
},
"example": "3"
}
Request body
JSON alternative to query parameters; query values win. deviceId and side must exist across query/body.
403 — API key revoked, expired, or not authorized for the resolved device.
{
"description": "API key revoked, expired, or not authorized for the resolved device.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"examples": {
"synthetic": {
"value": {
"error": "API key is not authorized for this device"
}
}
}
}
}
}
404 — No active remote_control session exists for the device.
{
"description": "No active remote_control session exists for the device.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"examples": {
"synthetic": {
"value": {
"error": "No active remote_control session for this device"
}
}
}
}
}
}
410 — The session exists but its host is disconnected.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request POST "$BASE_URL/api/remote/goal?deviceId=demo-table-01&side=home&zone=3" \
--header "X-API-Key: $IREF_API_KEY" \
--header "Content-Type: application/json" \
--data '{"deviceId":"demo-table-01","side":"home","zone":"3"}'
Lists matches ordered by status and most recently updated, excluding champion scenarios. Optional filters use AND. Each match includes per-game final scores. Responses contain persisted database rows in snake_case; additional fields may be present. Synthetic examples show representative fields, not real match or player data.
Authentication: Readable without credentials. An optional X-API-Key attributes usage; a supplied revoked key returns 403. This middleware does not require a key or enforce device grants.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats?device_id=demo-table-01&source=default"
Security requirements
[
{},
{
"StatsAttributionKey": []
}
]
GET /api/stats/{matchId}
Get a saved match and its games
Responses contain persisted database rows in snake_case; additional fields may be present. Synthetic examples show representative fields, not real match or player data.
Authentication: Readable without credentials. An optional X-API-Key attributes usage; a supplied revoked key returns 403. This middleware does not require a key or enforce device grants.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/DEMO2345"
Security requirements
[
{},
{
"StatsAttributionKey": []
}
]
GET /api/stats/{matchId}/{gameNumber}
Get a saved game
Retrieves one saved game by match ID and game number. Responses contain persisted database rows in snake_case; additional fields may be present. Synthetic examples show representative fields, not real match or player data.
Authentication: Readable without credentials. An optional X-API-Key attributes usage; a supplied revoked key returns 403. This middleware does not require a key or enforce device grants.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/DEMO2345/1"
Security requirements
[
{},
{
"StatsAttributionKey": []
}
]
GET /api/stats/{matchId}/{gameNumber}/possessions
Get game possessions and computed zone statistics
Returns camelCase events plus aggregates over ALL game events, even when limit narrows the event window. avgTime is a seconds string. matchHasConfirmedGoal checks the entire match, not just this game. No API key middleware; unknown games return empty results.
Authentication: Unauthenticated; no caller credentials are required.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/DEMO2345/1/possessions?limit=20"
GET /api/stats/{matchId}/all-possessions
Get possessions across every game
Returns camelCase possession events across a match, including gameNumber. No API key middleware is applied. Unknown matches return an empty array, not 404.
Authentication: Unauthenticated; no caller credentials are required.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/DEMO2345/all-possessions"
GET /api/stats/{matchId}/currentgame
Get the highest-numbered saved game
Selects the highest saved game number, which may be finalized. It does not use the match current_game_number field. Responses contain persisted database rows in snake_case; additional fields may be present. Synthetic examples show representative fields, not real match or player data.
Authentication: Readable without credentials. An optional X-API-Key attributes usage; a supplied revoked key returns 403. This middleware does not require a key or enforce device grants.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/DEMO2345/currentgame"
Security requirements
[
{},
{
"StatsAttributionKey": []
}
]
GET /api/stats/{matchId}/qrcode
Generate a match stats QR image
Returns a 400-pixel-wide PNG image, not a JSON body. Save the response to a .png file. Encodes this server’s /stats/{matchId} URL without checking whether the match exists.
Authentication: Readable without credentials. An optional X-API-Key attributes usage; a supplied revoked key returns 403. This middleware does not require a key or enforce device grants.
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/DEMO2345/qrcode"
Security requirements
[
{},
{
"StatsAttributionKey": []
}
]
GET /api/stats/device/{deviceId}/current
Get a device’s current match
Chooses the latest active match. last=true falls back to the most recent match of any status when there is no active match. Responses contain persisted database rows in snake_case; additional fields may be present. Synthetic examples show representative fields, not real match or player data.
Authentication: Readable without credentials. An optional X-API-Key attributes usage; a supplied revoked key returns 403. This middleware does not require a key or enforce device grants.
Fall back to the latest saved match if no active match exists. Only the exact string true enables this.
{
"name": "last",
"in": "query",
"description": "Fall back to the latest saved match if no active match exists. Only the exact string true enables this.",
"schema": {
"type": "boolean"
},
"example": true,
"required": false
}
{
"description": "No active match found for this device",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
},
"required": [
"error"
],
"additionalProperties": true
},
"examples": {
"synthetic": {
"summary": "Synthetic example",
"value": {
"error": "No active match found for this device"
}
}
}
}
}
}
500 — Failed to get device current match
{
"description": "Failed to get device current match",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
},
"required": [
"error"
],
"additionalProperties": true
},
"examples": {
"synthetic": {
"summary": "Synthetic example",
"value": {
"error": "Failed to get device current match"
}
}
}
}
}
}
curl example
# Set BASE_URL to your chosen iRefFoos server. Credential variables are never prefilled.
curl --request GET "$BASE_URL/api/stats/device/demo-table-01/current?last=true"
Security requirements
[
{},
{
"StatsAttributionKey": []
}
]
Authentication schemes
RemoteApiKey
{
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"description": "Issued API key. No key is embedded in this reference."
}
LegacyQueryApiKey
{
"type": "apiKey",
"in": "query",
"name": "apiKey",
"description": "Legacy alternative; prefer X-API-Key to avoid keys in URL logs."
}
StatsAttributionKey
{
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"description": "Optional usage attribution. This does not replace X-Stats-API-Key or host ownership."
}