Skip to content

Dealers ​

These APIs let an operator that runs its own live tables manage its dealer accounts, dealer badges and face photos, and look up dealer tool device status, the installer download URL and the dealer card log. Operators that do not run live tables do not need them.

MethodPathPurpose
GET/operator/v1/dealersList your dealers
POST/operator/v1/dealersCreate a dealer account
PATCH/operator/v1/dealers/{dealer_id}Change name, role, PIN or enabled status
POST/operator/v1/dealers/{dealer_id}/badgeIssue or reissue a dealer badge
DELETE/operator/v1/dealers/{dealer_id}/badgeRevoke a dealer badge
PUT/operator/v1/dealers/{dealer_id}/photoUpload a face photo
DELETE/operator/v1/dealers/{dealer_id}/photoRemove a face photo
GET/operator/v1/dealer-devicesDealer tool device status
GET/operator/v1/dealer-toolLatest dealer tool version and installer URLs
GET/operator/v1/dealer-card-logDealer card log (independent mode only)
  • Dealer accounts are created and modified only under this operator. Your dealers handle only this operator's dedicated live tables.
  • Referring to a dealer that belongs to another operator returns 404 DEALER_NOT_FOUND, exactly as for a dealer that does not exist.
  • dealer_id is a UUID string without a prefix (e.g. 0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6).
  • Device approval, blocking, table binding and the number of allowed devices are decided by the platform headquarters. This API only lets you view devices.
  • Responses to write requests carry an X-Audit-Id header. Account changes and photo changes can be reverted from the audit log.

GET /operator/v1/dealers ​

Lists your dealers, sorted by creation order.

Response example ​

json
{
  "dealers": [
    {
      "dealer_id": "0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6",
      "login": "maria01",
      "name": "Maria Santos",
      "role": "dealer",
      "status": "active",
      "rounds": 1842,
      "created_at": "2026-09-02T03:12:44.51Z",
      "photo_url": "{API_BASE}/dealer/v1/photos/0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6?v=mgx3k2a1",
      "badge_tail": "7QK2",
      "badge_issued_at": "2026-09-02T03:15:02.1Z",
      "badge_code": "DLR-8M3TZ0RW7QK2"
    }
  ]
}

Response fields ​

FieldTypeDescription
dealer_idstringDealer ID (UUID)
loginstringDealer tool sign-in ID
namestringDisplay name
rolestringdealer (dealer) or pitboss (pit boss — management privileges such as manual input, where cards are picked directly on the dealer tool screen)
statusstringactive or disabled (disabled — cannot sign in to the dealer tool)
roundsint64Number of rounds this dealer has run
created_attimestampAccount creation time
photo_urlstringPublic URL of the face photo. "" if none
badge_tailstring | nullLast 4 characters of the dealer badge code (null before issuance and after revocation)
badge_issued_attimestamp | nullDealer badge issue time
badge_codestringFull dealer badge code (DLR- + 12 characters). "" if not issued

Handling dealer badge codes

badge_code is the value scanned in the dealer tool to start a shift. Because the list response contains the full code, show it only on screens restricted to administrators. If a badge is lost, revoke or reissue it.

The photo at photo_url is a public URL that can be fetched without authentication; the v= value changes whenever the photo changes.

POST /operator/v1/dealers ​

Creates a dealer account.

Request fields ​

FieldTypeRequiredDescription
loginstringYes2–32 characters, starting with a lowercase letter or digit and consisting of lowercase letters, digits, _ and - (^[a-z0-9][a-z0-9_-]{1,31}$). Uppercase letters are stored as lowercase, and leading/trailing whitespace is trimmed. This is a namespace shared by all operators, so an ID already used by another operator cannot be used
namestringYes1–60 bytes (UTF-8). Leading/trailing whitespace is trimmed
pinstringYesDealer tool sign-in PIN, 4–32 characters
rolestringNodealer (default) or pitboss

Request example ​

