> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firstpromoter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tracking sales and commissions

> Assign sales and commissions to your promoters. To track sales and generate commissions correctly, you need to use this API call each time a non-zero amount sale is processed in your system, even if it comes from a recurring charge or one-time charge. <Note>To avoid fraudulent sales, we don't use JS conversion pixels to track sales, which are very unreliable and can be easily faked. Instead, we use server-side tracking for all sales to ensure that a sale is tracked only when you actually receive money in your billing account.  <br/><br/>To maintain the same standards with the API, we recommend making the sale API call (this call) only when you receive confirmation of the sale from your billing provider, such as from a webhook, an IPN, or a success response from an API charge call.<br/><br/>You just need to pass the sale amount (before taxes) and we'll take care of the rest. The commissions/rewards will be calculated based on that amount and the plan ID, in case you use the plan-level rewards feature.</Note> Using email or UID parameters, we identify the lead/customer who generated the sale, which also helps us determine the promoter who owns the reward/commission. <br/><br/>The lead is added to our system either by the client signup tracking script when the user signs up or by calling the signup API endpoint. There is also the option to bypass the signup tracking by using TID or ref_id parameters, which will create the lead and assign the sale in one go.<br/><br/>**If we don't find the lead in our system, it means that the sale is not a referral sale and you'll get a 204 response. You don't have to identify which sale is from referrals and which is not; we'll take care of that.** <Tip>**For zero-decimal** currencies like `JPY`, `amount` and `mrr` parameters should be sent as **whole values**. <br/><br/>**For other currencies**, `amount` and `mrr` parameter values should be in cents, i.e., you will need to **multiply the value by 100** before sending the request.</Tip><Tip>**HTTP Request** <br/>`POST https://firstpromoter.com/api/v1/track/sale`</Tip>



## OpenAPI

````yaml openapi-tracking POST /sale
openapi: 3.0.1
info:
  title: FirstPromoter Tracking API
  description: >-
    Our tracking API allows companies to track any type of signups, sales,
    cancellations and refunds for any billing provider, you are not limited to
    our built-in integrations with Stripe, Chargebee, Recurly and Braintree.
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://firstpromoter.com/api/v1/track
security:
  - apiKeyAuth: []
