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

# Affiliate programme

> Read partners, conversions, and payouts, invite partners, and react to affiliate webhooks.

Use the affiliate endpoints to sync your partner programme with your own systems: list partners, track attributed orders, and follow payouts.

<Info>
  Your store must be approved for the affiliate programme. Apply in the dashboard under **Affiliates**. Until then, every affiliate endpoint returns `403` with code `FEATURE_NOT_ENABLED`.
</Info>

## Endpoints

| Method | Path | Description |
| :- | :- | :- |
| `GET` | `/affiliates/partners` | List partners. Filter by `status` or search with `q`. |
| `POST` | `/affiliates/partners` | Invite a partner by email. The partner is active at once. |
| `GET` | `/affiliates/conversions` | List attributed orders with the commission state of each. |
| `GET` | `/affiliates/payouts` | List payout requests. Open requests come first. |

Approving partners, reviewing flagged conversions, and sending payouts stay in the dashboard.

## Amounts and IDs

* Amounts in API responses are integers in minor units. `commission: 499` in `USD` is \$4.99.
* Webhook payloads use major units. `commission: 4.99` is \$4.99.
* Partners and payouts use 16-character public IDs. Conversions use the order's public `invoice_id`.

## Pagination

List endpoints return 25 items per page with a `next_cursor`. Pass it back as `cursor` to get the next page. `next_cursor` is `null` on the last page.

```bash theme={"system"}
curl "https://app.papelship.com/api/v1/affiliates/conversions?status=valid&cursor=1832" \
  -H "x-api-key: your_api_key" \
  -H "x-store-hash: your_store_hash"
```

Each list also returns `counts`, the number of records per status:

```json theme={"system"}
{
  "success": true,
  "conversions": [ ... ],
  "next_cursor": 1807,
  "counts": { "valid": 40, "flagged": 2, "rejected": 1 }
}
```

## Invite a partner

```bash theme={"system"}
curl -X POST https://app.papelship.com/api/v1/affiliates/partners \
  -H "x-api-key: your_api_key" \
  -H "x-store-hash: your_store_hash" \
  -H "Content-Type: application/json" \
  -d '{ "email": "creator@example.com", "name": "Alex Creator" }'
```

```json Response (201) theme={"system"}
{ "success": true, "id": "7fKq2LmN9xPa3RtB" }
```

Read-only keys cannot invite partners.

## How orders are attributed

An order is credited to a partner in one of these ways, in priority order:

1. **Partner coupon.** The buyer used a coupon bound to the partner.
2. **Tracking link.** The buyer opened a partner link: `https://your-store.com/any-page?ref=CODE` or `https://your-store.com/r/CODE`. The storefront remembers the click for the programme's cookie window.
3. **API.** You passed `affiliateCode` when creating the invoice. The conversion has `source: "api"`.

The conversion is rejected when the buyer is the partner, or when another coupon is used and the programme does not allow coupon stacking. It is flagged for review when the order has a high fraud score or the partner gets an unusual number of orders in a short time.

## Commission states

| `commission_state` | Meaning |
| :- | :- |
| `unpaid` | The order is not completed yet. |
| `held` | Flagged. Waiting for your review in the dashboard. |
| `pending` | Inside the hold period. See `available_at`. |
| `available` | The partner can request a payout. |
| `none` | The conversion was rejected. |

Refunds reverse the commission automatically. `commission` is always the net amount.

## Webhooks

Subscribe to these events in **Developers › Webhooks**. They use the same envelope and `PapelShip-Signature` header as order events.

| Event | When |
| :- | :- |
| `affiliate.partner_applied` | Someone applies to your programme from the storefront. |
| `affiliate.conversion` | An attributed order completes and the commission is recorded. Sent once per order. |
| `affiliate.payout_requested` | A partner requests a payout. |
| `affiliate.payout_sent` | You mark a payout as sent. |

```json affiliate.conversion theme={"system"}
{
  "id": "evt_9b2c...",
  "object": "event",
  "type": "affiliate.conversion",
  "created": 1791100000,
  "livemode": true,
  "store": { "id": "0bHQn0bU2dei", "name": "Acme", "slug": "acme" },
  "data": {
    "object": {
      "object": "affiliate_conversion",
      "order_id": "c35ffd-19a1b2c3d4e-8c7a20",
      "partner": { "id": "7fKq2LmN9xPa3RtB", "email": "creator@example.com" },
      "source": "link",
      "link_code": "alex",
      "status": "valid",
      "commission": 4.99,
      "currency": "USD",
      "available_at": "2026-10-18T12:00:00.000Z",
      "created_at": "2026-10-04T12:00:00.000Z"
    }
  }
}
```

```json affiliate.payout_sent theme={"system"}
{
  "type": "affiliate.payout_sent",
  "data": {
    "object": {
      "object": "affiliate_payout",
      "id": "Qm3vX8kL2pN7rT4w",
      "partner": { "id": "7fKq2LmN9xPa3RtB", "email": "creator@example.com" },
      "amount": 125,
      "currency": "USD",
      "method": "crypto",
      "coin": "USDT",
      "network": "TRC20",
      "amount_coin": 125.04,
      "status": "sent",
      "tx_hash": "a1b2c3...",
      "created_at": "2026-10-02T09:30:00.000Z"
    }
  }
}
```

## Errors

Affiliate errors include a machine-readable `code`:

```json theme={"system"}
{ "success": false, "code": "ALREADY_MEMBER", "error": "This email is already a partner of your store." }
```

| Code | Status | Meaning |
| :- | :- | :- |
| `FEATURE_NOT_ENABLED` | `403` | The store is not approved for the affiliate programme. |
| `INVALID_EMAIL` | `400` | The email address is not valid. |
| `ALREADY_MEMBER` | `409` | The email is already a partner of this store. |
| `BANNED` | `409` | The partner is banned from this store. |
| `NOT_FOUND` | `404` | The partner or record does not exist. |


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