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

# Creator Affiliate Links — Trackable Links Per Creator

> Mint a permanent, stable tracking link for each of your creators per campaign. Creators share the link in their content; every click creates a new tracked transaction, so any number of their audience can claim and complete the same offer. Completions and payouts attribute back to the creator automatically, and a stats endpoint powers your own creator dashboard.

## Overview

If your platform hosts **creators** — influencers, streamers, newsletter authors, affiliates — you can give each of them a **permanent, trackable link per campaign**. The creator drops that link into their content; **every click creates a new tracked transaction**, so any number of their audience can claim and complete the same offer from that one link. Completions and payouts attribute back to the creator automatically, and a stats endpoint powers your own creator dashboard.

The integration is two REST calls: [mint the links](#endpoint-1-mint-creator-links) for a creator (safe to call on every dashboard load — it's idempotent), and [read the stats](#endpoint-2-creator-stats) for a creator to render their performance. Encore owns the link, the redirect, the transaction, and the attribution; you own the creator identity and the dashboard.

<Note>
  **One creator, one link per campaign, unlimited claims.** A creator link is not a single-use coupon. It is a permanent tracking link — each click spins up a fresh transaction and 302-redirects to the offer, so the same link works for the creator's entire audience. Multiple claims **and** multiple completions from one link are expected and correct (see [Link semantics](#link-semantics)).
</Note>

***

## How it works

```mermaid theme={null}
sequenceDiagram
    participant You as Your platform
    participant Creator
    participant Encore
    participant Fan as Creator's audience
    participant Advertiser

    You->>Encore: POST /creators/links { creatorId }
    Encore-->>You: { links: [ { campaignId, linkUrl, ... } ] }
    You->>Creator: surface linkUrl in your creator dashboard
    Creator->>Fan: shares linkUrl in their content
    Fan->>Encore: clicks link.encorekit.com short link
    Encore->>Encore: create a new transaction (per click)
    Encore-->>Fan: 302 → advertiser
    Fan->>Advertiser: converts
    Advertiser->>Encore: conversion postback
    Encore->>Encore: verify + attribute payout to creator
    You->>Encore: GET /creators/{creatorId}/stats
    Encore-->>You: { campaigns: [ { clicks, completions, earnings } ], totals }
```

The model is deliberately simple:

1. **Mint the links.** Call `/creators/links` with your own opaque `creatorId`. You get back one stable `linkUrl` per campaign your app is entitled to. Call it on every dashboard load — it's idempotent, so the same creator always gets the same links.
2. **The creator shares the link.** They drop `linkUrl` into their content — a bio, a video description, a post, a newsletter. It never expires.
3. **Every click is a new transaction.** Each open of the link creates a fresh transaction and 302-redirects to the offer with attribution. Any number of the creator's audience can claim and complete from the same link.
4. **Read the stats.** Call `/creators/{creatorId}/stats` to render the creator's clicks, completions, and earnings in your own dashboard. Real-time.

***

## Authentication

Pass the publishable key Encore provides you in the `X-API-Key` header.

```bash theme={null}
X-API-Key: pk_live_...
```

Use `pk_test_...` against the sandbox project, `pk_live_...` against production. Same key shape as our iOS / Android / Web SDKs and the [`/offers/feed`](/publishers/offers-api/feed) endpoint. These endpoints use **publishable-key auth only** — no HMAC.

Integrating directly over REST? Create a single app with platform **API** in the [dashboard](https://dashboard.encorekit.com) — you get one publishable key. If that key spans multiple platform-specific apps (a multi-app project), also send an `X-Platform` header so Encore knows which app to resolve; otherwise the request is rejected with `X-Platform header required for multi-app projects`:

```bash theme={null}
X-Platform: api   # one of: ios | android | web | api
```

A single-app key does not need `X-Platform`.

<Note>
  The **test** key (`pk_test_...`) mints links and returns stats for development but does **no click or conversion tracking** — clicks against a test-key link are accepted but not counted. Use `pk_live_...` for anything that should show up in your dashboard.
</Note>

***

## Endpoint 1 — mint creator links

Mint (or fetch) the tracking links for one creator. **Idempotent**: the same `creatorId` always returns the same `linkUrl` per campaign, so it is safe to call on every dashboard load. Links are minted for the campaigns **enabled for your app**, returned in your **configured campaign order** — you control both from the portal/admin (see the ordering note below). Each entry is catalog-grade: everything you need to render a rich offer card.

```http theme={null}
POST https://api.encorekit.com/encore/publisher/sdk/v1/creators/links
Content-Type: application/json
```

```json theme={null}
{
  "creatorId": "creator_abc123"
}
```

### Try it with curl

Drop in your publishable key and run.

```bash theme={null}
# X-Platform is only needed for multi-app projects — single-app keys can omit it.
curl --location --request POST 'https://api.encorekit.com/encore/publisher/sdk/v1/creators/links' \
  --header 'X-API-Key: YOUR_API_KEY' \
  --header 'X-Platform: api' \
  --header 'Content-Type: application/json' \
  --data '{
    "creatorId": "creator_abc123"
  }'
```

| Field       | Type   | Required | Notes                                                                                                                                                                                                                                      |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `creatorId` | string | ✓        | Your own opaque identifier for the creator — any stable id from your system (1–128 chars). It's the key everything attributes to; reuse the same value to get the same links back and to read the creator's stats. Never end-user-visible. |

### Response

Each entry is a full, catalog-grade offer — the same presentation fields as [`/offers/catalog`](/publishers/offer-catalog/integration) (logo, perk, badge, prices, the advertiser `organization`, and the `creatives` set) — **plus** a `payout` block and the creator's `linkUrl`. The one catalog field it drops is the per-creative `clickUrl`: for creator links the tracking link lives once at the **entry level** (`linkUrl`), not per creative.

```json theme={null}
{
  "creatorId": "creator-123",
  "links": [
    {
      "campaignId": "550e8400-e29b-41d4-a716-446655440000",
      "linkUrl": "https://link.encorekit.com/aB3xK9mQ2p",
      "payout": { "amount": 5.00, "currency": "USD", "model": "CPA" },
      "name": "Summer Sale",
      "perk": "3 months of Hulu free",
      "badgeLabel": "free_trial",
      "oldPrice": "$9.99",
      "newPrice": "$0.00",
      "categories": [
        { "id": "d4e5f6a7-0000-4000-8000-000000000001", "name": "Streaming" }
      ],
      "targetCountries": ["US", "GB"],
      "organization": {
        "id": "a1b2c3d4-0000-4000-8000-000000000001",
        "name": "Acme Corp",
        "description": "Streaming, music, and more.",
        "url": "https://acme.com",
        "logoUrl": "https://cdn.encorekit.com/org/acme/logo.png"
      },
      "creatives": [
        {
          "id": "c1d2e3f4-0000-4000-8000-000000000001",
          "title": "Get 3 months of Hulu free",
          "subtitle": "Summer Sale",
          "description": "Limited-time offer for new subscribers.",
          "primaryImageUrl": "https://cdn.encorekit.com/creative/hero.png",
          "logoUrl": "https://cdn.encorekit.com/creative/logo.png",
          "additionalImages": ["https://cdn.encorekit.com/creative/alt.png"],
          "ctaText": "Claim now",
          "supportedPlatforms": ["ios", "android"]
        }
      ]
    }
  ]
}
```

| Field                                    | Type                      | Notes                                                                                                                                                                                                                                                                                     |
| ---------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `creatorId`                              | string                    | Echoes the `creatorId` you sent.                                                                                                                                                                                                                                                          |
| `links`                                  | array                     | One entry per campaign — the campaigns **enabled for your app**, in your **configured order** (see the ordering note below). **Empty array** when your app has no eligible campaigns.                                                                                                     |
| `links[].campaignId`                     | UUID                      | The campaign this link points to. Use it to correlate with the [stats endpoint](#endpoint-2-creator-stats), which is keyed by the same `campaignId`.                                                                                                                                      |
| `links[].linkUrl`                        | URL                       | The creator's permanent tracking link on the fixed host `link.encorekit.com` (10-char slug). Stable per `creatorId` per campaign — safe to cache and to render on every dashboard load. Never expires. **This is the entry-level replacement for the catalog's per-creative `clickUrl`.** |
| `links[].payout`                         | object                    | What you earn on this campaign. Not present in the catalog response — it's added here so you can show creators the value.                                                                                                                                                                 |
| `links[].payout.amount`                  | number                    | The **publisher's share per completion** — same semantics as `earnings` on the [stats endpoint](#endpoint-2-creator-stats).                                                                                                                                                               |
| `links[].payout.currency`                | ISO-4217                  | Currency of `payout.amount`. Currently always `"USD"`.                                                                                                                                                                                                                                    |
| `links[].payout.model`                   | string                    | Payout model — one of `CPA` \| `CPC` \| `CPI` \| `CPM`.                                                                                                                                                                                                                                   |
| `links[].name`                           | string                    | The offer name (catalog parity — this is the former `campaignTitle`). Surface it to the creator so they know which offer they're promoting.                                                                                                                                               |
| `links[].perk`                           | string \| null            | The value proposition (e.g. `"3 months of Hulu free"`).                                                                                                                                                                                                                                   |
| `links[].badgeLabel`                     | string \| null            | A UI badge hint — one of `free_trial` \| `discount`, or `null`.                                                                                                                                                                                                                           |
| `links[].oldPrice`                       | string \| null            | Display price before the offer (e.g. `"$9.99"`), or `null`.                                                                                                                                                                                                                               |
| `links[].newPrice`                       | string \| null            | Display price with the offer (e.g. `"$0.00"`), or `null`.                                                                                                                                                                                                                                 |
| `links[].categories`                     | array                     | The campaign's categories — **additive beyond catalog parity** (the catalog response does not carry this). Each has an `id` and `name`; use them to power filter tabs on your offer wall. May be empty.                                                                                   |
| `links[].categories[].id`                | UUID                      | Category id.                                                                                                                                                                                                                                                                              |
| `links[].categories[].name`              | string                    | Category display name (e.g. `"Streaming"`).                                                                                                                                                                                                                                               |
| `links[].targetCountries`                | array of ISO-3166 alpha-2 | Where this campaign converts (e.g. `["US", "GB"]`). Surface it to the creator so they can pick offers matching their audience.                                                                                                                                                            |
| `links[].organization`                   | object                    | The advertiser (catalog parity).                                                                                                                                                                                                                                                          |
| `links[].organization.id`                | UUID                      | Advertiser id.                                                                                                                                                                                                                                                                            |
| `links[].organization.name`              | string                    | The advertiser / brand name (catalog parity — this is the former `brandName`).                                                                                                                                                                                                            |
| `links[].organization.description`       | string \| null            | About the advertiser.                                                                                                                                                                                                                                                                     |
| `links[].organization.url`               | URL \| null               | The advertiser's site.                                                                                                                                                                                                                                                                    |
| `links[].organization.logoUrl`           | URL \| null               | The advertiser's logo.                                                                                                                                                                                                                                                                    |
| `links[].creatives`                      | array                     | The **full active set** of creatives for this offer (catalog parity, minus each creative's `clickUrl`). Your client picks which to render as primary.                                                                                                                                     |
| `links[].creatives[].id`                 | UUID                      | Creative id.                                                                                                                                                                                                                                                                              |
| `links[].creatives[].title`              | string                    | Creative headline.                                                                                                                                                                                                                                                                        |
| `links[].creatives[].subtitle`           | string \| null            | Creative subtitle.                                                                                                                                                                                                                                                                        |
| `links[].creatives[].description`        | string \| null            | Creative body copy.                                                                                                                                                                                                                                                                       |
| `links[].creatives[].primaryImageUrl`    | URL \| null               | Hero image.                                                                                                                                                                                                                                                                               |
| `links[].creatives[].logoUrl`            | URL \| null               | Creative logo.                                                                                                                                                                                                                                                                            |
| `links[].creatives[].additionalImages`   | array of URL              | Extra images; may be empty.                                                                                                                                                                                                                                                               |
| `links[].creatives[].ctaText`            | string                    | Call-to-action label (e.g. `"Claim now"`).                                                                                                                                                                                                                                                |
| `links[].creatives[].supportedPlatforms` | array                     | Which surfaces this creative supports (`ios` / `android` / `web`). Use it to curate to the end user's platform when you serve a mixed audience.                                                                                                                                           |

All fields mirror [`/offers/catalog`](/publishers/offer-catalog/integration) except those called out above — the entry-level `linkUrl` (replacing per-creative `clickUrl`), the added `payout` block, and `categories` (additive; not in the catalog response). Nullable catalog fields stay `null` here just as they do in the catalog.

<Note>
  **You control which campaigns appear, and in what order.** `links` contains only the campaigns **enabled for your app**, returned in the **campaign order you configure in the portal/admin** — manual priority overrides are honored. Enable/disable campaigns and reorder them from the dashboard; the response reflects it on the next call.
</Note>

<Note>
  **`targetCountries` tells your creators where an offer converts.** Surface it in your dashboard so creators can pick campaigns that match their audience. Clicks from **outside** a campaign's target countries may not convert — a link shared to the wrong geo will still open and create a transaction, but it won't complete.
</Note>

<Note>
  **Build your offer wall from one call.** Each entry carries everything you need to render a rich offer card — the advertiser `organization` (name + `logoUrl`), `perk`, `badgeLabel`, `oldPrice`/`newPrice`, `payout`, and the `creatives` — with the same field vocabulary as [`/offers/catalog`](/publishers/offer-catalog/integration), plus `categories` for filter tabs. Two patterns publishers commonly build on top:

  * **Vanity links** — mount a pretty route on your own domain (e.g. `you.com/go/summer`) that 302-redirects to the entry's `linkUrl`. The creator shares your branded URL; attribution is unchanged.
  * **Branded claim page** — host your own offer page (your card + a "Claim" button) that sends the tap to `linkUrl`, which then 302s to the advertiser. Your brand, Encore's attribution.
</Note>

<Note>
  **Idempotent — call it freely.** Because the same `creatorId` always returns the same `linkUrl` per campaign, you don't need to store the links yourself. Call `/creators/links` on every dashboard load and render whatever comes back; new campaigns your app becomes entitled to simply appear as new entries.
</Note>

***

## Link semantics

A creator link is a **permanent tracking link**, not a single-use code. Each click behaves independently:

```mermaid theme={null}
sequenceDiagram
    participant Creator
    participant Fan as Fan (any number)
    participant Link as link.encorekit.com
    participant Encore
    participant Advertiser

    Creator->>Fan: shares one linkUrl
    Fan->>Link: clicks (each click, any fan)
    Link->>Encore: create a NEW transaction
    Encore-->>Fan: 302 → advertiser
    Fan->>Advertiser: claims + completes the offer
    Advertiser->>Encore: conversion postback
    Encore->>Encore: verify → mark completed → attribute payout to creator
```

* **Each click 302s to the offer with a fresh transaction id embedded.** One click, one transaction. The link is never "used up."
* **Multiple claims and multiple completions per link are expected and correct.** If a creator's link is clicked a thousand times, that's a thousand transactions — every one attributable, every completion counted toward the creator.
* **Attribution is automatic.** Because the transaction carries the creator, every completion and payout rolls up to that `creatorId` with no extra call from you.
* **Links never expire.** The same `linkUrl` keeps working for as long as the campaign is live.

***

## Endpoint 2 — creator stats

Read a creator's real-time performance, broken down per campaign, plus totals and a daily time series. Use it to render the creator's dashboard — the `daily` series is chart-ready.

```http theme={null}
GET https://api.encorekit.com/encore/publisher/sdk/v1/creators/{creatorId}/stats
```

### Query parameters

Both date bounds are optional. Omit them for all-time stats, or pass a `startDate` / `endDate` window to scope everything the endpoint returns — per-campaign aggregates, `totals`, **and** the `daily` series are all filtered to the range.

| Param       | Type         | Required | Notes                                                      |
| ----------- | ------------ | -------- | ---------------------------------------------------------- |
| `startDate` | `YYYY-MM-DD` | —        | Inclusive lower bound (UTC date). Omit for no lower bound. |
| `endDate`   | `YYYY-MM-DD` | —        | Inclusive upper bound (UTC date). Omit for no upper bound. |

A malformed date or a `startDate` later than `endDate` returns a **400**. Absent bounds mean all-time.

### Try it with curl

```bash theme={null}
# X-Platform is only needed for multi-app projects — single-app keys can omit it.
# startDate / endDate are optional — omit both for all-time stats.
curl --location --request GET \
  'https://api.encorekit.com/encore/publisher/sdk/v1/creators/creator_abc123/stats?startDate=2026-07-01&endDate=2026-07-16' \
  --header 'X-API-Key: YOUR_API_KEY' \
  --header 'X-Platform: api'
```

### Response

```json theme={null}
{
  "creatorId": "creator_abc123",
  "startDate": "2026-07-01",
  "endDate": "2026-07-16",
  "currency": "USD",
  "campaigns": [
    {
      "campaignId": "550e8400-e29b-41d4-a716-446655440000",
      "campaignTitle": "Acme Pro — 3 months free",
      "clicks": 1204,
      "completions": 87,
      "earnings": 261.00
    }
  ],
  "totals": {
    "clicks": 1204,
    "completions": 87,
    "earnings": 261.00
  },
  "daily": [
    { "date": "2026-07-15", "clicks": 312, "completions": 21, "earnings": 63.00 },
    { "date": "2026-07-16", "clicks": 289, "completions": 19, "earnings": 57.00 }
  ]
}
```

| Field                       | Type                   | Notes                                                                                                                                                                                                                                                                                                                                                                                   |
| --------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `creatorId`                 | string                 | Echoes the `creatorId` from the path.                                                                                                                                                                                                                                                                                                                                                   |
| `startDate`                 | `YYYY-MM-DD` \| absent | Echoes the `startDate` query param — **present only when you supplied one**; omitted entirely for all-time.                                                                                                                                                                                                                                                                             |
| `endDate`                   | `YYYY-MM-DD` \| absent | Echoes the `endDate` query param — **present only when you supplied one**; omitted entirely for all-time.                                                                                                                                                                                                                                                                               |
| `currency`                  | ISO-4217               | Currency for **every** `earnings` value in this response (per-campaign, `totals`, and `daily`). Currently always `"USD"`.                                                                                                                                                                                                                                                               |
| `campaigns`                 | array                  | Per-campaign breakdown, filtered to the date range when provided. Campaigns with **zero activity in range are dropped** — only campaigns with at least one click or completion appear. **Empty array** for a creator with no activity in range (or an unknown `creatorId` — see below). Correlate each entry with the [mint endpoint](#endpoint-1-mint-creator-links) via `campaignId`. |
| `campaigns[].campaignId`    | UUID                   | The campaign these numbers belong to. Same id as `links[].campaignId` from the mint endpoint.                                                                                                                                                                                                                                                                                           |
| `campaigns[].campaignTitle` | string                 | Human-readable campaign name.                                                                                                                                                                                                                                                                                                                                                           |
| `campaigns[].clicks`        | integer                | Link opens for this creator on this campaign. **Each open creates a transaction**, so this counts every click, not unique users.                                                                                                                                                                                                                                                        |
| `campaigns[].completions`   | integer                | Verified conversions attributed to this creator on this campaign.                                                                                                                                                                                                                                                                                                                       |
| `campaigns[].earnings`      | number                 | Your revenue share attributed to this creator on this campaign, in the top-level `currency`.                                                                                                                                                                                                                                                                                            |
| `totals.clicks`             | integer                | Sum of `clicks` across all campaigns for this creator, within the date range.                                                                                                                                                                                                                                                                                                           |
| `totals.completions`        | integer                | Sum of `completions` across all campaigns for this creator, within the date range.                                                                                                                                                                                                                                                                                                      |
| `totals.earnings`           | number                 | Sum of `earnings` across all campaigns, in the top-level `currency`. Because that's currently always `"USD"`, this is a straight sum with no conversion.                                                                                                                                                                                                                                |
| `daily`                     | array                  | Per-day time series **aggregated across all campaigns**, within the date range — ready to plot as a creator-performance chart. One entry per day **that has activity** (zero-activity days are omitted), ascending by `date`. **Empty array** when there's no activity in range.                                                                                                        |
| `daily[].date`              | `YYYY-MM-DD`           | The UTC day this row aggregates.                                                                                                                                                                                                                                                                                                                                                        |
| `daily[].clicks`            | integer                | Clicks on this day, across all campaigns.                                                                                                                                                                                                                                                                                                                                               |
| `daily[].completions`       | integer                | Completions on this day, across all campaigns.                                                                                                                                                                                                                                                                                                                                          |
| `daily[].earnings`          | number                 | Earnings on this day, across all campaigns, in the top-level `currency`.                                                                                                                                                                                                                                                                                                                |

<Note>
  **Which day a metric lands on.** `clicks` count on the transaction's **created** date. `completions` and `earnings` count on the **completion (verification) date** — the completion timestamp, falling back to the transaction's last-updated time when a completion timestamp isn't set. So a click on the 1st that completes on the 3rd shows its click on the 1st and its completion + earnings on the 3rd. All dates are **UTC**, and this is what the `daily` series and the `startDate`/`endDate` filter operate on.
</Note>

<Note>
  **Real-time, and safe for brand-new creators.** Stats update as clicks and completions land. An **unknown `creatorId`** returns a **200** with an empty `campaigns` array, zeroed `totals`, and an empty `daily` array — **not a 404** — so you can call it for a creator who has never shared a link yet and render an empty dashboard without special-casing.
</Note>

***

## End-to-end example

A small **creator dashboard backend**: fetch a creator's links, render the `linkUrl` list, then fetch that creator's stats. Both endpoints use publishable-key auth only — no HMAC.

<CodeGroup>
  ```js Node.js theme={null}
  const API_BASE = "https://api.encorekit.com/encore/publisher/sdk/v1";
  const API_KEY = process.env.ENCORE_API_KEY; // pk_live_... (or pk_test_... in sandbox)

  const headers = {
    "X-API-Key": API_KEY,
    "X-Platform": "api", // only needed for multi-app projects; omit for single-app keys
    "Content-Type": "application/json",
  };

  // 1. Mint (or fetch) this creator's links — idempotent, safe on every dashboard load.
  async function getCreatorLinks(creatorId) {
    const res = await fetch(`${API_BASE}/creators/links`, {
      method: "POST",
      headers,
      body: JSON.stringify({ creatorId }),
    });
    if (!res.ok) throw new Error(`links failed: ${res.status}`);
    const { links } = await res.json();
    return links; // [{ campaignId, linkUrl, payout, name, perk, badgeLabel, oldPrice, newPrice, targetCountries, organization, creatives }]
  }

  // 2. Read this creator's stats. startDate / endDate are optional (YYYY-MM-DD,
  //    UTC) — omit both for all-time. They scope campaigns, totals, and daily.
  async function getCreatorStats(creatorId, { startDate, endDate } = {}) {
    const qs = new URLSearchParams();
    if (startDate) qs.set("startDate", startDate);
    if (endDate) qs.set("endDate", endDate);
    const query = qs.toString() ? `?${qs}` : "";
    const res = await fetch(
      `${API_BASE}/creators/${encodeURIComponent(creatorId)}/stats${query}`,
      { method: "GET", headers }
    );
    if (!res.ok) throw new Error(`stats failed: ${res.status}`);
    return res.json(); // { creatorId, startDate?, endDate?, currency, campaigns, totals, daily }
  }

  async function renderCreatorDashboard(creatorId) {
    const [links, stats] = await Promise.all([
      getCreatorLinks(creatorId),
      // Scope to a window; drop the 2nd arg for all-time stats.
      getCreatorStats(creatorId, { startDate: "2026-07-01", endDate: "2026-07-16" }),
    ]);

    // Render the shareable links — surface targetCountries so the creator can
    // pick offers that match their audience.
    for (const link of links) {
      const geo = link.targetCountries.join(", ");
      console.log(`${link.name} (${link.organization.name}) — ${link.perk} — converts in ${geo}`);
      console.log(`  payout: $${link.payout.amount.toFixed(2)} ${link.payout.model} · share: ${link.linkUrl}`);
    }

    // Render performance.
    console.log(
      `Totals — clicks: ${stats.totals.clicks}, ` +
      `completions: ${stats.totals.completions}, ` +
      `earnings: $${stats.totals.earnings.toFixed(2)}`
    );

    // Chart the daily series — one point per day, already aggregated across campaigns.
    const chartPoints = stats.daily.map((d) => ({ x: d.date, y: d.clicks }));
    console.log(`Daily click series (${chartPoints.length} points):`, chartPoints);
  }

  renderCreatorDashboard("creator_abc123").catch(console.error);
  ```

  ```python Python theme={null}
  import os
  from urllib.parse import quote

  import requests

  API_BASE = "https://api.encorekit.com/encore/publisher/sdk/v1"
  API_KEY = os.environ["ENCORE_API_KEY"]  # pk_live_... (or pk_test_... in sandbox)

  HEADERS = {
      "X-API-Key": API_KEY,
      "X-Platform": "api",  # only needed for multi-app projects; omit for single-app keys
      "Content-Type": "application/json",
  }


  def get_creator_links(creator_id):
      """Mint (or fetch) this creator's links — idempotent, safe on every dashboard load."""
      res = requests.post(
          f"{API_BASE}/creators/links",
          headers=HEADERS,
          json={"creatorId": creator_id},
      )
      res.raise_for_status()
      return res.json()["links"]  # [{ campaignId, linkUrl, payout, name, perk, badgeLabel, oldPrice, newPrice, targetCountries, organization, creatives }]


  def get_creator_stats(creator_id, start_date=None, end_date=None):
      """Read this creator's stats.

      start_date / end_date are optional (YYYY-MM-DD, UTC) — omit both for
      all-time. They scope campaigns, totals, and the daily series.
      """
      params = {}
      if start_date:
          params["startDate"] = start_date
      if end_date:
          params["endDate"] = end_date
      res = requests.get(
          f"{API_BASE}/creators/{quote(creator_id, safe='')}/stats",
          headers=HEADERS,
          params=params,
      )
      res.raise_for_status()
      return res.json()  # { creatorId, startDate?, endDate?, currency, campaigns, totals, daily }


  def render_creator_dashboard(creator_id):
      links = get_creator_links(creator_id)
      # Scope to a window; drop the dates for all-time stats.
      stats = get_creator_stats(creator_id, start_date="2026-07-01", end_date="2026-07-16")

      # Render the shareable links — surface targetCountries so the creator can
      # pick offers that match their audience.
      for link in links:
          geo = ", ".join(link["targetCountries"])
          payout = link["payout"]
          print(f'{link["name"]} ({link["organization"]["name"]}) — {link["perk"]} — converts in {geo}')
          print(f'  payout: ${payout["amount"]:.2f} {payout["model"]} · share: {link["linkUrl"]}')

      # Render performance.
      totals = stats["totals"]
      print(
          f'Totals — clicks: {totals["clicks"]}, '
          f'completions: {totals["completions"]}, '
          f'earnings: ${totals["earnings"]:.2f}'
      )

      # Chart the daily series — one point per day, already aggregated across campaigns.
      chart_points = [(d["date"], d["clicks"]) for d in stats["daily"]]
      print(f"Daily click series ({len(chart_points)} points): {chart_points}")


  if __name__ == "__main__":
      render_creator_dashboard("creator_abc123")
  ```
</CodeGroup>

***

## Status codes

| Code          | Meaning                                                                                                                                                                                                                                                                                                               |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200`         | Success. On `/creators/links`, `links` may be an empty array if your app has no eligible campaigns. On `/creators/{creatorId}/stats`, an unknown `creatorId` returns 200 with an empty `campaigns` array and zeroed `totals` — never a 404.                                                                           |
| `400`         | Malformed request — `creatorId` missing or longer than 128 chars, a malformed `startDate` / `endDate` (not `YYYY-MM-DD`), or `startDate` later than `endDate`. Also returned as `X-Platform header required for multi-app projects` when a multi-app key omits the `X-Platform` header. Don't retry; fix the request. |
| `401`         | Missing or invalid `X-API-Key`.                                                                                                                                                                                                                                                                                       |
| `429`         | Rate-limited. Back off + retry.                                                                                                                                                                                                                                                                                       |
| `503`         | Server temporarily over capacity. Retry with backoff.                                                                                                                                                                                                                                                                 |
| `5xx` (other) | Encore-side failure — surface a soft error in your dashboard and retry.                                                                                                                                                                                                                                               |
