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

# Server-Side Tracking

> Choose the right Affonso backend tracking endpoint for conversions, events, and refunds

## Overview

Use Affonso's server-side tracking endpoints when your backend already knows that
something happened and you want Affonso to:

* resolve the correct referral
* match the correct incentive rule
* calculate commissions automatically when applicable
* advance referral lifecycle state from trusted backend events
* process full or partial refunds
* enforce idempotency on retries
* emit the standard transaction webhooks

This is the recommended integration path for backend-driven affiliate tracking.

<Info>
  If you want to integrate a custom payment provider with your own backend, see
  the step-by-step Helpcenter guide:
  [Custom Backend Payment Provider Integration](https://affonso.io/help/integrations/custom/custom-payment-provider-api).
</Info>

<Info>
  If your backend events already flow through Segment, use the dedicated
  Segment adapter guide:
  [Segment Track Events](/api/segment-track-events).
</Info>

## Which Endpoint to Use

Use `POST /conversions` when:

* you want Affonso to calculate the commission for you
* you have a billing event, order, invoice, or checkout completion on your server
* you want retry-safe idempotency with `external_event_id`

Use `POST /events` when:

* you want to send a normalized event from your backend
* the event may represent a conversion, lead, trial, or milestone
* you want one endpoint for both revenue and non-revenue lifecycle events

Use `POST /conversions/{id}/refund` when:

* you already recorded a conversion in Affonso
* you need to apply a full or partial refund
* you want Affonso to update the transaction and commission state for you

Use `POST /commissions` when:

* you already know the exact commission amount
* you are importing historical payouts or backfilling data
* you need a manual override rather than incentive-based calculation

This page is intentionally the orientation layer.

Use the endpoint reference pages for the exact request and response contract.

## What You Usually Need To Send

Most server-side requests include:

* an identifier that already matches a referral in Affonso
* the event or conversion details from your backend
* a stable `external_event_id` when you want retry-safe delivery

For purchases and other conversion events, you will usually also send:

* `sale_amount`
* `sale_amount_currency`

Use the endpoint reference pages for the exact required and optional fields.

## Idempotency and Retries

`external_event_id` is the provider-side idempotency key whenever you want
retry-safe ingestion. Use a stable unique identifier from your system, such as:

* order ID

* invoice ID

* checkout session ID

* payment event ID
  Behavior by endpoint:

* `POST /conversions` stays idempotent on `external_event_id`

* `POST /events` is idempotent when `external_event_id` is present

* `POST /conversions/{id}/refund` is idempotent when `external_event_id` is present

Reuse the exact same `external_event_id` when retrying the same upstream event.

## Choosing the Identifier

Use the identifier you can trust most in your integration:

* `external_user_id`: best when you sync the user ID from your own product or app into Affonso
* `referral_id`: best when you already know the Affonso referral ID to credit
* `customer_id`: best when you want to match using the customer ID from your payment provider or billing system, such as Stripe
* `affonso_id`: still works if your existing integration already uses it

Affonso does not create attribution from the identifier alone. The identifier
must resolve to an existing referral in your team. If no referral matches, the
request is rejected.

### Recommended choice

* Start with `external_user_id` when your backend has a stable user ID from your own product or app
* Use `referral_id` when you already know the Affonso referral ID
* Use `customer_id` when you want to match with the customer ID from your payment provider or billing system
* If your existing integration already uses `affonso_id`, you can keep using it
* If you send more than one identifier, they must all point to the same referral

## Request Signing

Request signing is optional and non-breaking.

When no signing secret is configured, standard Bearer API-key requests continue
to work without extra headers.

### Environment Variables

* `S2S_REQUEST_SIGNING_SECRET`

### Required Headers for Signed Requests

* `X-Affonso-Timestamp`: Unix timestamp in seconds
* `X-Affonso-Signature`: hex `HMAC_SHA256(secret, "<timestamp>.<raw_body>")`

Replay protection window: 5 minutes.

## What Affonso Does With These Requests

When the request is valid and the identifier matches an existing referral,
Affonso uses the endpoint you chose to:

* record conversions from trusted backend events
* process lead, trial, and milestone events
* apply full or partial refunds to existing conversions
* calculate commissions automatically when the selected endpoint supports it

For exact response fields and object shapes, use the endpoint reference pages.

## Example Flows

### Backend purchase

```bash cURL theme={null}
curl -X POST "https://api.affonso.io/v1/conversions" \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cust_123",
    "sale_amount": 99.00,
    "sale_amount_currency": "USD",
    "external_event_id": "inv_2026_000145",
    "sales_status": "complete",
    "is_subscription": true,
    "interval": "monthly",
    "price_ids": ["price_monthly_usd"]
  }'
```

Use `POST /events` instead when you want one backend endpoint for non-revenue
events such as leads, trials, or milestones.

## Tracking Examples With `POST /events`

Use these examples when you want to send normalized backend events through one
Affonso endpoint.

### Example: track a signup as `lead`

```bash cURL theme={null}
curl -X POST "https://api.affonso.io/v1/events" \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "signup_completed",
    "event_type": "lead",
    "referral_id": "ref_123",
    "external_user_id": "usr_104982",
    "external_event_id": "evt_signup_001",
    "metadata": {
      "email": "daniel.harper@northstar-health.io"
    }
  }'
```

### Example: track a downstream step as `trial`

```bash cURL theme={null}
curl -X POST "https://api.affonso.io/v1/events" \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "trial_started",
    "event_type": "trial",
    "external_user_id": "usr_104982",
    "external_event_id": "evt_trial_001"
  }'
```

### Example: track a product-specific purchase as `conversion`

```bash cURL theme={null}
curl -X POST "https://api.affonso.io/v1/events" \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "invoice_paid",
    "event_type": "conversion",
    "customer_id": "cus_R8d92kLm3pQx71",
    "external_event_id": "evt_conversion_001",
    "sale_amount": 2000,
    "sale_amount_currency": "USD",
    "product_ids": ["downstream"],
    "is_subscription": false
  }'
```

### Example: track a product milestone as `milestone`

```bash cURL theme={null}
curl -X POST "https://api.affonso.io/v1/events" \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "kyc_passed",
    "event_type": "milestone",
    "external_user_id": "usr_104982",
    "external_event_id": "evt_kyc_001"
  }'
```

<Info>
  Use `trial` for non-revenue trial starts. Use `conversion` when revenue
  happened or when you need product-specific incentive matching with
  `product_ids` or `price_ids`.
</Info>

## Next Steps

<CardGroup cols={2}>
  <Card title="Conversions API Reference" icon="code" href="/api/endpoint/conversions/create">
    Full request and response field reference for POST /conversions
  </Card>

  <Card title="Events API Reference" icon="timeline" href="/api/endpoint/events/create">
    Send normalized conversion, lead, trial, and milestone events
  </Card>

  <Card title="Segment Track Events" icon="shuffle" href="/api/segment-track-events">
    Send Segment track payloads to Affonso using the dedicated source endpoint
  </Card>

  <Card title="Refund Conversion" icon="rotate-left" href="/api/endpoint/conversions/refund">
    Apply a full or partial refund to an existing conversion
  </Card>

  <Card title="Manual Commissions" icon="wallet" href="/api/endpoint/commissions/create">
    Use the manual endpoint when you need to set the commission amount yourself
  </Card>
</CardGroup>
