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

# Record a purchase event

> Records a purchase event and triggers commission calculation for the buyer's upline.
Commissions are created based on the tenant's commission rules and the compressed upline.




## OpenAPI

````yaml api/openapi.yaml post /api/v1/events/purchase
openapi: 3.1.0
info:
  title: MLM Platform API
  version: 1.0.0
  description: >
    The MLM Platform API enables tenant developers to integrate commission
    tracking,

    member management, and referral systems into their applications.


    ## Authentication

    All API requests require a tenant API key passed in the `x-tenant-api-key`
    header.


    ## Environments

    - **LIVE**: Production environment with real data

    - **SANDBOX**: Test environment for development and testing


    API keys are scoped to specific environments. Use sandbox keys for testing.


    The environment is derived from the API key used for the request.

    The platform returns the selected environment in the response header
    `X-Environment`.

    If you send an `X-Environment` request header, it is treated as
    optional/debug-only.
  contact:
    name: MLM Platform Support
    email: support@mlm-platform.example.com
  license:
    name: Proprietary
    url: https://mlm-platform.example.com/terms
servers:
  - url: https://app.mlm-platform.com
    description: Production API
  - url: http://localhost:3000
    description: Local Development
security:
  - TenantApiKey: []
tags:
  - name: Auth
    description: Token exchange, validation, refresh, and revocation for OIDC federation
  - name: Events
    description: Purchase and commission events
  - name: Users
    description: Member management
  - name: Leads
    description: Lead capture and tracking
  - name: Referrals
    description: Referral links and codes
  - name: Payout
    description: Payout methods metadata for dynamic payout setup forms
  - name: Payout Accounts
    description: Member payout accounts (create/list/update/delete)
  - name: KYC
    description: Member KYC start, status, and document submission
  - name: Admin KYC
    description: Admin KYC review queue, details, and actions
  - name: Widget
    description: Embeddable widget authentication
  - name: Webhooks
    description: Webhook receivers for third-party providers (Sumsub)
paths:
  /api/v1/events/purchase:
    post:
      tags:
        - Events
      summary: Record a purchase event
      description: >
        Records a purchase event and triggers commission calculation for the
        buyer's upline.

        Commissions are created based on the tenant's commission rules and the
        compressed upline.
      operationId: recordPurchase
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >
            Optional idempotency key to safely retry the same purchase event.

            Use a stable identifier (for example an order ID) to prevent
            duplicate commission creation.
          schema:
            type: string
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseEventRequest'
            examples:
              basic:
                summary: Basic purchase
                value:
                  user_id: 550e8400-e29b-41d4-a716-446655440000
                  amount: 99.99
                  currency: USD
              withMetadata:
                summary: Purchase with metadata
                value:
                  user_id: 550e8400-e29b-41d4-a716-446655440000
                  amount: 199.99
                  currency: USD
                  metadata:
                    order_id: ORD-2024-001
                    product_name: Premium Subscription
      responses:
        '202':
          description: Purchase event accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseEventAcceptedResponse'
          headers:
            X-Environment:
              $ref: '#/components/headers/X-Environment'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    PurchaseEventRequest:
      type: object
      required:
        - user_id
        - amount
      properties:
        user_id:
          type: string
          format: uuid
          description: The buyer's user ID
        amount:
          type: number
          format: double
          minimum: 0.01
          description: Purchase amount in the specified currency
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          description: >-
            ISO 4217 currency code. If omitted, the tenant base currency is
            used.
        provider_transaction_id:
          type: string
          description: >-
            Optional upstream payment provider transaction identifier (for
            audit/reconciliation)
        metadata:
          type: object
          additionalProperties: true
          description: >-
            Additional metadata to store with the event and downstream
            commission ledger entries
    PurchaseEventAcceptedResponse:
      type: object
      description: Response returned when a purchase event is accepted for processing.
      required:
        - message
        - ledgerPayload
      properties:
        message:
          type: string
          description: Human-readable status message
        ledgerPayload:
          $ref: '#/components/schemas/PurchaseLedgerPayload'
        idempotency_key:
          type: string
          nullable: true
          description: >-
            Echoed idempotency key if one was provided via the Idempotency-Key
            header
    PurchaseLedgerPayload:
      type: object
      required:
        - tenantId
        - originalAmount
        - originalCurrency
        - baseCurrency
        - convertedAmount
        - fxRate
        - metadata
        - commissionsGenerated
      properties:
        tenantId:
          type: string
          format: uuid
          description: Tenant ID derived from the API key
        originalAmount:
          type: number
          description: Purchase amount provided in the request
        originalCurrency:
          type: string
          pattern: ^[A-Z]{3}$
          description: Currency provided in the request (normalized to uppercase)
        baseCurrency:
          type: string
          pattern: ^[A-Z]{3}$
          description: Tenant base currency used for ledger entries
        convertedAmount:
          type: number
          description: Purchase amount converted into the tenant base currency
        fxRate:
          type: number
          description: FX conversion rate applied
        metadata:
          type: object
          additionalProperties: true
          description: Original request payload captured as metadata
        commissionsGenerated:
          type: integer
          minimum: 0
          description: Number of commission ledger entries created
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message
        code:
          type: string
          description: Machine-readable error code
        details:
          type: object
          additionalProperties: true
          description: Additional error details
  headers:
    X-Environment:
      description: >-
        Indicates the environment (LIVE or SANDBOX) the request was processed in
        (derived from API key)
      schema:
        type: string
        enum:
          - LIVE
          - SANDBOX
  responses:
    BadRequest:
      description: Bad Request - Invalid input
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: Invalid request body
            code: VALIDATION_ERROR
            details:
              field: email
              message: Invalid email format
    Unauthorized:
      description: Unauthorized - Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missing_api_key:
              summary: Missing API key
              value:
                error: Authentication required
                code: UNAUTHORIZED
            invalid_api_key:
              summary: Invalid API key
              value:
                error: Invalid API key
                code: INVALID_API_KEY
    RateLimited:
      description: Too Many Requests - Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: Rate limit exceeded. Try again in 60 seconds.
            code: RATE_LIMITED
      headers:
        Retry-After:
          description: Seconds until rate limit resets
          schema:
            type: integer
        X-RateLimit-Remaining:
          description: Remaining requests in the current window
          schema:
            type: integer
        X-RateLimit-Reset:
          description: Unix timestamp (seconds) when the rate limit window resets
          schema:
            type: integer
    InternalError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: An unexpected error occurred
            code: INTERNAL_ERROR
  securitySchemes:
    TenantApiKey:
      type: apiKey
      in: header
      name: x-tenant-api-key
      description: >
        Tenant API key for authentication. Keys are scoped to specific
        environments

        (LIVE or SANDBOX). Obtain keys from the admin dashboard.

````