paths:
  /sale:
    post:
      description: >-
        Assign sales and commissions to your promoters. To track sales and
        generate commissions correctly, you need to use this API call each time
        a non-zero amount sale is processed in your system, even if it comes
        from a recurring charge or one-time charge. <Note>To avoid fraudulent
        sales, we don't use JS conversion pixels to track sales, which are very
        unreliable and can be easily faked. Instead, we use server-side tracking
        for all sales to ensure that a sale is tracked only when you actually
        receive money in your billing account.  <br/><br/>To maintain the same
        standards with the API, we recommend making the sale API call (this
        call) only when you receive confirmation of the sale from your billing
        provider, such as from a webhook, an IPN, or a success response from an
        API charge call.<br/><br/>You just need to pass the sale amount (before
        taxes) and we'll take care of the rest. The commissions/rewards will be
        calculated based on that amount and the plan ID, in case you use the
        plan-level rewards feature.</Note> Using email or UID parameters, we
        identify the lead/customer who generated the sale, which also helps us
        determine the promoter who owns the reward/commission. <br/><br/>The
        lead is added to our system either by the client signup tracking script
        when the user signs up or by calling the signup API endpoint. There is
        also the option to bypass the signup tracking by using TID or ref_id
        parameters, which will create the lead and assign the sale in one
        go.<br/><br/>**If we don't find the lead in our system, it means that
        the sale is not a referral sale and you'll get a 204 response. You don't
        have to identify which sale is from referrals and which is not; we'll
        take care of that.** <Tip>**For zero-decimal** currencies like `JPY`,
        `amount` and `mrr` parameters should be sent as **whole values**.
        <br/><br/>**For other currencies**, `amount` and `mrr` parameter values
        should be in cents, i.e., you will need to **multiply the value by 100**
        before sending the request.</Tip><Tip>**HTTP Request** <br/>`POST
        https://firstpromoter.com/api/v1/track/sale`</Tip>
      parameters:
        - name: email
          in: query
          description: |-
            `required if uid is null` 

              Email of the lead/sign-up
          schema:
            type: string
        - name: uid
          in: query
          description: |-
            `required if email is null` 

              uid of the lead added on signup tracking
          schema:
            type: string
        - name: event_id
          in: query
          required: true
          description: >-
            Transaction or sale event ID. It's required to avoid generating
            duplicate sales in case you mistakenly send the same API call
            multiple times.
          schema:
            type: string
        - name: amount
          in: query
          required: true
          description: >-
            The sale amount in cents. It's used to calculate
            commissions/rewards. 
             
             **For zero-decimal** currencies like `JPY`, `amount` and `mrr` parameters should be sent as **whole values**. 
             
             **For other currencies**, `amount` and `mrr` parameter values should be in cents, i.e., you will need to **multiply the value by 100** before sending the request.
          schema:
            type: string
        - name: quantity
          in: query
          description: >-
            Number of subscriptions/items refunded. If it's only one you can
            skip this parameter.
          schema:
            type: string
        - name: plan
          in: query
          description: >-
            Customer plan ID from the billing provider. It's used to calculate
            rewards in case you use plan-level rewards feature.
          schema:
            type: string
        - name: currency
          in: query
          description: >-
            This field is only required if the currency of the sale is not the
            same as the one set on FirstPromoter settings. We'll automatically
            convert the amount from this currency to the default one set on your
            FirstPromoter account.
          schema:
            type: string
        - name: mrr
          in: query
          description: >-
            Sets the Monthly Recurring Revenue generated by the customer. It's
            used only for calculating the MRR generated by the program, not for
            calculating the commissions.
          schema:
            type: string
        - name: promo_code
          in: query
          description: >-
            For promo code/coupon code tracking. If you gave a unique coupon to
            a promoter and you added it on his promotion, you can pass it here
            and it will CREATE a new lead and a sale for that promoter (if it
            doesn't exist already).
          schema:
            type: string
        - name: tid
          in: query
          description: >-
            You can avoid a signup tracking call by providing the `_fprom_tid`
            cookie value (visitor tracking id) read on your system
          schema:
            type: string
        - name: ref_id
          in: query
          description: >-
            You can avoid signup tracking call by providing the
            `ref_id`(referral id) of the promoter
          schema:
            type: string
        - name: skip_email_notification
          in: query
          description: Set this to `true` to skip email notifications. Default is `false`.
          schema:
            type: boolean
        - name: created_at
          in: query
          description: ISO 8601 date string of when the sale occurred. Defaults to now.
          schema:
            type: string
            format: date-time
        - name: subscription_id
          in: query
          description: >-
            Subscription ID from your billing provider. Stored in the lead
            metadata.
          schema:
            type: string
        - name: start_recurring_reward_in
          in: query
          description: >-
            Number of days to delay the first commission. The sale will be
            scheduled and tracked at `now + start_recurring_reward_in` days.
          schema:
            type: integer
        - name: recurring_reward_frequency
          in: query
          description: >-
            Interval in days between recurring commission events. Used together
            with `start_recurring_reward_in`.
          schema:
            type: integer
        - name: max_recurring
          in: query
          description: >-
            Maximum number of recurring commission events to generate. Requires
            `recurring_reward_frequency` to be set.
          schema:
            type: integer
        - name: ecom_sale
          in: query
          description: Set to `true` for e-commerce one-time sales (non-subscription).
          schema:
            type: boolean
      responses:
        '200':
          description: Sale tracked successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    example: 33847194
                  type:
                    type: string
                    example: sale
                  amount_cents:
                    type: integer
                    example: 1000
                  reward:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 10940014
                      status:
                        type: string
                        example: approved
                      amount:
                        type: integer
                        example: 200
                      unit:
                        type: string
                        example: cash
                      created_at:
                        type: string
                        format: date-time
                        example: '2024-09-11T14:22:12.160Z'
                      lead:
                        $ref: '#/components/schemas/Lead'
                      event_id:
                        type: string
                        example: test_sale_12340987
                      conversion_amount:
                        type: integer
                        example: 1000
                      tier_level:
                        type: integer
                        example: 1
                      split_type:
                        type: string
                        nullable: true
                        example: null
                  lead:
                    $ref: '#/components/schemas/Lead'
                  promoter:
                    $ref: '#/components/schemas/Promoter'
        '204':
          description: >-
            No Content — the lead was not found, meaning this is not a referral
            sale. No commission is generated.
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Error. Amount blank or invalid.
        '409':
          description: Conflict — a sale event with this `event_id` already exists.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: The 'sale' event with the id 'evt_123' already exists.
components:
  schemas:
    Lead:
      type: object
      properties:
        id:
          type: integer
          example: 20738339
        state:
          type: string
          example: cancelled
        email:
          type: string
          example: hello@testmintli.com
        uid:
          type: string
          nullable: true
          example: null
        customer_since:
          type: string
          format: date-time
          example: '2024-09-11T14:22:12.160Z'
        cancelled_at:
          type: string
          format: date-time
          example: '2024-09-11T15:07:46.174Z'
        plan_name:
          type: string
          nullable: true
          example: null
        suspicion:
          type: string
          example: no_suspicion
        username:
          type: string
          nullable: true
          example: null
        website:
          type: string
          nullable: true
          example: null
        created_at:
          type: string
          format: date-time
          example: '2024-09-09T16:22:44.168Z'
        split_promotion_id:
          type: string
          nullable: true
          example: null
        custom_fields:
          type: string
          nullable: true
          example: null
        split_percentage_value:
          type: string
          nullable: true
          example: null
        visitor_sub_id:
          type: string
          nullable: true
          example: null
    Promoter:
      type: object
      properties:
        id:
          type: integer
          description: ID of the promoter
          example: 3920164
        status:
          type: string
          description: Status of the promoter
          example: active
        cust_id:
          type: string
          example: ''
        email:
          type: string
          description: Email of the promoter
          example: peluwydo@mailinator.com
        created_at:
          type: string
          format: date-time
          description: ISO date of when the promoter was created
          example: '2022-04-26T15:28:24.800Z'
        temp_password:
          type: string
          description: Temporary password created for the promoter
          nullable: true
          example: xxxxxxxxxx
        default_promotion_id:
          type: integer
          example: 4210919
        pref:
          type: string
          example: db1znwe
        default_ref_id:
          type: string
          description: Default referral id of the promoter
          example: 8yi2epelut
        note:
          type: string
          description: A note/description of promoter
          nullable: true
          example: This is a note
        w8_form_url:
          type: string
          description: Url of the w8 form
          nullable: true
          example: null
        w9_form_url:
          type: string
          description: Url of the w9 form
          nullable: true
          example: null
        parent_promoter_id:
          type: integer
          description: Parent promoter id
          example: 577918
        earnings_balance:
          type: object
          description: Earning balance of the promoter
          properties:
            cash:
              type: integer
              example: 50744
        current_balance:
          type: object
          description: Current balance of the promoter
          properties:
            cash:
              type: integer
              example: 20044
        paid_balance:
          type: object
          description: Paid balance of the promoter
          properties:
            cash:
              type: integer
              example: 30700
        auth_token:
          type: string
          description: Authentication token generated when the promoter was created
          example: xxxxxxxxxxxxxx
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY

````