openapi: 3.0.3
info:
  title: Incentable API
  description: |
    The Incentable API allows you to programmatically manage your channel incentive programs.
    
    ## Authentication
    All API requests require a Bearer token in the Authorization header:
    ```
    Authorization: Bearer YOUR_API_KEY
    ```
    
    ## Rate Limits
    - Starter: 60 requests/minute
    - Professional: 300 requests/minute
    - Enterprise: Custom
    
    ## Need Help?
    - [API Documentation](/docs/api)
    - [Contact Support](/contact)
  version: 1.0.0
  contact:
    name: Incentable Support
    email: support@incentable.com
    url: https://incentable.com/contact
  license:
    name: Proprietary
    url: https://incentable.com/terms

servers:
  - url: https://api.incentable.com/v1
    description: Production API
  - url: https://api.staging.incentable.com/v1
    description: Staging API (for testing)

tags:
  - name: Members
    description: Manage program participants
  - name: Points
    description: Award and manage points
  - name: Rewards
    description: Rewards catalog and redemptions
  - name: Orders
    description: Track reward fulfillment
  - name: Leaderboards
    description: Rankings and competitions
  - name: Webhooks
    description: Event notifications

paths:
  # ============================================
  # MEMBERS
  # ============================================
  /members:
    get:
      tags: [Members]
      summary: List members
      description: Retrieve a paginated list of all members in your program.
      operationId: listMembers
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: status
          in: query
          description: Filter by member status
          schema:
            type: string
            enum: [active, inactive, pending]
        - name: search
          in: query
          description: Search by name or email
          schema:
            type: string
        - name: tier
          in: query
          description: Filter by tier name
          schema:
            type: string
      responses:
        '200':
          description: List of members
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Member'
                      meta:
                        $ref: '#/components/schemas/PaginationMeta'
        '401':
          $ref: '#/components/responses/Unauthorized'
    
    post:
      tags: [Members]
      summary: Create member
      description: Add a new member to your incentive program.
      operationId: createMember
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMemberRequest'
      responses:
        '201':
          description: Member created successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Member'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /members/{member_id}:
    get:
      tags: [Members]
      summary: Get member
      description: Retrieve a single member by ID.
      operationId: getMember
      parameters:
        - $ref: '#/components/parameters/MemberIdParam'
      responses:
        '200':
          description: Member details
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Member'
        '404':
          $ref: '#/components/responses/NotFound'
    
    patch:
      tags: [Members]
      summary: Update member
      description: Update an existing member's information.
      operationId: updateMember
      parameters:
        - $ref: '#/components/parameters/MemberIdParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMemberRequest'
      responses:
        '200':
          description: Member updated successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Member'
        '404':
          $ref: '#/components/responses/NotFound'
    
    delete:
      tags: [Members]
      summary: Delete member
      description: Remove a member from your program. This action is irreversible.
      operationId: deleteMember
      parameters:
        - $ref: '#/components/parameters/MemberIdParam'
      responses:
        '204':
          description: Member deleted successfully
        '404':
          $ref: '#/components/responses/NotFound'

  /members/{member_id}/balance:
    get:
      tags: [Members, Points]
      summary: Get member balance
      description: Retrieve a member's current points balance and lifetime stats.
      operationId: getMemberBalance
      parameters:
        - $ref: '#/components/parameters/MemberIdParam'
      responses:
        '200':
          description: Balance information
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Balance'

  /members/{member_id}/transactions:
    get:
      tags: [Members, Points]
      summary: Get transaction history
      description: Retrieve a member's point transaction history.
      operationId: getMemberTransactions
      parameters:
        - $ref: '#/components/parameters/MemberIdParam'
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: type
          in: query
          description: Filter by transaction type
          schema:
            type: string
            enum: [award, redeem, deduct, expire, adjust]
        - name: from
          in: query
          description: Start date (ISO 8601)
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          description: End date (ISO 8601)
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Transaction history
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Transaction'
                      meta:
                        $ref: '#/components/schemas/PaginationMeta'

  # ============================================
  # POINTS
  # ============================================
  /points/award:
    post:
      tags: [Points]
      summary: Award points
      description: Add points to a member's balance.
      operationId: awardPoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AwardPointsRequest'
      responses:
        '200':
          description: Points awarded successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Transaction'

  /points/award/bulk:
    post:
      tags: [Points]
      summary: Bulk award points
      description: Award points to multiple members in a single request.
      operationId: bulkAwardPoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkAwardRequest'
      responses:
        '200':
          description: Bulk award processed
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/BulkAwardResponse'

  /points/deduct:
    post:
      tags: [Points]
      summary: Deduct points
      description: Remove points from a member's balance (for adjustments only).
      operationId: deductPoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeductPointsRequest'
      responses:
        '200':
          description: Points deducted successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Transaction'

  # ============================================
  # REWARDS
  # ============================================
  /rewards:
    get:
      tags: [Rewards]
      summary: List rewards
      description: Retrieve all available rewards in your catalog.
      operationId: listRewards
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: category
          in: query
          description: Filter by category
          schema:
            type: string
        - name: status
          in: query
          description: Filter by status
          schema:
            type: string
            enum: [active, inactive]
        - name: type
          in: query
          description: Filter by reward type
          schema:
            type: string
            enum: [digital, physical]
      responses:
        '200':
          description: List of rewards
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Reward'
                      meta:
                        $ref: '#/components/schemas/PaginationMeta'

  /rewards/{reward_id}:
    get:
      tags: [Rewards]
      summary: Get reward
      description: Retrieve details for a specific reward.
      operationId: getReward
      parameters:
        - name: reward_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Reward details
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Reward'

  /rewards/redeem:
    post:
      tags: [Rewards]
      summary: Redeem reward
      description: Process a reward redemption for a member.
      operationId: redeemReward
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RedeemRewardRequest'
      responses:
        '200':
          description: Redemption successful
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Order'
        '400':
          description: Insufficient points or invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  # ============================================
  # ORDERS
  # ============================================
  /orders:
    get:
      tags: [Orders]
      summary: List orders
      description: Retrieve redemption orders for tracking and fulfillment.
      operationId: listOrders
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PerPageParam'
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, processing, shipped, completed, cancelled]
        - name: member_id
          in: query
          schema:
            type: string
      responses:
        '200':
          description: List of orders
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Order'

  /orders/{order_id}:
    get:
      tags: [Orders]
      summary: Get order
      operationId: getOrder
      parameters:
        - name: order_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Order details
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Order'
    
    patch:
      tags: [Orders]
      summary: Update order status
      description: Update the fulfillment status of an order.
      operationId: updateOrder
      parameters:
        - name: order_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrderRequest'
      responses:
        '200':
          description: Order updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Order'

  # ============================================
  # LEADERBOARDS
  # ============================================
  /leaderboards:
    get:
      tags: [Leaderboards]
      summary: List leaderboards
      description: Retrieve all leaderboards for your program.
      operationId: listLeaderboards
      responses:
        '200':
          description: List of leaderboards
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Leaderboard'

  /leaderboards/{leaderboard_id}/rankings:
    get:
      tags: [Leaderboards]
      summary: Get leaderboard rankings
      description: Retrieve current rankings for a leaderboard.
      operationId: getLeaderboardRankings
      parameters:
        - name: leaderboard_id
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          description: Number of rankings to return (default 10, max 100)
          schema:
            type: integer
            default: 10
            maximum: 100
      responses:
        '200':
          description: Leaderboard rankings
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/LeaderboardRanking'

