# Sale Tracking

> Track sales and revenue for affiliate commission attribution via Sale API or Stripe metadata. Triggers on "track sales", "payment tracking", "commission tracking".

- Skill: `affitor/sale-tracking` (Agent Skill)
- Install (CLI): `npx skillmds@latest add affitor/sale-tracking`
- Raw SKILL.md: https://api.skillmd.com/api/skills/affitor/sale-tracking/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Finance & Business
- License: MIT
- Author: affitor (https://skillmd.com/u/affitor)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/affitor/sale-tracking

---


# Sale Tracking

Record revenue after a customer pays so commissions are attributed to the correct affiliate partner.

## Option A: Sale API (any payment provider)

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

{
  "transaction_id": "txn_unique_id",
  "customer_key": "user_123",
  "amount_cents": 4900,
  "currency": "USD"
}
```

### Required fields

| Field | Type | Description |
|---|---|---|
| `transaction_id` | string | Unique per sale (duplicate = 409) |
| `amount_cents` | number | Positive integer in cents |
| `customer_key` or `click_id` | string | At least one required for attribution |

### Node.js example

```ts
await fetch('https://api.affitor.com/api/v1/track/sale', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.AFFITOR_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    transaction_id: order.id,
    customer_key: currentUser.id,
    click_id: req.cookies.affitor_click_id,
    amount_cents: order.totalCents,
    currency: 'USD',
  }),
});
```

## Option B: Stripe Metadata

Add these fields to Stripe Checkout session metadata:

```javascript
const session = await stripe.checkout.sessions.create({
  line_items: [{ price: 'price_xxx', quantity: 1 }],
  mode: 'payment',
  success_url: 'https://yoursite.com/success',
  cancel_url: 'https://yoursite.com/cancel',
  metadata: {
    affitor_click_id: clickId,
    affitor_customer_key: currentUser.id,
    program_id: 'YOUR_PROGRAM_ID',
  },
});
```

### For subscriptions

Duplicate metadata in both locations:

```javascript
const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  metadata: {
    affitor_click_id: clickId,
    affitor_customer_key: currentUser.id,
    program_id: 'YOUR_PROGRAM_ID',
  },
  subscription_data: {
    metadata: {
      affitor_click_id: clickId,
      affitor_customer_key: currentUser.id,
      program_id: 'YOUR_PROGRAM_ID',
    },
  },
});
```

Without `subscription_data.metadata`, renewal attribution will fail.

## Option C: Stripe Auto-Setup via CLI

```bash
npx affitor setup stripe
```

This auto-configures all Stripe webhooks via OAuth. No manual metadata needed for payment events.

## Test

```bash
npx affitor test sale
```

