瀏覽代碼

新增pinnacle API采集数据

flyzto 1 月之前
父節點
當前提交
542bb48008

+ 1 - 0
.gitignore

@@ -41,6 +41,7 @@ env/
 /build
 
 server/data
+pinnacle/data
 
 /cypress/videos/
 /cypress/screenshots/

File diff suppressed because it is too large
+ 401 - 0
pinnacle/api-docs.html


+ 45 - 0
pinnacle/libs/logs.js

@@ -0,0 +1,45 @@
+import dayjs from 'dayjs';
+
+export class Logs {
+
+  static out(...args) {
+    const timeString = dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');
+    if (typeof args[0] === 'string' && args[0].includes('%')) {
+      args[0] = `[${timeString}] ` + args[0];
+    }
+    else {
+      args.unshift(`[${timeString}]`);
+    }
+    console.log(...args);
+  }
+
+  static err(...args) {
+    const timeString = dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');
+    if (typeof args[0] === 'string' && args[0].includes('%')) {
+      args[0] = `[${timeString}] ` + args[0];
+    }
+    else {
+      args.unshift(`[${timeString}]`);
+    }
+    console.error(...args);
+  }
+
+  static outDev(...args) {
+    if (process.env.NODE_ENV == 'development') {
+      this.out(...args);
+    }
+  }
+
+  static errDev(...args) {
+    if (process.env.NODE_ENV == 'development') {
+      this.err(...args);
+    }
+  }
+
+  static outLine(string) {
+    process.stdout.write("\u001b[1A");
+    process.stdout.write("\u001b[2K");
+    this.out(string);
+  }
+
+}

+ 83 - 0
pinnacle/libs/pinnacleClient.js

@@ -0,0 +1,83 @@
+import axios from "axios";
+import { HttpsProxyAgent } from "https-proxy-agent";
+
+export const pinnacleRequest = async (options) => {
+  const {
+    endpoint,
+    params = {},
+    username,
+    password,
+    method = "GET",
+    data,
+    proxy,
+    timeout = 10000,
+  } = options;
+
+  if (!endpoint || !username || !password) {
+    throw new Error("endpoint、username、password is required");
+  }
+
+  const authHeader = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
+
+  const axiosConfig = {
+    baseURL: "https://api.pinnacle888.com",
+    url: endpoint,
+    method,
+    headers: {
+      "Authorization": authHeader,
+      "Accept": "application/json",
+      "Content-Type": "application/json",
+    },
+    params,
+    data,
+    timeout,
+  };
+
+  if (proxy) {
+    axiosConfig.proxy = false;
+    axiosConfig.httpsAgent = new HttpsProxyAgent(proxy);
+  }
+
+  return axios(axiosConfig).then(res => res.data);
+
+}
+
+export const getPsteryRelations = async (mk=-1) => {
+  const axiosConfig = {
+    baseURL: 'http://127.0.0.1:9055',
+    url: '/api/pstery/get_games_relation',
+    method: 'GET',
+    params: {
+      mk,
+    },
+    proxy: false,
+  };
+
+  return axios(axiosConfig).then(res => res.data);
+}
+
+export const updateBaseEvents = async (data) => {
+  const axiosConfig = {
+    baseURL: 'http://127.0.0.1:9055',
+    url: '/api/pstery/update_base_events',
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    data: JSON.stringify(data),
+    proxy: false,
+  };
+
+  return axios(axiosConfig).then(res => res.data);
+}
+
+export const notifyException = async (message) => {
+  const axiosConfig = {
+    baseURL: 'http://127.0.0.1:9055',
+    url: '/api/pstery/notify_exception',
+    method: 'POST',
+    data: { message },
+    proxy: false,
+  };
+  return axios(axiosConfig).then(res => res.data);
+}

+ 3962 - 0
pinnacle/linesapi.yaml