# ============================================
# COMPONENTS
# ============================================
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key

  parameters:
    PageParam:
      name: page
      in: query
      description: Page number
      schema:
        type: integer
        default: 1
        minimum: 1
    
    PerPageParam:
      name: per_page
      in: query
      description: Results per page
      schema:
        type: integer
        default: 25
        minimum: 1
        maximum: 100
    
    MemberIdParam:
      name: member_id
      in: path
      required: true
      description: Unique member identifier
      schema:
        type: string
        example: mem_abc123

  responses:
    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: unauthorized
              message: Invalid API key provided
    
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: not_found
              message: The requested resource was not found
    
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  schemas:
    # Base Responses
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
              example: invalid_request
            message:
              type: string
              example: The member_id field is required

    PaginationMeta:
      type: object
      properties:
        page:
          type: integer
          example: 1
        per_page:
          type: integer
          example: 25
        total:
          type: integer
          example: 156

    # Member Schemas
    Member:
      type: object
      properties:
        id:
          type: string
          example: mem_abc123
        email:
          type: string
          format: email
          example: john@example.com
        first_name:
          type: string
          example: John
        last_name:
          type: string
          example: Smith
        company:
          type: string
          example: Acme Corp
        phone:
          type: string
          example: "+1234567890"
        points_balance:
          type: integer
          example: 5000
        tier:
          type: string
          example: Gold
        status:
          type: string
          enum: [active, inactive, pending]
          example: active
        metadata:
          type: object
          additionalProperties: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    CreateMemberRequest:
      type: object
      required:
        - email
        - first_name
        - last_name
      properties:
        email:
          type: string
          format: email
        first_name:
          type: string
        last_name:
          type: string
        company:
          type: string
        phone:
          type: string
        metadata:
          type: object
          additionalProperties: true

    UpdateMemberRequest:
      type: object
      properties:
        first_name:
          type: string
        last_name:
          type: string
        company:
          type: string
        phone:
          type: string
        status:
          type: string
          enum: [active, inactive]
        metadata:
          type: object
          additionalProperties: true

    # Points Schemas
    Balance:
      type: object
      properties:
        member_id:
          type: string
        balance:
          type: integer
          description: Current available points
        lifetime_earned:
          type: integer
          description: Total points ever earned
        lifetime_redeemed:
          type: integer
          description: Total points ever redeemed
        pending:
          type: integer
          description: Points pending approval

    Transaction:
      type: object
      properties:
        transaction_id:
          type: string
          example: txn_def456
        member_id:
          type: string
        type:
          type: string
          enum: [award, redeem, deduct, expire, adjust]
        points:
          type: integer
          description: Positive for awards, negative for deductions
        reason:
          type: string
        reference:
          type: string
        balance_after:
          type: integer
        metadata:
          type: object
        created_at:
          type: string
          format: date-time

    AwardPointsRequest:
      type: object
      required:
        - member_id
        - points
        - reason
      properties:
        member_id:
          type: string
        points:
          type: integer
          minimum: 1
        reason:
          type: string
          description: Description of why points were awarded
        reference:
          type: string
          description: External reference (e.g., invoice number)
        metadata:
          type: object
          additionalProperties: true

    DeductPointsRequest:
      type: object
      required:
        - member_id
        - points
        - reason
      properties:
        member_id:
          type: string
        points:
          type: integer
          minimum: 1
        reason:
          type: string

    BulkAwardRequest:
      type: object
      required:
        - awards
      properties:
        awards:
          type: array
          items:
            type: object
            required:
              - member_id
              - points
              - reason
            properties:
              member_id:
                type: string
              points:
                type: integer
              reason:
                type: string

    BulkAwardResponse:
      type: object
      properties:
        processed:
          type: integer
        failed:
          type: integer
        transactions:
          type: array
          items:
            type: object
            properties:
              member_id:
                type: string
              transaction_id:
                type: string

    # Reward Schemas
    Reward:
      type: object
      properties:
        id:
          type: string
          example: rwd_001
        name:
          type: string
          example: Amazon Gift Card $25
        description:
          type: string
        points_cost:
          type: integer
          example: 2500
        category:
          type: string
          example: Gift Cards
        type:
          type: string
          enum: [digital, physical]
        status:
          type: string
          enum: [active, inactive]
        image_url:
          type: string
          format: uri
        stock:
          type: integer
          nullable: true
          description: null for unlimited stock

    RedeemRewardRequest:
      type: object
      required:
        - member_id
        - reward_id
      properties:
        member_id:
          type: string
        reward_id:
          type: string
        quantity:
          type: integer
          default: 1
        shipping_address:
          $ref: '#/components/schemas/ShippingAddress'

    ShippingAddress:
      type: object
      required:
        - name
        - line1
        - city
        - postal_code
        - country
      properties:
        name:
          type: string
        line1:
          type: string
        line2:
          type: string
        city:
          type: string
        state:
          type: string
        postal_code:
          type: string
        country:
          type: string
          description: ISO 3166-1 alpha-2 country code

    # Order Schemas
    Order:
      type: object
      properties:
        order_id:
          type: string
        member_id:
          type: string
        reward_id:
          type: string
        reward_name:
          type: string
        points_spent:
          type: integer
        status:
          type: string
          enum: [pending, processing, shipped, completed, cancelled]
        fulfillment:
          type: object
          properties:
            type:
              type: string
              enum: [digital, physical]
            code:
              type: string
              description: Gift card code (for digital rewards)
            tracking_number:
              type: string
            carrier:
              type: string
            delivered_at:
              type: string
              format: date-time
        shipping_address:
          $ref: '#/components/schemas/ShippingAddress'
        created_at:
          type: string
          format: date-time

    UpdateOrderRequest:
      type: object
      properties:
        status:
          type: string
          enum: [processing, shipped, completed, cancelled]
        tracking_number:
          type: string
        carrier:
          type: string

    # Leaderboard Schemas
    Leaderboard:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
        metric:
          type: string
          description: What is being measured (points, sales, etc.)
        period:
          type: string
          enum: [daily, weekly, monthly, quarterly, yearly, all_time]
        status:
          type: string
          enum: [active, inactive]

    LeaderboardRanking:
      type: object
      properties:
        rank:
          type: integer
        member_id:
          type: string
        member_name:
          type: string
        value:
          type: number
          description: The metric value
        change:
          type: integer
          description: Position change since last update (positive = moved up)

security:
  - BearerAuth: []

