openapi: 3.1.0
info:
  title: TakePair Partner API
  version: 1.0.0
  summary: Server RevShare API for an approved partner.
  description: |
    Base path `/affiliate/v1`. The cabinet shows a `tp_live_…` key once.
    Store it on the partner server and send `Authorization: Bearer`.
    The limit is 60 requests per minute per key.
    Dates are `YYYY-MM-DD` in UTC. Money is a decimal string with USDC or USDT.
    Player deposit amounts, player emails, and player ids are not in these responses.
    A read key cannot change the postback. Signing an outbound postback is not part of 1.0.
    Breaking changes ship as `/affiliate/v2`.
servers:
  - url: https://api.takepair.com/affiliate/v1
security:
  - bearerAuth: []
tags:
  - name: Partner
paths:
  /me:
    get:
      operationId: getMe
      summary: Deal and unpaid balance
      responses:
        '200':
          description: Percent, window, currency, minimum, and unpaid balance
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Me'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /stats:
    get:
      operationId: getStats
      summary: Period totals
      parameters:
        - $ref: '#/components/parameters/From'
        - $ref: '#/components/parameters/To'
        - $ref: '#/components/parameters/SubId'
      responses:
        '200':
          description: Clicks, registrations, first-deposit count, and RevShare
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Stats'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /stats/sub-ids:
    get:
      operationId: getStatsBySubId
      summary: Totals for each sub_id
      parameters:
        - $ref: '#/components/parameters/From'
        - $ref: '#/components/parameters/To'
      responses:
        '200':
          description: The same columns as the cabinet CSV
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubIdStats'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /accruals:
    get:
      operationId: listAccruals
      summary: Accrual rows
      parameters:
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Accruals without a player deposit, email, or id
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccrualPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /payouts:
    get:
      operationId: listPayouts
      summary: Statement and paid rows
      parameters:
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Accumulating, payable, or paid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /markets:
    get:
      operationId: listMarkets
      summary: Next open markets
      parameters:
        - name: locale
          in: query
          schema:
            type: string
            enum: [en, ru, es, zh]
      responses:
        '200':
          description: Up to 12 open public markets
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MarketPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /links:
    get:
      operationId: buildLink
      summary: Link for this partner
      parameters:
        - name: locale
          in: query
          schema:
            type: string
            enum: [en, ru, es, zh]
        - name: event_id
          in: query
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/SubId'
        - name: click_id
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Platform or market URL with this partner code
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PartnerLink'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
  /postbacks:
    get:
      operationId: listPostbacks
      summary: Delivery log
      parameters:
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Recent deliveries
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostbackPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /postback:
    put:
      operationId: savePostback
      summary: Save the HTTPS template
      description: Requires a manage key. Uses the same macros as the cabinet.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                postback_url:
                  type: string
                  maxLength: 512
      responses:
        '200':
          description: Saved template
          content:
            application/json:
              schema:
                type: object
                required: [postback_url]
                properties:
                  postback_url:
                    type: [string, 'null']
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
  /postback/test:
    post:
      operationId: testPostback
      summary: Send a test event
      description: Requires a manage key.
      responses:
        '201':
          description: Test delivery result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostbackTest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Partner key `tp_live_…`. A cabinet session token is not accepted.
  parameters:
    From:
      name: from
      in: query
      schema:
        type: string
        format: date
    To:
      name: to
      in: query
      schema:
        type: string
        format: date
    SubId:
      name: sub_id
      in: query
      schema:
        type: string
        maxLength: 64
    Cursor:
      name: cursor
      in: query
      schema:
        type: string
    Limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 50
  responses:
    BadRequest:
      description: The query is not valid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: The key is missing, unknown, or revoked
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: The program is paused, the partner cannot use the API, or the key lacks manage
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The market was not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: More than 60 requests in the current minute
      headers:
        Retry-After:
          schema:
            type: integer
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      additionalProperties: false
      required: [code, message]
      properties:
        code:
          type: string
          examples: [unauthorized, program_paused, scope_missing, rate_limited, invalid_range]
        message:
          type: string
    Money:
      type: object
      required: [currency, amount]
      properties:
        currency:
          type: string
          enum: [USDC, USDT]
        amount:
          type: string
    Deal:
      type: object
      required: [reward_percent, reward_window_days, basis]
      properties:
        reward_percent:
          type: string
        reward_window_days:
          type: integer
        basis:
          type: string
          const: FEE_OF_WIN
    Statement:
      type: object
      required: [status, currency, minimum, unpaid_amount, last_paid_at]
      properties:
        status:
          type: string
          enum: [accumulating, payable, paid, other_currency]
        currency:
          type: string
        minimum:
          type: string
        unpaid_amount:
          type: string
        last_paid_at:
          type: [string, 'null']
    Me:
      type: object
      required: [status, disabled, program_enabled, code, deal, payout]
      properties:
        status:
          type: string
        disabled:
          type: boolean
        program_enabled:
          type: [boolean, 'null']
        code:
          type: [string, 'null']
        deal:
          oneOf:
            - $ref: '#/components/schemas/Deal'
            - type: 'null'
        payout:
          oneOf:
            - $ref: '#/components/schemas/Statement'
            - type: 'null'
    Stats:
      type: object
      required: [from, to, sub_id, clicks, registrations, first_deposits, qualified, revshare]
      properties:
        from:
          type: [string, 'null']
        to:
          type: [string, 'null']
        sub_id:
          type: [string, 'null']
        clicks:
          type: integer
        registrations:
          type: integer
        first_deposits:
          type: integer
        qualified:
          type: integer
        revshare:
          type: array
          items:
            $ref: '#/components/schemas/Money'
    SubIdRow:
      type: object
      required: [sub_id, clicks, registrations, first_deposits, qualified, revshare]
      properties:
        sub_id:
          type: string
        clicks:
          type: integer
        registrations:
          type: integer
        first_deposits:
          type: integer
        qualified:
          type: integer
        revshare:
          type: string
    SubIdStats:
      type: object
      required: [from, to, items]
      properties:
        from:
          type: [string, 'null']
        to:
          type: [string, 'null']
        items:
          type: array
          items:
            $ref: '#/components/schemas/SubIdRow'
    Accrual:
      type: object
      required: [id, amount, currency, fee_amount, reward_percent, paid, created_at]
      properties:
        id:
          type: string
        amount:
          type: string
        currency:
          type: string
        fee_amount:
          type: string
        reward_percent:
          type: string
        paid:
          type: boolean
        client_rebate_amount:
          type: string
        created_at:
          type: string
          format: date-time
    AccrualPage:
      type: object
      required: [items, next_cursor]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Accrual'
        next_cursor:
          type: [string, 'null']
    PayoutRow:
      type: object
      required: [id, amount, currency, status, created_at]
      properties:
        id:
          type: string
        amount:
          type: string
        currency:
          type: string
        status:
          type: string
          const: paid
        created_at:
          type: string
          format: date-time
    PayoutPage:
      type: object
      required: [statement, items, next_cursor]
      properties:
        statement:
          oneOf:
            - $ref: '#/components/schemas/Statement'
            - type: 'null'
        items:
          type: array
          items:
            $ref: '#/components/schemas/PayoutRow'
        next_cursor:
          type: [string, 'null']
    Market:
      type: object
      required: [id, title, closes_at, symbol]
      properties:
        id:
          type: string
        title:
          type: string
        closes_at:
          type: [string, 'null']
        symbol:
          type: [string, 'null']
    MarketPage:
      type: object
      required: [items]
      properties:
        items:
          type: array
          maxItems: 12
          items:
            $ref: '#/components/schemas/Market'
    PartnerLink:
      type: object
      required: [code, url]
      properties:
        code:
          type: string
        url:
          type: string
    PostbackRow:
      type: object
      required: [id, event, status, http_status, attempts, last_error, created_at]
      properties:
        id:
          type: string
        event:
          type: string
        status:
          type: string
        http_status:
          type: [integer, 'null']
        attempts:
          type: integer
        last_error:
          type: [string, 'null']
        created_at:
          type: string
          format: date-time
    PostbackPage:
      type: object
      required: [items, next_cursor]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/PostbackRow'
        next_cursor:
          type: [string, 'null']
    PostbackTest:
      type: object
      required: [status, http_status, last_error]
      properties:
        status:
          type: string
        http_status:
          type: [integer, 'null']
        last_error:
          type: [string, 'null']
