{
 "openapi": "3.1.0",
 "info": {
  "title": "Notell slots operator API",
  "version": "2.0.0",
  "description": "TEST_ONLY platform: game mathematics provided by the platform, non-withdrawable units, no real payments. Server-to-server JSON over HTTPS; every request carries `partner` and `api_key` (keep the key on your server). For `/gameActions.do` and `/playerRtp.do` the caller IP must be on the project allowlist. Errors are `{\"status\":\"error\",\"message\":\"<CODE>\"}`. Guides: https://docs.notell-api.com/en/"
 },
 "servers": [
  {
   "url": "https://notell-api.com",
   "description": "Public API; partner + api_key"
  }
 ],
 "tags": [
  {
   "name": "launch"
  },
  {
   "name": "free spins"
  },
  {
   "name": "target outcomes"
  },
  {
   "name": "catalog"
  },
  {
   "name": "callbacks"
  },
  {
   "name": "rtp"
  }
 ],
 "paths": {
  "/playGame.do": {
   "post": {
    "operationId": "launchGame",
    "tags": [
     "launch"
    ],
    "summary": "Launch a game client with an own-backend session",
    "description": "`lang` is a standard language code (BCP 47: en, de, pt-BR, zh-Hans, zh-Hant, es-419 ...; case-insensitive, `_` accepted) mapped to each provider's own client code. A missing `lang` = the project's default language; a language the game does not support answers UNSUPPORTED_LANGUAGE. Relaunching with an unfinished round continues that round in the new language.",
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "description": "1-128 printable ASCII characters. A repeat with the same key and body returns the first answer; the same key with another body answers IDEMPOTENCY_CONFLICT (409).",
      "schema": {
       "type": "string",
       "minLength": 1,
       "maxLength": 128,
       "pattern": "^[\\x21-\\x7e]+$"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/LaunchRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Session link (hand only this link to the player).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/LaunchResponse"
        }
       }
      }
     },
     "400": {
      "description": "INVALID_REQUEST, UNSUPPORTED_LANGUAGE, REAL_MODE_DISABLED, PROMO_UNSUPPORTED, ROUND_IN_PROGRESS, BALANCE_UNAVAILABLE, INVALID_IDEMPOTENCY_KEY",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "UNAUTHORIZED",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "UNSUPPORTED_GAME",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "IDEMPOTENCY_CONFLICT",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/gameActions.do": {
   "post": {
    "operationId": "gameActions",
    "tags": [
     "free spins",
     "target outcomes"
    ],
    "summary": "Operator free spins and scheduled target outcomes",
    "description": "The `method` field selects the operation. Free spins: freespins_create, freespins_get, freespins_list, freespins_cancel. Target outcomes: outcome_schedule, outcome_get, outcome_list, outcome_cancel. The legacy methods freespins_set / freespins_delete (and freespins_get without an id) answer METHOD_RETIRED.",
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "description": "1-128 printable ASCII characters. A repeat with the same key and body returns the first answer; the same key with another body answers IDEMPOTENCY_CONFLICT (409).",
      "schema": {
       "type": "string",
       "minLength": 1,
       "maxLength": 128,
       "pattern": "^[\\x21-\\x7e]+$"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "oneOf": [
         {
          "$ref": "#/components/schemas/FreeSpinsCreate"
         },
         {
          "$ref": "#/components/schemas/FreeSpinsLookup"
         },
         {
          "$ref": "#/components/schemas/FreeSpinsList"
         },
         {
          "$ref": "#/components/schemas/OutcomeSchedule"
         },
         {
          "$ref": "#/components/schemas/OutcomeLookup"
         },
         {
          "$ref": "#/components/schemas/OutcomeList"
         }
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "`{status:\"ok\", grant}`, `{status:\"ok\", grants:[...]}`, `{status:\"ok\", outcome}` or `{status:\"ok\", outcomes:[...]}`.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "status"
         ],
         "properties": {
          "status": {
           "type": "string",
           "const": "ok"
          },
          "grant": {
           "$ref": "#/components/schemas/FreeSpinGrant"
          },
          "grants": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/FreeSpinGrant"
           }
          },
          "outcome": {
           "$ref": "#/components/schemas/TargetOutcome"
          },
          "outcomes": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/TargetOutcome"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "INVALID_REQUEST, METHOD_RETIRED, INVALID_FREE_SPIN_BET, PROJECT_BET_LIMIT, INVALID_EXPIRY, GAME_HAS_NO_BONUS, INVALID_MULTIPLIER, MULTIPLIER_ABOVE_MAX_WIN, INVALID_SPIN_NUMBER, INVALID_KIND, FORCED_OUTCOMES_UNSUPPORTED, INVALID_COUNT, INVALID_METHOD",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "UNAUTHORIZED",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "IP_NOT_ALLOWED",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "GAME_NOT_FOUND, GRANT_NOT_FOUND, OUTCOME_NOT_FOUND",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "IDEMPOTENCY_CONFLICT, DUPLICATE_EXTERNAL_ID",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/games/health": {
   "get": {
    "operationId": "gamesHealth",
    "tags": [
     "catalog"
    ],
    "summary": "Published games with launch languages and operator capabilities",
    "description": "`games[].game_id` lists the published games with `languages` (standard codes the original client supports), `free_spins` and `target_outcomes` (whether operator free spins / scheduled target outcomes are available for the game).",
    "responses": {
     "200": {
      "description": "Runtime release and games.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/GamesHealth"
        }
       }
      }
     }
    }
   }
  },
  "/capabilities": {
   "get": {
    "operationId": "capabilities",
    "tags": [
     "catalog"
    ],
    "summary": "Casino capability list (stable contract of the testcasino integration)",
    "description": "All released games with their currencies, launch languages restricted to ru / en / uk (the casino languages), default currency and language, promo support and informational mode names.",
    "responses": {
     "200": {
      "description": "Capabilities.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Capabilities"
        }
       }
      }
     }
    }
   }
  },
  "/health": {
   "get": {
    "operationId": "health",
    "tags": [
     "catalog"
    ],
    "summary": "Runtime liveness",
    "responses": {
     "200": {
      "description": "Database reachable.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "status",
          "mode"
         ],
         "properties": {
          "status": {
           "type": "string",
           "const": "ok"
          },
          "mode": {
           "type": "string",
           "const": "TEST_ONLY"
          },
          "backend": {
           "type": "string"
          },
          "client": {
           "type": "string"
          },
          "mathVersion": {
           "type": "string"
          },
          "runtime": {
           "type": "string"
          },
          "releaseId": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "503": {
      "description": "DATABASE_UNAVAILABLE",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/playerRtp.do": {
   "post": {
    "operationId": "playerRtp",
    "tags": [
     "rtp"
    ],
    "summary": "Personal RTP and bet limits of a player",
    "description": "Actions `get`, `set`, `auto`, `bet-limit`. The player RTP level is 60–100 %. The caller IP must be on the project allowlist.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PlayerRtpRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Player RTP state.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "status",
          "player"
         ],
         "properties": {
          "status": {
           "type": "string",
           "const": "ok"
          },
          "player": {
           "$ref": "#/components/schemas/PlayerRtp"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "INVALID_ACTION, INVALID_PLAYER, RTP_LEVEL_INVALID, RTP_LEVEL_OUT_OF_RANGE, RTP_PROVIDER_UNSUPPORTED, RTP_POLICY_REQUIRED, INVALID_REASON, INVALID_CURRENCY, INVALID_BET_LIMIT",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "UNAUTHORIZED",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "IP_NOT_ALLOWED",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  }
 },
 "webhooks": {
  "walletCallback": {
   "post": {
    "operationId": "walletCallback",
    "tags": [
     "callbacks"
    ],
    "summary": "Wallet callback sent by the platform to the operator: POST <callbackBaseUrl>/<currency>",
    "description": "Canonical JSON with the partner `api_key` in the body; 2 s timeout; the answer must be exact JSON `{status, balance, currency}` where `balance` is a JSON number. Methods: `session_info` (read the balance), `bet` (debit before a paid round), `win` (credit of a positive result), `round_info` (start / finish notifications), `freespins_finished` (one summary per finished free-spins grant: grant_id, external_id, player_id, currency, game, status, total, played, bet, total_win, finished_at; answer `{status:\"ok\"}`, retried with backoff until then). A retry carries the same transaction id and body, answer it from your record. Bets of free-spin rounds have amount 0 and `meta:{is_freespins:true, freespins:{grant_id, external_id, nominal_bet, remaining}}` (wins carry the same meta): accept a zero bet when `is_freespins` is true. One `freespins_finished` summary per finished grant is retried until you answer `{\"status\":\"ok\"}`.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "oneOf": [
         {
          "$ref": "#/components/schemas/WalletCallback"
         },
         {
          "$ref": "#/components/schemas/FreeSpinsFinished"
         }
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Operator answer.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WalletAnswer"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "required": [
     "status",
     "message"
    ],
    "properties": {
     "status": {
      "type": "string",
      "const": "error"
     },
     "message": {
      "type": "string",
      "pattern": "^[A-Z][A-Z0-9_]+$"
     }
    }
   },
   "LaunchRequest": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "provider",
     "partner",
     "api_key",
     "player_id",
     "currency",
     "symbol",
     "gametype"
    ],
    "properties": {
     "provider": {
      "type": "string",
      "const": "own"
     },
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "player_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128
     },
     "currency": {
      "type": "string",
      "enum": [
       "UAH",
       "USD",
       "EUR",
       "RUB"
      ]
     },
     "symbol": {
      "type": "string",
      "description": "Game id, see /games/health."
     },
     "gametype": {
      "type": "string",
      "const": "demo"
     },
     "lang": {
      "type": "string",
      "description": "Standard language code (BCP 47)."
     },
     "client_platform": {
      "type": "string",
      "enum": [
       "desktop",
       "mobile"
      ],
      "description": "Pragmatic clients only."
     },
     "region": {
      "type": "string",
      "enum": [
       "RU",
       "NONE"
      ]
     }
    }
   },
   "LaunchResponse": {
    "type": "object",
    "required": [
     "status",
     "link",
     "meta"
    ],
    "properties": {
     "status": {
      "type": "string",
      "const": "ok"
     },
     "link": {
      "type": "string",
      "format": "uri"
     },
     "meta": {
      "type": "object",
      "required": [
       "session_id"
      ],
      "properties": {
       "session_id": {
        "type": "string"
       },
       "currency": {
        "type": "string"
       },
       "language": {
        "type": "string"
       }
      }
     }
    }
   },
   "FreeSpinsCreate": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "method",
     "partner",
     "api_key",
     "player_id",
     "currency",
     "symbol",
     "count",
     "bet"
    ],
    "properties": {
     "method": {
      "type": "string",
      "const": "freespins_create"
     },
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "player_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "symbol": {
      "type": "string"
     },
     "count": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
     },
     "bet": {
      "type": "string",
      "pattern": "^[0-9]+(\\.[0-9]+)?$",
      "description": "Total bet of one spin; must be one of the game's own bets in its base mode and within the project's bet limits."
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 with zone; default now + 7 days, minimum now + 1 hour, maximum now + 30 days."
     },
     "external_id": {
      "type": "string"
     },
     "meta": {
      "type": "object"
     }
    }
   },
   "FreeSpinsLookup": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "method",
     "partner",
     "api_key"
    ],
    "properties": {
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "method": {
      "type": "string",
      "enum": [
       "freespins_get",
       "freespins_cancel"
      ]
     },
     "grant_id": {
      "type": "string"
     },
     "external_id": {
      "type": "string"
     }
    },
    "description": "freespins_get / freespins_cancel (idempotent): grant_id or external_id."
   },
   "FreeSpinsList": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "method",
     "partner",
     "api_key"
    ],
    "properties": {
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "method": {
      "type": "string",
      "const": "freespins_list"
     },
     "player_id": {
      "type": "string"
     },
     "symbol": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "used",
       "expired",
       "cancelled"
      ]
     }
    },
    "description": "At most 200 grants, newest first."
   },
   "FreeSpinGrant": {
    "type": "object",
    "properties": {
     "grant_id": {
      "type": "string"
     },
     "external_id": {
      "type": "string"
     },
     "player_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "symbol": {
      "type": "string"
     },
     "provider": {
      "type": "string"
     },
     "total": {
      "type": "integer"
     },
     "remaining": {
      "type": "integer"
     },
     "played": {
      "type": "integer"
     },
     "bet": {
      "type": "string",
      "pattern": "^[0-9]+(\\.[0-9]+)?$",
      "description": "Decimal amount as a string."
     },
     "total_win": {
      "type": "string",
      "pattern": "^[0-9]+(\\.[0-9]+)?$",
      "description": "Decimal amount as a string."
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "used",
       "expired",
       "cancelled"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time"
     },
     "finished_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "OutcomeSchedule": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "method",
     "partner",
     "api_key",
     "player_id",
     "symbol",
     "multiplier"
    ],
    "properties": {
     "method": {
      "type": "string",
      "const": "outcome_schedule"
     },
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "player_id": {
      "type": "string"
     },
     "symbol": {
      "type": "string"
     },
     "multiplier": {
      "type": [
       "number",
       "string"
      ],
      "description": "Win as a multiple of the spin's bet (+-2 %)."
     },
     "kind": {
      "type": "string",
      "enum": [
       "spin",
       "bonus"
      ]
     },
     "spin_number": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100000,
      "default": 1,
      "description": "The player's n-th paid spin in that game, counted from scheduling; free-spin rounds do not count."
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "Default 7 days, 1 hour - 90 days."
     },
     "external_id": {
      "type": "string"
     },
     "comment": {
      "type": "string"
     }
    }
   },
   "OutcomeLookup": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "method",
     "partner",
     "api_key"
    ],
    "properties": {
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "method": {
      "type": "string",
      "enum": [
       "outcome_get",
       "outcome_cancel"
      ]
     },
     "outcome_id": {
      "type": "string"
     },
     "external_id": {
      "type": "string"
     }
    }
   },
   "OutcomeList": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "method",
     "partner",
     "api_key"
    ],
    "properties": {
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "method": {
      "type": "string",
      "const": "outcome_list"
     },
     "player_id": {
      "type": "string"
     },
     "symbol": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "ready",
       "unreachable",
       "applied",
       "expired",
       "cancelled"
      ]
     }
    },
    "description": "At most 200 outcomes."
   },
   "TargetOutcome": {
    "type": "object",
    "properties": {
     "outcome_id": {
      "type": "string"
     },
     "external_id": {
      "type": "string"
     },
     "player_id": {
      "type": "string"
     },
     "symbol": {
      "type": "string"
     },
     "provider": {
      "type": "string"
     },
     "kind": {
      "type": "string",
      "enum": [
       "spin",
       "bonus"
      ]
     },
     "multiplier": {
      "type": "string",
      "description": "Win multiple of the bet as a string, for example \"50\"."
     },
     "spin_number": {
      "type": "integer"
     },
     "paid_spins_since": {
      "type": "integer"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "ready",
       "unreachable",
       "applied",
       "expired",
       "cancelled"
      ]
     },
     "variants": {},
     "comment": {
      "type": "string"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time"
     },
     "applied_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "round_id": {
      "type": [
       "string",
       "null"
      ]
     }
    }
   },
   "GamesHealth": {
    "type": "object",
    "required": [
     "status",
     "releaseId",
     "games"
    ],
    "properties": {
     "status": {
      "type": "string",
      "const": "ok"
     },
     "releaseId": {
      "type": "string"
     },
     "databasePurpose": {
      "type": "string"
     },
     "games": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "game_id"
       ],
       "properties": {
        "game_id": {
         "type": "string"
        },
        "languages": {
         "type": "array",
         "items": {
          "type": "string"
         }
        },
        "free_spins": {
         "type": "boolean"
        },
        "target_outcomes": {
         "type": "boolean"
        }
       }
      }
     }
    }
   },
   "Capabilities": {
    "type": "object",
    "required": [
     "status",
     "mode",
     "currencies",
     "games"
    ],
    "properties": {
     "status": {
      "type": "string",
      "const": "ok"
     },
     "mode": {
      "type": "string",
      "const": "TEST_ONLY"
     },
     "currencies": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "code": {
         "type": "string",
         "enum": [
          "UAH",
          "USD",
          "EUR",
          "RUB"
         ]
        },
        "precision": {
         "type": "integer",
         "const": 2
        }
       }
      }
     },
     "games": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "gameId",
        "name",
        "provider",
        "currencies",
        "languages",
        "defaultCurrency",
        "defaultLanguage",
        "promoSupported",
        "modes"
       ],
       "properties": {
        "gameId": {
         "type": "string"
        },
        "name": {
         "type": "string"
        },
        "provider": {
         "type": "string"
        },
        "currencies": {
         "type": "array",
         "items": {
          "type": "string"
         }
        },
        "languages": {
         "type": "array",
         "items": {
          "type": "string",
          "enum": [
           "ru",
           "en",
           "uk"
          ]
         }
        },
        "defaultCurrency": {
         "type": "string"
        },
        "defaultLanguage": {
         "type": "string",
         "enum": [
          "ru",
          "en",
          "uk"
         ]
        },
        "promoSupported": {
         "type": "boolean"
        },
        "modes": {
         "type": "array",
         "items": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   },
   "WalletCallback": {
    "type": "object",
    "required": [
     "method",
     "player_id",
     "api_key"
    ],
    "properties": {
     "method": {
      "type": "string",
      "enum": [
       "session_info",
       "bet",
       "win",
       "round_info",
       "freespins_finished"
      ]
     },
     "api_key": {
      "type": "string"
     },
     "player_id": {
      "type": "string"
     },
     "amount": {
      "type": "number",
      "description": "JSON number (not a string); 0 for a free-spin bet."
     },
     "meta": {
      "type": "object",
      "description": "symbol, time, transaction, round_id, session_id; free-spin rounds add is_freespins and freespins."
     }
    }
   },
   "FreeSpinsFinished": {
    "type": "object",
    "required": [
     "method",
     "grant_id",
     "player_id",
     "currency",
     "game",
     "status"
    ],
    "properties": {
     "method": {
      "type": "string",
      "const": "freespins_finished"
     },
     "grant_id": {
      "type": "string"
     },
     "external_id": {
      "type": "string"
     },
     "player_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "game": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "used",
       "expired",
       "cancelled"
      ]
     },
     "total": {
      "type": "integer"
     },
     "played": {
      "type": "integer"
     },
     "bet": {
      "type": "string",
      "pattern": "^[0-9]+(\\.[0-9]+)?$",
      "description": "Decimal amount as a string."
     },
     "total_win": {
      "type": "string",
      "pattern": "^[0-9]+(\\.[0-9]+)?$",
      "description": "Decimal amount as a string."
     },
     "finished_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "WalletAnswer": {
    "type": "object",
    "required": [
     "status"
    ],
    "properties": {
     "status": {
      "type": "string",
      "enum": [
       "ok",
       "error"
      ]
     },
     "balance": {
      "type": "number",
      "description": "JSON number."
     },
     "currency": {
      "type": "string"
     },
     "message": {
      "type": "string",
      "description": "e.g. INSUFFICIENT_FUNDS, IDEMPOTENCY_CONFLICT."
     }
    }
   },
   "PlayerRtpRequest": {
    "type": "object",
    "required": [
     "partner",
     "api_key",
     "action",
     "player_id"
    ],
    "properties": {
     "partner": {
      "type": "string"
     },
     "api_key": {
      "type": "string"
     },
     "action": {
      "type": "string",
      "enum": [
       "get",
       "set",
       "auto",
       "bet-limit"
      ]
     },
     "player_id": {
      "type": "string"
     },
     "provider": {
      "type": "string",
      "enum": [
       "endorphina",
       "pragmatic",
       "nolimitcity"
      ],
      "default": "endorphina",
      "description": "The provider the action applies to."
     },
     "rtp": {
      "type": "number",
      "minimum": 60,
      "maximum": 100,
      "description": "set: percent with at most 2 decimals, e.g. 94.5."
     },
     "reason": {
      "type": "string",
      "maxLength": 200,
      "description": "set / auto: shown in the player journal."
     },
     "currency": {
      "type": "string",
      "description": "bet-limit: currency code."
     },
     "min_minor": {
      "type": [
       "string",
       "null"
      ],
      "description": "bet-limit: minimum bet per spin in minor units; null together with max_minor removes the limit."
     },
     "max_minor": {
      "type": [
       "string",
       "null"
      ],
      "description": "bet-limit: maximum bet per spin in minor units."
     }
    }
   },
   "PlayerRtp": {
    "type": "object",
    "properties": {
     "partner": {
      "type": "string"
     },
     "player": {
      "type": "string"
     },
     "bound": {
      "type": "boolean"
     },
     "provider": {
      "type": "string"
     },
     "startBps": {
      "type": "integer",
      "description": "Starting RTP in basis points (9450 = 94.50 %)."
     },
     "currentBps": {
      "type": "integer",
      "description": "Current RTP in basis points."
     },
     "mode": {
      "type": "string",
      "enum": [
       "auto",
       "manual"
      ]
     },
     "roundsSinceAdjust": {
      "type": "integer"
     },
     "providerBps": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Project provider RTP in basis points."
     },
     "effective": {
      "type": [
       "object",
       "null"
      ],
      "properties": {
       "bps": {
        "type": "integer"
       },
       "source": {
        "type": "string",
        "enum": [
         "player",
         "provider-cap",
         "manual"
        ]
       }
      }
     },
     "betLimits": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "currency": {
         "type": "string"
        },
        "minMinor": {
         "type": "string"
        },
        "maxMinor": {
         "type": "string"
        }
       }
      }
     },
     "journal": {
      "type": "array",
      "items": {
       "type": "object"
      }
     }
    }
   }
  }
 }
}
