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

# Export AI Referrals

> Export human visits arriving from AI answer surfaces (ChatGPT, Perplexity, …) as JSON

```
POST /functions/v1/export-ai-referrals
```

<Info>
  **Beta.** This endpoint is new and its response shape may still change. It
  shares authentication, windowing, and domain scoping with
  [Export Analytics](/api-reference/endpoint/export-analytics).
</Info>

Returns a single JSON document of **AI referral traffic** for **every domain on your account** — both domains you own and domains [shared](/dashboard/analytics) with you. These are **human visitors** who arrived on your site from an AI answer surface (ChatGPT, Perplexity, Gemini, Copilot, Claude, and others), detected at the edge by the `Referer` header. For each domain it breaks the traffic down by **AI source**, by **day**, and by **landing page**.

<Warning>
  Always call this endpoint from a **server-side environment** (backend API, serverless function, build script, etc.). Never include your API key in client-side code — it will be visible to anyone inspecting your frontend.
</Warning>

<Info>
  Programmatic (API key) access requires the **Pro plan and above** — requests
  from Starter accounts return `403 plan_upgrade_required`.
</Info>

<Note>
  **These counts are a floor, not a total.** Some surfaces strip the `Referer`
  header, so those visits are invisible here. Google AI Overviews and Bing
  Copilot-in-search are also excluded on purpose: they share bare search
  hostnames (`google.com`, `bing.com`) with ordinary organic clicks, which would
  otherwise flood the channel with mis-attributed search traffic.
</Note>

## Request

### Headers

| Header          | Required | Description                    |
| --------------- | -------- | ------------------------------ |
| `Authorization` | Yes      | `Bearer hado_sk_your_key_here` |
| `Content-Type`  | Yes      | `application/json`             |

### Body Parameters

Choose the reporting window in **one of two ways** — a rolling `period`, or an explicit `startDate`/`endDate` range. The two are mutually exclusive.

| Parameter   | Type   | Required | Description                                                                                                                                                                                 |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `period`    | string | No       | Rolling window ending today: `1d`, `7d`, `30d`, `90d`, or `365d`. Defaults to `30d`. **Cannot** be combined with `startDate`/`endDate`.                                                     |
| `startDate` | string | No       | Start of an explicit date range, `YYYY-MM-DD` (UTC, inclusive).                                                                                                                             |
| `endDate`   | string | No       | End of an explicit date range, `YYYY-MM-DD` (UTC, inclusive). Optional — defaults to **today** when `startDate` is supplied. Cannot be sent without `startDate`.                            |
| `domainId`  | string | No       | Restrict the export to a single domain by its ID. Omit to export **every** domain your account can access (the default). Get IDs from [List Domains](/api-reference/endpoint/list-domains). |

**Range rules** — a request that breaks any of these returns `400 invalid_request`:

* `period` and `startDate`/`endDate` **cannot** be combined.
* `endDate` **cannot** be sent on its own — it requires a `startDate`.
* Dates must be real calendar dates in `YYYY-MM-DD` form (e.g. `2026-02-30` is rejected).
* `startDate` must not be after `endDate`, and neither may be in the future.
* The range may span at most **365 days** (inclusive), the same cap as the `365d` period.

### Example Request

```bash theme={null}
curl -X POST https://api.hadoseo.com/functions/v1/export-ai-referrals \
  -H "Authorization: Bearer hado_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "period": "30d"
  }'
```

## Response

### Success (200)

```json theme={null}
{
  "generatedAt": "2026-06-29T12:00:00.000Z",
  "period": "30d",
  "startDate": "2026-05-31",
  "endDate": "2026-06-29",
  "userId": "00000000-0000-0000-0000-000000000000",
  "domainCount": 1,
  "domains": [
    {
      "domain": "example.com",
      "domainId": "11111111-1111-1111-1111-111111111111",
      "role": "owner",
      "referralTotals": {
        "chatgpt":    { "surfaceType": "assistant", "count": 120 },
        "perplexity": { "surfaceType": "answer",    "count": 40 },
        "claude":     { "surfaceType": "assistant", "count": 15 }
      },
      "referralSeries": [
        { "date": "2026-06-28", "chatgpt": 12, "perplexity": 3 }
      ],
      "topLandingPaths": [
        {
          "path": "/pricing",
          "referralTotal": 88,
          "bySource": { "chatgpt": 60, "perplexity": 28 }
        }
      ],
      "landingPathCount": 1,
      "truncated": false,
      "overflow": { "referralTotal": 9, "bySource": { "chatgpt": 6, "perplexity": 3 } }
    }
  ]
}
```