@@ -0,0 +1,3962 @@
+swagger: '2.0'
+info:
+  version: 1.0.0
+  title: Pinnacle888 - Lines API Reference
+  description: |
+    All about odds and fixtures
+
+    # Authentication
+
+    API uses HTTP Basic access authentication.You need to send Authorization HTTP Request header:
+
+    `Authorization: Basic <Base64 value of UTF-8 encoded "username:password">`
+
+    Example:
+
+    `Authorization: Basic U03MyOT23YbzMDc6d3c3O1DQ1`
+  x-logo:
+    url: ''
+host: api.pinnacle888.com
+schemes:
+  - https
+security:
+  - basicAuth: []
+paths:
+  /v3/fixtures:
+    get:
+      tags:
+        - Fixtures
+      summary: Get Fixtures - v3
+      description: Returns all **non-settled** events for the given sport. Please note that it is possible that the event is in Get Fixtures response but not in Get Odds. This happens when the odds are not currently available for wagering. Please note that it is possible to receive the same exact response when using **since** parameter. This is rare and can be caused by internal updates of event properties.
+      operationId: Fixtures_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: The sport id to retrieve the fixutres for.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: isLive
+          in: query
+          description: To retrieve ONLY live events set the value to 1 (isLive=1). Missing or any other value will result in retrieval of events regardless of their Live status.
+          required: false
+          type: boolean
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous fixtures response. When since parameter is not provided, the fixtures are delayed up to 1 minute to encourage the use of the parameter.
+          required: false
+          type: integer
+          format: int64
+        - name: eventIds
+          in: query
+          description: Comma separated list of event ids to filter by
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/FixturesResponseV3'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/fixtures/special:
+    get:
+      tags:
+        - Fixtures
+      summary: Get Special Fixtures - v2
+      description: Returns all **non-settled** specials for the given sport.
+      operationId: Fixtures_Special_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: Id of a sport for which to retrieve the specials.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last field from the previous response. When since parameter is not provided, the fixtures are delayed up to 1 min to encourage the use of the parameter.
+          required: false
+          type: integer
+          format: int64
+        - name: category
+          in: query
+          description: The category the special falls under.
+          required: false
+          type: string
+        - name: eventId
+          in: query
+          description: Id of an event associated with a special.
+          required: false
+          type: integer
+          format: int64
+        - name: specialId
+          in: query
+          description: Id of the special.
+          required: false
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SpecialsFixturesResponseV2'
+          examples:
+            application/json:
+              sportId: 4
+              last: 636433059508250600
+              leagues:
+                - id: 487
+                  specials:
+                    - id: 1
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 4th quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 1
+                          name: Odd
+                          rotNum: 100
+                        - id: 2
+                          name: Even
+                          rotNum: 101
+                    - id: 2
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 3rd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 3
+                          name: Odd
+                          rotNum: 100
+                        - id: 4
+                          name: Even
+                          rotNum: 101
+                    - id: 3
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 2nd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: H
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 5
+                          name: Odd
+                          rotNum: 100
+                        - id: 6
+                          name: Even
+                          rotNum: 101
+                    - id: 4
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 1st quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 7
+                          name: Odd
+                          rotNum: 100
+                        - id: 8
+                          name: Even
+                          rotNum: 101
+                    - id: 5
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 4th quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: null
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 9
+                          name: Odd
+                          rotNum: 100
+                        - id: 10
+                          name: Even
+                          rotNum: 101
+                    - id: 6
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 3rd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 11
+                          name: Odd
+                          rotNum: 100
+                        - id: 12
+                          name: Even
+                          rotNum: 101
+                    - id: 7
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 2nd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 13
+                          name: Odd
+                          rotNum: 100
+                        - id: 14
+                          name: Even
+                          rotNum: 101
+                    - id: 8
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 1st quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: H
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 15
+                          name: Odd
+                          rotNum: 100
+                        - id: 16
+                          name: Even
+                          rotNum: 101
+                    - id: 9
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Who will win the NBA finals?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: Outright Winner
+                      units: ""
+                      status: I
+                      contestants:
+                        - id: 17
+                          name: Golden State Warriors
+                          rotNum: 100
+                        - id: 18
+                          name: Cleveland Cavaliers
+                          rotNum: 101
+                        - id: 19
+                          name: San Antonio Spurs
+                          rotNum: 102
+                        - id: 20
+                          name: Chicago Bulls
+                          rotNum: 103
+                - id: 578
+                  specials:
+                    - id: 10
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Who will win the WNBA finals?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: Outright Winner
+                      units: ""
+                      status: I
+                      contestants:
+                        - id: 21
+                          name: Minnesota Lynx
+                          rotNum: 100
+                        - id: 22
+                          name: Indiana Fever
+                          rotNum: 101
+                        - id: 23
+                          name: Phoenix Mercury
+                          rotNum: 102
+                        - id: 24
+                          name: Chicago Sky
+                          rotNum: 103
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v3/fixtures/settled:
+    get:
+      tags:
+        - Fixtures
+      summary: Get Settled Fixtures - v3
+      description: Returns fixtures settled in the last 24 hours for the given sport.
+      operationId: Fixtures_Settled_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          required: true
+          description: Id of the sport for which to retrieve the settled.
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          required: false
+          description: The leagueIds array may contain a list of comma separated league ids.
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          required: false
+          description: This is used to receive incremental updates. Use the value of last from previous response.
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SettledFixturesSportV3'
+          examples:
+            application/json:
+              sportId: 0
+              last: 0
+              leagues:
+                - id: 0
+                  events:
+                    - id: 0
+                      periods:
+                        - number: 0
+                          status: 0
+                          settlementId: 0
+                          settledAt: '2017-09-03T18:21:22.3846289-07:00'
+                          team1Score: 0
+                          team2Score: 0
+                          cancellationReason:
+                            code: string
+                            details:
+                              correctTeam1Id: string
+                              correctTeam2Id: string
+                              correctListedPitcher1: string
+                              correctListedPitcher2: string
+                              correctSpread: '0.0'
+                              correctTotalPoints: '0.0'
+                              correctTeam1TotalPoints: '0.0'
+                              correctTeam2TotalPoints: '0.0'
+                              correctTeam1Score: '0'
+                              correctTeam2Score: '0'
+                              correctTeam1TennisSetsScore: '0'
+                              correctTeam2TennisSetsScore: '0'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v3/fixtures/special/settled:
+    get:
+      tags:
+        - Fixtures
+      summary: Get Settled Special Fixtures - v3
+      description: Returns all specials which are settled in the last 24 hours for the given Sport.
+      operationId: Fixtures_Specials_Settled_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: Id of the sport for which to retrieve the settled specials.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: Array of leagueIds. This is optional parameter.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous response.
+          required: false
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SettledSpecialsResponseV3'
+          examples:
+            application/json:
+              sportId: 0
+              last: 0
+              leagues:
+                - id: 0
+                  specials:
+                    - id: 0
+                      status: 0
+                      settlementId: 0
+                      settledAt: '2017-10-11T15:05:50.996671Z'
+                      contestants:
+                        - id: 1
+                          name: Barranquilla
+                          outcome: "X"
+                        - id: 2
+                          name: Valledupar
+                          outcome: "X"
+                      cancellationReason:
+                        code: string
+                        details:
+                          correctTeam1Id: string
+                          correctTeam2Id: string
+                          correctListedPitcher1: string
+                          correctListedPitcher2: string
+                          correctSpread: '0.0'
+                          correctTotalPoints: '0.0'
+                          correctTeam1TotalPoints: '0.0'
+                          correctTeam2TotalPoints: '0.0'
+                          correctTeam1Score: '0'
+                          correctTeam2Score: '0'
+                          correctTeam1TennisSetsScore: '0'
+                          correctTeam2TennisSetsScore: '0'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v3/odds:
+    get:
+      tags:
+        - Odds
+      summary: Get Straight Odds - v3
+      description: Returns straight odds for all non-settled events. Please note that it is possible that the event is in Get Fixtures response but not in Get Odds. This happens when the odds are not currently available for wagering.
+      operationId: Odds_Straight_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: The sportid for which to retrieve the odds.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: Format in which we return the odds. Default is American. [American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous odds response. When since parameter is not provided, the odds are delayed up to 1 min to encourage the use of the parameter. Please note that when using since parameter you will get in the response ONLY changed periods. If a period did not have any changes it will not be in the response.
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: To retrieve ONLY live odds set the value to 1 (isLive=1). Otherwise response will have all odds.
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: Filter by EventIds
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+        - name: toCurrencyCode
+          in: query
+          description: 3 letter currency code as in the [/currency](https://pinny888.github.io/docs/?api=lines#tag/Others/operation/Currencies_V2_Get) response. Limits will be returned in the requested currency. Default is USD.
+          required: false
+          type: string
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/OddsResponseV3'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: true
+  /v4/odds:
+    get:
+      tags:
+        - Odds
+      summary: Get Straight Odds - v4
+      description: Returns straight odds for all non-settled events. Please note that it is possible that the event is in Get Fixtures response but not in Get Odds. This happens when the odds are not currently available for wagering.
+      operationId: Odds_Straight_V4_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: The sportid for which to retrieve the odds.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: Format in which we return the odds. Default is American. [American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous odds response. When since parameter is not provided, the odds are delayed up to 1 min to encourage the use of the parameter. Please note that when using since parameter you will get in the response ONLY changed periods. If a period did not have any changes it will not be in the response.
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: To retrieve ONLY live odds set the value to 1 (isLive=1). Otherwise response will have all odds.
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: Filter by EventIds
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+        - name: toCurrencyCode
+          in: query
+          description: 3 letter currency code as in the [/currency](https://pinny888.github.io/docs/?api=lines#tag/Others/operation/Currencies_V2_Get) response. Limits will be returned in the requested currency. Default is USD.
+          required: false
+          type: string
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/OddsResponseV4'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v3/odds/parlay:
+    get:
+      tags:
+        - Odds
+      summary: Get Parlay Odds - v3
+      description: Returns parlay odds for all non-settled events. Please note that it is possible that the event is in Get Fixtures response but notin Get Odds. This happens when the odds are not currently available for wagering.
+      operationId: Odds_Parlays_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: The sportid for which to retrieve the odds.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: Format in which we return the odds. Default is American. [American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous odds response. When since parameter is not provided, the odds are delayed up to 1 min to encourage the use of the parameter. Please note that when using since parameter you will get in the response ONLY changed periods. If a period didn’t have any changes it will not be in the response.
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: To retrieve ONLY live odds set the value to 1 (isLive=1). Otherwise response will have all odds.
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: Filter by EventIds
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/ParlayOddsResponseV3'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: true
+  /v4/odds/parlay:
+    get:
+      tags:
+        - Odds
+      summary: Get Parlay Odds - v4
+      description: Returns parlay odds for all non-settled events. Please note that it is possible that the event is in Get Fixtures response but notin Get Odds. This happens when the odds are not currently available for wagering.
+      operationId: Odds_Parlays_V4_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: The sportid for which to retrieve the odds.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: Format in which we return the odds. Default is American. [American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous odds response. When since parameter is not provided, the odds are delayed up to 1 min to encourage the use of the parameter. Please note that when using since parameter you will get in the response ONLY changed periods. If a period didn’t have any changes it will not be in the response.
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: To retrieve ONLY live odds set the value to 1 (isLive=1). Otherwise response will have all odds.
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: Filter by EventIds
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/ParlayOddsResponseV4'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/odds/teaser:
+    get:
+      tags:
+        - Odds
+      summary: Get Teaser Odds - v1
+      description: Returns odds for specified teaser.
+      operationId: Odds_Teasers_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: teaserId
+          in: query
+          description: Unique identifier.Teaser details can be retrieved from a call to Get Teaser Groups endpoint.
+          required: true
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/TeaserOddsResponse'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/odds/special:
+    get:
+      tags:
+        - Odds
+      summary: Get Special Odds - v2
+      description: Returns odds for specials for all non-settled events.
+      operationId: Odds_Special_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: oddsFormat
+          in: query
+          description: Format the odds are returned in. [American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: sportId
+          in: query
+          description: Id of a sport for which to retrieve the specials.
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: The leagueIds array may contain a list of comma separated league ids.
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          description: This is used to receive incremental updates. Use the value of last from previous response. When since parameter is not provided, the fixtures are delayed up to 1 min to encourage the use of the parameter.
+          required: false
+          type: integer
+          format: int64
+        - name: specialId
+          in: query
+          description: Id of the special. This is an optional argument.
+          required: false
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SpecialOddsResponseV2'
+          examples:
+            application/json:
+              sportId: 4
+              last: 636433059510590700
+              leagues:
+                - id: 487
+                  specials:
+                    - id: 1
+                      maxBet: 100
+                      contestantLines:
+                        - id: 1
+                          lineId: 1001
+                          price: -199
+                          handicap: null
+                          max: 100
+                        - id: 2
+                          lineId: 1002
+                          price: -198
+                          handicap: null
+                          max: 100
+                    - id: 7
+                      maxBet: 100
+                      contestantLines:
+                        - id: 13
+                          lineId: 1013
+                          price: -187
+                          handicap: null
+                          max: 100
+                        - id: 14
+                          lineId: 1014
+                          price: -186
+                          handicap: null
+                          max: 100
+                - id: 578
+                  specials:
+                    - id: 10
+                      maxBet: 100
+                      contestantLines:
+                        - id: 21
+                          lineId: 1021
+                          price: -179
+                          handicap: null
+                          max: 100
+                        - id: 22
+                          lineId: 1022
+                          price: -178
+                          handicap: null
+                          max: 100
+                        - id: 23
+                          lineId: 1023
+                          price: -177
+                          handicap: null
+                          max: 100
+                        - id: 24
+                          lineId: 1024
+                          price: -176
+                          handicap: null
+                          max: 100
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v2/line:
+    get:
+      tags:
+        - Line
+      summary: Get Straight Line - v2
+      description: Returns latest line.
+      operationId: Line_Straight_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: leagueId
+          in: query
+          description: League Id.
+          required: true
+          type: integer
+          format: int32
+        - name: handicap
+          in: query
+          description: This is needed for SPREAD, TOTAL_POINTS and TEAM_TOTAL_POINTS bet types
+          required: true
+          type: number
+          format: double
+        - name: oddsFormat
+          in: query
+          description: Format in which we return the odds. Default is American.
+          required: true
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: sportId
+          in: query
+          description: Sport identification
+          required: true
+          type: integer
+          format: int32
+        - name: eventId
+          in: query
+          description: Event identification
+          required: true
+          type: integer
+          format: int64
+        - name: periodNumber
+          in: query
+          description: This represents the period of the match. Please check Get Periods endpoint for the list of currently supported periods per sport.
+          required: true
+          type: integer
+          format: int32
+        - name: betType
+          in: query
+          description: Bet Type
+          required: true
+          type: string
+          enum:
+            - SPREAD
+            - MONEYLINE
+            - TOTAL_POINTS
+            - TEAM_TOTAL_POINTS
+        - name: team
+          in: query
+          description: Chosen team type. This is needed only for SPREAD, MONEYLINE and TEAM_TOTAL_POINTS bet types
+          required: false
+          type: string
+          enum:
+            - Team1
+            - Team2
+            - Draw
+        - name: side
+          in: query
+          description: Chosen side. This is needed only for TOTAL_POINTS and TEAM_TOTAL_POINTS
+          required: false
+          type: string
+          enum:
+            - OVER
+            - UNDER
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/LineResponseV2'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v3/line/parlay:
+    post:
+      tags:
+        - Line
+      summary: Get Parlay Line - v3
+      description: Returns parlay lines and calculate odds.
+      operationId: Line_Parlay_V3_Post
+      consumes:
+        - application/json
+      produces:
+        - application/json
+      parameters:
+        - in: body
+          name: request
+          required: true
+          schema:
+            $ref: '#/definitions/ParlayLinesRequestV3'
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/ParlayLinesResponseV3'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/line/teaser:
+    post:
+      tags:
+        - Line
+      summary: Get Teaser Line - v1
+      description: Validates a teaser bet prior to submission. Returns bet limit and price on success.
+      operationId: Line_Teaser_V1_Post
+      consumes:
+        - application/json
+      produces:
+        - application/json
+      parameters:
+        - in: body
+          name: teaserLinesRequest
+          required: true
+          schema:
+            $ref: '#/definitions/LinesRequestTeaser'
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/TeaserLinesResponse'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/line/special:
+    get:
+      tags:
+        - Line
+      operationId: Line_Special_V2_Get
+      summary: Get Special Line - v2
+      description: Returns special lines and calculate odds.
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: oddsFormat
+          in: query
+          description: Format the odds are returned in. [American, Decimal, HongKong, Indonesian, Malay]
+          required: true
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: specialId
+          in: query
+          description: Id of the special.
+          required: true
+          type: integer
+          format: int64
+        - name: contestantId
+          in: query
+          description: Id of the contestant.
+          required: true
+          type: integer
+          format: int64
+        - name: handicap
+          in: query
+          description: handicap of the contestant. As contestant's handicap is a mutable property, it may happened that line/special returns status:SUCCESS, but with the different handicap from the one that client had at the moment of calling the line/special. One can specify handicap parameter in the request and if the contestant's handicap changed, it would return status:NOT_EXISTS. This way line/special is more aligned to how /line works.
+          required: false
+          type: number
+          format: double
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SpecialLineResponse'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v3/sports:
+    get:
+      tags:
+        - Others
+      summary: Get Sports - v3
+      description: Returns all sports with the status whether they currently have lines or not.
+      operationId: Sports_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SportsResponseV3'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/LinesErrorResponse'
+  /v3/leagues:
+    get:
+      tags:
+        - Others
+      summary: Get Leagues - v3
+      description: Returns all sports leagues with the status whether they currently have lines or not.
+      operationId: Leagues_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: Sport id for which the leagues are requested.
+          required: true
+          type: string
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/LeaguesV3'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/periods:
+    get:
+      tags:
+        - Others
+      summary: Get Periods - v1
+      description: Returns all periods for a given sport.
+      operationId: Periods_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          required: true
+          type: string
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SportPeriod'
+          examples:
+            application/json:
+              periods:
+                - number: 0
+                  description: Match
+                  shortDescription: FT
+                - number: 1
+                  description: 1st Half
+                  shortDescription: 1st H
+                - number: 2
+                  description: 2nd Half
+                  shortDescription: 2nd H
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/inrunning:
+    get:
+      tags:
+        - Others
+      summary: Get In-Running - v2
+      description: Returns all live soccer events that have a status that indicates the event is in progress.
+      operationId: InRunning_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/InRunningResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedLinesErrorResponse'
+  /v1/teaser/groups:
+    get:
+      tags:
+        - Others
+      summary: Get Teaser Groups - v1
+      description: Returns all teaser groups.
+      operationId: Teaser_Groups_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: oddsFormat
+          in: query
+          description: Format the odds are returned in. [American, Decimal, HongKong, Indonesian, Malay]
+          required: true
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/TeaserGroupsResponse'
+        '400':
+          description: BadRequest
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/cancellationreasons:
+    get:
+      tags:
+        - Others
+      summary: Get Cancellation Reasons - v1
+      description: Lookup for all the cancellation reasons
+      operationId: CancellationReasons_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/CancellationReasonResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/currencies:
+    get:
+      tags:
+        - Others
+      summary: Get Currencies - v2
+      description: Returns the list of supported currencies
+      operationId: Currencies_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/SuccessfulCurrenciesResponse'
+        '401':
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: InternalServerError
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+securityDefinitions:
+  basicAuth:
+    type: basic
+definitions:
+  ErrorResponse:
+    type: object
+    properties:
+      code:
+        type: string
+        description: Identifier representing the type of error that occurred.
+      message:
+        type: string
+        description: Description of the error.
+    description: Contains details of an error that was encountered.
+  ExtendedErrorResponse:
+    type: object
+    properties:
+      ref:
+        type: string
+      code:
+        type: string
+      message:
+        type: string
+  LinesErrorResponse:
+    type: object
+    properties:
+      status:
+        type: string
+      error:
+        $ref: '#/definitions/ErrorResponse'
+      code:
+        type: integer
+        format: int32
+        description: Code identifying an error that occurred.
+  ExtendedLinesErrorResponse:
+    type: object
+    properties:
+      ref:
+        type: string
+      status:
+        type: string
+      error:
+        $ref: '#/definitions/ErrorResponse'
+      code:
+        type: integer
+        format: int32
+        description: Code identifying an error that occurred.
+  CancellationReasonResponse:
+    type: object
+    properties:
+      cancellationReasons:
+        type: array
+        description: Contains a list of Cancellation Reasons.
+        items:
+          $ref: '#/definitions/CancellationReason'
+    description: Cancellation Response Data
+  CancellationReason:
+    type: object
+    properties:
+      code:
+        type: string
+        description: Cancellation code assigned by the server
+        example: FBS_CW_65
+      description:
+        type: string
+        description: Text description for the cancellation reason
+        example: The event was postponed
+    description: Cancellation Data
+  SuccessfulCurrenciesResponse:
+    type: object
+    properties:
+      currencies:
+        type: array
+        description: Currencies container.
+        items:
+          $ref: '#/definitions/Currency'
+  Currency:
+    type: object
+    properties:
+      code:
+        type: string
+        description: Currency code.
+        example: AED
+      name:
+        type: string
+        description: Currency name.
+        example: United Arab Emirates Dirham
+      rate:
+        type: number
+        format: double
+        description: Exchange rate to USD.
+        example: 3.6738
+  FixturesResponseV1:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      league:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/FixturesLeagueV1'
+  FixturesLeagueV1:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League ID.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/FixtureV1'
+  FixtureV1:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event id.
+      starts:
+        type: string
+        format: date-time
+        description: Start time of the event in UTC.
+      home:
+        type: string
+        description: Home team name.
+      away:
+        type: string
+        description: Away team name.
+      rotNum:
+        type: string
+        description: Team1 rotation number. Please note that in the next version of /fixtures, rotNum property will be decomissioned. ParentId can be used instead to group the related events.
+      liveStatus:
+        type: integer
+        format: int32
+        description: |
+          Indicates live status of the event.
+
+          0 = No live betting will be offered on this event,
+          1 = Live betting event,
+          2 = Live betting will be offered on this event
+        enum:
+          - 0
+          - 1
+          - 2
+      homePitcher:
+        type: string
+        description: Home team pitcher. Only for Baseball.
+      awayPitcher:
+        type: string
+        description: Away team pitcher. Only for Baseball.
+      status:
+        type: string
+        description: |
+
+          Status of the event.
+
+          O = This is the starting status of a game. It means that the lines are open for betting,
+          H = This status indicates that the lines are temporarily unavailable for betting,
+          I = This status indicates that one or more lines have a red circle (lower maximum bet amount)
+        enum:
+          - O
+          - H
+          - I
+      parlayRestriction:
+        type: integer
+        format: int32
+        description: |
+
+          Parlay status of the event.
+
+          0 = Allowed to parlay, without restrictions,
+          1 = Not allowed to parlay this event,
+          2 = Allowed to parlay with the restrictions. You can not have more than one leg from the same event in the parlay. All events with the same rotation number are treated as same event.
+        enum:
+          - 0
+          - 1
+          - 2
+  FixturesResponseV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      league:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/FixturesLeagueV3'
+  FixturesLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League ID.
+      name:
+        type: string
+        description: League Name.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/FixtureV3'
+  FixtureV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event id.
+      parentId:
+        type: integer
+        format: int64
+        description: If event is linked to another event, parentId will be populated.  Live event would have pre game event as parent id.
+      starts:
+        type: string
+        format: date-time
+        description: Start time of the event in UTC.
+      home:
+        type: string
+        description: Home team name.
+      away:
+        type: string
+        description: Away team name.
+      liveStatus:
+        type: integer
+        format: int32
+        description: |
+          Indicates live status of the event.
+
+          0 = No live betting will be offered on this event,
+          1 = Live betting event,
+          2 = Live betting will be offered on this event
+        enum:
+          - 0
+          - 1
+          - 2
+      homePitcher:
+        type: string
+        description: Home team pitcher. Only for Baseball.
+      awayPitcher:
+        type: string
+        description: Away team pitcher. Only for Baseball.
+      betAcceptanceType:
+        type: integer
+        format: int32
+        description: |
+
+          Soccer live event bet acceptance type. This type indicates that the live soccer event is offered to the corresponding customer.
+
+          0 = Not Applicable. No bet acceptance type restriction.
+          1 = Danger Zone.
+          2 = Live Delay.
+          3 = Both.
+        enum:
+          - 0
+          - 1
+          - 2
+          - 3
+      parlayRestriction:
+        type: integer
+        format: int32
+        description: |
+
+          Parlay status of the event.
+
+          0 = Allowed to parlay, without restrictions,
+          1 = Not allowed to parlay this event,
+          2 = Allowed to parlay with the restrictions. You cannot have more than one leg from the same event in the parlay. All events with the same rotation number are treated as same event.
+        enum:
+          - 0
+          - 1
+          - 2
+      altTeaser:
+        type: boolean
+        description: Whether an event is offer with alternative teaser points. Events with alternative teaser points may vary from teaser definition.
+      resultingUnit:
+        type: string
+        description: |
+          Specifies based on what the event will be resulted, e.g. Corners, Bookings
+      version:
+        type: integer
+        format: int64
+        description: |
+           Fixture version, goes up when there is a change in the fixture.
+  SettledFixturesSportV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      leagues:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/SettledFixturesLeagueV3'
+  SettledFixturesLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/SettledFixturesEventV3'
+  SettledFixturesEventV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event Id.
+      periods:
+        type: array
+        description: Contains a list of periods.
+        items:
+          $ref: '#/definitions/SettledFixturesPeriodV3'
+  SettledFixturesPeriodV3:
+    type: object
+    properties:
+      number:
+        type: integer
+        format: int32
+        description: This represents the period of the match. For example, for soccer we have 0 (Game), 1 (1st Half) & 2 (2nd Half)
+      status:
+        type: integer
+        format: int32
+        description: |
+          Period settlement status.
+
+          1 = Event period is settled,
+          2 = Event period is re-settled,
+          3 = Event period is cancelled,
+          4 = Event period is re-settled as cancelled,
+          5 = Event is deleted
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+      settlementId:
+        type: integer
+        format: int64
+        description: Unique id of the settlement. In case of a re-settlement, a new settlementId and settledAt will be generated.
+      settledAt:
+        type: string
+        format: date-time
+        description: Date and time in UTC when the period was settled.
+      team1Score:
+        type: integer
+        format: int32
+        description: Team1 score.
+      team2Score:
+        type: integer
+        format: int32
+        description: Team2 score.
+      cancellationReason:
+        $ref: '#/definitions/CancellationReasonType'
+  CancellationReasonType:
+    type: object
+    properties:
+      code:
+        type: string
+        description: Cancellation Reason Code
+      details:
+        $ref: '#/definitions/CancellationReasonDetailsType'
+  CancellationReasonDetailsType:
+    type: object
+    properties:
+      key:
+        type: string
+      value:
+        type: string
+  InRunningResponse:
+    type: object
+    properties:
+      sports:
+        type: array
+        description: Sports container
+        items:
+          $ref: '#/definitions/InRunningSport'
+  InRunningSport:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: Sport Id
+      leagues:
+        type: array
+        description: Leagues container
+        items:
+          $ref: '#/definitions/InRunningLeague'
+  InRunningLeague:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id
+      events:
+        type: array
+        description: Events container
+        items:
+          $ref: '#/definitions/InRunningEvent'
+  InRunningEvent:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Game Id
+      state:
+        type: integer
+        format: int32
+        description: |
+          State of the game.
+
+          1 = First half in progress,
+          2 = Half time in progress,
+          3 = Second half in progress,
+          4 = End of regular time,
+          5 = First half extra time in progress,
+          6 = Extra time half time in progress,
+          7 = Second half extra time in progress,
+          8 = End of extra time,
+          9 = End of Game,
+          10 = Game is temporary suspended,
+          11 = Penalties in progress
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+          - 6
+          - 7
+          - 8
+          - 9
+          - 10
+          - 11
+      elapsed:
+        type: integer
+        format: int32
+        description: Elapsed minutes
+  LeaguesV3:
+    type: object
+    properties:
+      leagues:
+        type: array
+        description: Leagues container
+        items:
+          $ref: '#/definitions/LeagueV3'
+  LeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id.
+      name:
+        type: string
+        description: Name of the league.
+      homeTeamType:
+        type: string
+        description: Specifies whether the home team is team1 or team2. You need this information to place a bet.
+      hasOfferings:
+        type: boolean
+        description: Whether the league currently has events or specials.
+      container:
+        type: string
+        description: Represents grouping for the league, usually a region/country
+      allowRoundRobins:
+        type: boolean
+        description: Specifies whether you can place parlay round robins on events in this league.
+      leagueSpecialsCount:
+        type: integer
+        format: int32
+        description: Indicates how many specials are in the given league.
+      eventSpecialsCount:
+        type: integer
+        format: int32
+        description: Indicates how many game specials are in the given league.
+      eventCount:
+        type: integer
+        format: int32
+        description: Indicates how many events are in the given league.
+  LineResponseV2:
+    type: object
+    properties:
+      status:
+        type: string
+        description: If the value is NOT_EXISTS, than this will be the only parameter in the response. All other params would be empty. [SUCCESS = OK, NOT_EXISTS = Line not offered anymore]
+        enum:
+          - SUCCESS
+          - NOT_EXISTS
+      price:
+        type: number
+        format: double
+        description: Latest price.
+      lineId:
+        type: integer
+        format: int64
+        description: Line identification needed to place a bet.
+      altLineId:
+        type: integer
+        format: int64
+        description: This would be needed to place the bet if the handicap is on alternate line, otherwise it will not be populated in the response.
+      team1Score:
+        type: integer
+        format: int32
+        description: Team 1 score for the period 0. Applicable to soccer only.
+      team2Score:
+        type: integer
+        format: int32
+        description: Team 2 score for the period 0. Applicable to soccer only.
+      team1RedCards:
+        type: integer
+        format: int32
+        description: Team 1 red cards for the period 0. Applicable to soccer only.
+      team2RedCards:
+        type: integer
+        format: int32
+        description: Team 2 red cards for the period 0. Applicable to soccer only.
+      maxRiskStake:
+        type: number
+        format: double
+        description: Maximum bettable risk amount.
+      minRiskStake:
+        type: number
+        format: double
+        description: Minimum bettable risk amount.
+      maxWinStake:
+        type: number
+        format: double
+        description: Maximum bettable win amount.
+      minWinStake:
+        type: number
+        format: double
+        description: Minimum bettable win amount.
+      effectiveAsOf:
+        type: string
+        description: Line is effective as of this date and time in UTC.
+      periodTeam1Score:
+        type: integer
+        format: int32
+        description: Team 1 score for the supported periods. Applicable to soccer only.
+      periodTeam2Score:
+        type: integer
+        format: int32
+        description: Team 2 score for the supported periods. Applicable to soccer only.
+      periodTeam1RedCards:
+        type: integer
+        format: int32
+        description: Team 1 red cards for the supported periods. Applicable to soccer only.
+      periodTeam2RedCards:
+        type: integer
+        format: int32
+        description: Team 2 red cards for the supported periods. Applicable to soccer only.
+  ParlayLinesRequestV3:
+    type: object
+    properties:
+      oddsFormat:
+        type: string
+        description: Odds in the response will be in this format. [American, Decimal, HongKong, Indonesian, Malay]
+        enum:
+          - American
+          - Decimal
+          - HongKong
+          - Indonesian
+          - Malay
+      legs:
+        type: array
+        description: This is a collection of legs
+        items:
+          $ref: '#/definitions/ParlayLineRequestV3'
+  ParlayLineRequestV3:
+    type: object
+    properties:
+      uniqueLegId:
+        type: string
+        description: This unique id of the leg. It used to identify and match leg in the response.
+      eventId:
+        type: integer
+        format: int64
+        description: Id of the event.
+      periodNumber:
+        type: integer
+        format: int32
+        description: This represents the period of the match. For example, for soccer we have 0 (Game), 1 (1st Half), 2 (2nd Half)
+      legBetType:
+        type: string
+        description: SPREAD, MONEYLINE, TOTAL_POINTS and TEAM_TOTAL_POINTS are supported.
+        enum:
+          - SPREAD
+          - MONEYLINE
+          - TOTAL_POINTS
+          - TEAM_TOTAL_POINTS
+      team:
+        type: string
+        description: Chosen team type. This is needed only for SPREAD and MONEYLINE wager types. [Team1, Team2, Draw (MONEYLINE only)]
+        enum:
+          - Team1
+          - Team2
+          - Draw
+      side:
+        type: string
+        description: Chosen side. This is needed only for TOTAL_POINTS wager type.  [OVER, UNDER]
+        enum:
+          - OVER
+          - UNDER
+      handicap:
+        type: number
+        format: double
+        description: This is needed for SPREAD and TOTAL_POINTS bet type.
+    required:
+      - uniqueLegId
+      - eventId
+      - periodNumber
+      - legBetType
+  ParlayLinesResponseV3:
+    type: object
+    properties:
+      status:
+        type: string
+        description: Status of the parlay [VALID = Parlay is valid, PROCESSED_WITH_ERROR = Parlay contains error(s)]
+        example: PROCESSED_WITH_ERROR
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      error:
+        type: string
+        description: INVALID_LEGS. Signifies that one or more legs are invalid. Populated only if status is PROCESSED_WITH_ERROR.
+        example: INVALID_LEGS
+      minRiskStake:
+        type: number
+        format: double
+        description: Minimum allowed stake amount.
+      maxParlayRiskStake:
+        type: number
+        format: double
+        description: Maximum allowed stake amount for parlay bets.
+      maxRoundRobinTotalRisk:
+        type: number
+        format: double
+        description: Maximum allowed total stake amount for all the parlay bets in the round robin.
+      maxRoundRobinTotalWin:
+        type: number
+        format: double
+        description: Maximum allowed total win amount for all the parlay bets in the round robin.
+      roundRobinOptionWithOdds:
+        type: array
+        description: Provides array with all acceptable Round Robin options with parlay odds for that option.
+        items:
+          $ref: '#/definitions/RoundRobinOptionWithOddsV3'
+      legs:
+        type: array
+        description: The collection of legs (the format of the object is described below).
+        items:
+          $ref: '#/definitions/ParlayLineLeg'
+    required:
+      - status
+  RoundRobinOptionWithOddsV3:
+    type: object
+    properties:
+      roundRobinOption:
+        type: string
+        description: |
+          RoundRobinOptions
+
+            Parlay = Single parlay that include all wagers (No Round Robin),
+            TwoLegRoundRobin = Multiple parlays having 2 wagers each (round robin style),
+            ThreeLegRoundRobin = Multiple parlays having 3 wagers each (round robin style),
+            FourLegRoundRobin = Multiple parlays having 4 wagers each (round robin style),
+            FiveLegRoundRobin = Multiple parlays having 5 wagers each (round robin style),
+            SixLegRoundRobin = Multiple parlays having 6 wagers each (round robin style),
+            SevenLegRoundRobin = Multiple parlays having 7 wagers each (round robin style),
+            EightLegRoundRobin = Multiple parlays having 8 wagers each (round robin style)
+        enum:
+          - Parlay
+          - TwoLegRoundRobin
+          - ThreeLegRoundRobin
+          - FourLegRoundRobin
+          - FiveLegRoundRobin
+          - SixLegRoundRobin
+          - SevenLegRoundRobin
+          - EightLegRoundRobin
+      odds:
+        type: number
+        format: double
+        description: Parlay odds for this option.
+      unroundedDecimalOdds:
+        type: number
+        format: double
+        description: Unrounded parlay odds in decimal format to be used for calculations only
+      numberOfBets:
+        type: number
+        format: int
+        description: Number of bets in the roundRobinOption.
+    required:
+      - roundRobinOption
+      - odds
+      - unroundedDecimalOdds
+  ParlayLineLeg:
+    type: object
+    properties:
+      status:
+        type: string
+        description: Status of the request. [VALID = Valid leg, PROCESSED_WITH_ERROR = Processed with error]
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      errorCode:
+        type: string
+        description: |
+          When Status is PROCESSED_WITH_ERROR, provides a code indicating the specific problem.
+
+            CORRELATED = The leg is correlated with another one,
+            CANNOT_PARLAY_LIVE_GAME = The wager is placed on Live game,
+            EVENT_NO_LONGER_AVAILABLE_FOR_BETTING = The event is no longer offered for Parlays,
+            EVENT_NOT_OFFERED_FOR_PARLAY = The event is not offered for Parlays,
+            LINE_DOES_NOT_BELONG_TO_EVENT = LineId does not match the EventId specified in the request,
+            WAGER_TYPE_NO_LONGER_AVAILABLE_FOR_BETTING = Wager Type no longer available for betting,
+            WAGER_TYPE_NOT_VALID_FOR_PARLAY =  Wager Type not valid for parlay,
+            WAGER_TYPE_CONFLICTS_WITH_OTHER_LEG = Wager Type conflicts with other leg
+        enum:
+
+          - CORRELATED
+          - CANNOT_PARLAY_LIVE_GAME
+          - EVENT_NO_LONGER_AVAILABLE_FOR_BETTING
+          - EVENT_NOT_OFFERED_FOR_PARLAY
+          - LINE_DOES_NOT_BELONG_TO_EVENT
+          - WAGER_TYPE_NO_LONGER_AVAILABLE_FOR_BETTING
+          - WAGER_TYPE_NOT_VALID_FOR_PARLAY
+          - WAGER_TYPE_CONFLICTS_WITH_OTHER_LEG
+      legId:
+        type: string
+        description: Echo of the legId from the request.
+      lineId:
+        type: integer
+        format: int64
+        description: Line identification.
+      altLineId:
+        type: integer
+        format: int64
+        description: If alternate Line was requested, the Id of that line will be returned.
+      price:
+        type: number
+        format: double
+        description: Price
+      correlatedLegs:
+        type: array
+        description: If errorCode is CORRELATED will contain legIds of all correlated legs.
+        items:
+          type: string
+    required:
+      - legId
+      - status
+  LinesRequestTeaser:
+    type: object
+    properties:
+      teaserId:
+        type: integer
+        format: int64
+        description: Unique identifier. Teaser details can be retrieved from a call to v1/teaser/groups endpoint.
+      oddsFormat:
+        type: string
+        description: Format the odds are returned in.. = [American, Decimal, HongKong, Indonesian, Malay]
+        enum:
+          - American
+          - Decimal
+          - HongKong
+          - Indonesian
+          - Malay
+      legs:
+        type: array
+        description: Collection of Teaser Legs.
+        items:
+          $ref: '#/definitions/TeaserLineRequest'
+    required:
+      - teaserId
+      - oddsFormat
+      - legs
+  TeaserLineRequest:
+    type: object
+    properties:
+      legId:
+        type: string
+        description: Client genereated GUID for uniquely identifying the leg.
+      eventId:
+        type: integer
+        format: int64
+        description: Unique identifier.
+      periodNumber:
+        type: integer
+        format: int32
+        description: Period of the match that is being bet on. v1/periods endpoint can be used to retrieve all periods for a sport.
+      betType:
+        type: string
+        description: Type of bet. Currently only SPREAD and TOTAL_POINTS are supported. [SPREAD, TOTAL_POINTS]
+        enum:
+          - SPREAD
+          - TOTAL_POINTS
+      team:
+        type: string
+        description: Team being bet on for a spread line. [Team1, Team2]
+        enum:
+          - Team1
+          - Team2
+      side:
+        type: string
+        description: Side of a total line being bet on. [OVER, UNDER]
+        enum:
+          - OVER
+          - UNDER
+      handicap:
+        type: number
+        format: double
+        description: Number of points.
+    required:
+      - legId
+      - eventId
+      - periodNumber
+      - betType
+      - handicap
+  TeaserLinesResponse:
+    type: object
+    properties:
+      status:
+        type: string
+        description: Status of the request. [VALID = Teaser is valid, PROCESSED_WITH_ERROR = Teaser contains one or more errors]
+        example: PROCESSED_WITH_ERROR
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      errorCode:
+        type: string
+        description: |
+          When Status is PROCESSED_WITH_ERROR, provides a code indicating the specific problem.
+
+            INVALID_LEGS = One or more of the legs is invalid,
+            SAME_EVENT_ONLY_REQUIRED = Teaser specified requires that all legs are from the same event,
+            TEASER_DISABLED = Teaser has been disabled and cannot be bet on,
+            TEASER_DOES_NOT_EXIST = The teaser identifier could not be found,
+            TOO_FEW_LEGS = You do not meet the minimum number of legs requirement for the teaser specified,
+            TOO_MANY_LEGS = You are above the maximum number of legs for the teaser specified,
+            UNKNOWN = An unknown error has occurred
+        enum:
+          - INVALID_LEGS
+          - SAME_EVENT_ONLY_REQUIRED
+          - TEASER_DISABLED
+          - TEASER_DOES_NOT_EXIST
+          - TOO_FEW_LEGS
+          - TOO_MANY_LEGS
+          - UNKNOWN
+      price:
+        type: number
+        format: double
+        description: Price for the bet.
+      minRiskStake:
+        type: number
+        format: double
+        description: Minimum bet amount for WIN_RISK_TYPE.RISK.
+      maxRiskStake:
+        type: number
+        format: double
+        description: Maximum bet amount for WIN_RISK_TYPE.RISK.
+      minWinStake:
+        type: number
+        format: double
+        description: Minimum bet amount for WIN_RISK_TYPE.WIN.
+      maxWinStake:
+        type: number
+        format: double
+        description: Maximum bet amount for WIN_RISK_TYPE.WIN.
+      legs:
+        type: array
+        description: Collection of Teaser Legs from the request.
+        items:
+          $ref: '#/definitions/TeaserLineLeg'
+    required:
+      - status
+      - legs
+  TeaserLineLeg:
+    type: object
+    properties:
+      status:
+        type: string
+        description: Status of the request. [VALID = Teaser is valid, PROCESSED_WITH_ERROR = Teaser contains error(s)]
+        example: PROCESSED_WITH_ERROR
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      errorCode:
+        type: string
+        description: |
+          When Status is PROCESSED_WITH_ERROR, provides a code indicating the specific problem.
+
+            EVENT_NOT_FOUND = The event specified could not be found,
+            POINTS_NO_LONGER_AVAILABLE = The points requested are no longer available. This means that the lines moved,
+            UNKNOWN = An unknown error has occured,
+            WAGER_TYPE_NOT_VALID_FOR_TEASER = The specified wager type is not valid for teasers
+        enum:
+          - EVENT_NOT_FOUND
+          - POINTS_NO_LONGER_AVAILABLE
+          - UNKNOWN
+          - WAGER_TYPE_NOT_VALID_FOR_TEASER
+      legId:
+        type: string
+        description: Echo of the unique id for the leg from the request.
+      lineId:
+        type: integer
+        format: int64
+        description: Line identification.
+    required:
+      - legId
+      - status
+  OddsResponseV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      leagues:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/OddsLeagueV3'
+  OddsResponseV4:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      leagues:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/OddsLeagueV4'
+  OddsLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/OddsEventV3'
+  OddsLeagueV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/OddsEventV4'
+  OddsEventV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event Id.
+      awayScore:
+        type: number
+        format: double
+        description: Away team score. Only for live soccer events.Supported only for full match period (number=0).
+      homeScore:
+        type: number
+        format: double
+        description: Home team score. Only for live soccer events.Supported only for full match period (number=0).
+      awayRedCards:
+        type: integer
+        format: int32
+        description: Away team red cards. Only for live soccer events. Supported only for full match period (number=0).
+      homeRedCards:
+        type: integer
+        format: int32
+        description: Home team red cards. Only for live soccer events.Supported only for full match period (number=0).
+      periods:
+        type: array
+        description: Contains a list of periods.
+        items:
+          $ref: '#/definitions/OddsPeriodV3'
+  OddsEventV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event Id.
+      awayScore:
+        type: number
+        format: double
+        description: Away team score. Only for live soccer events.Supported only for full match period (number=0).
+      homeScore:
+        type: number
+        format: double
+        description: Home team score. Only for live soccer events.Supported only for full match period (number=0).
+      awayRedCards:
+        type: integer
+        format: int32
+        description: Away team red cards. Only for live soccer events. Supported only for full match period (number=0).
+      homeRedCards:
+        type: integer
+        format: int32
+        description: Home team red cards. Only for live soccer events.Supported only for full match period (number=0).
+      periods:
+        type: array
+        description: Contains a list of periods.
+        items:
+          $ref: '#/definitions/OddsPeriodV4'
+  OddsPeriodV3:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: Line Id.
+      number:
+        type: integer
+        format: int32
+        description: This represents the period of the match. For example, for soccer we have  0 (Game), 1 (1st Half) & 2 (2nd Half)
+      cutoff:
+        type: string
+        format: date-time
+        description: Period’s wagering cut-off date in UTC.
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - online, period is open for betting
+              2 - offline, period is not open for betting
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: Maximum spread bet. Only in straight odds response.
+      maxMoneyline:
+        type: number
+        format: double
+        description: Maximum moneyline bet. Only in straight odds response.
+      maxTotal:
+        type: number
+        format: double
+        description: Maximum total points bet. Only in straight odds response.
+      maxTeamTotal:
+        type: number
+        format: double
+        description: Maximum team total points bet. Only in straight odds response.
+      moneylineUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last moneyline update.
+      spreadUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last spread update.
+      totalUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last total update.
+      teamTotalUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last team total update.
+      spreads:
+        type: array
+        description: Container for spread odds.
+        items:
+          $ref: '#/definitions/OddsSpreadV3'
+      moneyline:
+        $ref: '#/definitions/OddsMoneylineV3'
+      totals:
+        type: array
+        description: Container for team total points.
+        items:
+          $ref: '#/definitions/OddsTotalV3'
+      teamTotal:
+        $ref: '#/definitions/OddsTeamTotalsV3'
+      awayScore:
+        type: number
+        format: double
+        description: Period away team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeScore:
+        type: number
+        format: double
+        description: Period home team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      awayRedCards:
+        type: number
+        format: int32
+        description: Period away team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeRedCards:
+        type: number
+        format: int32
+        description: Period home team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time number=3).
+  OddsPeriodV4:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: Line Id.
+      number:
+        type: integer
+        format: int32
+        description: This represents the period of the match. For example, for soccer we have  0 (Game), 1 (1st Half) & 2 (2nd Half)
+      cutoff:
+        type: string
+        format: date-time
+        description: Period’s wagering cut-off date in UTC.
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - online, period is open for betting
+              2 - offline, period is not open for betting
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: Maximum spread bet. Only in straight odds response.
+      maxMoneyline:
+        type: number
+        format: double
+        description: Maximum moneyline bet. Only in straight odds response.
+      maxTotal:
+        type: number
+        format: double
+        description: Maximum total points bet. Only in straight odds response.
+      maxTeamTotal:
+        type: number
+        format: double
+        description: Maximum team total points bet. Only in straight odds response.
+      moneylineUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last moneyline update.
+      spreadUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last spread update.
+      totalUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last total update.
+      teamTotalUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last team total update.
+      spreads:
+        type: array
+        description: Container for spread odds.
+        items:
+          $ref: '#/definitions/OddsSpreadV4'
+      moneyline:
+        $ref: '#/definitions/OddsMoneylineV4'
+      totals:
+        type: array
+        description: Container for team total points.
+        items:
+          $ref: '#/definitions/OddsTotalV4'
+      teamTotal:
+        $ref: '#/definitions/OddsTeamTotalsV4'
+      awayScore:
+        type: number
+        format: double
+        description: Period away team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeScore:
+        type: number
+        format: double
+        description: Period home team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      awayRedCards:
+        type: number
+        format: int32
+        description: Period away team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeRedCards:
+        type: number
+        format: int32
+        description: Period home team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time number=3).
+  OddsSpreadV3:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: This is present only if it’s alternative line.
+      hdp:
+        type: number
+        format: double
+        description: Home team handicap.
+      home:
+        type: number
+        format: double
+        description: Home team price.
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxSpread` market limit.
+  OddsSpreadV4:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: This is present only if it’s alternative line.
+      hdp:
+        type: number
+        format: double
+        description: Home team handicap.
+      home:
+        type: number
+        format: double
+        description: Home team price.
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxSpread` market limit.
+  OddsMoneylineV3:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: Away team price
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      draw:
+        type: number
+        format: double
+        description: Draw price. This is present only for events we offer price for draw.
+  OddsMoneylineV4:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: Away team price
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      draw:
+        type: number
+        format: double
+        description: Draw price. This is present only for events we offer price for draw.
+  OddsTotalV3:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: This is present only if it’s alternative line.
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxTotal` market limit.
+  OddsTotalV4:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: This is present only if it’s alternative line.
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxTotal` market limit.
+  OddsTeamTotalsV3:
+    type: object
+    properties:
+      home:
+        $ref: '#/definitions/OddsTeamTotalV3'
+      away:
+        $ref: '#/definitions/OddsTeamTotalV3'
+  OddsTeamTotalsV4:
+    type: object
+    properties:
+      home:
+        type: array
+        description: Container for Home team's total points.
+        items:
+          $ref: '#/definitions/OddsTeamTotalV4'
+      away:
+        type: array
+        description: Container for Away team's total points.
+        items:
+          $ref: '#/definitions/OddsTeamTotalV4'
+  OddsTeamTotalV3:
+    type: object
+    properties:
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+  OddsTeamTotalV4:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: This is present only if it’s alternative line.
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxTeamTotal` market limit.
+    required:
+      - points
+      - over
+      - under
+  ParlayOddsResponseV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      leagues:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/ParlayOddsLeagueV3'
+    required:
+      - sportId
+      - last
+      - leagues
+  ParlayOddsResponseV4:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: Same as requested sport Id.
+      last:
+        type: integer
+        format: int64
+        description: Use this value for the subsequent requests for since query parameter to get just the changes since previous response.
+      leagues:
+        type: array
+        description: Contains a list of Leagues.
+        items:
+          $ref: '#/definitions/ParlayOddsLeagueV4'
+    required:
+      - sportId
+      - last
+      - leagues
+  ParlayOddsLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/ParlayOddsEventV3'
+    required:
+      - id
+      - events
+  ParlayOddsLeagueV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: League Id.
+      events:
+        type: array
+        description: Contains a list of events.
+        items:
+          $ref: '#/definitions/ParlayOddsEventV4'
+    required:
+      - id
+      - events
+  ParlayOddsEventV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event Id.
+      awayScore:
+        type: number
+        format: double
+        description: Away team score. Only for live soccer events.
+      homeScore:
+        type: number
+        format: double
+        description: Home team score. Only for live soccer events.
+      awayRedCards:
+        type: integer
+        format: int32
+        description: Away team red cards. Only for live soccer events.
+      homeRedCards:
+        type: integer
+        format: int32
+        description: Home team red cards. Only for live soccer events.
+      periods:
+        type: array
+        description: Contains a list of periods.
+        items:
+          $ref: '#/definitions/ParlayOddsPeriodV3'
+    required:
+      - id
+      - periods
+  ParlayOddsEventV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Event Id.
+      awayScore:
+        type: number
+        format: double
+        description: Away team score. Only for live soccer events.
+      homeScore:
+        type: number
+        format: double
+        description: Home team score. Only for live soccer events.
+      awayRedCards:
+        type: integer
+        format: int32
+        description: Away team red cards. Only for live soccer events.
+      homeRedCards:
+        type: integer
+        format: int32
+        description: Home team red cards. Only for live soccer events.
+      periods:
+        type: array
+        description: Contains a list of periods.
+        items:
+          $ref: '#/definitions/ParlayOddsPeriodV4'
+    required:
+      - id
+      - periods
+  ParlayOddsPeriodV3:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: Line Id.
+      number:
+        type: integer
+        format: int32
+        description: This represents the period of the match. For example, for soccer we have 0 (Game), 1 (1st Half) & 2 (2nd Half)
+      cutoff:
+        type: string
+        format: date-time
+        description: Period’s wagering cut-off date in UTC.
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - online, period is open for betting
+              2 - offline, period is not open for betting
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: Maximum spread bet. Only in straight odds response.
+      maxMoneyline:
+        type: number
+        format: double
+        description: Maximum moneyline bet. Only in straight odds response.
+      maxTotal:
+        type: number
+        format: double
+        description: Maximum total points bet. Only in straight odds response.
+      maxTeamTotal:
+        type: number
+        format: double
+        description: Maximum team total points bet. Only in straight odds response.
+      moneylineUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last moneyline update.
+      spreadUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last spread update.
+      totalUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last total update.
+      teamTotalUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last team total update.
+      spreads:
+        type: array
+        description: Container for spread odds.
+        items:
+          $ref: '#/definitions/ParlayOddsSpreadV3'
+      moneyline:
+        $ref: '#/definitions/ParlayOddsMoneylineV3'
+      totals:
+        type: array
+        description: Container for team total points.
+        items:
+          $ref: '#/definitions/ParlayOddsTotalV3'
+      teamTotal:
+        $ref: '#/definitions/ParlayOddsTeamTotalsV3'
+      awayScore:
+        type: number
+        format: double
+        description: Period away team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeScore:
+        type: number
+        format: double
+        description: Period home team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      awayRedCards:
+        type: number
+        format: double
+        description: Period away team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeRedCards:
+        type: number
+        format: double
+        description: Period home team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time number=3).
+    required:
+      - lineId
+      - number
+      - cutoff
+  ParlayOddsPeriodV4:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: Line Id.
+      number:
+        type: integer
+        format: int32
+        description: This represents the period of the match. For example, for soccer we have 0 (Game), 1 (1st Half) & 2 (2nd Half)
+      cutoff:
+        type: string
+        format: date-time
+        description: Period’s wagering cut-off date in UTC.
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - online, period is open for betting
+              2 - offline, period is not open for betting
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: Maximum spread bet. Only in straight odds response.
+      maxMoneyline:
+        type: number
+        format: double
+        description: Maximum moneyline bet. Only in straight odds response.
+      maxTotal:
+        type: number
+        format: double
+        description: Maximum total points bet. Only in straight odds response.
+      maxTeamTotal:
+        type: number
+        format: double
+        description: Maximum team total points bet. Only in straight odds response.
+      moneylineUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last moneyline update.
+      spreadUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last spread update.
+      totalUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last total update.
+      teamTotalUpdatedAt:
+        type: number
+        format: double
+        description: Date time of the last team total update.
+      spreads:
+        type: array
+        description: Container for spread odds.
+        items:
+          $ref: '#/definitions/ParlayOddsSpreadV4'
+      moneyline:
+        $ref: '#/definitions/ParlayOddsMoneylineV4'
+      totals:
+        type: array
+        description: Container for team total points.
+        items:
+          $ref: '#/definitions/ParlayOddsTotalV4'
+      teamTotal:
+        $ref: '#/definitions/ParlayOddsTeamTotalsV4'
+      awayScore:
+        type: number
+        format: double
+        description: Period away team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeScore:
+        type: number
+        format: double
+        description: Period home team score. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      awayRedCards:
+        type: number
+        format: double
+        description: Period away team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time (number=3).
+      homeRedCards:
+        type: number
+        format: double
+        description: Period home team red cards. Only for live soccer events. Supported only for Match (number=0) and Extra Time number=3).
+    required:
+      - lineId
+      - number
+      - cutoff
+  ParlayOddsSpreadV3:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: This is present only if it’s alternative line.
+      hdp:
+        type: number
+        format: double
+        description: Home team handicap.
+      home:
+        type: number
+        format: double
+        description: Home team price.
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxSpread` market limit.
+    required:
+      - hdp
+      - home
+      - away
+  ParlayOddsSpreadV4:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: This is present only if it’s alternative line.
+      hdp:
+        type: number
+        format: double
+        description: Home team handicap.
+      home:
+        type: number
+        format: double
+        description: Home team price.
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxSpread` market limit.
+    required:
+      - hdp
+      - home
+      - away
+  ParlayOddsMoneylineV3:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: Away team price
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      draw:
+        type: number
+        format: double
+        description: Draw price. This is present only for events we offer price for draw.
+    required:
+      - home
+      - away
+  ParlayOddsMoneylineV4:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: Away team price
+      away:
+        type: number
+        format: double
+        description: Away team price.
+      draw:
+        type: number
+        format: double
+        description: Draw price. This is present only for events we offer price for draw.
+    required:
+      - home
+      - away
+  ParlayOddsTotalV3:
+    $ref: '#/definitions/ParlayOddsTotalsV3'
+  ParlayOddsTotalV4:
+    $ref: '#/definitions/ParlayOddsTotalsV4'
+  ParlayOddsTeamTotalsV3:
+    type: object
+    properties:
+      away:
+        $ref: '#/definitions/ParlayOddsTotalsV3'
+      home:
+        $ref: '#/definitions/ParlayOddsTotalsV3'
+  ParlayOddsTeamTotalsV4:
+    type: object
+    properties:
+      away:
+        type: array
+        description: Container for Away team's total points.
+        items:
+          $ref: '#/definitions/ParlayOddsTeamTotalV4'
+      home:
+        type: array
+        description: Container for Home team's total points.
+        items:
+          $ref: '#/definitions/ParlayOddsTeamTotalV4'
+  ParlayOddsTotalsV3:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: Line Id for the alternate line. This is present only if it’s alternative line.
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxTotal` market limit.
+    required:
+      - points
+      - over
+      - under
+  ParlayOddsTotalsV4:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: Line Id for the alternate line. This is present only if it’s alternative line.
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxTotal` market limit.
+    required:
+      - points
+      - over
+      - under
+  ParlayOddsTeamTotalV4:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: This is present only if it’s alternative line.
+      points:
+        type: number
+        format: double
+        description: Total points.
+      over:
+        type: number
+        format: double
+        description: Over price.
+      under:
+        type: number
+        format: double
+        description: Under price.
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: Maximum bet volume. Present only on alternative lines, if set it overides `maxTeamTotal` market limit.
+    required:
+      - points
+      - over
+      - under
+  TeaserOddsResponse:
+    type: object
+    properties:
+      teaserId:
+        type: integer
+        format: int64
+        description: Unique identifier. Teaser details can be retrieved from a call to Get Teaser Groups endpoint.
+      sportId:
+        type: integer
+        format: int32
+        description: Unique identifier. Sport details can be retrieved from a call to Get Sports endpoint.
+      leagues:
+        type: array
+        description: A collection of League.
+        items:
+          $ref: '#/definitions/TeaserOddsLeague'
+  TeaserOddsLeague:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: Unique identifier. League details can be retrieved from a call to Get Leagues endpoint.
+      events:
+        type: array
+        description: A collection of Event.
+        items:
+          $ref: '#/definitions/TeaserOddsEvent'
+  TeaserOddsEvent:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Unique identifier.
+      periods:
+        type: array
+        description: A collection of periods indicating the period numbers available for betting.
+        items:
+          $ref: '#/definitions/TeaserOddsPeriod'
+  TeaserOddsPeriod:
+    type: object
+    properties:
+      number:
+        type: integer
+        format: int32
+        description: Period of the match that the request is for. Refer to v1/periods endpoint to retrieve all valid periods for a sport.
+      lineId:
+        type: integer
+        format: int64
+        description: Unique identifier.
+      spreadUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last spread update.
+      totalUpdatedAt:
+        type: string
+        format: date-time
+        description: Date time of the last total update.
+      spread:
+        $ref: '#/definitions/TeaserOddsSpread'
+      total:
+        $ref: '#/definitions/TeaserOddsTotalPoints'
+  TeaserOddsSpread:
+    type: object
+    properties:
+      maxBet:
+        type: number
+        format: double
+        description: Maximum bet amount.
+      homeHdp:
+        type: number
+        format: double
+        description: Home team handicap. Refer to Get Fixtures endpoint to determine home and away teams.
+      awayHdp:
+        type: number
+        format: double
+        description: Away team handicap. Refer to Get Fixtures endpoint to determine home and away teams.
+      altHdp:
+        type: boolean
+        description: Whether the spread is offer with alterantive teaser points. Events with alternative teaser points may vary from teaser definition.
+        example: false
+  TeaserOddsTotalPoints:
+    type: object
+    properties:
+      maxBet:
+        type: number
+        format: double
+        description: Maximum bet amount.
+      overPoints:
+        type: number
+        format: double
+        description: Over points.
+      underPoints:
+        type: number
+        format: double
+        description: Under points.
+  SportPeriod:
+    type: object
+    properties:
+      number:
+        type: integer
+        format: int32
+        description: Period Number
+      description:
+        type: string
+        description: Description for the period
+      shortDescription:
+        type: string
+        description: Short description for the period
+  SportsResponseV3:
+    type: object
+    properties:
+      sports:
+        type: array
+        description: Sports container.
+        items:
+          $ref: '#/definitions/SportV3'
+  SportV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: Sport Id.
+      name:
+        type: string
+        description: Sport name.
+      hasOfferings:
+        type: boolean
+        description: Whether the sport currently has events or specials.
+      leagueSpecialsCount:
+        type: integer
+        format: int32
+        description: Indicates how many specials are in the given sport.
+      eventSpecialsCount:
+        type: integer
+        format: int32
+        description: Indicates how many event specials are in the given sport.
+      eventCount:
+        type: integer
+        format: int32
+        description: Indicates how many events are in the given sport.
+  TeaserGroupsResponse:
+    type: object
+    properties:
+      teaserGroups:
+        type: array
+        description: A collection of TeaserGroups containing available teasers.
+        items:
+          $ref: '#/definitions/TeaserGroups'
+  TeaserGroups:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Unique identifier.
+      name:
+        type: string
+        description: Friendly name for the Teaser Group
+      teasers:
+        type: array
+        description: A collection of Teaser.
+        items:
+          $ref: '#/definitions/TeaserGroupsTeaser'
+  TeaserGroupsTeaser:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: Unique identifier.
+      description:
+        type: string
+        description: Description for the Teaser.
+      sportId:
+        type: integer
+        format: int32
+        description: Unique Sport identifier. Sport details can be retrieved from a call to v2/sports endpoint.
+      minLegs:
+        type: integer
+        format: int32
+        description: Minimum number of legs that must be selected.
+      maxLegs:
+        type: integer
+        format: int32
+        description: Maximum number of legs that can be selected.
+      sameEventOnly:
+        type: boolean
+        description: If 'true' then all legs must be from the same event, otherwise legs can be from different events.
+      payouts:
+        type: array
+        description: A collection of Payout indicating all possible payout combinations.
+        items:
+          $ref: '#/definitions/TeaserGroupsPayout'
+      leagues:
+        type: array
+        description: A collection of Leagues available to the teaser.
+        items:
+          $ref: '#/definitions/TeaserGroupsLeague'
+  TeaserGroupsPayout:
+    type: object
+    properties:
+      numberOfLegs:
+        type: integer
+        format: int32
+        description: Number of legs that must be bet and won to get the associated price.
+      price:
+        type: number
+        format: double
+        description: Price of the bet given the specified number of legs.
+  TeaserGroupsLeague:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: Unique identifier. League details can be retrieved from a call to v2/leagues endpoint.
+      spread:
+        $ref: '#/definitions/TeaserGroupsBetType'
+      total:
+        $ref: '#/definitions/TeaserGroupsBetType'
+  TeaserGroupsBetType:
+    type: object
+    properties:
+      points:
+        type: number
+        format: double
+        description: Number of points the line will be teased for the given league.
+  SpecialsFixturesResponseV2:
+    type: object
+    properties:
+      sportId:
+        format: int32
+        description: Id of a sport for which to retrieve the odds.
+        type: integer
+      last:
+        format: int64
+        description: Used for retrieving changes only on subsequent requests. Provide this value as the Since paramter in subsequent calls to only retrieve changes.
+        type: integer
+      leagues:
+        description: Contains a list of Leagues.
+        type: array
+        items:
+          $ref: '#/definitions/SpecialsFixturesLeagueV2'
+  SpecialsFixturesLeagueV2:
+    type: object
+    properties:
+      id:
+        format: int32
+        description: FixturesLeague Id.
+        type: integer
+      specials:
+        description: A collection of Specials
+        type: array
+        items:
+          $ref: '#/definitions/SpecialFixtureV2'
+  SpecialFixtureV2:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: Unique Id
+        type: integer
+      betType:
+        description: The type [MULTI_WAY_HEAD_TO_HEAD, SPREAD, OVER_UNDER]
+        enum:
+          - MULTI_WAY_HEAD_TO_HEAD
+          - SPREAD
+          - OVER_UNDER
+        type: string
+      name:
+        description: Name of the special.
+        type: string
+      date:
+        format: date-time
+        description: Date of the special in UTC.
+        type: string
+      cutoff:
+        format: date-time
+        description: Wagering cutoff date in UTC.
+        type: string
+      category:
+        description: The category that the special falls under.
+        type: string
+      units:
+        description: Measurment in the context of the special. This is applicable to specials bet type spead and over/under. In a hockey special this could be goals.
+        type: string
+      status:
+        description: |
+          Status of the Special
+
+          O = This is the starting status of a game. It means that the lines are open for betting,
+          H = This status indicates that the lines are temporarily unavailable for betting,
+          I = This status indicates that one or more lines have a red circle (a lower maximum bet amount)
+        enum:
+          - O
+          - H
+          - I
+        type: string
+      event:
+        $ref: '#/definitions/SpecialsFixturesEventV2'
+      contestants:
+        description: ContestantLines available for wagering.
+        type: array
+        items:
+          $ref: '#/definitions/SpecialsFixturesContestant'
+      liveStatus:
+        format: int32
+        description: |
+          When a special is linked to an event, we will return live status of the event, otherwise it will be 0. 0 = No live betting will be offered on this event, 1 = Live betting event, 2 = Live betting will be offered on this match, but on a different event.
+
+          Please note that live delay is applied when placing bets on special with LiveStatus=1
+        enum:
+          - 0
+          - 1
+          - 2
+        type: integer
+  SpecialsFixturesEventV2:
+    type: object
+    description: Optional event asscoaited with the special.
+    properties:
+      id:
+        format: int32
+        description: Event Id
+        type: integer
+      periodNumber:
+        format: int32
+        description: The period of the match. For example in soccer 0 (Game), 1 (1st Half) & 2 (2nd Half)
+        type: integer
+      home:
+        description: Home team name.
+        type: string
+      away:
+        description: Away team name.
+        type: string
+  SpecialsFixturesContestant:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: Contestant Id.
+        type: integer
+      name:
+        description: Name of the contestant.
+        type: string
+      rotNum:
+        format: int32
+        description: Rotation Number.
+        type: integer
+  SettledSpecialsResponseV3:
+    description: Response dto for SettledSpecials request
+    type: object
+    properties:
+      sportId:
+        format: int32
+        description: Id of a sport for which to retrieve the odds.
+        type: integer
+      last:
+        format: int64
+        description: Last index for the settled fixture
+        type: integer
+      leagues:
+        description: List of Leagues.
+        type: array
+        items:
+          $ref: '#/definitions/SettledSpecialsLeagueV3'
+  SettledSpecialsLeagueV3:
+    description: League Dto to hold all settled specials for the league
+    type: object
+    properties:
+      id:
+        format: int32
+        description: League Id.
+        type: integer
+      specials:
+        description: A collection of Settled Specials
+        type: array
+        items:
+          $ref: '#/definitions/SettledSpecialV3'
+  SettledSpecialV3:
+    description: Settled Special
+    type: object
+    properties:
+      id:
+        format: int64
+        description: Id for the Settled Special
+        type: integer
+      status:
+        format: int32
+        description: Status of the settled special.
+        type: integer
+      settlementId:
+        format: int64
+        description: Id for the Settled Special
+        type: integer
+      settledAt:
+        format: date-time
+        description: Settled DateTime
+        type: string
+      cancellationReason:
+        $ref: '#/definitions/CancellationReasonType'
+        description: Cancellation Reason for Special Event
+      contestants:
+        description: A collection of contestants
+        type: array
+        items:
+          $ref: '#/definitions/SettledContestants'
+  SettledContestants:
+    description: Settled Special
+    type: object
+    properties:
+      id:
+        format: int64
+        description: Contestant Id.
+        type: integer
+      name:
+        description: Contestant name
+        type: string
+        example: Union Magdalena
+      outcome:
+        type: string
+        description: |
+          Contestant outcomes.
+
+          W = Won,
+          L = Lost,
+          X = Cancelled,
+          T = Tie,
+          Z = Scratched
+        enum:
+          - W
+          - L
+          - X
+          - T
+          - Z
+  SpecialLineResponse:
+    type: object
+    properties:
+      status:
+        description: Status [SUCCESS = OK, NOT_EXISTS = Line not offered anymore]
+        enum:
+          - SUCCESS
+          - NOT_EXISTS
+        type: string
+      specialId:
+        format: int64
+        description: Special Id.
+        type: integer
+      contestantId:
+        format: int64
+        description: Contestant Id.
+        type: integer
+      minRiskStake:
+        format: double
+        description: Minimum bettable risk amount.
+        type: number
+      maxRiskStake:
+        format: double
+        description: Maximum bettable risk amount.
+        type: number
+      minWinStake:
+        format: double
+        description: Minimum bettable win amount.
+        type: number
+      maxWinStake:
+        format: double
+        description: Maximum bettable win amount.
+        type: number
+      lineId:
+        format: int64
+        description: Line identification needed to place a bet.
+        type: integer
+      price:
+        format: double
+        description: Latest price.
+        type: number
+      handicap:
+        format: double
+        description: Handicap.
+        type: number
+  SpecialOddsResponseV2:
+    type: object
+    properties:
+      sportId:
+        format: int32
+        description: Id of a sport for which to retrieve the odds.
+        type: integer
+      last:
+        format: int64
+        description: Used for retrieving changes only on subsequent requests. Provide this value as the Since paramter in subsequent calls to only retrieve changes.
+        type: integer
+      leagues:
+        description: Contains a list of Leagues.
+        type: array
+        items:
+          $ref: '#/definitions/SpecialOddsLeagueV2'
+  SpecialOddsLeagueV2:
+    type: object
+    properties:
+      id:
+        format: int32
+        description: League id.
+        type: integer
+      specials:
+        description: A collection of FixturesSpecial.
+        type: array
+        items:
+          $ref: '#/definitions/SpecialOddsSpecialV2'
+  SpecialOddsSpecialV2:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: Special Id.
+        type: integer
+      maxRisk:
+        format: double
+        description: Maximum risk amount.
+        type: number
+      contestantLines:
+        description: ContestantLines available for wagering on.
+        type: array
+        items:
+          $ref: '#/definitions/SpecialOddsContestantLineV2'
+  SpecialOddsContestantLineV2:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: ContestantLine Id.
+        type: integer
+      lineId:
+        format: int64
+        description: Line identifier required for placing a bet.
+        type: integer
+      price:
+        format: double
+        description: Price of the line.
+        type: number
+      handicap:
+        format: double
+        description: 'A number indicating the spread, over/under etc.'
+        type: number
+      max:
+        format: double
+        description: Maximum bet volume amount per contestant. See [How to calculate max risk from the max volume](https://github.com/pinny888/pinny888.github.io/blob/main/FAQs.md#how-to-calculate-max-risk-from-the-max-volume-limits-in-odds)
+        type: number

+ 3962 - 0
pinnacle/linesapi_zh.yaml

@@ -0,0 +1,3962 @@
+swagger: '2.0'
+info:
+  version: 1.0.0
+  title: Pinnacle888 - Lines API 参考文档
+  description: |
+    关于赔率和赛程的所有信息
+
+    # 身份验证
+
+    API 使用 HTTP Basic 访问身份验证。您需要发送 Authorization HTTP 请求头:
+
+    `Authorization: Basic <Base64 value of UTF-8 encoded "username:password">`
+
+    示例:
+
+    `Authorization: Basic U03MyOT23YbzMDc6d3c3O1DQ1`
+  x-logo:
+    url: ''
+host: api.pinnacle888.com
+schemes:
+  - https
+security:
+  - basicAuth: []
+paths:
+  /v3/fixtures:
+    get:
+      tags:
+        - Fixtures
+      summary: 获取赛程 - v3
+      description: 返回指定运动的所有**未结算**赛事。请注意,赛事可能出现在 Get Fixtures 响应中,但不在 Get Odds 中。这种情况发生在赔率目前不可用于投注时。请注意,使用 **since** 参数时,可能会收到完全相同的响应。这种情况很少见,可能是由于赛事属性的内部更新导致的。
+      operationId: Fixtures_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要获取赛程的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: isLive
+          in: query
+          description: 要仅检索直播赛事,请将值设置为 1 (isLive=1)。缺少或任何其他值将导致检索所有赛事,无论其直播状态如何。
+          required: false
+          type: boolean
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次 fixtures 响应中的 last 值。如果不提供 since 参数,赛程最多会延迟 1 分钟,以鼓励使用该参数。
+          required: false
+          type: integer
+          format: int64
+        - name: eventIds
+          in: query
+          description: 用于过滤的逗号分隔的赛事 ID 列表
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/FixturesResponseV3'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/fixtures/special:
+    get:
+      tags:
+        - Fixtures
+      summary: 获取特殊赛程 - v2
+      description: 返回指定运动的所有**未结算**特殊赛事。
+      operationId: Fixtures_Special_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要检索特殊赛事的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次响应中的 last 字段值。如果不提供 since 参数,赛程最多会延迟 1 分钟,以鼓励使用该参数。
+          required: false
+          type: integer
+          format: int64
+        - name: category
+          in: query
+          description: 特殊赛事所属的类别。
+          required: false
+          type: string
+        - name: eventId
+          in: query
+          description: 与特殊赛事关联的赛事 ID。
+          required: false
+          type: integer
+          format: int64
+        - name: specialId
+          in: query
+          description: 特殊赛事的 ID。
+          required: false
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SpecialsFixturesResponseV2'
+          examples:
+            application/json:
+              sportId: 4
+              last: 636433059508250600
+              leagues:
+                - id: 487
+                  specials:
+                    - id: 1
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 4th quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 1
+                          name: Odd
+                          rotNum: 100
+                        - id: 2
+                          name: Even
+                          rotNum: 101
+                    - id: 2
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 3rd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 3
+                          name: Odd
+                          rotNum: 100
+                        - id: 4
+                          name: Even
+                          rotNum: 101
+                    - id: 3
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 2nd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: H
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 5
+                          name: Odd
+                          rotNum: 100
+                        - id: 6
+                          name: Even
+                          rotNum: 101
+                    - id: 4
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 1st quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 1
+                        periodNumber: 0
+                      contestants:
+                        - id: 7
+                          name: Odd
+                          rotNum: 100
+                        - id: 8
+                          name: Even
+                          rotNum: 101
+                    - id: 5
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 4th quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: null
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 9
+                          name: Odd
+                          rotNum: 100
+                        - id: 10
+                          name: Even
+                          rotNum: 101
+                    - id: 6
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 3rd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 11
+                          name: Odd
+                          rotNum: 100
+                        - id: 12
+                          name: Even
+                          rotNum: 101
+                    - id: 7
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 2nd quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: I
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 13
+                          name: Odd
+                          rotNum: 100
+                        - id: 14
+                          name: Even
+                          rotNum: 101
+                    - id: 8
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Will the 1st quarter be odd or even?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: 1/4 Totals
+                      units: ""
+                      status: H
+                      event:
+                        id: 2
+                        periodNumber: 0
+                      contestants:
+                        - id: 15
+                          name: Odd
+                          rotNum: 100
+                        - id: 16
+                          name: Even
+                          rotNum: 101
+                    - id: 9
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Who will win the NBA finals?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: Outright Winner
+                      units: ""
+                      status: I
+                      contestants:
+                        - id: 17
+                          name: Golden State Warriors
+                          rotNum: 100
+                        - id: 18
+                          name: Cleveland Cavaliers
+                          rotNum: 101
+                        - id: 19
+                          name: San Antonio Spurs
+                          rotNum: 102
+                        - id: 20
+                          name: Chicago Bulls
+                          rotNum: 103
+                - id: 578
+                  specials:
+                    - id: 10
+                      betType: MULTI_WAY_HEAD_TO_HEAD
+                      name: Who will win the WNBA finals?
+                      date: '2017-10-11T14:00:00Z'
+                      cutoff: '2017-10-11T14:00:00Z'
+                      category: Outright Winner
+                      units: ""
+                      status: I
+                      contestants:
+                        - id: 21
+                          name: Minnesota Lynx
+                          rotNum: 100
+                        - id: 22
+                          name: Indiana Fever
+                          rotNum: 101
+                        - id: 23
+                          name: Phoenix Mercury
+                          rotNum: 102
+                        - id: 24
+                          name: Chicago Sky
+                          rotNum: 103
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v3/fixtures/settled:
+    get:
+      tags:
+        - Fixtures
+      summary: 获取已结算赛程 - v3
+      description: 返回指定运动在过去 24 小时内已结算的赛程。
+      operationId: Fixtures_Settled_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          required: true
+          description: 要检索已结算赛事的运动 ID。
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          required: false
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          required: false
+          description: 用于接收增量更新。使用上次响应中的 last 字段值。
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SettledFixturesSportV3'
+          examples:
+            application/json:
+              sportId: 0
+              last: 0
+              leagues:
+                - id: 0
+                  events:
+                    - id: 0
+                      periods:
+                        - number: 0
+                          status: 0
+                          settlementId: 0
+                          settledAt: '2017-09-03T18:21:22.3846289-07:00'
+                          team1Score: 0
+                          team2Score: 0
+                          cancellationReason:
+                            code: string
+                            details:
+                              correctTeam1Id: string
+                              correctTeam2Id: string
+                              correctListedPitcher1: string
+                              correctListedPitcher2: string
+                              correctSpread: '0.0'
+                              correctTotalPoints: '0.0'
+                              correctTeam1TotalPoints: '0.0'
+                              correctTeam2TotalPoints: '0.0'
+                              correctTeam1Score: '0'
+                              correctTeam2Score: '0'
+                              correctTeam1TennisSetsScore: '0'
+                              correctTeam2TennisSetsScore: '0'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v3/fixtures/special/settled:
+    get:
+      tags:
+        - Fixtures
+      summary: 获取已结算特殊赛程 - v3
+      description: 返回指定运动在过去 24 小时内已结算的所有特殊赛事。
+      operationId: Fixtures_Specials_Settled_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要检索已结算特殊赛事的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组。这是可选参数。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次响应中的 last 字段值。
+          required: false
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SettledSpecialsResponseV3'
+          examples:
+            application/json:
+              sportId: 0
+              last: 0
+              leagues:
+                - id: 0
+                  specials:
+                    - id: 0
+                      status: 0
+                      settlementId: 0
+                      settledAt: '2017-10-11T15:05:50.996671Z'
+                      contestants:
+                        - id: 1
+                          name: Barranquilla
+                          outcome: "X"
+                        - id: 2
+                          name: Valledupar
+                          outcome: "X"
+                      cancellationReason:
+                        code: string
+                        details:
+                          correctTeam1Id: string
+                          correctTeam2Id: string
+                          correctListedPitcher1: string
+                          correctListedPitcher2: string
+                          correctSpread: '0.0'
+                          correctTotalPoints: '0.0'
+                          correctTeam1TotalPoints: '0.0'
+                          correctTeam2TotalPoints: '0.0'
+                          correctTeam1Score: '0'
+                          correctTeam2Score: '0'
+                          correctTeam1TennisSetsScore: '0'
+                          correctTeam2TennisSetsScore: '0'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v3/odds:
+    get:
+      tags:
+        - Odds
+      summary: 获取直盘赔率 - v3
+      description: 返回所有未结算赛事的直盘赔率。请注意,赛事可能出现在 Get Fixtures 响应中,但不在 Get Odds 中。这种情况发生在赔率目前不可用于投注时。
+      operationId: Odds_Straight_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要检索赔率的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。默认为 American。[American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次 odds 响应中的 last 值。如果不提供 since 参数,赔率最多会延迟 1 分钟,以鼓励使用该参数。请注意,使用 since 参数时,响应中只包含已更改的周期。如果某个周期没有任何更改,它将不会出现在响应中。
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: 要仅检索直播赔率,请将值设置为 1 (isLive=1)。否则响应将包含所有赔率。
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: 按 EventIds 过滤
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+        - name: toCurrencyCode
+          in: query
+          description: 3 字母货币代码,如 [/currency](https://pinny888.github.io/docs/?api=lines#tag/Others/operation/Currencies_V2_Get) 响应中所示。限额将以请求的货币返回。默认为 USD。
+          required: false
+          type: string
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/OddsResponseV3'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: true
+  /v4/odds:
+    get:
+      tags:
+        - Odds
+      summary: 获取直盘赔率 - v4
+      description: 返回所有未结算赛事的直盘赔率。请注意,赛事可能出现在 Get Fixtures 响应中,但不在 Get Odds 中。这种情况发生在赔率目前不可用于投注时。
+      operationId: Odds_Straight_V4_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要检索赔率的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。默认为 American。[American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次 odds 响应中的 last 值。如果不提供 since 参数,赔率最多会延迟 1 分钟,以鼓励使用该参数。请注意,使用 since 参数时,响应中只包含已更改的周期。如果某个周期没有任何更改,它将不会出现在响应中。
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: 要仅检索直播赔率,请将值设置为 1 (isLive=1)。否则响应将包含所有赔率。
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: 按 EventIds 过滤
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+        - name: toCurrencyCode
+          in: query
+          description: 3 字母货币代码,如 [/currency](https://pinny888.github.io/docs/?api=lines#tag/Others/operation/Currencies_V2_Get) 响应中所示。限额将以请求的货币返回。默认为 USD。
+          required: false
+          type: string
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/OddsResponseV4'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v3/odds/parlay:
+    get:
+      tags:
+        - Odds
+      summary: 获取串关赔率 - v3
+      description: 返回所有未结算赛事的串关赔率。请注意,赛事可能出现在 Get Fixtures 响应中,但不在 Get Odds 中。这种情况发生在赔率目前不可用于投注时。
+      operationId: Odds_Parlays_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要检索赔率的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。默认为 American。[American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次 odds 响应中的 last 值。如果不提供 since 参数,赔率最多会延迟 1 分钟,以鼓励使用该参数。请注意,使用 since 参数时,响应中只包含已更改的周期。如果某个周期没有任何更改,它将不会出现在响应中。
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: 要仅检索直播赔率,请将值设置为 1 (isLive=1)。否则响应将包含所有赔率。
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: 按 EventIds 过滤
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/ParlayOddsResponseV3'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: true
+  /v4/odds/parlay:
+    get:
+      tags:
+        - Odds
+      summary: 获取串关赔率 - v4
+      description: 返回所有未结算赛事的串关赔率。请注意,赛事可能出现在 Get Fixtures 响应中,但不在 Get Odds 中。这种情况发生在赔率目前不可用于投注时。
+      operationId: Odds_Parlays_V4_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 要检索赔率的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。默认为 American。[American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次 odds 响应中的 last 值。如果不提供 since 参数,赔率最多会延迟 1 分钟,以鼓励使用该参数。请注意,使用 since 参数时,响应中只包含已更改的周期。如果某个周期没有任何更改,它将不会出现在响应中。
+          required: false
+          type: integer
+          format: int64
+        - name: isLive
+          in: query
+          description: 要仅检索直播赔率,请将值设置为 1 (isLive=1)。否则响应将包含所有赔率。
+          required: false
+          type: boolean
+        - name: eventIds
+          in: query
+          description: 按 EventIds 过滤
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int64
+          collectionFormat: multi
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/ParlayOddsResponseV4'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/odds/teaser:
+    get:
+      tags:
+        - Odds
+      summary: 获取过关赔率 - v1
+      description: 返回指定过关的赔率。
+      operationId: Odds_Teasers_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: teaserId
+          in: query
+          description: 唯一标识符。可以从 Get Teaser Groups 端点调用中检索过关详情。
+          required: true
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/TeaserOddsResponse'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/odds/special:
+    get:
+      tags:
+        - Odds
+      summary: 获取特殊赔率 - v2
+      description: 返回所有未结算赛事的特殊赔率。
+      operationId: Odds_Special_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。[American, Decimal, HongKong, Indonesian, Malay]
+          required: false
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: sportId
+          in: query
+          description: 要检索特殊赛事的运动 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: leagueIds
+          in: query
+          description: leagueIds 数组可包含逗号分隔的联赛 ID 列表。
+          required: false
+          type: array
+          items:
+            type: integer
+            format: int32
+          collectionFormat: multi
+        - name: since
+          in: query
+          description: 用于接收增量更新。使用上次响应中的 last 值。如果不提供 since 参数,赛程最多会延迟 1 分钟,以鼓励使用该参数。
+          required: false
+          type: integer
+          format: int64
+        - name: specialId
+          in: query
+          description: 特殊赛事的 ID。这是可选参数。
+          required: false
+          type: integer
+          format: int64
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SpecialOddsResponseV2'
+          examples:
+            application/json:
+              sportId: 4
+              last: 636433059510590700
+              leagues:
+                - id: 487
+                  specials:
+                    - id: 1
+                      maxBet: 100
+                      contestantLines:
+                        - id: 1
+                          lineId: 1001
+                          price: -199
+                          handicap: null
+                          max: 100
+                        - id: 2
+                          lineId: 1002
+                          price: -198
+                          handicap: null
+                          max: 100
+                    - id: 7
+                      maxBet: 100
+                      contestantLines:
+                        - id: 13
+                          lineId: 1013
+                          price: -187
+                          handicap: null
+                          max: 100
+                        - id: 14
+                          lineId: 1014
+                          price: -186
+                          handicap: null
+                          max: 100
+                - id: 578
+                  specials:
+                    - id: 10
+                      maxBet: 100
+                      contestantLines:
+                        - id: 21
+                          lineId: 1021
+                          price: -179
+                          handicap: null
+                          max: 100
+                        - id: 22
+                          lineId: 1022
+                          price: -178
+                          handicap: null
+                          max: 100
+                        - id: 23
+                          lineId: 1023
+                          price: -177
+                          handicap: null
+                          max: 100
+                        - id: 24
+                          lineId: 1024
+                          price: -176
+                          handicap: null
+                          max: 100
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v2/line:
+    get:
+      tags:
+        - Line
+      summary: 获取直盘线 - v2
+      description: 返回最新线。
+      operationId: Line_Straight_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: leagueId
+          in: query
+          description: 联赛 ID。
+          required: true
+          type: integer
+          format: int32
+        - name: handicap
+          in: query
+          description: SPREAD、TOTAL_POINTS 和 TEAM_TOTAL_POINTS 投注类型需要此参数
+          required: true
+          type: number
+          format: double
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。默认为 American。
+          required: true
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: sportId
+          in: query
+          description: 运动标识
+          required: true
+          type: integer
+          format: int32
+        - name: eventId
+          in: query
+          description: 赛事标识
+          required: true
+          type: integer
+          format: int64
+        - name: periodNumber
+          in: query
+          description: 这代表比赛的周期。请查看 Get Periods 端点以获取每个运动当前支持的周期列表。
+          required: true
+          type: integer
+          format: int32
+        - name: betType
+          in: query
+          description: 投注类型
+          required: true
+          type: string
+          enum:
+            - SPREAD
+            - MONEYLINE
+            - TOTAL_POINTS
+            - TEAM_TOTAL_POINTS
+        - name: team
+          in: query
+          description: 选择的队伍类型。仅 SPREAD、MONEYLINE 和 TEAM_TOTAL_POINTS 投注类型需要此参数
+          required: false
+          type: string
+          enum:
+            - Team1
+            - Team2
+            - Draw
+        - name: side
+          in: query
+          description: 选择的侧。仅 TOTAL_POINTS 和 TEAM_TOTAL_POINTS 需要此参数
+          required: false
+          type: string
+          enum:
+            - OVER
+            - UNDER
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/LineResponseV2'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v3/line/parlay:
+    post:
+      tags:
+        - Line
+      summary: 获取串关线 - v3
+      description: 返回串关线并计算赔率。
+      operationId: Line_Parlay_V3_Post
+      consumes:
+        - application/json
+      produces:
+        - application/json
+      parameters:
+        - in: body
+          name: request
+          required: true
+          schema:
+            $ref: '#/definitions/ParlayLinesRequestV3'
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/ParlayLinesResponseV3'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/line/teaser:
+    post:
+      tags:
+        - Line
+      summary: 获取过关线 - v1
+      description: 在提交前验证过关投注。成功时返回投注限额和价格。
+      operationId: Line_Teaser_V1_Post
+      consumes:
+        - application/json
+      produces:
+        - application/json
+      parameters:
+        - in: body
+          name: teaserLinesRequest
+          required: true
+          schema:
+            $ref: '#/definitions/LinesRequestTeaser'
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/TeaserLinesResponse'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/line/special:
+    get:
+      tags:
+        - Line
+      operationId: Line_Special_V2_Get
+      summary: 获取特殊线 - v2
+      description: 返回特殊线并计算赔率。
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。[American, Decimal, HongKong, Indonesian, Malay]
+          required: true
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+        - name: specialId
+          in: query
+          description: 特殊赛事的 ID。
+          required: true
+          type: integer
+          format: int64
+        - name: contestantId
+          in: query
+          description: 参赛者 ID。
+          required: true
+          type: integer
+          format: int64
+        - name: handicap
+          in: query
+          description: 参赛者的让分。由于参赛者的让分是一个可变属性,可能会发生 line/special 返回 status:SUCCESS,但让分与客户端在调用 line/special 时拥有的让分不同。可以在请求中指定 handicap 参数,如果参赛者的让分已更改,它将返回 status:NOT_EXISTS。这样 line/special 与 /line 的工作方式更加一致。
+          required: false
+          type: number
+          format: double
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SpecialLineResponse'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+      deprecated: false
+  /v3/sports:
+    get:
+      tags:
+        - Others
+      summary: 获取运动项目 - v3
+      description: 返回所有运动项目及其当前是否有线的状态。
+      operationId: Sports_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SportsResponseV3'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/LinesErrorResponse'
+  /v3/leagues:
+    get:
+      tags:
+        - Others
+      summary: 获取联赛 - v3
+      description: 返回所有体育联赛及其当前是否有线的状态。
+      operationId: Leagues_V3_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          description: 请求联赛的运动 ID。
+          required: true
+          type: string
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/LeaguesV3'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/periods:
+    get:
+      tags:
+        - Others
+      summary: 获取周期 - v1
+      description: 返回指定运动的所有周期。
+      operationId: Periods_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: sportId
+          in: query
+          required: true
+          type: string
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SportPeriod'
+          examples:
+            application/json:
+              periods:
+                - number: 0
+                  description: 全场
+                  shortDescription: FT
+                - number: 1
+                  description: 上半场
+                  shortDescription: 1st H
+                - number: 2
+                  description: 下半场
+                  shortDescription: 2nd H
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/inrunning:
+    get:
+      tags:
+        - Others
+      summary: 获取进行中赛事 - v2
+      description: 返回所有状态显示为正在进行中的直播足球赛事。
+      operationId: InRunning_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/InRunningResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedLinesErrorResponse'
+  /v1/teaser/groups:
+    get:
+      tags:
+        - Others
+      summary: 获取过关组 - v1
+      description: 返回所有过关组。
+      operationId: Teaser_Groups_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters:
+        - name: oddsFormat
+          in: query
+          description: 返回赔率的格式。[American, Decimal, HongKong, Indonesian, Malay]
+          required: true
+          type: string
+          enum:
+            - American
+            - Decimal
+            - HongKong
+            - Indonesian
+            - Malay
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/TeaserGroupsResponse'
+        '400':
+          description: 错误请求
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v1/cancellationreasons:
+    get:
+      tags:
+        - Others
+      summary: 获取取消原因 - v1
+      description: 查找所有取消原因
+      operationId: CancellationReasons_V1_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/CancellationReasonResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+  /v2/currencies:
+    get:
+      tags:
+        - Others
+      summary: 获取货币 - v2
+      description: 返回支持的货币列表
+      operationId: Currencies_V2_Get
+      consumes: []
+      produces:
+        - application/json
+      parameters: []
+      responses:
+        '200':
+          description: 成功
+          schema:
+            $ref: '#/definitions/SuccessfulCurrenciesResponse'
+        '401':
+          description: 未授权
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '403':
+          description: 禁止访问
+          schema:
+            $ref: '#/definitions/ErrorResponse'
+        '500':
+          description: 服务器内部错误
+          schema:
+            $ref: '#/definitions/ExtendedErrorResponse'
+securityDefinitions:
+  basicAuth:
+    type: basic
+definitions:
+  ErrorResponse:
+    type: object
+    properties:
+      code:
+        type: string
+        description: 标识发生的错误类型的标识符。
+      message:
+        type: string
+        description: 错误描述。
+    description: 包含遇到的错误详细信息。
+  ExtendedErrorResponse:
+    type: object
+    properties:
+      ref:
+        type: string
+      code:
+        type: string
+      message:
+        type: string
+  LinesErrorResponse:
+    type: object
+    properties:
+      status:
+        type: string
+      error:
+        $ref: '#/definitions/ErrorResponse'
+      code:
+        type: integer
+        format: int32
+        description: 标识发生的错误的代码。
+  ExtendedLinesErrorResponse:
+    type: object
+    properties:
+      ref:
+        type: string
+      status:
+        type: string
+      error:
+        $ref: '#/definitions/ErrorResponse'
+      code:
+        type: integer
+        format: int32
+        description: 标识发生的错误的代码。
+  CancellationReasonResponse:
+    type: object
+    properties:
+      cancellationReasons:
+        type: array
+        description: 包含取消原因列表。
+        items:
+          $ref: '#/definitions/CancellationReason'
+    description: 取消原因响应数据
+  CancellationReason:
+    type: object
+    properties:
+      code:
+        type: string
+        description: 服务器分配的取消代码
+        example: FBS_CW_65
+      description:
+        type: string
+        description: 取消原因的文本描述
+        example: The event was postponed
+    description: 取消数据
+  SuccessfulCurrenciesResponse:
+    type: object
+    properties:
+      currencies:
+        type: array
+        description: 货币容器。
+        items:
+          $ref: '#/definitions/Currency'
+  Currency:
+    type: object
+    properties:
+      code:
+        type: string
+        description: 货币代码。
+        example: AED
+      name:
+        type: string
+        description: 货币名称。
+        example: United Arab Emirates Dirham
+      rate:
+        type: number
+        format: double
+        description: 对美元的汇率。
+        example: 3.6738
+  FixturesResponseV1:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      league:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/FixturesLeagueV1'
+  FixturesLeagueV1:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/FixtureV1'
+  FixtureV1:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      starts:
+        type: string
+        format: date-time
+        description: 赛事开始时间(UTC)。
+      home:
+        type: string
+        description: 主队名称。
+      away:
+        type: string
+        description: 客队名称。
+      rotNum:
+        type: string
+        description: Team1 轮换号码。请注意,在 /fixtures 的下一版本中,rotNum 属性将被弃用。可以使用 ParentId 来分组相关赛事。
+      liveStatus:
+        type: integer
+        format: int32
+        description: |
+          指示赛事的直播状态。
+
+          0 = 此赛事不提供直播投注,
+          1 = 直播投注赛事,
+          2 = 将为此赛事提供直播投注
+        enum:
+          - 0
+          - 1
+          - 2
+      homePitcher:
+        type: string
+        description: 主队投手。仅适用于棒球。
+      awayPitcher:
+        type: string
+        description: 客队投手。仅适用于棒球。
+      status:
+        type: string
+        description: |
+
+          赛事状态。
+
+          O = 这是比赛的起始状态。这意味着线开放投注,
+          H = 此状态表示线暂时不可用于投注,
+          I = 此状态表示一条或多条线有红圈(较低的最大投注金额)
+        enum:
+          - O
+          - H
+          - I
+      parlayRestriction:
+        type: integer
+        format: int32
+        description: |
+
+          赛事的串关状态。
+
+          0 = 允许串关,无限制,
+          1 = 不允许串关此赛事,
+          2 = 允许串关,但有限制。串关中不能有来自同一赛事的多个腿。具有相同轮换号码的所有赛事被视为同一赛事。
+        enum:
+          - 0
+          - 1
+          - 2
+  FixturesResponseV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      league:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/FixturesLeagueV3'
+  FixturesLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      name:
+        type: string
+        description: 联赛名称。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/FixtureV3'
+  FixtureV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      parentId:
+        type: integer
+        format: int64
+        description: 如果赛事链接到另一个赛事,将填充 parentId。直播赛事将把赛前赛事作为父 ID。
+      starts:
+        type: string
+        format: date-time
+        description: 赛事开始时间(UTC)。
+      home:
+        type: string
+        description: 主队名称。
+      away:
+        type: string
+        description: 客队名称。
+      liveStatus:
+        type: integer
+        format: int32
+        description: |
+          指示赛事的直播状态。
+
+          0 = 此赛事不提供直播投注,
+          1 = 直播投注赛事,
+          2 = 将为此赛事提供直播投注
+        enum:
+          - 0
+          - 1
+          - 2
+      homePitcher:
+        type: string
+        description: 主队投手。仅适用于棒球。
+      awayPitcher:
+        type: string
+        description: 客队投手。仅适用于棒球。
+      betAcceptanceType:
+        type: integer
+        format: int32
+        description: |
+
+          足球直播赛事投注接受类型。此类型表示向相应客户提供直播足球赛事。
+
+          0 = 不适用。无投注接受类型限制。
+          1 = 危险区。
+          2 = 直播延迟。
+          3 = 两者都有。
+        enum:
+          - 0
+          - 1
+          - 2
+          - 3
+      parlayRestriction:
+        type: integer
+        format: int32
+        description: |
+
+          赛事的串关状态。
+
+          0 = 允许串关,无限制,
+          1 = 不允许串关此赛事,
+          2 = 允许串关,但有限制。串关中不能有来自同一赛事的多个腿。具有相同轮换号码的所有赛事被视为同一赛事。
+        enum:
+          - 0
+          - 1
+          - 2
+      altTeaser:
+        type: boolean
+        description: 赛事是否提供替代过关点数。具有替代过关点数的赛事可能与过关定义不同。
+      resultingUnit:
+        type: string
+        description: |
+          指定赛事基于什么结算,例如角球、黄牌
+      version:
+        type: integer
+        format: int64
+        description: |
+           赛程版本,当赛程有更改时会增加。
+  SettledFixturesSportV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      leagues:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/SettledFixturesLeagueV3'
+  SettledFixturesLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/SettledFixturesEventV3'
+  SettledFixturesEventV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      periods:
+        type: array
+        description: 包含周期列表。
+        items:
+          $ref: '#/definitions/SettledFixturesPeriodV3'
+  SettledFixturesPeriodV3:
+    type: object
+    properties:
+      number:
+        type: integer
+        format: int32
+        description: 这代表比赛的周期。例如,对于足球我们有 0(全场)、1(上半场)和 2(下半场)。
+      status:
+        type: integer
+        format: int32
+        description: |
+          周期结算状态。
+
+          1 = 赛事周期已结算,
+          2 = 赛事周期已重新结算,
+          3 = 赛事周期已取消,
+          4 = 赛事周期已重新结算为取消,
+          5 = 赛事已删除
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+      settlementId:
+        type: integer
+        format: int64
+        description: 结算的唯一 ID。如果重新结算,将生成新的 settlementId 和 settledAt。
+      settledAt:
+        type: string
+        format: date-time
+        description: 周期结算的日期和时间(UTC)。
+      team1Score:
+        type: integer
+        format: int32
+        description: Team1 得分。
+      team2Score:
+        type: integer
+        format: int32
+        description: Team2 得分。
+      cancellationReason:
+        $ref: '#/definitions/CancellationReasonType'
+  CancellationReasonType:
+    type: object
+    properties:
+      code:
+        type: string
+        description: 取消原因代码
+      details:
+        $ref: '#/definitions/CancellationReasonDetailsType'
+  CancellationReasonDetailsType:
+    type: object
+    properties:
+      key:
+        type: string
+      value:
+        type: string
+  InRunningResponse:
+    type: object
+    properties:
+      sports:
+        type: array
+        description: 运动容器
+        items:
+          $ref: '#/definitions/InRunningSport'
+  InRunningSport:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 运动 ID
+      leagues:
+        type: array
+        description: 联赛容器
+        items:
+          $ref: '#/definitions/InRunningLeague'
+  InRunningLeague:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID
+      events:
+        type: array
+        description: 赛事容器
+        items:
+          $ref: '#/definitions/InRunningEvent'
+  InRunningEvent:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 比赛 ID
+      state:
+        type: integer
+        format: int32
+        description: |
+          比赛状态。
+
+          1 = 上半场进行中,
+          2 = 半场休息进行中,
+          3 = 下半场进行中,
+          4 = 常规时间结束,
+          5 = 加时赛上半场进行中,
+          6 = 加时赛半场休息进行中,
+          7 = 加时赛下半场进行中,
+          8 = 加时赛结束,
+          9 = 比赛结束,
+          10 = 比赛暂时暂停,
+          11 = 点球大战进行中
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+          - 6
+          - 7
+          - 8
+          - 9
+          - 10
+          - 11
+      elapsed:
+        type: integer
+        format: int32
+        description: 已过分钟数
+  LeaguesV3:
+    type: object
+    properties:
+      leagues:
+        type: array
+        description: 联赛容器
+        items:
+          $ref: '#/definitions/LeagueV3'
+  LeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      name:
+        type: string
+        description: 联赛名称。
+      homeTeamType:
+        type: string
+        description: 指定主队是 team1 还是 team2。您需要此信息来下注。
+      hasOfferings:
+        type: boolean
+        description: 联赛当前是否有赛事或特殊赛事。
+      container:
+        type: string
+        description: 代表联赛的分组,通常是地区/国家
+      allowRoundRobins:
+        type: boolean
+        description: 指定您是否可以在此联赛的赛事上下注串关循环赛。
+      leagueSpecialsCount:
+        type: integer
+        format: int32
+        description: 指示给定联赛中有多少特殊赛事。
+      eventSpecialsCount:
+        type: integer
+        format: int32
+        description: 指示给定联赛中有多少比赛特殊赛事。
+      eventCount:
+        type: integer
+        format: int32
+        description: 指示给定联赛中有多少赛事。
+  LineResponseV2:
+    type: object
+    properties:
+      status:
+        type: string
+        description: 如果值为 NOT_EXISTS,则这将是响应中的唯一参数。所有其他参数都将为空。[SUCCESS = 成功, NOT_EXISTS = 不再提供线]
+        enum:
+          - SUCCESS
+          - NOT_EXISTS
+      price:
+        type: number
+        format: double
+        description: 最新价格。
+      lineId:
+        type: integer
+        format: int64
+        description: 下注所需的线标识。
+      altLineId:
+        type: integer
+        format: int64
+        description: 如果让分在替代线上,则需要此参数来下注,否则响应中将不会填充此参数。
+      team1Score:
+        type: integer
+        format: int32
+        description: 周期 0 的 Team 1 得分。仅适用于足球。
+      team2Score:
+        type: integer
+        format: int32
+        description: 周期 0 的 Team 2 得分。仅适用于足球。
+      team1RedCards:
+        type: integer
+        format: int32
+        description: 周期 0 的 Team 1 红牌数。仅适用于足球。
+      team2RedCards:
+        type: integer
+        format: int32
+        description: 周期 0 的 Team 2 红牌数。仅适用于足球。
+      maxRiskStake:
+        type: number
+        format: double
+        description: 最大可投注风险金额。
+      minRiskStake:
+        type: number
+        format: double
+        description: 最小可投注风险金额。
+      maxWinStake:
+        type: number
+        format: double
+        description: 最大可投注赢利金额。
+      minWinStake:
+        type: number
+        format: double
+        description: 最小可投注赢利金额。
+      effectiveAsOf:
+        type: string
+        description: 线在此日期和时间(UTC)生效。
+      periodTeam1Score:
+        type: integer
+        format: int32
+        description: 支持周期的 Team 1 得分。仅适用于足球。
+      periodTeam2Score:
+        type: integer
+        format: int32
+        description: 支持周期的 Team 2 得分。仅适用于足球。
+      periodTeam1RedCards:
+        type: integer
+        format: int32
+        description: 支持周期的 Team 1 红牌数。仅适用于足球。
+      periodTeam2RedCards:
+        type: integer
+        format: int32
+        description: 支持周期的 Team 2 红牌数。仅适用于足球。
+  ParlayLinesRequestV3:
+    type: object
+    properties:
+      oddsFormat:
+        type: string
+        description: 响应中的赔率将采用此格式。[American, Decimal, HongKong, Indonesian, Malay]
+        enum:
+          - American
+          - Decimal
+          - HongKong
+          - Indonesian
+          - Malay
+      legs:
+        type: array
+        description: 这是腿的集合
+        items:
+          $ref: '#/definitions/ParlayLineRequestV3'
+  ParlayLineRequestV3:
+    type: object
+    properties:
+      uniqueLegId:
+        type: string
+        description: 腿的唯一 ID。用于在响应中识别和匹配腿。
+      eventId:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      periodNumber:
+        type: integer
+        format: int32
+        description: 这代表比赛的周期。例如,对于足球我们有 0(全场)、1(上半场)、2(下半场)。
+      legBetType:
+        type: string
+        description: 支持 SPREAD、MONEYLINE、TOTAL_POINTS 和 TEAM_TOTAL_POINTS。
+        enum:
+          - SPREAD
+          - MONEYLINE
+          - TOTAL_POINTS
+          - TEAM_TOTAL_POINTS
+      team:
+        type: string
+        description: 选择的队伍类型。仅 SPREAD 和 MONEYLINE 投注类型需要此参数。[Team1, Team2, Draw(仅限 MONEYLINE)]
+        enum:
+          - Team1
+          - Team2
+          - Draw
+      side:
+        type: string
+        description: 选择的侧。仅 TOTAL_POINTS 投注类型需要此参数。[OVER, UNDER]
+        enum:
+          - OVER
+          - UNDER
+      handicap:
+        type: number
+        format: double
+        description: SPREAD 和 TOTAL_POINTS 投注类型需要此参数。
+    required:
+      - uniqueLegId
+      - eventId
+      - periodNumber
+      - legBetType
+  ParlayLinesResponseV3:
+    type: object
+    properties:
+      status:
+        type: string
+        description: 串关状态 [VALID = 串关有效, PROCESSED_WITH_ERROR = 串关包含错误]
+        example: PROCESSED_WITH_ERROR
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      error:
+        type: string
+        description: INVALID_LEGS。表示一个或多个腿无效。仅在状态为 PROCESSED_WITH_ERROR 时填充。
+        example: INVALID_LEGS
+      minRiskStake:
+        type: number
+        format: double
+        description: 允许的最小投注金额。
+      maxParlayRiskStake:
+        type: number
+        format: double
+        description: 串关投注允许的最大投注金额。
+      maxRoundRobinTotalRisk:
+        type: number
+        format: double
+        description: 循环赛中所有串关投注允许的最大总投注金额。
+      maxRoundRobinTotalWin:
+        type: number
+        format: double
+        description: 循环赛中所有串关投注允许的最大总赢利金额。
+      roundRobinOptionWithOdds:
+        type: array
+        description: 提供所有可接受的循环赛选项数组,以及该选项的串关赔率。
+        items:
+          $ref: '#/definitions/RoundRobinOptionWithOddsV3'
+      legs:
+        type: array
+        description: 腿的集合(对象的格式如下所述)。
+        items:
+          $ref: '#/definitions/ParlayLineLeg'
+    required:
+      - status
+  RoundRobinOptionWithOddsV3:
+    type: object
+    properties:
+      roundRobinOption:
+        type: string
+        description: |
+          循环赛选项
+
+            Parlay = 包含所有投注的单个串关(非循环赛),
+            TwoLegRoundRobin = 多个串关,每个有 2 个投注(循环赛风格),
+            ThreeLegRoundRobin = 多个串关,每个有 3 个投注(循环赛风格),
+            FourLegRoundRobin = 多个串关,每个有 4 个投注(循环赛风格),
+            FiveLegRoundRobin = 多个串关,每个有 5 个投注(循环赛风格),
+            SixLegRoundRobin = 多个串关,每个有 6 个投注(循环赛风格),
+            SevenLegRoundRobin = 多个串关,每个有 7 个投注(循环赛风格),
+            EightLegRoundRobin = 多个串关,每个有 8 个投注(循环赛风格)
+        enum:
+          - Parlay
+          - TwoLegRoundRobin
+          - ThreeLegRoundRobin
+          - FourLegRoundRobin
+          - FiveLegRoundRobin
+          - SixLegRoundRobin
+          - SevenLegRoundRobin
+          - EightLegRoundRobin
+      odds:
+        type: number
+        format: double
+        description: 此选项的串关赔率。
+      unroundedDecimalOdds:
+        type: number
+        format: double
+        description: 未四舍五入的串关赔率(十进制格式),仅用于计算
+      numberOfBets:
+        type: number
+        format: int
+        description: roundRobinOption 中的投注数量。
+    required:
+      - roundRobinOption
+      - odds
+      - unroundedDecimalOdds
+  ParlayLineLeg:
+    type: object
+    properties:
+      status:
+        type: string
+        description: 请求状态。[VALID = 有效腿, PROCESSED_WITH_ERROR = 处理时出错]
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      errorCode:
+        type: string
+        description: |
+          当状态为 PROCESSED_WITH_ERROR 时,提供一个代码指示具体问题。
+
+            CORRELATED = 该腿与另一个腿相关,
+            CANNOT_PARLAY_LIVE_GAME = 投注放在直播比赛上,
+            EVENT_NO_LONGER_AVAILABLE_FOR_BETTING = 该赛事不再可用于串关,
+            EVENT_NOT_OFFERED_FOR_PARLAY = 该赛事不提供串关,
+            LINE_DOES_NOT_BELONG_TO_EVENT = LineId 与请求中指定的 EventId 不匹配,
+            WAGER_TYPE_NO_LONGER_AVAILABLE_FOR_BETTING = 投注类型不再可用于投注,
+            WAGER_TYPE_NOT_VALID_FOR_PARLAY = 投注类型对串关无效,
+            WAGER_TYPE_CONFLICTS_WITH_OTHER_LEG = 投注类型与其他腿冲突
+        enum:
+
+          - CORRELATED
+          - CANNOT_PARLAY_LIVE_GAME
+          - EVENT_NO_LONGER_AVAILABLE_FOR_BETTING
+          - EVENT_NOT_OFFERED_FOR_PARLAY
+          - LINE_DOES_NOT_BELONG_TO_EVENT
+          - WAGER_TYPE_NO_LONGER_AVAILABLE_FOR_BETTING
+          - WAGER_TYPE_NOT_VALID_FOR_PARLAY
+          - WAGER_TYPE_CONFLICTS_WITH_OTHER_LEG
+      legId:
+        type: string
+        description: 来自请求的 legId 的回显。
+      lineId:
+        type: integer
+        format: int64
+        description: 线标识。
+      altLineId:
+        type: integer
+        format: int64
+        description: 如果请求了替代线,将返回该线的 ID。
+      price:
+        type: number
+        format: double
+        description: 价格
+      correlatedLegs:
+        type: array
+        description: 如果 errorCode 为 CORRELATED,将包含所有相关腿的 legIds。
+        items:
+          type: string
+    required:
+      - legId
+      - status
+  LinesRequestTeaser:
+    type: object
+    properties:
+      teaserId:
+        type: integer
+        format: int64
+        description: 唯一标识符。可以从调用 v1/teaser/groups 端点检索过关详情。
+      oddsFormat:
+        type: string
+        description: 返回赔率的格式。[American, Decimal, HongKong, Indonesian, Malay]
+        enum:
+          - American
+          - Decimal
+          - HongKong
+          - Indonesian
+          - Malay
+      legs:
+        type: array
+        description: 过关腿的集合。
+        items:
+          $ref: '#/definitions/TeaserLineRequest'
+    required:
+      - teaserId
+      - oddsFormat
+      - legs
+  TeaserLineRequest:
+    type: object
+    properties:
+      legId:
+        type: string
+        description: 客户端生成的用于唯一识别腿的 GUID。
+      eventId:
+        type: integer
+        format: int64
+        description: 唯一标识符。
+      periodNumber:
+        type: integer
+        format: int32
+        description: 正在投注的比赛周期。可以使用 v1/periods 端点检索某项运动的所有周期。
+      betType:
+        type: string
+        description: 投注类型。目前仅支持 SPREAD 和 TOTAL_POINTS。[SPREAD, TOTAL_POINTS]
+        enum:
+          - SPREAD
+          - TOTAL_POINTS
+      team:
+        type: string
+        description: 让分盘投注的队伍。[Team1, Team2]
+        enum:
+          - Team1
+          - Team2
+      side:
+        type: string
+        description: 总分盘投注的侧。[OVER, UNDER]
+        enum:
+          - OVER
+          - UNDER
+      handicap:
+        type: number
+        format: double
+        description: 点数。
+    required:
+      - legId
+      - eventId
+      - periodNumber
+      - betType
+      - handicap
+  TeaserLinesResponse:
+    type: object
+    properties:
+      status:
+        type: string
+        description: 请求状态。[VALID = 过关有效, PROCESSED_WITH_ERROR = 过关包含一个或多个错误]
+        example: PROCESSED_WITH_ERROR
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      errorCode:
+        type: string
+        description: |
+          当状态为 PROCESSED_WITH_ERROR 时,提供一个代码指示具体问题。
+
+            INVALID_LEGS = 一个或多个腿无效,
+            SAME_EVENT_ONLY_REQUIRED = 指定的过关要求所有腿来自同一赛事,
+            TEASER_DISABLED = 过关已被禁用,无法投注,
+            TEASER_DOES_NOT_EXIST = 找不到过关标识符,
+            TOO_FEW_LEGS = 您不满足指定过关的最小腿数要求,
+            TOO_MANY_LEGS = 您超过了指定过关的最大腿数,
+            UNKNOWN = 发生未知错误
+        enum:
+          - INVALID_LEGS
+          - SAME_EVENT_ONLY_REQUIRED
+          - TEASER_DISABLED
+          - TEASER_DOES_NOT_EXIST
+          - TOO_FEW_LEGS
+          - TOO_MANY_LEGS
+          - UNKNOWN
+      price:
+        type: number
+        format: double
+        description: 投注价格。
+      minRiskStake:
+        type: number
+        format: double
+        description: WIN_RISK_TYPE.RISK 的最小投注金额。
+      maxRiskStake:
+        type: number
+        format: double
+        description: WIN_RISK_TYPE.RISK 的最大投注金额。
+      minWinStake:
+        type: number
+        format: double
+        description: WIN_RISK_TYPE.WIN 的最小投注金额。
+      maxWinStake:
+        type: number
+        format: double
+        description: WIN_RISK_TYPE.WIN 的最大投注金额。
+      legs:
+        type: array
+        description: 来自请求的过关腿集合。
+        items:
+          $ref: '#/definitions/TeaserLineLeg'
+    required:
+      - status
+      - legs
+  TeaserLineLeg:
+    type: object
+    properties:
+      status:
+        type: string
+        description: 请求状态。[VALID = 过关有效, PROCESSED_WITH_ERROR = 过关包含错误]
+        example: PROCESSED_WITH_ERROR
+        enum:
+          - VALID
+          - PROCESSED_WITH_ERROR
+      errorCode:
+        type: string
+        description: |
+          当状态为 PROCESSED_WITH_ERROR 时,提供一个代码指示具体问题。
+
+            EVENT_NOT_FOUND = 找不到指定的赛事,
+            POINTS_NO_LONGER_AVAILABLE = 请求的点数不再可用。这意味着线已移动,
+            UNKNOWN = 发生未知错误,
+            WAGER_TYPE_NOT_VALID_FOR_TEASER = 指定的投注类型对过关无效
+        enum:
+          - EVENT_NOT_FOUND
+          - POINTS_NO_LONGER_AVAILABLE
+          - UNKNOWN
+          - WAGER_TYPE_NOT_VALID_FOR_TEASER
+      legId:
+        type: string
+        description: 来自请求的腿的唯一 ID 回显。
+      lineId:
+        type: integer
+        format: int64
+        description: 线标识。
+    required:
+      - legId
+      - status
+  OddsResponseV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      leagues:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/OddsLeagueV3'
+  OddsResponseV4:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      leagues:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/OddsLeagueV4'
+  OddsLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/OddsEventV3'
+  OddsLeagueV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/OddsEventV4'
+  OddsEventV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      awayScore:
+        type: number
+        format: double
+        description: 客队得分。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      homeScore:
+        type: number
+        format: double
+        description: 主队得分。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      awayRedCards:
+        type: integer
+        format: int32
+        description: 客队红牌数。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      homeRedCards:
+        type: integer
+        format: int32
+        description: 主队红牌数。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      periods:
+        type: array
+        description: 包含周期列表。
+        items:
+          $ref: '#/definitions/OddsPeriodV3'
+  OddsEventV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      awayScore:
+        type: number
+        format: double
+        description: 客队得分。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      homeScore:
+        type: number
+        format: double
+        description: 主队得分。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      awayRedCards:
+        type: integer
+        format: int32
+        description: 客队红牌数。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      homeRedCards:
+        type: integer
+        format: int32
+        description: 主队红牌数。仅适用于直播足球赛事。仅支持全场周期(number=0)。
+      periods:
+        type: array
+        description: 包含周期列表。
+        items:
+          $ref: '#/definitions/OddsPeriodV4'
+  OddsPeriodV3:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: 线 ID。
+      number:
+        type: integer
+        format: int32
+        description: 这代表比赛的周期。例如,对于足球我们有 0(全场)、1(上半场)和 2(下半场)。
+      cutoff:
+        type: string
+        format: date-time
+        description: 周期的投注截止日期(UTC)。
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - 在线,周期开放投注
+              2 - 离线,周期不开放投注
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: 最大让分盘投注。仅在直盘赔率响应中。
+      maxMoneyline:
+        type: number
+        format: double
+        description: 最大独赢盘投注。仅在直盘赔率响应中。
+      maxTotal:
+        type: number
+        format: double
+        description: 最大总分盘投注。仅在直盘赔率响应中。
+      maxTeamTotal:
+        type: number
+        format: double
+        description: 最大队伍总分盘投注。仅在直盘赔率响应中。
+      moneylineUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次独赢盘更新的日期时间。
+      spreadUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次让分盘更新的日期时间。
+      totalUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次总分盘更新的日期时间。
+      teamTotalUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次队伍总分盘更新的日期时间。
+      spreads:
+        type: array
+        description: 让分盘赔率容器。
+        items:
+          $ref: '#/definitions/OddsSpreadV3'
+      moneyline:
+        $ref: '#/definitions/OddsMoneylineV3'
+      totals:
+        type: array
+        description: 队伍总分容器。
+        items:
+          $ref: '#/definitions/OddsTotalV3'
+      teamTotal:
+        $ref: '#/definitions/OddsTeamTotalsV3'
+      awayScore:
+        type: number
+        format: double
+        description: 周期客队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeScore:
+        type: number
+        format: double
+        description: 周期主队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      awayRedCards:
+        type: number
+        format: int32
+        description: 周期客队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeRedCards:
+        type: number
+        format: int32
+        description: 周期主队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+  OddsPeriodV4:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: 线 ID。
+      number:
+        type: integer
+        format: int32
+        description: 这代表比赛的周期。例如,对于足球我们有 0(全场)、1(上半场)和 2(下半场)。
+      cutoff:
+        type: string
+        format: date-time
+        description: 周期的投注截止日期(UTC)。
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - 在线,周期开放投注
+              2 - 离线,周期不开放投注
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: 最大让分盘投注。仅在直盘赔率响应中。
+      maxMoneyline:
+        type: number
+        format: double
+        description: 最大独赢盘投注。仅在直盘赔率响应中。
+      maxTotal:
+        type: number
+        format: double
+        description: 最大总分盘投注。仅在直盘赔率响应中。
+      maxTeamTotal:
+        type: number
+        format: double
+        description: 最大队伍总分盘投注。仅在直盘赔率响应中。
+      moneylineUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次独赢盘更新的日期时间。
+      spreadUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次让分盘更新的日期时间。
+      totalUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次总分盘更新的日期时间。
+      teamTotalUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次队伍总分盘更新的日期时间。
+      spreads:
+        type: array
+        description: 让分盘赔率容器。
+        items:
+          $ref: '#/definitions/OddsSpreadV4'
+      moneyline:
+        $ref: '#/definitions/OddsMoneylineV4'
+      totals:
+        type: array
+        description: 队伍总分容器。
+        items:
+          $ref: '#/definitions/OddsTotalV4'
+      teamTotal:
+        $ref: '#/definitions/OddsTeamTotalsV4'
+      awayScore:
+        type: number
+        format: double
+        description: 周期客队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeScore:
+        type: number
+        format: double
+        description: 周期主队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      awayRedCards:
+        type: number
+        format: int32
+        description: 周期客队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeRedCards:
+        type: number
+        format: int32
+        description: 周期主队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+  OddsSpreadV3:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: 仅在为替代线时存在。
+      hdp:
+        type: number
+        format: double
+        description: 主队让分。
+      home:
+        type: number
+        format: double
+        description: 主队价格。
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxSpread` 市场限额。
+  OddsSpreadV4:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: 仅在为替代线时存在。
+      hdp:
+        type: number
+        format: double
+        description: 主队让分。
+      home:
+        type: number
+        format: double
+        description: 主队价格。
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxSpread` 市场限额。
+  OddsMoneylineV3:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: 客队价格
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      draw:
+        type: number
+        format: double
+        description: 平局价格。仅在我们提供平局价格的事件中存在。
+  OddsMoneylineV4:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: 客队价格
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      draw:
+        type: number
+        format: double
+        description: 平局价格。仅在我们提供平局价格的事件中存在。
+  OddsTotalV3:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: 仅在为替代线时存在。
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxTotal` 市场限额。
+  OddsTotalV4:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: 仅在为替代线时存在。
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxTotal` 市场限额。
+  OddsTeamTotalsV3:
+    type: object
+    properties:
+      home:
+        $ref: '#/definitions/OddsTeamTotalV3'
+      away:
+        $ref: '#/definitions/OddsTeamTotalV3'
+  OddsTeamTotalsV4:
+    type: object
+    properties:
+      home:
+        type: array
+        description: 主队总分容器。
+        items:
+          $ref: '#/definitions/OddsTeamTotalV4'
+      away:
+        type: array
+        description: 客队总分容器。
+        items:
+          $ref: '#/definitions/OddsTeamTotalV4'
+  OddsTeamTotalV3:
+    type: object
+    properties:
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+  OddsTeamTotalV4:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: 仅在为替代线时存在。
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxTeamTotal` 市场限额。
+    required:
+      - points
+      - over
+      - under
+  ParlayOddsResponseV3:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      leagues:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/ParlayOddsLeagueV3'
+    required:
+      - sportId
+      - last
+      - leagues
+  ParlayOddsResponseV4:
+    type: object
+    properties:
+      sportId:
+        type: integer
+        format: int32
+        description: 与请求的运动 ID 相同。
+      last:
+        type: integer
+        format: int64
+        description: 在后续请求中使用此值作为 since 查询参数,以仅获取自上次响应以来的更改。
+      leagues:
+        type: array
+        description: 包含联赛列表。
+        items:
+          $ref: '#/definitions/ParlayOddsLeagueV4'
+    required:
+      - sportId
+      - last
+      - leagues
+  ParlayOddsLeagueV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/ParlayOddsEventV3'
+    required:
+      - id
+      - events
+  ParlayOddsLeagueV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 联赛 ID。
+      events:
+        type: array
+        description: 包含赛事列表。
+        items:
+          $ref: '#/definitions/ParlayOddsEventV4'
+    required:
+      - id
+      - events
+  ParlayOddsEventV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      awayScore:
+        type: number
+        format: double
+        description: 客队得分。仅适用于直播足球赛事。
+      homeScore:
+        type: number
+        format: double
+        description: 主队得分。仅适用于直播足球赛事。
+      awayRedCards:
+        type: integer
+        format: int32
+        description: 客队红牌数。仅适用于直播足球赛事。
+      homeRedCards:
+        type: integer
+        format: int32
+        description: 主队红牌数。仅适用于直播足球赛事。
+      periods:
+        type: array
+        description: 包含周期列表。
+        items:
+          $ref: '#/definitions/ParlayOddsPeriodV3'
+    required:
+      - id
+      - periods
+  ParlayOddsEventV4:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 赛事 ID。
+      awayScore:
+        type: number
+        format: double
+        description: 客队得分。仅适用于直播足球赛事。
+      homeScore:
+        type: number
+        format: double
+        description: 主队得分。仅适用于直播足球赛事。
+      awayRedCards:
+        type: integer
+        format: int32
+        description: 客队红牌数。仅适用于直播足球赛事。
+      homeRedCards:
+        type: integer
+        format: int32
+        description: 主队红牌数。仅适用于直播足球赛事。
+      periods:
+        type: array
+        description: 包含周期列表。
+        items:
+          $ref: '#/definitions/ParlayOddsPeriodV4'
+    required:
+      - id
+      - periods
+  ParlayOddsPeriodV3:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: 线 ID。
+      number:
+        type: integer
+        format: int32
+        description: 这代表比赛的周期。例如,对于足球我们有 0(全场)、1(上半场)和 2(下半场)。
+      cutoff:
+        type: string
+        format: date-time
+        description: 周期的投注截止日期(UTC)。
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - 在线,周期开放投注
+              2 - 离线,周期不开放投注
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: 最大让分盘投注。仅在直盘赔率响应中。
+      maxMoneyline:
+        type: number
+        format: double
+        description: 最大独赢盘投注。仅在直盘赔率响应中。
+      maxTotal:
+        type: number
+        format: double
+        description: 最大总分盘投注。仅在直盘赔率响应中。
+      maxTeamTotal:
+        type: number
+        format: double
+        description: 最大队伍总分盘投注。仅在直盘赔率响应中。
+      moneylineUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次独赢盘更新的日期时间。
+      spreadUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次让分盘更新的日期时间。
+      totalUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次总分盘更新的日期时间。
+      teamTotalUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次队伍总分盘更新的日期时间。
+      spreads:
+        type: array
+        description: 让分盘赔率容器。
+        items:
+          $ref: '#/definitions/ParlayOddsSpreadV3'
+      moneyline:
+        $ref: '#/definitions/ParlayOddsMoneylineV3'
+      totals:
+        type: array
+        description: 队伍总分容器。
+        items:
+          $ref: '#/definitions/ParlayOddsTotalV3'
+      teamTotal:
+        $ref: '#/definitions/ParlayOddsTeamTotalsV3'
+      awayScore:
+        type: number
+        format: double
+        description: 周期客队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeScore:
+        type: number
+        format: double
+        description: 周期主队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      awayRedCards:
+        type: number
+        format: double
+        description: 周期客队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeRedCards:
+        type: number
+        format: double
+        description: 周期主队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+    required:
+      - lineId
+      - number
+      - cutoff
+  ParlayOddsPeriodV4:
+    type: object
+    properties:
+      lineId:
+        type: integer
+        format: int64
+        description: 线 ID。
+      number:
+        type: integer
+        format: int32
+        description: 这代表比赛的周期。例如,对于足球我们有 0(全场)、1(上半场)和 2(下半场)。
+      cutoff:
+        type: string
+        format: date-time
+        description: 周期的投注截止日期(UTC)。
+      status:
+        type: integer
+        format: int32
+        description: |
+              1 - 在线,周期开放投注
+              2 - 离线,周期不开放投注
+        example: 1
+      maxSpread:
+        type: number
+        format: double
+        description: 最大让分盘投注。仅在直盘赔率响应中。
+      maxMoneyline:
+        type: number
+        format: double
+        description: 最大独赢盘投注。仅在直盘赔率响应中。
+      maxTotal:
+        type: number
+        format: double
+        description: 最大总分盘投注。仅在直盘赔率响应中。
+      maxTeamTotal:
+        type: number
+        format: double
+        description: 最大队伍总分盘投注。仅在直盘赔率响应中。
+      moneylineUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次独赢盘更新的日期时间。
+      spreadUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次让分盘更新的日期时间。
+      totalUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次总分盘更新的日期时间。
+      teamTotalUpdatedAt:
+        type: number
+        format: double
+        description: 最后一次队伍总分盘更新的日期时间。
+      spreads:
+        type: array
+        description: 让分盘赔率容器。
+        items:
+          $ref: '#/definitions/ParlayOddsSpreadV4'
+      moneyline:
+        $ref: '#/definitions/ParlayOddsMoneylineV4'
+      totals:
+        type: array
+        description: 队伍总分容器。
+        items:
+          $ref: '#/definitions/ParlayOddsTotalV4'
+      teamTotal:
+        $ref: '#/definitions/ParlayOddsTeamTotalsV4'
+      awayScore:
+        type: number
+        format: double
+        description: 周期客队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeScore:
+        type: number
+        format: double
+        description: 周期主队得分。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      awayRedCards:
+        type: number
+        format: double
+        description: 周期客队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+      homeRedCards:
+        type: number
+        format: double
+        description: 周期主队红牌数。仅适用于直播足球赛事。仅支持全场(number=0)和加时赛(number=3)。
+    required:
+      - lineId
+      - number
+      - cutoff
+  ParlayOddsSpreadV3:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: 仅在为替代线时存在。
+      hdp:
+        type: number
+        format: double
+        description: 主队让分。
+      home:
+        type: number
+        format: double
+        description: 主队价格。
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxSpread` 市场限额。
+    required:
+      - hdp
+      - home
+      - away
+  ParlayOddsSpreadV4:
+    type: object
+    properties:
+      altLineId:
+        type: integer
+        format: int64
+        description: 仅在为替代线时存在。
+      hdp:
+        type: number
+        format: double
+        description: 主队让分。
+      home:
+        type: number
+        format: double
+        description: 主队价格。
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxSpread` 市场限额。
+    required:
+      - hdp
+      - home
+      - away
+  ParlayOddsMoneylineV3:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: 客队价格
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      draw:
+        type: number
+        format: double
+        description: 平局价格。仅在我们提供平局价格的事件中存在。
+    required:
+      - home
+      - away
+  ParlayOddsMoneylineV4:
+    type: object
+    properties:
+      home:
+        type: number
+        format: double
+        description: 客队价格
+      away:
+        type: number
+        format: double
+        description: 客队价格。
+      draw:
+        type: number
+        format: double
+        description: 平局价格。仅在我们提供平局价格的事件中存在。
+    required:
+      - home
+      - away
+  ParlayOddsTotalV3:
+    $ref: '#/definitions/ParlayOddsTotalsV3'
+  ParlayOddsTotalV4:
+    $ref: '#/definitions/ParlayOddsTotalsV4'
+  ParlayOddsTeamTotalsV3:
+    type: object
+    properties:
+      away:
+        $ref: '#/definitions/ParlayOddsTotalsV3'
+      home:
+        $ref: '#/definitions/ParlayOddsTotalsV3'
+  ParlayOddsTeamTotalsV4:
+    type: object
+    properties:
+      away:
+        type: array
+        description: 客队总分容器。
+        items:
+          $ref: '#/definitions/ParlayOddsTeamTotalV4'
+      home:
+        type: array
+        description: 主队总分容器。
+        items:
+          $ref: '#/definitions/ParlayOddsTeamTotalV4'
+  ParlayOddsTotalsV3:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: 替代线的线 ID。仅在为替代线时存在。
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxTotal` 市场限额。
+    required:
+      - points
+      - over
+      - under
+  ParlayOddsTotalsV4:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: 替代线的线 ID。仅在为替代线时存在。
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxTotal` 市场限额。
+    required:
+      - points
+      - over
+      - under
+  ParlayOddsTeamTotalV4:
+    type: object
+    properties:
+      altLineId:
+        type: number
+        format: int64
+        description: 仅在为替代线时存在。
+      points:
+        type: number
+        format: double
+        description: 总分。
+      over:
+        type: number
+        format: double
+        description: 大价格。
+      under:
+        type: number
+        format: double
+        description: 小价格。
+      max:
+        type: number
+        format: double
+        nullable: true
+        description: 最大投注量。仅在替代线上存在,如果设置,将覆盖 `maxTeamTotal` 市场限额。
+    required:
+      - points
+      - over
+      - under
+  TeaserOddsResponse:
+    type: object
+    properties:
+      teaserId:
+        type: integer
+        format: int64
+        description: 唯一标识符。可以从调用 Get Teaser Groups 端点检索过关详情。
+      sportId:
+        type: integer
+        format: int32
+        description: 唯一标识符。可以从调用 Get Sports 端点检索运动详情。
+      leagues:
+        type: array
+        description: 联赛集合。
+        items:
+          $ref: '#/definitions/TeaserOddsLeague'
+  TeaserOddsLeague:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 唯一标识符。可以从调用 Get Leagues 端点检索联赛详情。
+      events:
+        type: array
+        description: 赛事集合。
+        items:
+          $ref: '#/definitions/TeaserOddsEvent'
+  TeaserOddsEvent:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 唯一标识符。
+      periods:
+        type: array
+        description: 周期集合,指示可用于投注的周期编号。
+        items:
+          $ref: '#/definitions/TeaserOddsPeriod'
+  TeaserOddsPeriod:
+    type: object
+    properties:
+      number:
+        type: integer
+        format: int32
+        description: 请求的比赛周期。请参考 v1/periods 端点以检索某项运动的所有有效周期。
+      lineId:
+        type: integer
+        format: int64
+        description: 唯一标识符。
+      spreadUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次让分盘更新的日期时间。
+      totalUpdatedAt:
+        type: string
+        format: date-time
+        description: 最后一次总分盘更新的日期时间。
+      spread:
+        $ref: '#/definitions/TeaserOddsSpread'
+      total:
+        $ref: '#/definitions/TeaserOddsTotalPoints'
+  TeaserOddsSpread:
+    type: object
+    properties:
+      maxBet:
+        type: number
+        format: double
+        description: 最大投注金额。
+      homeHdp:
+        type: number
+        format: double
+        description: 主队让分。请参考 Get Fixtures 端点以确定主队和客队。
+      awayHdp:
+        type: number
+        format: double
+        description: 客队让分。请参考 Get Fixtures 端点以确定主队和客队。
+      altHdp:
+        type: boolean
+        description: 让分是否提供替代过关点数。具有替代过关点数的事件可能与过关定义不同。
+        example: false
+  TeaserOddsTotalPoints:
+    type: object
+    properties:
+      maxBet:
+        type: number
+        format: double
+        description: 最大投注金额。
+      overPoints:
+        type: number
+        format: double
+        description: 大点数。
+      underPoints:
+        type: number
+        format: double
+        description: 小点数。
+  SportPeriod:
+    type: object
+    properties:
+      number:
+        type: integer
+        format: int32
+        description: 周期编号
+      description:
+        type: string
+        description: 周期的描述
+      shortDescription:
+        type: string
+        description: 周期的简短描述
+  SportsResponseV3:
+    type: object
+    properties:
+      sports:
+        type: array
+        description: 运动容器.
+        items:
+          $ref: '#/definitions/SportV3'
+  SportV3:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 运动 ID.
+      name:
+        type: string
+        description: 运动名称。
+      hasOfferings:
+        type: boolean
+        description: 运动当前是否有赛事或特殊赛事。
+      leagueSpecialsCount:
+        type: integer
+        format: int32
+        description: 指示给定运动中有多少特殊赛事。
+      eventSpecialsCount:
+        type: integer
+        format: int32
+        description: 指示给定运动中有多少赛事特殊赛事。
+      eventCount:
+        type: integer
+        format: int32
+        description: 指示给定运动中有多少赛事。
+  TeaserGroupsResponse:
+    type: object
+    properties:
+      teaserGroups:
+        type: array
+        description: 包含可用过关的过关组集合。
+        items:
+          $ref: '#/definitions/TeaserGroups'
+  TeaserGroups:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 唯一标识符。
+      name:
+        type: string
+        description: 过关组的友好名称
+      teasers:
+        type: array
+        description: 过关集合。
+        items:
+          $ref: '#/definitions/TeaserGroupsTeaser'
+  TeaserGroupsTeaser:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int64
+        description: 唯一标识符。
+      description:
+        type: string
+        description: 过关的描述。
+      sportId:
+        type: integer
+        format: int32
+        description: 唯一运动标识符。可以从调用 v2/sports 端点检索运动详情。
+      minLegs:
+        type: integer
+        format: int32
+        description: 必须选择的最小腿数。
+      maxLegs:
+        type: integer
+        format: int32
+        description: 可以选择的最大腿数。
+      sameEventOnly:
+        type: boolean
+        description: 如果为 'true',则所有腿必须来自同一赛事,否则腿可以来自不同赛事。
+      payouts:
+        type: array
+        description: 指示所有可能赔付组合的赔付集合。
+        items:
+          $ref: '#/definitions/TeaserGroupsPayout'
+      leagues:
+        type: array
+        description: 可用于过关的联赛集合。
+        items:
+          $ref: '#/definitions/TeaserGroupsLeague'
+  TeaserGroupsPayout:
+    type: object
+    properties:
+      numberOfLegs:
+        type: integer
+        format: int32
+        description: 必须投注并获胜才能获得相关价格的腿数。
+      price:
+        type: number
+        format: double
+        description: 给定指定腿数的投注价格。
+  TeaserGroupsLeague:
+    type: object
+    properties:
+      id:
+        type: integer
+        format: int32
+        description: 唯一标识符。可以从调用 v2/leagues 端点检索联赛详情。
+      spread:
+        $ref: '#/definitions/TeaserGroupsBetType'
+      total:
+        $ref: '#/definitions/TeaserGroupsBetType'
+  TeaserGroupsBetType:
+    type: object
+    properties:
+      points:
+        type: number
+        format: double
+        description: 对于给定联赛,线将被调整的点数。
+  SpecialsFixturesResponseV2:
+    type: object
+    properties:
+      sportId:
+        format: int32
+        description: 要检索赔率的运动 ID。
+        type: integer
+      last:
+        format: int64
+        description: 用于仅在后续请求中检索更改。在后续调用中提供此值作为 Since 参数,以仅检索更改。
+        type: integer
+      leagues:
+        description: 包含联赛列表。
+        type: array
+        items:
+          $ref: '#/definitions/SpecialsFixturesLeagueV2'
+  SpecialsFixturesLeagueV2:
+    type: object
+    properties:
+      id:
+        format: int32
+        description: 赛程联赛 ID。
+        type: integer
+      specials:
+        description: 特殊赛事集合
+        type: array
+        items:
+          $ref: '#/definitions/SpecialFixtureV2'
+  SpecialFixtureV2:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: 唯一 ID
+        type: integer
+      betType:
+        description: 类型 [MULTI_WAY_HEAD_TO_HEAD, SPREAD, OVER_UNDER]
+        enum:
+          - MULTI_WAY_HEAD_TO_HEAD
+          - SPREAD
+          - OVER_UNDER
+        type: string
+      name:
+        description: 特殊赛事名称。
+        type: string
+      date:
+        format: date-time
+        description: 特殊赛事的日期(UTC)。
+        type: string
+      cutoff:
+        format: date-time
+        description: 投注截止日期(UTC)。
+        type: string
+      category:
+        description: 特殊赛事所属的类别。
+        type: string
+      units:
+        description: 特殊赛事上下文中的测量单位。这适用于特殊投注类型让分和大小。在曲棍球特殊赛事中,这可能是进球数。
+        type: string
+      status:
+        description: |
+          特殊赛事状态
+
+          O = 这是比赛的起始状态。这意味着线开放投注,
+          H = 此状态表示线暂时不可用于投注,
+          I = 此状态表示一条或多条线有红圈(较低的最大投注金额)
+        enum:
+          - O
+          - H
+          - I
+        type: string
+      event:
+        $ref: '#/definitions/SpecialsFixturesEventV2'
+      contestants:
+        description: 可用于投注的参赛者线。
+        type: array
+        items:
+          $ref: '#/definitions/SpecialsFixturesContestant'
+      liveStatus:
+        format: int32
+        description: |
+          当特殊赛事链接到赛事时,我们将返回赛事的直播状态,否则将为 0。0 = 此赛事不提供直播投注,1 = 直播投注赛事,2 = 将为此比赛提供直播投注,但在不同赛事上。
+
+          请注意,在 LiveStatus=1 的特殊赛事上下注时,会应用直播延迟。
+        enum:
+          - 0
+          - 1
+          - 2
+        type: integer
+  SpecialsFixturesEventV2:
+    type: object
+    description: 与特殊赛事关联的可选赛事。
+    properties:
+      id:
+        format: int32
+        description: 赛事 ID
+        type: integer
+      periodNumber:
+        format: int32
+        description: 比赛的周期。例如在足球中 0(全场)、1(上半场)和 2(下半场)
+        type: integer
+      home:
+        description: 主队名称。
+        type: string
+      away:
+        description: 客队名称。
+        type: string
+  SpecialsFixturesContestant:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: 参赛者 ID。
+        type: integer
+      name:
+        description: 参赛者名称。
+        type: string
+      rotNum:
+        format: int32
+        description: 轮换号码。
+        type: integer
+  SettledSpecialsResponseV3:
+    description: 已结算特殊赛事请求的响应 dto
+    type: object
+    properties:
+      sportId:
+        format: int32
+        description: 要检索赔率的运动 ID。
+        type: integer
+      last:
+        format: int64
+        description: 已结算赛程的最后索引
+        type: integer
+      leagues:
+        description: 联赛列表。
+        type: array
+        items:
+          $ref: '#/definitions/SettledSpecialsLeagueV3'
+  SettledSpecialsLeagueV3:
+    description: 用于保存联赛所有已结算特殊赛事的联赛 Dto
+    type: object
+    properties:
+      id:
+        format: int32
+        description: 联赛 ID。
+        type: integer
+      specials:
+        description: 已结算特殊赛事集合
+        type: array
+        items:
+          $ref: '#/definitions/SettledSpecialV3'
+  SettledSpecialV3:
+    description: 已结算特殊赛事
+    type: object
+    properties:
+      id:
+        format: int64
+        description: 已结算特殊赛事的 ID
+        type: integer
+      status:
+        format: int32
+        description: 已结算特殊赛事的状态。
+        type: integer
+      settlementId:
+        format: int64
+        description: 已结算特殊赛事的 ID
+        type: integer
+      settledAt:
+        format: date-time
+        description: 结算日期时间
+        type: string
+      cancellationReason:
+        $ref: '#/definitions/CancellationReasonType'
+        description: 特殊赛事的取消原因
+      contestants:
+        description: 参赛者集合
+        type: array
+        items:
+          $ref: '#/definitions/SettledContestants'
+  SettledContestants:
+    description: 已结算特殊赛事
+    type: object
+    properties:
+      id:
+        format: int64
+        description: 参赛者 ID。
+        type: integer
+      name:
+        description: 参赛者名称
+        type: string
+        example: Union Magdalena
+      outcome:
+        type: string
+        description: |
+          参赛者结果。
+
+          W = 获胜,
+          L = 失败,
+          X = 取消,
+          T = 平局,
+          Z = 取消
+        enum:
+          - W
+          - L
+          - X
+          - T
+          - Z
+  SpecialLineResponse:
+    type: object
+    properties:
+      status:
+        description: 状态 [SUCCESS = 成功, NOT_EXISTS = 不再提供线]
+        enum:
+          - SUCCESS
+          - NOT_EXISTS
+        type: string
+      specialId:
+        format: int64
+        description: 特殊赛事 ID。
+        type: integer
+      contestantId:
+        format: int64
+        description: 参赛者 ID。
+        type: integer
+      minRiskStake:
+        format: double
+        description: 最小可投注风险金额。
+        type: number
+      maxRiskStake:
+        format: double
+        description: 最大可投注风险金额。
+        type: number
+      minWinStake:
+        format: double
+        description: 最小可投注赢利金额。
+        type: number
+      maxWinStake:
+        format: double
+        description: 最大可投注赢利金额。
+        type: number
+      lineId:
+        format: int64
+        description: 下注所需的线标识。
+        type: integer
+      price:
+        format: double
+        description: 最新价格。
+        type: number
+      handicap:
+        format: double
+        description: 让分。
+        type: number
+  SpecialOddsResponseV2:
+    type: object
+    properties:
+      sportId:
+        format: int32
+        description: 要检索赔率的运动 ID。
+        type: integer
+      last:
+        format: int64
+        description: 用于仅在后续请求中检索更改。在后续调用中提供此值作为 Since 参数,以仅检索更改。
+        type: integer
+      leagues:
+        description: 包含联赛列表。
+        type: array
+        items:
+          $ref: '#/definitions/SpecialOddsLeagueV2'
+  SpecialOddsLeagueV2:
+    type: object
+    properties:
+      id:
+        format: int32
+        description: 联赛 ID。
+        type: integer
+      specials:
+        description: 赛程特殊赛事集合。
+        type: array
+        items:
+          $ref: '#/definitions/SpecialOddsSpecialV2'
+  SpecialOddsSpecialV2:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: 特殊赛事 ID。
+        type: integer
+      maxRisk:
+        format: double
+        description: 最大风险金额。
+        type: number
+      contestantLines:
+        description: 可用于投注的参赛者线。
+        type: array
+        items:
+          $ref: '#/definitions/SpecialOddsContestantLineV2'
+  SpecialOddsContestantLineV2:
+    type: object
+    properties:
+      id:
+        format: int64
+        description: 参赛者线 ID。
+        type: integer
+      lineId:
+        format: int64
+        description: 下注所需的线标识符。
+        type: integer
+      price:
+        format: double
+        description: 线的价格。
+        type: number
+      handicap:
+        format: double
+        description: 表示让分、大小等的数字。
+        type: number
+      max:
+        format: double
+        description: 每个参赛者的最大投注量金额。请参阅[如何从最大投注量计算最大风险](https://github.com/pinny888/pinny888.github.io/blob/main/FAQs.md#how-to-calculate-max-risk-from-the-max-volume-limits-in-odds)
+        type: number

+ 623 - 0
pinnacle/main.js

@@ -0,0 +1,623 @@
+import { writeFileSync } from 'fs';
+import 'dotenv/config';
+
+import { pinnacleRequest, getPsteryRelations, updateBaseEvents, notifyException } from "./libs/pinnacleClient.js";
+import { Logs } from "./libs/logs.js";
+
+
+const cacheFilePath = 'data/gamesCache.json';
+
+
+const GLOBAL_DATA = {
+  filtedLeagues: [],
+  filtedGames: [],
+  gamesMap: {},
+  straightFixturesVersion: 0,
+  straightFixturesCount: 0,
+  specialFixturesVersion: 0,
+  straightOddsVersion: 0,
+  specialsOddsVersion: 0,
+  requestErrorCount: 0,
+  loopActive: false,
+};
+
+
+/**
+ * 获取指定时区当前日期或时间
+ * @param {number} offsetHours - 时区相对 UTC 的偏移(例如:-4 表示 GMT-4)
+ * @param {boolean} [withTime=false] - 是否返回完整时间(默认只返回日期)
+ * @returns {string} 格式化的日期或时间字符串
+ */
+const getDateInTimezone = (offsetHours, withTime = false) => {
+  const nowUTC = new Date();
+  const targetTime = new Date(nowUTC.getTime() + offsetHours * 60 * 60 * 1000);
+
+  const year = targetTime.getUTCFullYear();
+  const month = String(targetTime.getUTCMonth() + 1).padStart(2, '0');
+  const day = String(targetTime.getUTCDate()).padStart(2, '0');
+
+  if (!withTime) {
+    return `${year}-${month}-${day}`;
+  }
+
+  const hours = String(targetTime.getUTCHours()).padStart(2, '0');
+  const minutes = String(targetTime.getUTCMinutes()).padStart(2, '0');
+  const seconds = String(targetTime.getUTCSeconds()).padStart(2, '0');
+
+  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+
+
+const pinnacleGet = async (endpoint, params) => {
+  return pinnacleRequest({
+    endpoint,
+    params,
+    username: process.env.PINNACLE_USERNAME,
+    password: process.env.PINNACLE_PASSWORD,
+    proxy: process.env.NODE_HTTP_PROXY,
+  })
+  .catch(err => {
+    const source = { endpoint, params };
+    if (err?.response?.data) {
+      const data = err.response.data;
+      Object.assign(source, data);
+    }
+    err.source = source;
+    return Promise.reject(err);
+  });
+};
+
+
+// const pinnaclePost = async(endpoint, data) => {
+//   return pinnacleRequest({
+//     endpoint,
+//     data,
+//     method: 'POST',
+//     username: process.env.PINNACLE_USERNAME,
+//     password: process.env.PINNACLE_PASSWORD,
+//     proxy: process.env.NODE_HTTP_PROXY,
+//   });
+// };
+
+
+const updateFiltedGames = async () => {
+  return getPsteryRelations()
+  .then(res => {
+    if (res.statusCode !== 200) {
+      throw new Error(`Failed to update filted leagues: ${res.message}`);
+    }
+    Logs.outDev('res', res);
+    const games = res.data.map(game => {
+      const { eventId, leagueId } = game?.rel?.ps ?? {};
+      return {
+        eventId,
+        leagueId,
+      };
+    });
+
+    GLOBAL_DATA.filtedLeagues = [...new Set(games.map(game => game.leagueId).filter(leagueId => leagueId))];
+    GLOBAL_DATA.filtedGames = games.map(game => game.eventId).filter(eventId => eventId);
+  })
+  .catch(err => {
+    Logs.err(err.message);
+  })
+  .finally(() => {
+    setTimeout(updateFiltedGames, 1000 * 30);
+  });
+}
+
+
+const getStraightFixtures = async () => {
+  const leagueIds = GLOBAL_DATA.filtedLeagues.join(',');
+  let since = GLOBAL_DATA.straightFixturesVersion;
+  if (GLOBAL_DATA.straightFixturesCount > 12) {
+    since = 0;
+    GLOBAL_DATA.straightFixturesCount = 0;
+  }
+  GLOBAL_DATA.straightFixturesCount++;
+  return pinnacleGet('/v3/fixtures', { sportId: 29, leagueIds, since })
+  .then(data => {
+    const { league, last } = data;
+    if (!last) {
+      return {};
+    }
+    GLOBAL_DATA.straightFixturesVersion = last;
+    const games = league?.map(league => {
+      const { id: leagueId, events } = league;
+      return events?.map(event => {
+        const { starts } = event;
+        const timestamp = new Date(starts).getTime();
+        return { leagueId, ...event, timestamp };
+      });
+    })
+    .flat() ?? [];
+    const update = since == 0 ? 'full' : 'increment';
+    return { games, update };
+  });
+}
+
+
+const updateStraightFixtures = async () => {
+  return getStraightFixtures()
+  .then(data => {
+    const { games, update } = data;
+    const { gamesMap } = GLOBAL_DATA;
+    if (games?.length) {
+      games.forEach(game => {
+        const { id } = game;
+        if (!gamesMap[id]) {
+          gamesMap[id] = game;
+        }
+        else {
+          Object.assign(gamesMap[id], game);
+        }
+      });
+    }
+    if (update && update == 'full') {
+      const gamesSet = new Set(games.map(game => game.id));
+      Object.keys(gamesMap).forEach(key => {
+        if (!gamesSet.has(+key)) {
+          delete gamesMap[key];
+        }
+      });
+    }
+  });
+}
+
+
+const getStraightOdds = async () => {
+  const leagueIds = GLOBAL_DATA.filtedLeagues.join(',');
+  const since = GLOBAL_DATA.straightOddsVersion;
+  return pinnacleGet('/v3/odds', { sportId: 29, oddsFormat: 'Decimal', leagueIds, since })
+  .then(data => {
+    const { leagues, last } = data;
+    if (!last) {
+      return [];
+    }
+    GLOBAL_DATA.straightOddsVersion = last;
+    const games = leagues?.flatMap(league => league.events);
+    return games?.map(item => {
+      const { periods, ...rest } = item;
+      const period = periods?.find(period => period.number == 0) ?? {};
+      return { ...rest, period };
+    }) ?? [];
+  });
+}
+
+
+const updateStraightOdds = async () => {
+  return getStraightOdds()
+  .then(games => {
+    if (games.length) {
+      const { gamesMap } = GLOBAL_DATA;
+      games.forEach(game => {
+        const { id, ...rest } = game;
+        const localGame = gamesMap[id];
+        if (localGame) {
+          Object.assign(localGame, rest);
+        }
+      });
+    }
+  });
+}
+
+
+const getSpecialFixtures = async () => {
+  const leagueIds = GLOBAL_DATA.filtedLeagues.join(',');
+  const since = GLOBAL_DATA.specialFixturesVersion;
+  return pinnacleGet('/v2/fixtures/special', { sportId: 29, leagueIds, since })
+  .then(data => {
+    const { leagues, last } = data;
+    if (!last) {
+      return [];
+    }
+    GLOBAL_DATA.specialFixturesVersion = last;
+    const specials = leagues?.map(league => {
+      const { specials } = league;
+      return specials?.filter(special => special.event)
+      .map(special => {
+        const { event: { id: eventId }, ...rest } = special ?? { event: {} };
+        return { eventId, ...rest };
+      }) ?? [];
+    })
+    .flat()
+    .filter(special => {
+      if (special.name != 'Winning Margin' && special.name != 'Exact Total Goals') {
+        return false;
+      }
+      return true;
+    });
+    return specials ?? [];
+  });
+}
+
+
+const updateSpecialFixtures = async () => {
+  return getSpecialFixtures()
+  .then(specials => {
+    if (specials.length) {
+      const { gamesMap } = GLOBAL_DATA;
+      const gamesSpecialsMap = {};
+      specials.forEach(special => {
+        const { eventId } = special;
+        if (!gamesSpecialsMap[eventId]) {
+          gamesSpecialsMap[eventId] = {};
+        }
+        if (special.name == 'Winning Margin') {
+          gamesSpecialsMap[eventId].winningMargin = special;
+        } else if (special.name == 'Exact Total Goals') {
+          gamesSpecialsMap[eventId].exactTotalGoals = special;
+        }
+      });
+
+      Object.keys(gamesSpecialsMap).forEach(eventId => {
+        if (!gamesMap[eventId]) {
+          return;
+        }
+
+        if (!gamesMap[eventId].specials) {
+          gamesMap[eventId].specials = {};
+        }
+
+        const localSpecials = gamesMap[eventId].specials;
+        const remoteSpecials = gamesSpecialsMap[eventId];
+
+        if (localSpecials.winningMargin && !remoteSpecials.winningMargin) {
+          Logs.out('delete winningMargin', localSpecials.winningMargin);
+          delete localSpecials.winningMargin;
+        }
+        else if (!localSpecials.winningMargin && remoteSpecials.winningMargin) {
+          // Logs.out('add winningMargin', remoteSpecials.winningMargin);
+          localSpecials.winningMargin = remoteSpecials.winningMargin;
+        }
+
+        if (localSpecials.exactTotalGoals && !remoteSpecials.exactTotalGoals) {
+          Logs.out('delete exactTotalGoals', localSpecials.exactTotalGoals);
+          delete localSpecials.exactTotalGoals;
+        }
+        else if (!localSpecials.exactTotalGoals && remoteSpecials.exactTotalGoals) {
+          // Logs.out('add exactTotalGoals', remoteSpecials.exactTotalGoals);
+          localSpecials.exactTotalGoals = remoteSpecials.exactTotalGoals;
+        }
+
+      });
+    }
+  });
+}
+
+
+const getSpecialsOdds = async () => {
+  const leagueIds = GLOBAL_DATA.filtedLeagues.join(',');
+  const since = GLOBAL_DATA.specialsOddsVersion;
+  return pinnacleGet('/v2/odds/special', { sportId: 29, oddsFormat: 'Decimal', leagueIds, since })
+  .then(data => {
+    const { leagues, last } = data;
+    if (!last) {
+      return [];
+    }
+    GLOBAL_DATA.specialsOddsVersion = last;
+    return leagues?.flatMap(league => league.specials);
+  });
+}
+
+
+const updateSpecialsOdds = async () => {
+  return getSpecialsOdds()
+  .then(specials => {
+    if (specials.length) {
+      const { gamesMap } = GLOBAL_DATA;
+      const contestants = Object.values(gamesMap)
+      .filter(game => game.specials)
+      .map(game => {
+        const { specials } = game;
+        const contestants = Object.values(specials).map(special => {
+          const { contestants } = special;
+          return contestants.map(contestant => [contestant.id, contestant]);
+        });
+        return contestants;
+      }).flat(2);
+      const contestantsMap = new Map(contestants);
+      const lines = specials.flatMap(special => special.contestantLines);
+      lines.forEach(line => {
+        const { id, handicap, lineId, max, price } = line;
+        const contestant = contestantsMap.get(id);
+        if (!contestant) {
+          return;
+        }
+        contestant.handicap = handicap;
+        contestant.lineId = lineId;
+        contestant.max = max;
+        contestant.price = price;
+      });
+    }
+  });
+}
+
+
+const getInRunning = async () => {
+  return pinnacleGet('/v2/inrunning')
+  .then(data => {
+    const sportId = 29;
+    const leagues = data.sports?.find(sport => sport.id == sportId)?.leagues ?? [];
+    return leagues.filter(league => {
+      const { id } = league;
+      const filtedLeaguesSet = new Set(GLOBAL_DATA.filtedLeagues);
+      return filtedLeaguesSet.has(id);
+    }).flatMap(league => league.events);
+  });
+}
+
+
+const updateInRunning = async () => {
+  return getInRunning()
+  .then(games => {
+    if (!games.length) {
+      return;
+    }
+    const { gamesMap } = GLOBAL_DATA;
+    games.forEach(game => {
+      const { id, state, elapsed } = game;
+      const localGame = gamesMap[id];
+      if (localGame) {
+        Object.assign(localGame, { state, elapsed });
+      }
+    });
+  });
+}
+
+
+const ratioAccept = (ratio) => {
+  if (ratio > 0) {
+    return 'a'
+  }
+  return ''
+}
+const ratioString = (ratio) => {
+  ratio = Math.abs(ratio);
+  ratio = ratio.toString();
+  ratio = ratio.replace(/\./, '');
+  return ratio;
+}
+
+const parseSpreads = (spreads, wm) => {
+  // 让分盘
+  if (!spreads?.length) {
+    return null;
+  }
+  const events = {};
+  spreads.forEach(spread => {
+    const { hdp, home, away } = spread;
+
+    if (!(hdp % 1) || !!(hdp % 0.5)) {
+      // 整数或不能被0.5整除的让分盘不处理
+      return;
+    }
+
+    const ratio_ro = hdp;
+    const ratio_r = ratio_ro - wm;
+    events[`ior_r${ratioAccept(ratio_r)}h_${ratioString(ratio_r)}`] = {
+      v: home,
+      r: wm != 0 ? `ior_r${ratioAccept(ratio_ro)}h_${ratioString(ratio_ro)}` : undefined
+    };
+    events[`ior_r${ratioAccept(-ratio_r)}c_${ratioString(ratio_r)}`] = {
+      v: away,
+      r: wm != 0 ? `ior_r${ratioAccept(-ratio_ro)}c_${ratioString(ratio_ro)}` : undefined
+    };
+  });
+  return events;
+}
+
+const parseMoneyline = (moneyline) => {
+  // 胜平负
+  if (!moneyline) {
+    return null;
+  }
+  const { home, away, draw } = moneyline;
+  return {
+    'ior_mh': { v: home },
+    'ior_mc': { v: away },
+    'ior_mn': { v: draw },
+  }
+}
+
+const parsePeriod = (period, wm) => {
+  const { cutoff='', status=0, spreads=[], moneyline={} } = period;
+  const cutoffTime = new Date(cutoff).getTime();
+  const nowTime = Date.now();
+
+  if (status != 1 || cutoffTime < nowTime) {
+    return null;
+  }
+
+  const events = {};
+  Object.assign(events, parseSpreads(spreads, wm));
+  Object.assign(events, parseMoneyline(moneyline));
+
+  return events;
+}
+
+const parseWinningMargin = (winningMargin, home, away) => {
+  const { cutoff='', status='', contestants=[] } = winningMargin;
+  const cutoffTime = new Date(cutoff).getTime();
+  const nowTime = Date.now();
+
+  if (status != 'O' || cutoffTime < nowTime || !contestants?.length) {
+    return null;
+  }
+
+  const events = {};
+  contestants.forEach(contestant => {
+    const { name, price } = contestant;
+    const nr = name.match(/\d+$/)?.[0];
+    if (!nr) {
+      return;
+    }
+    let side;
+    if (name.startsWith(home)) {
+      side = 'h';
+    }
+    else if (name.startsWith(away)) {
+      side = 'c';
+    }
+    else {
+      return;
+    }
+    events[`ior_wm${side}_${nr}`] = { v: price };
+  });
+  return events;
+}
+
+const parseExactTotalGoals = (exactTotalGoals) => {
+  const { cutoff='', status='', contestants=[] } = exactTotalGoals;
+  const cutoffTime = new Date(cutoff).getTime();
+  const nowTime = Date.now();
+
+  if (status != 'O' || cutoffTime < nowTime || !contestants?.length) {
+    return null;
+  }
+
+  const events = {};
+  contestants.forEach(contestant => {
+    const { name, price } = contestant;
+    if (+name >= 1 && +name <= 7) {
+      events[`ior_ot_${name}`] = { v: price };
+    }
+  });
+  return events;
+}
+
+const parseRbState = (state) => {
+  let stage = null;
+  if (state == 1) {
+    stage = '1H';
+  }
+  else if (state == 2) {
+    stage = 'HT';
+  }
+  else if (state == 3) {
+    stage = '2H';
+  }
+  return stage;
+}
+
+const parseGame = (game) => {
+  const { eventId=0, originId=0, period={}, specials={}, home, away, marketType, state, elapsed, homeScore=0, awayScore=0 } = game;
+  const { winningMargin={}, exactTotalGoals={} } = specials;
+  const wm = homeScore - awayScore;
+  const score = `${homeScore}-${awayScore}`;
+  const events = parsePeriod(period, wm) ?? {};
+  const stage = parseRbState(state);
+  const retime = elapsed ? `${elapsed}'` : '';
+  const evtime = Date.now();
+  Object.assign(events, parseWinningMargin(winningMargin, home, away));
+  Object.assign(events, parseExactTotalGoals(exactTotalGoals));
+  return { eventId, originId, events, evtime, stage, retime, score, wm, marketType };
+}
+
+
+const getGames = () => {
+  const { filtedGames, gamesMap } = GLOBAL_DATA;
+  const filtedGamesSet = new Set(filtedGames);
+  const nowTime = Date.now();
+  const gamesData = {};
+  Object.values(gamesMap).forEach(game => {
+    const { id, liveStatus, parentId, resultingUnit, timestamp } = game;
+
+    if (resultingUnit !== 'Regular') {
+      return false;  // 非常规赛事不处理
+    }
+
+    const gmtMinus4Date = getDateInTimezone(-4);
+    const todayEndTime = new Date(`${gmtMinus4Date} 23:59:59 GMT-4`).getTime();
+    const tomorrowEndTime = todayEndTime + 24 * 60 * 60 * 1000;
+    if (liveStatus == 1 && timestamp < nowTime) {
+      game.marketType = 2;  // 滚球赛事
+    }
+    else if (liveStatus != 1 && timestamp > nowTime && timestamp <= todayEndTime) {
+      game.marketType = 1;  // 今日赛事
+    }
+    else if (liveStatus != 1 && timestamp > todayEndTime && timestamp <= tomorrowEndTime) {
+      game.marketType = 0;  // 明日早盘赛事
+    }
+    else {
+      game.marketType = -1;  // 非近期赛事
+    }
+
+    if (game.marketType < 0) {
+      return false;  // 非近期赛事不处理
+    }
+
+    let actived = false;
+    if (liveStatus != 1 && filtedGamesSet.has(id)) {
+      actived = true;  // 在赛前列表中
+      game.eventId = id;
+      game.originId = 0;
+    }
+    else if (liveStatus == 1 && filtedGamesSet.has(parentId)) {
+      actived = true;  // 在滚球列表中
+      game.eventId = parentId;
+      game.originId = id;
+    }
+
+    if (actived) {
+      const gameInfo = parseGame(game);
+      const { marketType, ...rest } = gameInfo;
+      if (!gamesData[marketType]) {
+        gamesData[marketType] = [];
+      }
+      gamesData[marketType].push(rest);
+    }
+  });
+  return gamesData;
+}
+
+
+const pinnacleDataLoop = () => {
+  updateStraightFixtures()
+  .then(() => {
+    return Promise.all([
+      updateStraightOdds(),
+      updateSpecialFixtures(),
+      updateInRunning(),
+    ]);
+  })
+  .then(() => {
+    return updateSpecialsOdds();
+  })
+  .then(() => {
+    GLOBAL_DATA.requestErrorCount = 0;
+    const { straightFixturesVersion: sfv, specialFixturesVersion: pfv, straightOddsVersion: sov, specialsOddsVersion: pov } = GLOBAL_DATA;
+    const timestamp = Math.max(sfv, pfv, sov, pov);
+    const games = getGames();
+    const data = { games, timestamp };
+    updateBaseEvents(data);
+    Logs.outDev('games data', data);
+    writeFileSync(cacheFilePath, JSON.stringify(GLOBAL_DATA.gamesMap, null, 2));
+  })
+  .catch(err => {
+    GLOBAL_DATA.requestErrorCount++;
+    if (GLOBAL_DATA.requestErrorCount > 10) {
+      GLOBAL_DATA.loopActive = false;
+      notifyException('Pinnacle API request errors have reached the limit.');
+    }
+    Logs.err(err.message, err.source);
+  })
+  .finally(() => {
+    if (!GLOBAL_DATA.loopActive) {
+      return;
+    }
+    setTimeout(pinnacleDataLoop, 1000 * 5);
+  });
+}
+
+
+(() => {
+  if (!process.env.PINNACLE_USERNAME || !process.env.PINNACLE_PASSWORD) {
+    Logs.err('USERNAME or PASSWORD is not set');
+    return;
+  }
+  GLOBAL_DATA.loopActive = true;
+  updateFiltedGames().then(pinnacleDataLoop);
+})();
+
+

+ 361 - 0
pinnacle/package-lock.json

@@ -0,0 +1,361 @@
+{
+  "name": "pinnacle_api_test",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "pinnacle_api_test",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "axios": "^1.12.2",
+        "dayjs": "^1.11.18",
+        "dotenv": "^17.2.3",
+        "https-proxy-agent": "^7.0.6"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.4",
+      "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz",
+      "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
+    "node_modules/axios": {
+      "version": "1.12.2",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.12.2.tgz",
+      "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.6",
+        "form-data": "^4.0.4",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/dayjs": {
+      "version": "1.11.18",
+      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.18.tgz",
+      "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
+      "license": "MIT"
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/dotenv": {
+      "version": "17.2.3",
+      "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-17.2.3.tgz",
+      "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://dotenvx.com"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
+      "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
+      "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "hasown": "^2.0.2",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "license": "MIT"
+    },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    }
+  }
+}

+ 19 - 0
pinnacle/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "pinnacle",
+  "version": "1.0.0",
+  "description": "",
+  "main": "main.js",
+  "type": "module",
+  "scripts": {
+    "dev": "nodemon --ignore data/ --ignore node_modules/ --inspect=9228 main.js",
+    "start": "pm2 start main.js --name pinnacle"
+  },
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "axios": "^1.12.2",
+    "dayjs": "^1.11.18",
+    "dotenv": "^17.2.3",
+    "https-proxy-agent": "^7.0.6"
+  }
+}

+ 52 - 12
server/models/GamesPs.js

@@ -284,6 +284,8 @@ const updateGamesList = (({ platform, mk, games } = {}) => {
  */
 const syncBaseEvents = ({ mk, games, outrights }) => {
 
+  Logs.out('syncBaseEvents', { mk, games });
+
   const {
     expireTimeEvents, expireTimeSpecial,
     subsidyTime, subsidyAmount,
@@ -294,7 +296,7 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
   const marketType = getMarketType(mk);
   const baseList = GAMES.Baselist;
   if (!baseList[marketType]) {
-    return;
+    return 0;
   }
 
   const baseMap = new Map(baseList[marketType].map(item => [item.eventId, item]));
@@ -303,17 +305,29 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
     const { eventId, originId, stage, retime, score, wm, evtime, events } = game;
     const baseGame = baseMap.get(eventId);
     if (baseGame) {
-      const { mk } = baseGame;
+      const { mk, timestamp } = baseGame;
       const isRb = (mk == 2);
-      if (isRb) {
-        Object.keys(events).forEach(ior => {
-          if ((ior.startsWith('ior_r') || ior.startsWith('ior_m')) && subsidyRbWmAmount) {
-            const sourceOdds = events[ior].v;
-            events[ior].v = fixFloat(sourceOdds * (1 + subsidyRbWmAmount), 3);
-            events[ior].s = sourceOdds
-          }
-        });
-      }
+      const isSubsidy = timestamp > nowTime && timestamp < nowTime + 1000*60*60*subsidyTime;
+      Object.keys(events).forEach(ior => {
+        if (isRb && (ior.startsWith('ior_r') || ior.startsWith('ior_m') || ior.startsWith('ior_wm')) && subsidyRbWmAmount) {
+          // 滚球胜平负
+          const sourceOdds = events[ior].v;
+          events[ior].v = fixFloat(sourceOdds * (1 + subsidyRbWmAmount), 3);
+          events[ior].s = sourceOdds
+        }
+        else if (isRb && ior.startsWith('ior_ot') && subsidyRbOtAmount) {
+          // 滚球进球数
+          const sourceOdds = events[ior].v;
+          events[ior].v = fixFloat(sourceOdds * (1 + subsidyRbOtAmount), 3);
+          events[ior].s = sourceOdds
+        }
+        else if (!isRb && isSubsidy && ior.startsWith('ior_ot') && subsidyAmount) {
+          // 赛前进球数
+          const sourceOdds = events[ior].v;
+          events[ior].v = fixFloat(sourceOdds * (1 + subsidyAmount), 3);
+          events[ior].s = sourceOdds
+        }
+      });
       baseGame.originId = originId;
       baseGame.stage = stage;
       baseGame.retime = retime;
@@ -450,6 +464,32 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
   }
 }
 
+const updateBaseEvents = ({ games, timestamp }) => {
+  return new Promise((resolve, reject) => {
+    if (!games) {
+      return reject(new Error('GAMES_INVALID'));
+    }
+    if (!timestamp) {
+      return reject(new Error('TIMESTAMP_INVALID'));
+    }
+
+    let update = 0;
+    const { UpdateTimestamp } = GAMES;
+    const tp = 'ps_9_9';
+    if (!UpdateTimestamp[tp] || UpdateTimestamp[tp] < timestamp) {
+      UpdateTimestamp[tp] = timestamp;
+    }
+    else {
+      return resolve({ update });
+    }
+
+    Object.keys(games).forEach(mk => {
+      update += syncBaseEvents({ mk, games: games[mk] ?? [] });
+    });
+    resolve({ update });
+  });
+}
+
 const updateGamesEvents = ({ platform, mk, games, outrights, timestamp, tp }) => {
   return new Promise((resolve, reject) => {
     if (!platform || (!games && !outrights)) {
@@ -1308,7 +1348,7 @@ process.on('SIGUSR2', () => {
 
 module.exports = {
   updateLeaguesList, getFilteredLeagues,
-  updateGamesList, updateGamesEvents,
+  updateGamesList, updateGamesEvents, updateBaseEvents,
   getGamesRelation,
   updateGamesResult,
   updateOriginalData, getOriginalData,

+ 12 - 0
server/routes/pstery.js

@@ -27,6 +27,18 @@ router.post('/update_games_events', (req, res) => {
   })
 });
 
+// 更新内盘盘口
+router.post('/update_base_events', (req, res) => {
+  const { games, timestamp } = req.body ?? {};
+  Games.updateBaseEvents({ games, timestamp })
+  .then(() => {
+    res.sendSuccess();
+  })
+  .catch(err => {
+    res.badRequest(err.message);
+  });
+});
+
 // 更新联赛列表
 router.post('/update_leagues_list', (req, res) => {
   const { mk, leagues, platform } = req.body ?? {};

Some files were not shown because too many files changed in this diff