Track Sale

Record an attributed sale and create the partner commission from your backend

Call this endpoint from your server after a payment succeeds to record the conversion and trigger commission creation.

Endpoint

POST https://api.affitor.com/api/v1/track/sale
Authorization: Bearer YOUR_PROGRAM_API_KEY
Content-Type: application/json

Authentication

All requests require a program API key sent as a Bearer token in the Authorization header. The API key is found in your program settings in the Affitor dashboard.

Authorization: Bearer YOUR_PROGRAM_API_KEY

Request Fields

transaction_idstringRequired

Your unique payment identifier. Used for duplicate detection — re-sending the same value returns 409.

amount_centsintegerRequired

Sale amount in the smallest currency unit (e.g. cents for USD). Must be a positive integer.

customer_keystringConditional

Your internal customer/user ID, set during the signup tracking step. Used to resolve attribution. At least one of customer_key or click_id must match an existing customer record.

click_idstringConditional

The Affitor click ID (affitor_click_id cookie value). Used as fallback attribution when customer_key is not provided.

currencystringOptional

ISO 4217 currency code. Defaults to USD.

sale_typestringOptional

"payment" (default) or "subscription".

paymentsubscription
line_itemsobjectOptional

Arbitrary line-item detail to store with the sale record.

is_recurringbooleanOptional

true if this is a recurring billing charge. Defaults to false.

subscription_idstringOptional

Your subscription identifier. Required for proper recurring commission attribution.

subscription_intervalstringOptional

"monthly", "quarterly", or "annual".

monthlyquarterlyannual
product_idstringOptional

Your product identifier. Used for per-product commission policy matching.


Request Body Example

curl -X POST https://api.affitor.com/api/v1/track/sale \
-H "Authorization: Bearer YOUR_PROGRAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "transaction_id": "txn_abc123",
  "customer_key": "usr_9876",
  "amount_cents": 4900,
  "currency": "USD",
  "sale_type": "payment"
}'

Subscription example

{
  "transaction_id": "inv_sub_001",
  "customer_key": "usr_9876",
  "amount_cents": 4900,
  "currency": "USD",
  "sale_type": "subscription",
  "is_recurring": true,
  "subscription_id": "sub_stripe_xyz",
  "subscription_interval": "monthly",
  "product_id": "prod_pro_plan"
}

Response

{
"success": true,
"sale_id": 42,
"commission_id": 17,
"message": "Sale tracked successfully"
}
FieldTypeDescription
successbooleantrue on success.
sale_idintegerID of the created sale event record.
commission_idintegerID of the created commission record.
messagestringHuman-readable confirmation.
Idempotency

Re-sending the same transaction_id returns 409 Conflict — Affitor does not create a duplicate sale. This is intentional: you can safely retry on network failure by checking for 409 before treating the call as failed.

409 is not an error

A 409 response means the sale was already recorded successfully. Do not retry a 409 — treat it as a successful prior call and continue your payment flow normally.


Error Responses

StatusWhen
400transaction_id missing or not a string
400amount_cents missing, not a positive integer
400Neither customer_key nor click_id resolved a customer record
400Customer does not belong to the program identified by the API key
400No partner-program relationship found for the resolved customer
401Missing or malformed Authorization header
401API key does not match any active program
409transaction_id already recorded — duplicate sale
500Commission creation failed internally

Test Mode

Send additional_data.test_mode: true to create a test sale event without affecting production data. The API key is still required but transaction_id and amount_cents are optional in test mode.

{
  "additional_data": {
    "test_mode": true
  }
}

Test mode response:

{
  "success": true,
  "message": "Test sale event tracked successfully",
  "data": {
    "eventId": 12,
    "programId": 3,
    "test_mode": true
  }
}

Edit on GitHub
© 2026 Affitor