bash
curl -X POST {API_BASE}/operator/v1/dealers \
  -H 'Content-Type: application/json; charset=utf-8' \
  -H 'X-Operator: acme' -H 'X-Api-Key: ak_live_…' \
  -H 'X-Timestamp: 1760839200123' -H 'X-Nonce: 5d7f9a1c3e5b7d9f1a3c5e7b' -H 'X-Signature: 4c8a…' \
  -d '{"login":"maria01","name":"Maria Santos","pin":"482913","role":"dealer"}'

Response example ​

201 Created

json
{ "dealer_id": "0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6" }

Errors ​

HTTPCodeSituation
400INVALID_REQUEST (message invalid json)Body is not JSON
400INVALID_REQUEST (details.fields)Invalid format in login, name, pin or role (all invalid fields are listed)
409DUPLICATElogin already exists
500INTERNAL_ERRORFailed to save

PATCH /operator/v1/dealers/{dealer_id} ​

Changes the name, role, PIN or enabled status. Only the fields you send are changed.

Request fields ​

FieldTypeRequiredDescription
namestringNo1–60 bytes
rolestringNodealer or pitboss
pinstringNoNew PIN, 4–32 characters. "" leaves it unchanged
statusstringNoactive or disabled

Disabling a dealer (disabled) or changing their role disconnects any dealer tool session that dealer is signed in to, and the dealer tool returns to the sign-in screen. login cannot be changed.

Request example ​

bash
curl -X PATCH {API_BASE}/operator/v1/dealers/0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6 \
  -H 'Content-Type: application/json; charset=utf-8' \
  -H 'X-Operator: acme' -H 'X-Api-Key: ak_live_…' \
  -H 'X-Timestamp: 1760839200123' -H 'X-Nonce: 1a3c5e7b9d1f3a5c7e9b1d3f' -H 'X-Signature: e09b…' \
  -d '{"status":"disabled"}'

Response ​

204 No Content (no body)

Errors ​

HTTPCodeSituation
404DEALER_NOT_FOUNDMalformed ID, dealer does not exist, or dealer belongs to another operator
400INVALID_REQUEST (message invalid json)Body is not JSON
400INVALID_REQUEST (details.fields)Invalid format in name, role, status or pin
500INTERNAL_ERRORFailed to save

POST /operator/v1/dealers/{dealer_id}/badge ​

Issues a dealer badge. If one already exists, it is reissued with a new code and the previous code stops working immediately. There is no body (sign an empty body or {}).

Response example ​

json
{ "code": "DLR-8M3TZ0RW7QK2", "tail": "7QK2", "login": "maria01", "name": "Maria Santos", "role": "dealer" }
FieldDescription
codeFull dealer badge code — print it as a barcode or QR code and give it to the dealer
tailLast 4 characters of the code (badge_tail in the list)
login, name, roleDealer details to print on the badge alongside the code

Errors ​

HTTPCodeSituation
404DEALER_NOT_FOUNDDealer does not exist or belongs to another operator
500INTERNAL_ERRORFailed to save

DELETE /operator/v1/dealers/{dealer_id}/badge ​

Revokes a dealer badge (e.g. when lost). Until a new badge is issued, the dealer cannot start a shift with a badge. There is no body.

Response ​

204 No Content

Errors ​

HTTPCodeSituation
404DEALER_NOT_FOUNDDealer does not exist or belongs to another operator
500INTERNAL_ERRORFailed to save

PUT /operator/v1/dealers/{dealer_id}/photo ​

Uploads a dealer's face photo. It is used on the on-duty dealer card at the top of the dealer tool and in the list on the management screen, and is applied immediately to any dealer tool where the dealer is on duty.

Request fields ​

FieldTypeRequiredDescription
imagestringYesImage as base64, or as a data URL (data:image/jpeg;base64,…)

Image requirements: JPEG or PNG, no more than 2048px in width and in height. A square image is recommended.

The effective size limit is the 64KB request body

