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

# Move a referral to another affiliate

> Move a referred customer to another affiliate, with the same rules as the move in the dashboard. Requires `write` scope. Preview it first with POST /v1/referrals/move/preview.

`mode: forward` (from now on only): the customer's future payments credit the new affiliate, and every existing commission stays where it is. It needs the customer's email or Stripe customer id on record.

`mode: history` (include history): also moves the customer's unpaid commissions (pending, confirmed or held), at the amounts they were earned at. Paid commissions always stay with the affiliate who was paid. It is refused while any of those commissions is in a payout run that hasn't been paid; remove them from the run first.

The new affiliate must be active (not suspended, banned, archived or left) and the same kind of data as the customer (test or live). A refused move changes nothing. No money moves: payouts still pay only confirmed commissions, through your own payout method.

A move changes who unpaid commissions are owed to, so it needs a REST API key: MCP connector tokens are refused with 403, as they are for the other money-bearing writes. A connector can preview the move; you apply it here with an API key, or in the dashboard.



## OpenAPI

````yaml /openapi.yaml post /v1/referrals/move
openapi: 3.1.0
info:
  title: Affixo API
  version: 1.0.0
  description: |
    The Affixo REST API for affiliate program management and server-to-server
    conversion tracking.

    All requests authenticate with a workspace key (`sa_live_…`) as a Bearer
    token. Scopes: `read` / `write` / `track` / `*`.
servers:
  - url: https://go.affixo.dev
    description: Production
security: []
tags:
  - name: Affiliates
    description: Manage affiliates (workspace key)
  - name: Campaigns
    description: Create and configure campaigns + commission rules (workspace key)
  - name: Links
    description: Manage referral links (workspace key)
  - name: Risk
    description: AI risk assessments for fraud triage (workspace key)
  - name: Commissions
    description: Approve, deny, and manage commissions (workspace key)
  - name: Conversions
    description: Re-attribute and manage conversions (workspace key)
  - name: Webhooks
    description: Manage webhook endpoint subscriptions (workspace key)
  - name: Reports
    description: Aggregated reporting data (workspace key)
  - name: Resources
    description: Read campaigns, commissions, conversions, payouts (workspace key)
  - name: Referrals
    description: >-
      Move a referred customer to another affiliate, and send test referrals
      (workspace key)
  - name: Tracking
    description: >-
      Server-to-server click & conversion tracking (workspace key, scope
      "track")
  - name: Products
    description: >-
      Your Stripe product catalog and which products earn commission (workspace
      key)
paths:
  /v1/referrals/move:
    post:
      tags:
        - Referrals
      summary: Move a referral to another affiliate
      description: >-
        Move a referred customer to another affiliate, with the same rules as
        the move in the dashboard. Requires `write` scope. Preview it first with
        POST /v1/referrals/move/preview.


        `mode: forward` (from now on only): the customer's future payments
        credit the new affiliate, and every existing commission stays where it
        is. It needs the customer's email or Stripe customer id on record.


        `mode: history` (include history): also moves the customer's unpaid
        commissions (pending, confirmed or held), at the amounts they were
        earned at. Paid commissions always stay with the affiliate who was paid.
        It is refused while any of those commissions is in a payout run that
        hasn't been paid; remove them from the run first.


        The new affiliate must be active (not suspended, banned, archived or
        left) and the same kind of data as the customer (test or live). A
        refused move changes nothing. No money moves: payouts still pay only
        confirmed commissions, through your own payout method.


        A move changes who unpaid commissions are owed to, so it needs a REST
        API key: MCP connector tokens are refused with 403, as they are for the
        other money-bearing writes. A connector can preview the move; you apply
        it here with an API key, or in the dashboard.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/ReferralMoveTarget'
                - type: object
                  required:
                    - mode
                  properties:
                    mode:
                      type: string
                      enum:
                        - forward
                        - history
      responses:
        '200':
          description: The move
          content:
            application/json:
              schema:
                type: object
                properties:
                  object:
                    type: string
                    example: referral_move
                  data:
                    type: object
                    properties:
                      reassignment_id:
                        type: string
                        format: uuid
                      referral_id:
                        type:
                          - string
                          - 'null'
                        format: uuid
                      mode:
                        type: string
                        enum:
                          - forward
                          - history
                      from_affiliate_id:
                        type: string
                        format: uuid
                      to_affiliate_id:
                        type: string
                        format: uuid
                      conversions_moved:
                        type: integer
                      commissions_moved:
                        type: integer
                      moved_totals:
                        $ref: '#/components/schemas/MoneyTotals'
                      paid_stayed:
                        type: integer
                      paid_totals:
                        $ref: '#/components/schemas/MoneyTotals'
                      kept_unpaid:
                        type: integer
                      credits_future_payments:
                        type: boolean
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/DashboardLocked'
        '403':
          $ref: '#/components/responses/InsufficientScope'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: >-
            The move was refused and nothing changed: a commission is in an
            unpaid payout run (history), the customer has no email or Stripe
            customer id (forward), or the referral already belongs to that
            affiliate.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: move_refused
                  message:
                    type: string
                    example: >-
                      1 of these commissions is in a payout run that hasn't been
                      paid yet. Remove it from that run first, then move the
                      referral.
                  hint:
                    type: string
        '422':
          $ref: '#/components/responses/MoveTargetIneligible'
      security:
        - WorkspaceKey: []
components:
  schemas:
    ReferralMoveTarget:
      type: object
      required:
        - to_affiliate_id
      description: >-
        Name the customer by `referral_id` or by one of their sales with
        `conversion_id`.
      properties:
        to_affiliate_id:
          type: string
          format: uuid
        conversion_id:
          type: string
          format: uuid
        referral_id:
          type: string
          format: uuid
    MoneyTotals:
      type: array
      description: One total per currency.
      items:
        type: object
        properties:
          currency:
            type: string
            example: usd
          amount:
            type: number
            example: 90
    Error:
      type: object
      properties:
        error:
          type: string
        need:
          type: string
          description: Present on insufficient_scope.
        detail:
          type: string
  responses:
    BadRequest:
      description: Invalid or missing parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: invalid_json
    Unauthorized:
      description: Missing or invalid bearer token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: unauthorized
    DashboardLocked:
      description: >-
        Your plan's dashboard and management access is locked until you upgrade.
        Tracking keeps working.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: plan_restricted
    InsufficientScope:
      description: The key lacks the required scope
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: insufficient_scope
            need: write
    NotFound:
      description: Resource not found / not in workspace
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: link_not_found
    MoveTargetIneligible:
      description: >-
        The new affiliate can't take this referral: not active (suspended,
        banned, archived or left), a test affiliate for a live customer (or the
        other way round), or the customer themself. Nothing changed.
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: affiliate_not_eligible
              message:
                type: string
                example: >-
                  Ray isn't an active affiliate, so they can't take over a
                  referral. Approve or restore them first.
              hint:
                type: string
  securitySchemes:
    WorkspaceKey:
      type: http
      scheme: bearer
      description: 'Workspace API key, e.g. `sa_live_…`. Scopes: read / write / track / *.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.