<!-- Markdown copy of https://docs.creatorain.com/partner-api/reference/operations/createpartnerlocation/ -->
# Enrol a store

POST

/locations

Select code sampleFetchcURL

```js
const url = 'https://data.creatorain.com/partner/v1/locations';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"partner_location_id":"store_123","name":"Example Noodle House","address":{"line1":"100 Main St","city":"San Jose","state":"CA","postal_code":"95113","country":"US"},"plan":{"videos_per_month":2,"term_months":3},"signature_dishes":[{"name":"Signature tempura platter","image_url":"https://cdn.example.com/tempura.jpg"}],"preferred_language":"zh","approved_at":"2026-09-09T18:22:00Z","approved_by":"ops@example.com","approval_mode":"auto","timezone":"America/Los_Angeles","opening_hours":{"mon":[["11:00","15:00"],["17:00","21:30"]],"tue":[["11:00","21:30"]],"wed":[["11:00","21:30"]],"thu":[["11:00","21:30"]],"fri":[["11:00","22:00"]],"sat":[["11:00","22:00"]],"sun":[["11:00","21:00"]]},"merchant_contact":{"name":"Alex Kim","phone":"+14155550100","email":"owner@example.com"}}'
};

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

```sh
curl --request POST \
  --url https://data.creatorain.com/partner/v1/locations \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{ "partner_location_id": "store_123", "name": "Example Noodle House", "address": { "line1": "100 Main St", "city": "San Jose", "state": "CA", "postal_code": "95113", "country": "US" }, "plan": { "videos_per_month": 2, "term_months": 3 }, "signature_dishes": [ { "name": "Signature tempura platter", "image_url": "https://cdn.example.com/tempura.jpg" } ], "preferred_language": "zh", "approved_at": "2026-09-09T18:22:00Z", "approved_by": "ops@example.com", "approval_mode": "auto", "timezone": "America/Los_Angeles", "opening_hours": { "mon": [ [ "11:00", "15:00" ], [ "17:00", "21:30" ] ], "tue": [ [ "11:00", "21:30" ] ], "wed": [ [ "11:00", "21:30" ] ], "thu": [ [ "11:00", "21:30" ] ], "fri": [ [ "11:00", "22:00" ] ], "sat": [ [ "11:00", "22:00" ] ], "sun": [ [ "11:00", "21:00" ] ] }, "merchant_contact": { "name": "Alex Kim", "phone": "+14155550100", "email": "owner@example.com" } }'