The Operator API reads at most 64KB (65,536 bytes) of a request body. Because the photo is sent as base64 (about 4/3 of the original size), an original image larger than about 48KB gets its body truncated, signature verification fails and you receive 401 INVALID_SIGNATURE. Before uploading, crop the image to a square and shrink it (for example to an approx. 400×400px JPEG) so it is 48KB or less. (The photo check itself allows up to 512KB, but the body limit applies first.)

Request example ​

bash
IMG=$(base64 -w0 maria.jpg)   # macOS: base64 -i maria.jpg
curl -X PUT {API_BASE}/operator/v1/dealers/0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6/photo \
  -H 'Content-Type: application/json; charset=utf-8' \
  -H 'X-Operator: acme' -H 'X-Api-Key: ak_live_…' \
  -H 'X-Timestamp: 1760839200123' -H 'X-Nonce: 9b1d3f5a7c9e1b3d5f7a9c1e' -H 'X-Signature: 77d1…' \
  -d "{\"image\":\"data:image/jpeg;base64,${IMG}\"}"

Compute the signature over the exact body bytes you actually send. → Authentication and signing

Response example ​

json
{ "photo_url": "{API_BASE}/dealer/v1/photos/0199e8a1-6b2c-7d3e-9f40-a1b2c3d4e5f6?v=mgx3q8z0" }

Errors ​

HTTPCodeSituation
401INVALID_SIGNATUREBody exceeded 64KB and was truncated (see the warning above) — or an ordinary signature error
404DEALER_NOT_FOUNDDealer does not exist or belongs to another operator
400INVALID_REQUESTBody is not JSON
400BAD_PHOTONot base64, empty image, not JPEG or PNG, larger than 2048px, or larger than 512KB
500INTERNAL_ERRORFailed to save

DELETE /operator/v1/dealers/{dealer_id}/photo ​

Removes the face photo. The dealer tool shows a default image instead. There is no body.

Response ​

204 No Content

Errors ​

HTTPCodeSituation
404DEALER_NOT_FOUNDDealer does not exist or belongs to another operator
500INTERNAL_ERRORFailed to delete

GET /operator/v1/dealer-devices ​

Status of the dealer tool devices (dealer PCs) bound to this operator. Remote support connection details are not included.

Response example ​

json
{
  "active": 2,
  "limit": 4,
  "devices": [
    {
      "id": "0199e9c4-2f1a-7b3c-8d4e-5f6a7b8c9d0e",
      "name": "STUDIO-PC-01",
      "status": "active",
      "online": true,
      "logged_in": true,
      "dealer": "maria01",
      "on_duty": "Maria Santos",
      "operator": "acme",
      "operator_name": "Acme Casino",
      "app_version": "0.2.28",
      "os": "windows 11",
      "last_ip": "203.0.113.24",
      "last_seen_at": "2026-10-19T02:10:11.3Z",
      "created_at": "2026-09-01T08:00:00Z",
      "table_id": "tbl_0198c1d2e3f47a5b8c9d0e1f2a3b4c5d",
      "open_tables": ["tbl_0198c1d2e3f47a5b8c9d0e1f2a3b4c5d"],
      "setup_ready": true,
      "live": {
        "app_version": "0.2.28",
        "os": "windows 11",
        "scanner": "connected",
        "stream": { "state": "live", "latency_ms": 180, "bitrate_kbps": 2500, "width": 1920, "height": 1080, "fps": 30 },
        "cpu": 23.5,
        "mem": 41.2
      }
    }
  ]
}

Response fields ​

FieldTypeDescription
activeintNumber of approved (status: active) devices
limitint | nullNumber of allowed devices set by the platform headquarters. null if unlimited
devices[].idstringDevice ID (UUID)
devices[].namestringDevice name
devices[].statusstringpending (awaiting approval), active (approved) or disabled (blocked)
devices[].onlineboolWhether the device is currently connected
devices[].logged_inboolWhether a dealer is signed in
devices[].dealer, on_dutystringSign-in ID and name of the on-duty dealer (only while signed in)
devices[].app_version, osstringDealer tool version and operating system
devices[].last_ip, last_seen_atLast connection IP and time
devices[].table_idstringBound table (omitted if none)
devices[].requested_table_idstringTable the dealer tool has requested to be bound to (only when present)
devices[].open_tablesstring[]Tables currently open in the dealer tool
devices[].setup_readyboolWhether all integration settings (game server, media server, table) are configured
devices[].liveobjectReal-time status (last report while online) — scanner (connected, disconnected, virtual, none), stream (state: live, connecting, off, error; plus latency, bitrate, resolution, fps), cpu and mem (%), update (automatic update progress — only when present)
devices[].last_statusobjectSummary of the last status for reference while offline (only when present)

