<!-- Markdown copy of https://docs.creatorain.com/partner-api/reference/operations/getpartnermonthlybilling/ -->
# That month's reconciliation detail, per store

GET

/billing/monthly

Select code sampleFetchcURL

```js
const url = 'https://data.creatorain.com/partner/v1/billing/monthly?month=2026-09&limit=50';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```sh
curl --request GET \
  --url 'https://data.creatorain.com/partner/v1/billing/monthly?month=2026-09&limit=50' \
  --header 'Authorization: Bearer <token>'
```

-   Production (live stores; a live key is issued per partner)
-   Sandbox, for integration testing (test keys, test stores)

One row per store enrolled under your key, except that a TERMINATED store with nothing to reconcile in the month (no video published, no visit completed and no no-show) is left out instead of listed as a line of zeros. A terminated store that did have any of those stays, with `status: terminated`. A page can therefore hold fewer rows than `limit`: follow `next_cursor` until it is null. Each row: videos published in the month, the plan the store is on, completed visits and no-shows, and the finished amounts for the month. This is what an invoice is checked against. You do no price maths: `amount_due` is what we bill you for the store, `merchant_amount` is what the merchant owes with your surcharge included.

THE AMOUNTS. `billed_videos` = `videos_published` - `makeup_videos` (free replacement videos are never billed). `merchant_amount` = `billed_videos` x (the flat merchant price + your surcharge, both locked on the store for THAT month). `amount_due` is what we bill you: for each billed video, that video’s actual creator cost plus our fee per video (`fee_per_video` in the pricing block), summed. A video whose creator was paid nothing (comped) still carries the fee. It is not a fixed price per video. A plan or approval change re-locks from the next month, so each month uses its own lock. A store with no locked price (confirmed before pricing) is billed the same way from the current default terms: creator cost plus our fee, and `merchant_amount` from the default merchant price. Both are null only when pricing is not set up at all. While a billed video’s creator cost is not known yet, `amount_due` is null and `cost_pending_videos` says how many videos are waiting; it is never a 0 that under-bills. See `amounts_note`. Currency units, like every price on this API.

THE MONTH IS THE STORE’S MONTH. A video published at 23:30 on 30 September in Los Angeles is a September video; bucketed in UTC it would be 06:30 on 1 October and would land on the wrong invoice, with both sides looking at a real timestamp and reading it in different clocks. Each store’s window is resolved on that store’s own clock, and it is half open: `[local 1st 00:00, local 1st of next month 00:00)`, so no video is counted twice or lost.

Visits are counted by VISIT DATE, which our reservations already store in the venue’s own calendar, so a visit marked completed in October for a September booking is a September visit.

`month` is REQUIRED and has no default. “This month” would be the obvious default and is the wrong one here: a scheduled job whose parameter went missing would silently start reporting whichever month it ran in, and the first sign of that is a merchant charged twice.

`note` states the one limitation of these numbers and is on every response. Our per-store pin on content landed on 2026-09-09, so anything published before that date carries no store and is not counted here.

PARTNER KEY ONLY. A store token cannot read this: a chain’s billing is your business, not one merchant’s.

## Authorizations

-   **[partnerApiKey](/partner-api/reference/#partnerapikey)**

## Parameters

### Query Parameters

**month**

required

string

/^\\d{4}-(0\[1-9\]|1\[0-2\])$/

The month to report, `YYYY-MM`, in each STORE’S own calendar. Required, with no default.

#### Example

```
2026-09
```

**cursor**

string

The `next_cursor` from the previous page, sent back UNCHANGED. Omit it for the first page.

It is opaque: do not build one yourself. It names a POSITION in the sort order rather than a count of rows to skip, which is why a page stays stable when a booking is touched between two requests. A cursor we did not issue is refused with `400 validation_error`, rather than silently treated as the first page, so a broken client fails loudly instead of looping over page one for ever.

**limit**

integer

default: 50 \>= 1 <= 200

Rows per page. Default 50, maximum 200. A larger value is CLAMPED to 200 rather than refused, so you never have to guess the ceiling.

## Responses

### 200

A page of stores, with the month’s counts for each.

Media typeapplication/json

object

**month**

required

The month asked for, echoed back, so a stored report says what it is of.

string

**note**

required

The one limitation of these numbers, on every response rather than in a document somebody has to remember to read.

string

**amounts\_note**

required

When the amounts are null, and that make-up videos are never billed. On every response.

string

**generated\_at**

required

When this was computed, RFC 3339 in UTC. A fact about our run rather than a time at any store, so it carries no store offset.

string format: date-time

**items**

required

Array<object>

One store’s month. Counts only: there is no personal data anywhere in this report.

object

**partner\_location\_id**

YOUR id for the store, which is what your own billing is keyed on.

string

**location\_id**

Our id for the same store.

string format: uuid

**videos\_published**

Videos filmed at this store that are LIVE and were published inside the month IN THIS STORE’S OWN CLOCK. See the endpoint description for why that matters. Only videos made on your key’s campaign count: a video another campaign made at the same restaurant is not on your invoice.

integer

**plan\_videos\_per\_month**

The plan in force in THAT month (a plan change applies from the next month), echoed so an invoice line can be checked without a second call.

integer

nullable

**plan\_term\_months**

integer

nullable

**reservations\_completed**

Visits at this store marked completed, by VISIT DATE in the store’s calendar. Only visits booked on your key’s campaign count.

integer

**no\_shows**

Visits at this store marked no\_show, by the same date and the same campaign.

integer

**status**

The store’s state at the moment of the read, so a row of zeroes can be explained without a second call. A terminated store appears only if it had a video or a visit in the month.

string

Allowed values: active paused terminated

**makeup\_videos**

Of `videos_published`, the free replacement videos (after a no-show, or for a video the merchant rejected). Never billed.

integer

**billed\_videos**

`videos_published` - `makeup_videos`: the videos the two amounts are for.

integer

**cost\_pending\_videos**

Billed videos whose creator cost is not known yet. While above 0, `amount_due` is null.

integer

**currency**

The currency of the amounts. Null when the store has no locked price.

string

nullable

**amount\_due**

What CreatoRain bills you for this store this month: the sum over billed videos of (that video’s creator cost + our locked fee per video). Null for a store with no locked price, or while `cost_pending_videos` is above 0.

number

nullable

**merchant\_amount**

What the merchant owes for the month with your surcharge included, ready for your invoice: `billed_videos` x (the flat merchant price + your locked surcharge). Null for a store with no locked price.

number

nullable

**next\_cursor**

required

Send this back as `cursor` for the next page of STORES. The stores are ordered by `partner_location_id` ascending rather than by recency, because a reconciliation file is diffed against last month’s and a stable order is worth more here than newness.

string

nullable

#### Example

```json
{
  "month": "2026-09",
  "note": "content published before 2026-09-09 carries no store and is not counted",
  "amounts_note": "amount_due and merchant_amount are null for a store with no locked price (confirmed before pricing); amount_due is also null while a billed video has no known creator cost (see cost_pending_videos); make-up videos are never billed",
  "items": [
    {
      "partner_location_id": "store_123",
      "videos_published": 2,
      "plan_videos_per_month": 2,
      "plan_term_months": 3,
      "reservations_completed": 3,
      "no_shows": 1,
      "status": "active",
      "makeup_videos": 0,
      "billed_videos": 3,
      "cost_pending_videos": 0,
      "currency": "USD",
      "amount_due": 450,
      "merchant_amount": 1125
    }
  ]
}
```

### 400

`validation_error`. `field` names the offending parameter.

Media typeapplication/json

object

**error**

required

object

**code**

required

The stable value to branch on.

string

Allowed values: unauthorized forbidden\_ip rate\_limited validation\_error location\_already\_exists location\_not\_found location\_terminated reservation\_not\_found conflict internal\_error

**message**

required

A human sentence. Copy, not contract; it may be reworded.

string

**field**

The request field at fault, dotted for a nested one (`plan.term_months`).

string

#### Example

```json
{
  "error": {
    "code": "unauthorized"
  }
}
```

### 401

`unauthorized`. A missing, malformed, unknown or revoked key; or an invalid, expired or wrong-store dashboard token. One answer for every case on purpose: the holder of a bad credential learns nothing from the difference.

Media typeapplication/json

object

**error**

required

object

**code**

required

The stable value to branch on.

string

Allowed values: unauthorized forbidden\_ip rate\_limited validation\_error location\_already\_exists location\_not\_found location\_terminated reservation\_not\_found conflict internal\_error

**message**

required

A human sentence. Copy, not contract; it may be reworded.

string

**field**

The request field at fault, dotted for a nested one (`plan.term_months`).

string

#### Example

```json
{
  "error": {
    "code": "unauthorized"
  }
}
```

### 429

`rate_limited`. Over this key’s requests-per-minute ceiling.

Media typeapplication/json

object

**error**

required

object

**code**

required

The stable value to branch on.

string

Allowed values: unauthorized forbidden\_ip rate\_limited validation\_error location\_already\_exists location\_not\_found location\_terminated reservation\_not\_found conflict internal\_error

**message**

required

A human sentence. Copy, not contract; it may be reworded.

string

**field**

The request field at fault, dotted for a nested one (`plan.term_months`).

string

#### Example

```json
{
  "error": {
    "code": "unauthorized"
  }
}
```
