> ## Documentation index
> Fetch the complete documentation index at: https://docs.prescientai.com/llms.txt
> Use this file to discover all available pages before exploring further. Add `.md` to any page URL to get that page as Markdown.

# Pull reported spend for a date range

> Steps and code that copy the reported spend of each campaign and day from the Prescient GraphQL API, one page at a time.

To copy reported spend, send the [`reportedMetrics`](https://docs.prescientai.com/api/queries/reported-metrics) query and follow the cursor until no page is left. Each row is the spend of one campaign on one day.

## How do you pull the rows?

1. Choose the date range with `startDate` and `endDate`, in the `YYYY-MM-DD` format. Both dates are in the range. If you leave them out, the range is the last 30 days.

2. Send the query with no `after` value.

   ```graphql title="Query"
   query ReportedMetrics(
     $startDate: ISO8601Date
     $endDate: ISO8601Date
     $after: BigInt
   ) {
     reportedMetrics(startDate: $startDate, endDate: $endDate, after: $after) {
       data {
         reportedDate
         channelName
         campaignId
         campaignName
         spend
       }
       pageInfo {
         endCursor
         hasNextPage
       }
     }
   }
   ```

   ```json title="Variables"
   {
     "startDate": "2026-01-01",
     "endDate": "2026-01-31",
     "after": null
   }
   ```

3. If `pageInfo.hasNextPage` is `true`, send the same query with `after` set to `pageInfo.endCursor`.

4. Stop when `hasNextPage` is `false`. The last page can have no rows. See [Pagination](https://docs.prescientai.com/api/pagination).

## What does the full loop look like?

**JavaScript**

```js
const QUERY = `
  query ReportedMetrics($startDate: ISO8601Date, $endDate: ISO8601Date, $after: BigInt) {
    reportedMetrics(startDate: $startDate, endDate: $endDate, after: $after) {
      data { reportedDate channelName campaignId campaignName spend }
      pageInfo { endCursor hasNextPage }
    }
  }`;

async function pullReportedSpend(startDate, endDate) {
  const rows = [];
  let after = null;
  do {
    const response = await fetch('https://api.prescient-ai.io/graphql', {
      method: 'POST',
      headers: {
        Authorization: `apikey ${process.env.PRESCIENT_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ query: QUERY, variables: { startDate, endDate, after } }),
    });
    const { data, errors } = await response.json();
    if (errors) throw new Error(errors[0].message);

    const page = data.reportedMetrics;
    rows.push(...page.data);
    after = page.pageInfo.hasNextPage ? page.pageInfo.endCursor : null;
  } while (after !== null);
  return rows;
}
```

**Python**

```python
import os
import requests

QUERY = """
query ReportedMetrics($startDate: ISO8601Date, $endDate: ISO8601Date, $after: BigInt) {
  reportedMetrics(startDate: $startDate, endDate: $endDate, after: $after) {
    data { reportedDate channelName campaignId campaignName spend }
    pageInfo { endCursor hasNextPage }
  }
}
"""


def pull_reported_spend(start_date, end_date):
    rows = []
    after = None
    while True:
        response = requests.post(
            "https://api.prescient-ai.io/graphql",
            headers={"Authorization": f"apikey {os.environ['PRESCIENT_API_KEY']}"},
            json={
                "query": QUERY,
                "variables": {"startDate": start_date, "endDate": end_date, "after": after},
            },
        )
        body = response.json()
        if body.get("errors"):
            raise RuntimeError(body["errors"][0]["message"])

        page = body["data"]["reportedMetrics"]
        rows.extend(page["data"])
        if not page["pageInfo"]["hasNextPage"]:
            return rows
        after = page["pageInfo"]["endCursor"]
```

## Which rows does the query return?

- The query returns a row only for a campaign and day with spend above zero.
- `campaignName` can be `null`.
- To get the rows of some campaigns, set `campaignIds` to a list of campaign IDs.
- If your key has a channel scope, the query returns only the channels in that scope. See [Authentication](https://docs.prescientai.com/api/authentication).

To learn how reported figures differ from modeled figures, see [Modeled and reported figures](https://docs.prescientai.com/attribution/modeled-and-reported-figures).