Integration settings fields such as operator, operator_name, game_server and media_server may also be included. Fields without a value are omitted.

Errors ​

HTTPCodeSituation
500INTERNAL_ERRORTemporary server error

GET /operator/v1/dealer-tool ​

Returns the latest dealer tool version to install on dealer PCs and its download URLs. Show the link on your management screen and have it opened in the browser on the dealer PC to install. When the installed dealer tool is launched for the first time, enter the operator code (operator); the tool can be used after the platform headquarters approves it.

Response example ​

json
{
  "version": "0.2.28",
  "notes": "Improved video encoding",
  "pub_date": "2026-10-18T10:00:00Z",
  "files": [
    { "platform": "windows-x86_64", "alias": "windows", "file": "R-Live-Dealer_0.2.28_x64-setup.exe", "size": 9876543,
      "url": "{API_BASE}/dealer/v1/download/windows" }
  ],
  "operator": "acme"
}

Response fields ​

FieldTypeDescription
versionstringLatest published version. "" if nothing has been published
notes, pub_datestringVersion notes and publish time (omitted if nothing has been published)
files[]arrayInstaller per platform. [] if nothing has been published
files[].platformstringwindows-x86_64, darwin-aarch64 (Apple silicon) or darwin-x86_64 (Intel Mac)
files[].aliasstringShort name: windows, mac or mac-intel
files[].file, sizeFile name and size (bytes)
files[].urlstringStable download URL — when a new version is published, the same URL serves the latest file
operatorstringOperator code to enter on the dealer tool's first screen (= X-Operator)

Download URLs require no authentication, but may be restricted so that they open only from studio networks allowed by the platform. The installed dealer tool updates itself after the current round ends when a new version is published.

To be agreed

Supported platforms (Windows, macOS), the allowed range of studio networks and the device approval procedure are agreed at contract time.

GET /operator/v1/dealer-card-log ​

The log of dealer card inputs (scanner, manual, virtual) received on your own dedicated tables. It is an audit record for checking which card a dealer entered, when, by which method, and whether the server accepted it.

Independent mode only

Available only to independent mode (independent) operators. Tables of prepaid mode (prepaid) operators are run by the platform headquarters, so they get 403 CARD_LOG_FORBIDDEN. Inputs on shared tables are not shown.

Query parameters ​

ParameterTypeRequiredDescription
from, totimestampNo[from, to) based on the time the server received the input (received_at). Defaults to the last 24 hours. Same format as the common query parameters
table_idstringNoThis table only (an empty result if malformed)
round_idstringNoThis round only (an empty result if malformed)
dealerstringNoThis dealer sign-in ID (login) only
sourcestringNoscanner, wedge, manual or virtual
resultstringNoaccepted, rejected or no_reply
grouproundNoIf round, returns per-round groups instead of inputs
no_round1NoOnly inputs that do not belong to a round (input list only)
limitintegerNoDefault 100, maximum 500
offsetintegerNoNumber of rows to skip

Response example — input list ​