```

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

Called once when a merchant approves joining. `partner_location_id` is YOUR id for the store and is the idempotency key, so a retry is safe:

State when the call arrives

Answer

No store with this `partner_location_id`

`201` and the store is created

It exists with the same name and address

`200` with the same body plus a `warning`

It exists with a different name or address

`409 location_already_exists`

It exists and its contract was terminated

`201`, the store is re-activated

A repeat of a store that is still live is never an error for an identical body: it answers `200` with the same body and a top-level `warning` object, `{"code": "location_already_exists", "message": "This location already exists"}`, so your system can tell a repeat from a first create. Nothing is written. A different name or address for a live store is `409` with the same `code` and `message`.

A store whose contract was terminated is added again directly with the same call: it is re-activated (the same store and history, not a second one), it gets a NEW price lock from the plan you send, it is offered to creators again, and `location.activated` is sent again. There is no warning. Its hours and timezone are kept (change them with PATCH).

A changed `partner_location_id` is a DIFFERENT store, so the id must be stable in your system. Use `PATCH /locations/{partner_location_id}` to change a store’s name, address or plan; a create with changed details is refused rather than silently applied.

## Store facts worth sending

-   **`timezone`**: the store’s IANA zone. When sent it wins over the zone we derive from the address state, which is an hour off in states with two zones (El Paso, the Florida panhandle). Every time we give you for the store, every reminder and the visit-day text use it.
-   **`opening_hours`**: the week from your POS. When sent we use it and do not look the store up; `hours.source` reads `partner`, and the store is never held for missing hours. When not sent we look the hours up ourselves as before.
-   **`merchant_contact`**: who at the restaurant hears from us. Its email receives our store notices instead of your account owner, and its phone receives the visit-day text.
-   **`approval_mode`**: `auto` (default) or `sample_review`.

A repeat of a create (same id, name and address) is `200` and writes nothing, whatever extra fields it carries. To change any of these on an existing store, use `PATCH`.

## What a new store starts with, without you sending it

-   **Creator bookings are AUTO-CONFIRMED.** A creator who books a slot at your store has a confirmed visit immediately; there is no approval step waiting on somebody at the restaurant, and per-booking review is a later product. Your merchant hears about the booking through the notice we send and, if you have wired it, through the `reservation.confirmed` webhook.
-   **A creator visit window inside the store’s opening hours**, with our house rules on top: no Saturday visits, Friday visits end at 17:00, Sunday visits start at 15:00. A break in the day (an afternoon closure) is kept, so no creator is offered a time when the door is shut. An operator can change the window per store afterwards.

## Authorizations

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

## Request Bodyrequired

Media typeapplication/json

Deliberately small. Social accounts, cuisine, blackout dates and daily visit caps are NOT accepted: every extra field slows onboarding and is one more thing to get wrong, and we fill those ourselves. `timezone`, `opening_hours` and `merchant_contact` are optional but worth sending: they remove the three most common reasons a store waits or a notice is missed. An unrecognised field is refused rather than ignored, so a value can never be silently dropped.

object

**partner\_location\_id**

required

Your id for the store. The idempotency key, and the store’s identity. Must be stable.

string

<= 200 characters

**name**

required

string

<= 300 characters

**address**

Stored as one line, `line1, city, state postal_code, country`. The store’s time zone is derived from it, so `state` and `postal_code` are worth sending even where they feel optional.

object

**line1**

string

nullable <= 300 characters

**city**

string

nullable <= 120 characters

**state**

string

nullable <= 120 characters

**postal\_code**

string

nullable <= 40 characters

**country**

string

nullable <= 120 characters

**plan**

What the merchant bought. We store your numbers as you sent them AND the total they imply (`videos_per_month` x `term_months`), because 2 x 3 and 6 x 1 are the same total and are not the same contract, and reconciliation is held in your units.

The standard plan is 2 to 10 videos a month and a term of 3, 8 or 12 months (longer is allowed). A plan below 2 videos a month, or below 3 months, is NOT refused: it is accepted and carries the plan surcharge on its price (`pricing.plan_surcharge`).

A value outside the ranges below is refused with `400 validation_error` and `field` set to `plan.videos_per_month` or `plan.term_months`. Only what a request sends is checked: a store stored earlier with other values keeps working, and a PATCH of another field does not have to restate its plan.

object

**videos\_per\_month**

The merchant’s choice, a whole number from 1 to 10 (2 to 10 is standard; 1 adds the plan surcharge). Paced per month (see Monthly pacing).

integer

\>= 1 <= 10

**term\_months**

The contract length in months, 1 to 120 (3 or more is standard; below 3 adds the plan surcharge). The collaboration end date is the start date plus this many months.

integer

\>= 1 <= 120

**signature\_dishes**

Array<object>

<= 50 items

object

**name**

required

string

<= 300 characters

**image\_url**

An http(s) link to the dish photo. Stored with the dish.

string format: uri

nullable <= 2000 characters

**preferred\_language**

The language the MERCHANT is addressed in. Omit when you do not know; it is not defaulted to en.

string

Allowed values: zh en

**approval\_mode**

How creators are approved for this store. `auto` (the default) books matching creators straight away. `sample_review` means the merchant first approves a batch of 5 sample creators (`GET /locations/{partner_location_id}/creator-samples`); nothing starts until that decision.

string

default: auto

Allowed values: auto sample\_review

**timezone**

The store’s IANA time zone, `Area/Location` (for example `America/Los_Angeles`). When set it wins over the zone we derive from the address. Fixed offsets (`+05:00`), `UTC` and abbreviations (`PST`) are refused with `400 validation_error`, `field: timezone`: a restaurant’s clock needs daylight saving rules.

string

<= 64 characters

**opening\_hours**

The store’s week from your POS, venue-local. Keys `mon` to `sun`; each is a list of `["HH:MM", "HH:MM"]` open and close pairs (24 hour), so an afternoon break is two pairs. A close must be later than its open on the same day; `24:00` means open until midnight, and a later close goes on the next day as `["00:00", ...]`. A day you leave out, or send as `[]`, is CLOSED. Overlapping pairs are merged. At least one open pair is required.

Creators are offered times inside these hours with our house rules on top (no Saturday, Friday until 17:00, Sunday from 15:00). A week that is only open when those rules allow no visit (for example Saturday only) is stored, and the store reports `hours.state: missing` with `source: partner` until the hours change.

object

\>= 1 properties

**mon**

Array<Array<string>>

<= 6 items

**tue**

Array<Array<string>>

<= 6 items

**wed**

Array<Array<string>>

<= 6 items

**thu**

Array<Array<string>>

<= 6 items

**fri**

Array<Array<string>>

<= 6 items

**sat**

Array<Array<string>>

<= 6 items

**sun**

Array<Array<string>>

<= 6 items

**merchant\_contact**

The person at the restaurant. `email` receives our store notices (instead of your account owner); `phone` receives the visit-day text message. Never shown to creators.

object

\>= 1 properties

**name**

string

nullable <= 100 characters

**phone**

E.164, for example `+14155550100`. Anything else is refused with `field: merchant_contact.phone`.

string

nullable <= 20 characters

**email**

string format: email

nullable <= 100 characters

**approved\_at**

When your back office approved this store, RFC 3339. The store’s collaboration start date is the STORE-LOCAL day of this instant, so an evening approval on the US west coast does not start the store a day early. Defaults to now when omitted.

string format: date-time

**approved\_by**

Who approved it on your side. Opaque to us; never resolved against our own accounts.

string

<= 300 characters

### Examples

Exampleexample

A store joining

```json
{
  "partner_location_id": "store_123",
  "name": "Example Noodle House",
  "address": {
    "line1": "100 Main St",
    "city": "San Jose",
    "state": "CA",
    "postal_code": "95113",
    "country": "US"
  },
  "plan": {
    "videos_per_month": 2,
    "term_months": 3
  },
  "signature_dishes": [
    {
      "name": "Signature tempura platter",
      "image_url": "https://cdn.example.com/tempura.jpg"
    }
  ],
  "preferred_language": "zh",
  "approved_at": "2026-09-09T18:22:00Z",
  "approved_by": "ops@example.com",
  "approval_mode": "auto",
  "timezone": "America/Los_Angeles",
  "opening_hours": {
    "mon": [
      [
        "11:00",
        "15:00"
      ],
      [
        "17:00",
        "21:30"
      ]
    ],
    "tue": [
      [
        "11:00",
        "21:30"
      ]
    ],
    "wed": [
      [
        "11:00",
        "21:30"
      ]
    ],
    "thu": [
      [
        "11:00",
        "21:30"
      ]
    ],
    "fri": [
      [
        "11:00",
        "22:00"
      ]
    ],
    "sat": [
      [
        "11:00",
        "22:00"
      ]
    ],
    "sun": [
      [
        "11:00",
        "21:00"
      ]
    ]
  },
  "merchant_contact": {
    "name": "Alex Kim",
    "phone": "+14155550100",
    "email": "owner@example.com"
  }
}
```

## Responses

### 200

The store already existed with the same name and address. The body is the same as the one the original create returned, plus a top-level `warning` (`location_already_exists`, “This location already exists”). Nothing was written.

Media typeapplication/json

object

**location\_id**

OUR id for the store. Stable, and what every other endpoint refers to it by.

string format: uuid

**partner\_location\_id**

Your id, as you sent it (trimmed).

string

**status**

`paused` means no NEW scheduling: creators are not offered the store and a new booking is refused, while bookings already confirmed are untouched. Resume opens it again. `terminated` means the contract has ended. Terminated wins over paused.

string

Allowed values: active paused terminated

**network**

A display label for the local creator pool, for example `example-pool`. Label only.

string

nullable

**dashboard\_url**

The embeddable merchant dashboard for this store, carrying a freshly minted 30 minute read-only token. Null when this deployment hosts no embedded dashboard, rather than a plausible URL pointing at nothing: an iframe rendered from a dead URL shows a merchant a blank panel, which is worse than a field you can branch on. Mint a fresh one with `POST /locations/{partner_location_id}/dashboard-token` when you render the embed.

string

nullable

**timezone**

IANA name for the store as we resolve it: the `timezone` you sent when you sent one, otherwise derived from the address. Null when neither yields one.

string

nullable

**created\_at**

RFC 3339 with the store’s offset.

string

nullable

**hours**

Whether we hold this store’s real opening hours, and where they came from. A store with no hours is still `active`: the contract exists and nothing about the enrolment failed. What it cannot do yet is take a creator booking, because our two date pickers are built from the stored week and an absent one disables both. `state: missing` is a request to chase the hours at source, which is the one place they actually exist.

object

**state**

required

string

Allowed values: missing found

**source**

required

Where the hours came from. `partner` means you sent them (`opening_hours`); the rest are our own lookups or an operator (`manual`). Null for a store never checked.

string

nullable

Allowed values: partner places gemini website manual none

**approval\_mode**

How creators are approved for this store. `auto` (the default) books matching creators straight away. `sample_review` means the merchant first approves a batch of 5 sample creators (`GET /locations/{partner_location_id}/creator-samples`); nothing starts until that decision.

string

default: auto

Allowed values: auto sample\_review

**pricing**

The store’s price for the month it is in: the same block as the quote, LOCKED when the store was confirmed. A change to `plan.videos_per_month` or `approval_mode` re-locks it from the next month (at the base price and your surcharge at that moment), shown meanwhile as `upcoming`. A later surcharge change does not move it. A store confirmed before pricing existed has no locked price: its block is worked out from the current default terms and marked `locked: false`, `source: default` (nothing is stored for it, and it shows the default creator cost range). NULL only when pricing is not set up at all.

Read with a merchant’s store token, only the merchant price is returned (`creatorain` and `surcharge` are left out).

object

**currency**

required

string

**billing\_unit**

required

string

Allowed values: published\_video

**creatorain**

required

What we bill the partner per published video. Not a fixed price.

object

**fee\_per\_video**

required

number

**creator\_cost\_per\_video**

required

Estimate range of the creator cost per video (on a quote, and on a store with no locked price; null on a locked store). The bill uses the actual cost.

object

**min**

number

**max**

number

**billed\_as**

required

string

Allowed values: creator\_cost\_plus\_fee

**surcharge**

required

object

**per\_video**

number

**plan\_surcharge**

required

The non-standard plan line, included in `merchant`. 0 / false for a standard plan.

object

**per\_video**

number

**applies**

boolean

**placeholder**

True while the amount is provisional.

boolean

**merchant**

required

object

**per\_video**

required

number

**per\_month**

required

Per\_video x videos per month. Null for a store with no plan.

number

nullable

**per\_season**

required

Per\_month x 3.

number

nullable

**season\_videos**

required

integer

nullable

**note**

required

string

**locked\_at**

When the price in force was locked (UTC). Null when `locked` is false.

string

nullable

**locked**

False for a store with no locked price, priced from the current defaults.

boolean

**source**

string

Allowed values: locked default

**upcoming**

The price from `from_month` (the store’s next month), when a re-lock is waiting.

object

**from\_month**

string

**currency**

string

**creatorain**

What we bill the partner per published video. Not a fixed price.

object

**fee\_per\_video**

required

number

**creator\_cost\_per\_video**

required

Estimate range of the creator cost per video (on a quote, and on a store with no locked price; null on a locked store). The bill uses the actual cost.

object

**min**

number

**max**

number

**billed\_as**

required

string

Allowed values: creator\_cost\_plus\_fee

**surcharge**

object

**per\_video**

number

**plan\_surcharge**

object

**per\_video**

number

**applies**

boolean

**placeholder**

boolean

**merchant**

object

**per\_video**

required

number

**per\_month**

required

Per\_video x videos per month. Null for a store with no plan.

number

nullable

**per\_season**

required

Per\_month x 3.

number

nullable

**season\_videos**

integer

nullable

**first\_visit\_business\_days**

The first-visit commitment for this store, in business days (Monday to Friday, store clock, skipping Thanksgiving Day, Christmas Day, New Year’s Day and any weekday the store’s own opening hours say it is closed), as agreed in your contract. Locked when the store is created. Null for a store created before this field existed. Show it as given.

integer

nullable

**first\_visit\_due\_by**

The store-local date the first creator visit is due by: `first_visit_business_days` counted from the day after the confirm day (`approved_at` when you sent it, otherwise the day the store was created). Locked at creation.

string format: date

nullable

**rules**

WHAT THIS STORE ASKS OF A CREATOR: the terms you set with `PATCH`, read back. Always present, ordered by attribute then operator, and `[]` for a store that asks nothing - which is what a store has until you send its first rule.

THIS IS THE SAME ARRAY `PATCH` ACCEPTS, so the obvious read-modify-write is safe: read a store, change one entry, send the array back. `value` is returned in the shape we STORED it, which is the normalised one - a bare `20000` you sent for `follower_count` reads back as `{"count": 20000, "platform": null}`, and sending that object again changes nothing.

It is deliberately NOT our internal effective rule set. Terms an operator set on our own dashboard through the older per-venue columns are not folded in here, because you can neither send nor clear those through this API and a term you cannot remove is worse than one you cannot see. Everything this array contains, `clear_rules` can remove.

Array<object>

One term this store asks of a creator.

`ethnicity`, `age_band` and `gender` are real members of our attribute list and are REFUSED with `422 validation_error` on both this API and our dashboard. Filtering paid work by a protected characteristic needs a written policy agreed with counsel, and until one exists we will not store the rule.

`follower_count` takes `gte` or `lte` and a value of `{"count": N}`, optionally with `"platform"` to say WHERE the count is measured - `{"count": 20000, "platform": "tiktok"}` means twenty thousand on TikTok, not twenty thousand in total from somebody who also has a TikTok handle. `platform` and `language` take `eq` with one value or `in` with a list; over a creator who works on several, `eq` means “this is one of hers”, never “this is her only one”.

`home_metro` (local creators only) takes `in`; `radius_miles` (within N miles of this store) takes `lte` and the miles, `25` or `{"miles": 25}`, from 1 to 500. Both are measured from this store’s own address, which we resolve when you write the rule and again when the address moves; an address we cannot place in a US city is a `422`.

`performance_index` (content performance score, 0 to 100) and `engagement_rate` (percent, `3.5` means 3.5%) take `gte` and a number. They are floors.

A creator we hold no answer for is decided by the store’s own policy, which passes by default - so adding a `language` rule today records your intent and excludes nobody until we hold languages. The follower bar, the platform, `home_metro`, `radius_miles`, `performance_index` and `engagement_rate` are the exception and always exclude a creator we cannot measure.

object

**attribute**

required

string

Allowed values: follower\_count platform language home\_metro radius\_miles performance\_index engagement\_rate

**operator**

required

string

Allowed values: gte lte in eq

**value**

required

One of:

-   [integer](#tab-panel-0-0)
-   [string](#tab-panel-0-1)
-   [Array<string>](#tab-panel-0-2)
-   [object](#tab-panel-0-3)

integer

string

Array<string>

object

**count**

integer

**platform**

string

nullable

Allowed values: instagram tiktok youtube facebook

**warning**

object

**code**

string

Allowed values: location\_already\_exists

**message**

string

#### Example

```json
{
  "partner_location_id": "store_123",
  "status": "active",
  "network": "example-pool",
  "timezone": "America/Los_Angeles",
  "created_at": "2026-09-10T13:22:00-07:00",
  "hours": {
    "state": "missing",
    "source": "partner"
  },
  "approval_mode": "auto",
  "pricing": {
    "currency": "USD",
    "billing_unit": "published_video",
    "creatorain": {
      "fee_per_video": 10,
      "creator_cost_per_video": {
        "min": 20,
        "max": 40
      },
      "billed_as": "creator_cost_plus_fee"
    },
    "surcharge": {
      "per_video": 10
    },
    "plan_surcharge": {
      "per_video": 5,
      "applies": false,
      "placeholder": true
    },
    "merchant": {
      "per_video": 100,
      "per_month": 200,
      "per_season": 600
    },
    "season_videos": 6,
    "source": "locked",
    "upcoming": {
      "from_month": "2026-11",
      "creatorain": {
        "fee_per_video": 10,
        "creator_cost_per_video": {
          "min": 20,
          "max": 40
        },
        "billed_as": "creator_cost_plus_fee"
      },
      "merchant": {
        "per_video": 100,
        "per_month": 200,
        "per_season": 600
      }
    }
  },
  "first_visit_due_by": "2026-10-06",
  "rules": [
    {
      "attribute": "follower_count",
      "operator": "gte",
      "value": {
        "count": 20000,
        "platform": "tiktok"
      }
    },
    {
      "attribute": "platform",
      "operator": "eq",
      "value": "tiktok"
    }
  ],
  "warning": {
    "code": "location_already_exists",
    "message": "This location already exists"
  }
}
```

### 201

The store was created.

Media typeapplication/json

The store as we hold it. ONE body for every verb on a location: the create’s 201 (also returned when a terminated store is added again), an identical repeat’s 200 (plus a `warning`), the `PATCH` response, and pause, resume and terminate. Write one receiver for it. `GET /locations/{partner_location_id}` returns this plus progress and the next visit (`LocationState`).

object

**location\_id**

OUR id for the store. Stable, and what every other endpoint refers to it by.

string format: uuid

**partner\_location\_id**

Your id, as you sent it (trimmed).

string

**status**

`paused` means no NEW scheduling: creators are not offered the store and a new booking is refused, while bookings already confirmed are untouched. Resume opens it again. `terminated` means the contract has ended. Terminated wins over paused.

string

Allowed values: active paused terminated

**network**

A display label for the local creator pool, for example `example-pool`. Label only.

string

nullable

**dashboard\_url**

The embeddable merchant dashboard for this store, carrying a freshly minted 30 minute read-only token. Null when this deployment hosts no embedded dashboard, rather than a plausible URL pointing at nothing: an iframe rendered from a dead URL shows a merchant a blank panel, which is worse than a field you can branch on. Mint a fresh one with `POST /locations/{partner_location_id}/dashboard-token` when you render the embed.

string

nullable

**timezone**

IANA name for the store as we resolve it: the `timezone` you sent when you sent one, otherwise derived from the address. Null when neither yields one.

string

nullable

**created\_at**

RFC 3339 with the store’s offset.

string

nullable

**hours**

Whether we hold this store’s real opening hours, and where they came from. A store with no hours is still `active`: the contract exists and nothing about the enrolment failed. What it cannot do yet is take a creator booking, because our two date pickers are built from the stored week and an absent one disables both. `state: missing` is a request to chase the hours at source, which is the one place they actually exist.

object

**state**

required

string

Allowed values: missing found

**source**

required

Where the hours came from. `partner` means you sent them (`opening_hours`); the rest are our own lookups or an operator (`manual`). Null for a store never checked.

string

nullable

Allowed values: partner places gemini website manual none

**approval\_mode**

How creators are approved for this store. `auto` (the default) books matching creators straight away. `sample_review` means the merchant first approves a batch of 5 sample creators (`GET /locations/{partner_location_id}/creator-samples`); nothing starts until that decision.

string

default: auto

Allowed values: auto sample\_review

**pricing**

The store’s price for the month it is in: the same block as the quote, LOCKED when the store was confirmed. A change to `plan.videos_per_month` or `approval_mode` re-locks it from the next month (at the base price and your surcharge at that moment), shown meanwhile as `upcoming`. A later surcharge change does not move it. A store confirmed before pricing existed has no locked price: its block is worked out from the current default terms and marked `locked: false`, `source: default` (nothing is stored for it, and it shows the default creator cost range). NULL only when pricing is not set up at all.

Read with a merchant’s store token, only the merchant price is returned (`creatorain` and `surcharge` are left out).

object

**currency**

required

string

**billing\_unit**

required

string

Allowed values: published\_video

**creatorain**

required

What we bill the partner per published video. Not a fixed price.

object

**fee\_per\_video**

required

number

**creator\_cost\_per\_video**

required

Estimate range of the creator cost per video (on a quote, and on a store with no locked price; null on a locked store). The bill uses the actual cost.

object

**min**

number

**max**

number

**billed\_as**

required

string

Allowed values: creator\_cost\_plus\_fee

**surcharge**

required

object

**per\_video**

number

**plan\_surcharge**

required

The non-standard plan line, included in `merchant`. 0 / false for a standard plan.

object

**per\_video**

number

**applies**

boolean

**placeholder**

True while the amount is provisional.

boolean

**merchant**

required

object

**per\_video**

required

number

**per\_month**

required

Per\_video x videos per month. Null for a store with no plan.

number

nullable

**per\_season**

required

Per\_month x 3.

number

nullable

**season\_videos**

required

integer

nullable

**note**

required

string

**locked\_at**

When the price in force was locked (UTC). Null when `locked` is false.

string

nullable

**locked**

False for a store with no locked price, priced from the current defaults.

boolean

**source**

string

Allowed values: locked default

**upcoming**

The price from `from_month` (the store’s next month), when a re-lock is waiting.

object

**from\_month**

string

**currency**

string

**creatorain**

What we bill the partner per published video. Not a fixed price.

object

**fee\_per\_video**

required

number

**creator\_cost\_per\_video**

required

Estimate range of the creator cost per video (on a quote, and on a store with no locked price; null on a locked store). The bill uses the actual cost.

object

**min**

number

**max**

number

**billed\_as**

required

string

Allowed values: creator\_cost\_plus\_fee

**surcharge**

object

**per\_video**

number

**plan\_surcharge**

object

**per\_video**

number

**applies**

boolean

**placeholder**

boolean

**merchant**

object

**per\_video**

required

number

**per\_month**

required

Per\_video x videos per month. Null for a store with no plan.

number

nullable

**per\_season**

required

Per\_month x 3.

number

nullable

**season\_videos**

integer

nullable

**first\_visit\_business\_days**

The first-visit commitment for this store, in business days (Monday to Friday, store clock, skipping Thanksgiving Day, Christmas Day, New Year’s Day and any weekday the store’s own opening hours say it is closed), as agreed in your contract. Locked when the store is created. Null for a store created before this field existed. Show it as given.

integer

nullable

**first\_visit\_due\_by**

The store-local date the first creator visit is due by: `first_visit_business_days` counted from the day after the confirm day (`approved_at` when you sent it, otherwise the day the store was created). Locked at creation.

string format: date

nullable

**rules**

WHAT THIS STORE ASKS OF A CREATOR: the terms you set with `PATCH`, read back. Always present, ordered by attribute then operator, and `[]` for a store that asks nothing - which is what a store has until you send its first rule.

THIS IS THE SAME ARRAY `PATCH` ACCEPTS, so the obvious read-modify-write is safe: read a store, change one entry, send the array back. `value` is returned in the shape we STORED it, which is the normalised one - a bare `20000` you sent for `follower_count` reads back as `{"count": 20000, "platform": null}`, and sending that object again changes nothing.

It is deliberately NOT our internal effective rule set. Terms an operator set on our own dashboard through the older per-venue columns are not folded in here, because you can neither send nor clear those through this API and a term you cannot remove is worse than one you cannot see. Everything this array contains, `clear_rules` can remove.

Array<object>

One term this store asks of a creator.

`ethnicity`, `age_band` and `gender` are real members of our attribute list and are REFUSED with `422 validation_error` on both this API and our dashboard. Filtering paid work by a protected characteristic needs a written policy agreed with counsel, and until one exists we will not store the rule.

`follower_count` takes `gte` or `lte` and a value of `{"count": N}`, optionally with `"platform"` to say WHERE the count is measured - `{"count": 20000, "platform": "tiktok"}` means twenty thousand on TikTok, not twenty thousand in total from somebody who also has a TikTok handle. `platform` and `language` take `eq` with one value or `in` with a list; over a creator who works on several, `eq` means “this is one of hers”, never “this is her only one”.

`home_metro` (local creators only) takes `in`; `radius_miles` (within N miles of this store) takes `lte` and the miles, `25` or `{"miles": 25}`, from 1 to 500. Both are measured from this store’s own address, which we resolve when you write the rule and again when the address moves; an address we cannot place in a US city is a `422`.

`performance_index` (content performance score, 0 to 100) and `engagement_rate` (percent, `3.5` means 3.5%) take `gte` and a number. They are floors.

A creator we hold no answer for is decided by the store’s own policy, which passes by default - so adding a `language` rule today records your intent and excludes nobody until we hold languages. The follower bar, the platform, `home_metro`, `radius_miles`, `performance_index` and `engagement_rate` are the exception and always exclude a creator we cannot measure.

object

**attribute**

required

string

Allowed values: follower\_count platform language home\_metro radius\_miles performance\_index engagement\_rate

**operator**

required

string

Allowed values: gte lte in eq

**value**

required

One of:

-   [integer](#tab-panel-1-0)
-   [string](#tab-panel-1-1)
-   [Array<string>](#tab-panel-1-2)
-   [object](#tab-panel-1-3)

integer

string

Array<string>

object

**count**

integer

**platform**

string

nullable

Allowed values: instagram tiktok youtube facebook

#### Example

```json
{
  "partner_location_id": "store_123",
  "status": "active",
  "network": "example-pool",
  "timezone": "America/Los_Angeles",
  "created_at": "2026-09-10T13:22:00-07:00",
  "hours": {
    "state": "missing",
    "source": "partner"
  },
  "approval_mode": "auto",
  "pricing": {
    "currency": "USD",
    "billing_unit": "published_video",
    "creatorain": {
      "fee_per_video": 10,
      "creator_cost_per_video": {
        "min": 20,
        "max": 40
      },
      "billed_as": "creator_cost_plus_fee"
    },
    "surcharge": {
      "per_video": 10
    },
    "plan_surcharge": {
      "per_video": 5,
      "applies": false,
      "placeholder": true
    },
    "merchant": {
      "per_video": 100,
      "per_month": 200,
      "per_season": 600
    },
    "season_videos": 6,
    "source": "locked",
    "upcoming": {
      "from_month": "2026-11",
      "creatorain": {
        "fee_per_video": 10,
        "creator_cost_per_video": {
          "min": 20,
          "max": 40
        },
        "billed_as": "creator_cost_plus_fee"
      },
      "merchant": {
        "per_video": 100,
        "per_month": 200,
        "per_season": 600
      }
    }
  },
  "first_visit_due_by": "2026-10-06",
  "rules": [
    {
      "attribute": "follower_count",
      "operator": "gte",
      "value": {
        "count": 20000,
        "platform": "tiktok"
      }
    },
    {
      "attribute": "platform",
      "operator": "eq",
      "value": "tiktok"
    }
  ]
}
```

### 400

`validation_error`. `field` names the offending path, for example `plan.term_months`.

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`. Missing, malformed, unknown or revoked key.

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"
  }
}
```

### 403

`forbidden_ip`. A valid key presented from an address outside its allowlist.

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"
  }
}
```

### 409

`location_already_exists` when this `partner_location_id` already names a live store with a different name or address.

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

#### Examples

Examplealready\_exists

```json
{
  "error": {
    "code": "location_already_exists",
    "message": "This location already exists",
    "field": "partner_location_id"
  }
}
```

### 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"
  }
}
```

### 500

`internal_error`. Never carries a cause; quote the reference in the message.

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"
  }
}
```