### Fields

| Field                        | Type           | Description                                                                                                                                                                                                                                                                                                                       |
| ---------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `generatedAt`                | string         | ISO 8601 timestamp of when the export was produced.                                                                                                                                                                                                                                                                               |
| `period`                     | string \| null | The rolling period applied, or `null` when an explicit `startDate`/`endDate` range was requested.                                                                                                                                                                                                                                 |
| `startDate`                  | string         | Resolved start of the window (`YYYY-MM-DD`, inclusive).                                                                                                                                                                                                                                                                           |
| `endDate`                    | string         | Resolved end of the window (`YYYY-MM-DD`, inclusive).                                                                                                                                                                                                                                                                             |
| `userId`                     | string         | The account that owns the API key.                                                                                                                                                                                                                                                                                                |
| `domainCount`                | number         | Number of domains included.                                                                                                                                                                                                                                                                                                       |
| `domains[].domain`           | string         | The domain name.                                                                                                                                                                                                                                                                                                                  |
| `domains[].domainId`         | string         | The domain's unique ID.                                                                                                                                                                                                                                                                                                           |
| `domains[].role`             | string         | Access level for this domain: `owner`, `manager`, or `viewer`.                                                                                                                                                                                                                                                                    |
| `domains[].referralTotals`   | object         | Keyed by AI source (`chatgpt`, `perplexity`, `gemini`, `copilot`, `claude`, …). Each value has the source's `surfaceType` and its total `count` for the window.                                                                                                                                                                   |
| `domains[].referralSeries`   | array          | Per-day breakdown; each entry has a `date` plus a visit count under each AI source key.                                                                                                                                                                                                                                           |
| `domains[].topLandingPaths`  | array          | Landing pages ranked by referral volume: `path`, `referralTotal`, and a `bySource` breakdown. Capped at the top **500** paths per domain.                                                                                                                                                                                         |
| `domains[].landingPathCount` | number         | Total distinct landing paths in the window (before the 500-path cap).                                                                                                                                                                                                                                                             |
| `domains[].truncated`        | boolean        | `true` when there were more than 500 landing paths and `topLandingPaths` was capped.                                                                                                                                                                                                                                              |
| `domains[].overflow`         | object         | Referrals recorded against the synthetic `__overflow__` landing path (created when a domain-day exceeds the per-day path cap at ingest): `referralTotal` plus a `bySource` breakdown. Kept out of `topLandingPaths` but still counted in `referralTotals`/`referralSeries`. **Omitted entirely** when the domain has no overflow. |

### AI sources

Each source carries a `surfaceType` describing the kind of AI surface it is:

| `surfaceType` | Meaning                                            | Examples                         |
| ------------- | -------------------------------------------------- | -------------------------------- |
| `assistant`   | General-purpose chat assistant                     | ChatGPT, Gemini, Copilot, Claude |
| `answer`      | Answer engine                                      | Perplexity                       |
| `search`      | AI search surface                                  | —                                |
| `other`       | Anything else, including unrecognised AI referrers | `unknown`                        |

<Note>
  Referrers that look like an AI surface but don't match a known source are
  bucketed under `unknown` (`surfaceType: "other"`) so no AI-referred visit is
  silently dropped.
</Note>

### Error Responses

| Status | Body                                                             | Description                                                                                                                                                                                    |
| ------ | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | `{ "error": "invalid_request", "message": "..." }`               | Invalid `period`; a malformed, out-of-order, or future date; a range over 365 days; `period` combined with a date range; or `endDate` without `startDate`. The `message` field explains which. |
| 401    | `{ "error": "invalid_api_key" }`                                 | API key is missing, invalid, or revoked.                                                                                                                                                       |
| 403    | `{ "error": "plan_upgrade_required" }`                           | Programmatic export requires the Pro plan or above.                                                                                                                                            |
| 404    | `{ "error": "domain_not_found" }`                                | The `domainId` doesn't exist or isn't accessible to your account.                                                                                                                              |
| 429    | `{ "error": "rate_limit_exceeded", "usage": 300, "limit": 300 }` | Monthly or per-minute rate limit exceeded.                                                                                                                                                     |

## Examples

### JavaScript / Node.js

```javascript theme={null}
const response = await fetch(
  "https://api.hadoseo.com/functions/v1/export-ai-referrals",
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.HADOSEO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ period: "30d" }),
  },
);

const report = await response.json();
for (const domain of report.domains) {
  for (const [source, { count }] of Object.entries(domain.referralTotals)) {
    console.log(`${domain.domain}: ${count} visits from ${source}`);
  }
}
```