json
{
  "entries": [
    {
      "received_at": "2026-10-19T02:10:04.512Z",
      "id": "0199f3c1-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
      "dealer": "maria01",
      "role": "dealer",
      "device_id": "0199e9c4-2f1a-7b3c-8d4e-5f6a7b8c9d0e",
      "device_name": "STUDIO-PC-01",
      "ip": "203.0.113.24",
      "source": "scanner",
      "card": "AS",
      "raw": "1S14",
      "scanner_id": "HID-0A3F",
      "scanned_at": "2026-10-19T02:10:04.43Z",
      "lag_ms": 82,
      "result": "accepted",
      "position": "seat_3",
      "reject_code": null,
      "reject_reason": null,
      "table_id": "tbl_0198c1d2e3f47a5b8c9d0e1f2a3b4c5d",
      "table_name": "Live Hold'em 1",
      "table_names": { "en": "Live Hold'em 1" },
      "game_code": "live_holdem",
      "round_id": "rnd_0199f3a2c4e57b1d9a2e4f6081c3d5e7",
      "round_no": 66,
      "round_status": "settled"
    }
  ],
  "has_more": false
}

Input fields ​

FieldTypeDescription
received_attimestampTime the server received the input (UTC)
idstringInput record ID
dealer, rolestringSign-in ID and role of the dealer who entered the card
device_id, device_namestringDevice the input came from
ipstring | nullDevice IP
sourcestringscanner, wedge (keyboard-emulating scanner), manual (manual input by a pit boss) or virtual (virtual scanner — test environments)
cardstring | nullCard (e.g. AS)
rawstring | nullRaw value read by the scanner
scanner_idstring | nullScanner identifier
scanned_attimestamp | nullTime the device read the card
lag_msint | nullTime (ms) from the device reading the card until the server received it. Includes any clock difference on the device
resultstringaccepted, rejected or no_reply (no response)
positionstring | nullCard position (e.g. seat_3)
reject_code, reject_reasonstring | nullRejection code and reason
hiddenboolIf true, card and raw are masked because the round is in progress (only when present)
table_id, table_name, table_names, game_codeTable
round_id, round_no, round_statusRound (null if the input does not belong to a round)

For inputs in a round that is in progress (round_status: "open"), the card values (card, raw) are masked as null and hidden: true is added. They become visible once the round ends.

Response example — per-round groups (group=round) ​

json
{
  "rounds": [
    {
      "table_id": "tbl_0198c1d2e3f47a5b8c9d0e1f2a3b4c5d",
      "table_name": "Live Hold'em 1",
      "table_names": { "en": "Live Hold'em 1" },
      "game_code": "live_holdem",
      "round_id": "rnd_0199f3a2c4e57b1d9a2e4f6081c3d5e7",
      "round_no": 66,
      "round_status": "settled",
      "first_at": "2026-10-19T02:10:01.2Z",
      "last_at": "2026-10-19T02:11:01.9Z",
      "n": 19, "n_accepted": 19, "n_rejected": 0, "n_no_reply": 0,
      "n_scanned": 19, "n_manual": 0, "n_virtual": 0, "n_late": 0, "n_pitboss": 0,
      "max_lag_ms": 140,
      "dealers": ["maria01"],
      "devices": ["STUDIO-PC-01"]
    }
  ],
  "has_more": true
}
FieldDescription
first_at, last_atTime of the first and last input in the round
n, n_accepted, n_rejected, n_no_replyNumber of inputs, and counts per result
n_scanned, n_manual, n_virtualCounts per input method (n_scanned = scanner + wedge)
n_lateNumber of inputs that took more than 5 seconds from scan to server receipt
n_pitbossNumber of inputs entered by a pit boss
max_lag_msLongest lag (ms). null if there is no scan time at all
dealers, devicesDealers and devices that entered cards

Inputs that do not belong to a round (e.g. rejections before a round starts) are grouped into one row per table, with round_id set to null. To expand the inputs of a round row, query the input list again with the same conditions plus round_id (for a row without a round, table_id + no_round=1). Groups are ordered by most recent last input first.

The inputs of a single round are also available as card_log in round details.

Pagination ​

Offset-based. If has_more: true, increase offset by limit and query again. The input list is ordered by received_at, most recent first.

Errors ​

HTTPCodeSituation
403CARD_LOG_FORBIDDENPrepaid mode operator
500INTERNAL_ERRORTemporary server error

Docs v1.0.0 · Operator API v1