Skip to content

One store's current state, progress and next visit

GET
/locations/{partner_location_id}
curl --request GET \
--url https://data.creatorain.com/partner/v1/locations/store_123 \
--header 'Authorization: Bearer <token>'

The store as we hold it, plus this quarter’s progress and the next confirmed creator visit. This is the read the embedded merchant dashboard is built from.

EITHER CREDENTIAL: your partner key (any store of the key), or that store’s own 30 minute token from POST /locations/{partner_location_id}/dashboard-token, sent as Authorization: Bearer <token> or ?token=<token>. A store token presented for any other store answers 401 unauthorized, and it answers the same 401 whether or not that other store exists.

published_count counts videos filmed at THIS store that are live. Videos published before 2026-09-09 carry no store and are not counted; that is a property of the data, not of the query.

rules is this store’s matching terms as they now stand, in the same shape PATCH accepts. This is the read to reconcile against if a PATCH response was ever lost.

partner_location_id
required
string
<= 200 characters

YOUR id for the store, as you sent it to POST /locations.

Example

store_123

The store, its progress and its next visit.

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
progress

This store’s progress against its plan.

object
season_target

Videos per SEASON (three months): videos_per_month x 3, following the plan in force for each month of the current season (a PATCH applies from the next month). Null when the store has no plan.

integer
nullable
quarter_target

DEPRECATED. The old name of season_target, sent for one more release with the same value. Read season_target. Before this release it held the whole-term total.

integer
nullable
published_count

Videos filmed at this store that are live.

integer
booked_count

Confirmed visits at this store that are still in the future. Same value as booked_upcoming, kept so existing readers do not break; new code should read booked_upcoming. NOT the same as pipeline.booked, which counts every creator who ever booked this season, including visits already done.

integer
booked_upcoming

Confirmed visits at this store that are still in the future (upcoming only; done, cancelled and past visits are not counted). pipeline.booked is the season total of creators who booked, so it is normally the larger of the two.

integer
next_visit

The next confirmed creator visit, or null when none is booked.

object
reservation_id
string format: uuid
arrive_at

RFC 3339 with the STORE’S offset. The digits are the restaurant’s wall clock.

string
nullable
timezone
string
nullable
notices

How the merchant at this store is reached by email. TWO BOOLEANS AND NO ADDRESS: the address a notice goes to is an account holder’s, and this body can be read with a store dashboard token, which is a merchant’s browser credential.

object
contact_present

Whether there is anybody to write to at all. False means nothing we send about this store’s bookings reaches a human, which is worth seeing before a creator turns up rather than afterwards.

boolean
single_channel

True when the address the notices go to IS the store’s own published inbox: one inbox doing two jobs. It matters because a filter, a holiday auto-responder or a bounce then takes out the booking notice and the marketing conversation together, so the visit-day fallback has to be a different channel rather than a second mail.

boolean
blocking_reasons

What stops this store from recruiting creators. Empty when recruiting can run. A store recruits only when the campaign is running, its opening hours are known and it is not paused or terminated. A paused store reports store_paused (resume it and it clears). A terminated store reports store_terminated and never store_paused: its contract is over and it cannot be resumed. When recruiting starts we send the location.recruiting webhook once, with campaign_id and first_visit_due_by.

Array<string>
Allowed values: hours_missing campaign_not_running store_paused store_terminated
pipeline

This season’s creator pipeline for the store, as counts. Cumulative: each creator is counted once, at her furthest stage, in that stage and every earlier one, so contacted >= interested >= accepted >= booked >= visited >= posted. declined (said no, or no answer after follow-ups) is separate and also inside contacted. Contacted and interested count creators in the store’s metro area; accepted and later need a signature, booking or video at THIS store.

object
contacted
integer
interested
integer
accepted
integer
booked

Creators who booked a visit here this season, counted once each at their furthest stage, done visits included. Not the same as progress.booked_upcoming, which is only the confirmed visits still to come.

integer
visited
integer
posted
integer
declined
integer
results

This season’s results (guide 8.1 to 8.4). Updates with each weekly reading of the videos. Null when the store has no season yet.

object
season_starts_on
string format: date
season_ends_on

Last day of the season.

string format: date
season_videos_published
integer
season_videos_target
integer
nullable
season_posts

Posts behind those videos (a cross-post is 2 posts, 1 video).

integer
season_plays
integer
posts_read

The season’s posts that have been read: a reading has written their numbers. At most season_posts; the rest have not been read yet, so they count toward no play or average.

integer
season_plays_posts_measured

The read posts whose plays are measured, the posts season_plays adds up. Below posts_read when a platform did not publish a post’s plays. With 0, season_plays is 0 because nothing was counted, not because the videos got no plays.

integer
average_likes_per_video
integer
nullable
average_shares_per_video

Over TikTok posts only. Null with none.

integer
nullable
average_creator_followers
integer
nullable
estimated_new_guests

Estimated groups of guests who came because of the videos. Our own model, from each post’s plays, likes, comments, shares and saves and the share of the creator’s followers who are local to the store. Updates weekly, fixed at the final reading. An estimate, not a commitment. Show it with a (?) and estimated_new_guests_help.

integer
estimated_new_guests_note
string
estimated_new_guests_help

Tooltip text for the (?) icon.

string
commitment

The season commitment check (guide 8.4). Status is met, not_met or pending. Before the final reading a check is met once reached (provisional for averages) or pending; at the final reading met or not_met. Average shares is not_measured at the final reading when no post of the season publishes shares. First visit compares the first visit that has happened with first_visit_due_by.

object
videos
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
average_creator_followers
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
season_plays
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
average_likes_per_video
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
average_shares_per_video
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
first_visit
object
value
string format: date
nullable
target
string format: date
nullable
status
string
Allowed values: met not_met pending
measured_at
string format: date-time
nullable
final
boolean
previous_season_results

The season before this one. Its final reading comes 2 weeks after it ends; from then on final is true and the block never changes. Null in the first season.

object
season_starts_on
string format: date
season_ends_on

Last day of the season.

string format: date
season_videos_published
integer
season_videos_target
integer
nullable
season_posts

Posts behind those videos (a cross-post is 2 posts, 1 video).

integer
season_plays
integer
posts_read

The season’s posts that have been read: a reading has written their numbers. At most season_posts; the rest have not been read yet, so they count toward no play or average.

integer
season_plays_posts_measured

The read posts whose plays are measured, the posts season_plays adds up. Below posts_read when a platform did not publish a post’s plays. With 0, season_plays is 0 because nothing was counted, not because the videos got no plays.

integer
average_likes_per_video
integer
nullable
average_shares_per_video

Over TikTok posts only. Null with none.

integer
nullable
average_creator_followers
integer
nullable
estimated_new_guests

Estimated groups of guests who came because of the videos. Our own model, from each post’s plays, likes, comments, shares and saves and the share of the creator’s followers who are local to the store. Updates weekly, fixed at the final reading. An estimate, not a commitment. Show it with a (?) and estimated_new_guests_help.

integer
estimated_new_guests_note
string
estimated_new_guests_help

Tooltip text for the (?) icon.

string
commitment

The season commitment check (guide 8.4). Status is met, not_met or pending. Before the final reading a check is met once reached (provisional for averages) or pending; at the final reading met or not_met. Average shares is not_measured at the final reading when no post of the season publishes shares. First visit compares the first visit that has happened with first_visit_due_by.

object
videos
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
average_creator_followers
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
season_plays
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
average_likes_per_video
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
average_shares_per_video
object
value
integer
nullable
target
integer
nullable
status
string
Allowed values: met not_met pending not_measured
first_visit
object
value
string format: date
nullable
target
string format: date
nullable
status
string
Allowed values: met not_met pending
measured_at
string format: date-time
nullable
final
boolean

Example

{
"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"
}
],
"progress": {
"season_target": 6,
"quarter_target": 6,
"published_count": 2,
"booked_count": 1,
"booked_upcoming": 1
},
"next_visit": {
"arrive_at": "2026-09-14T19:00:00-07:00",
"timezone": "America/Los_Angeles"
},
"blocking_reasons": [
"hours_missing"
],
"pipeline": {
"contacted": 38,
"interested": 7,
"accepted": 3,
"booked": 1,
"visited": 0,
"posted": 0,
"declined": 4
},
"results": {
"season_starts_on": "2026-10-01",
"season_ends_on": "2026-12-31",
"season_videos_published": 3,
"season_videos_target": 9,
"season_posts": 4,
"season_plays": 58400,
"posts_read": 4,
"season_plays_posts_measured": 4,
"average_likes_per_video": 785,
"average_shares_per_video": 106,
"average_creator_followers": 13070,
"estimated_new_guests": 24,
"estimated_new_guests_note": "Estimate from video engagement data. Not a commitment.",
"commitment": {
"videos": {
"value": 58400,
"target": 60000,
"status": "met"
},
"average_creator_followers": {
"value": 58400,
"target": 60000,
"status": "met"
},
"season_plays": {
"value": 58400,
"target": 60000,
"status": "met"
},
"average_likes_per_video": {
"value": 58400,
"target": 60000,
"status": "met"
},
"average_shares_per_video": {
"value": 58400,
"target": 60000,
"status": "met"
},
"first_visit": {
"value": "2026-10-03",
"target": "2026-10-06",
"status": "met"
}
},
"measured_at": "2026-11-09T02:00:00Z",
"final": false
},
"previous_season_results": {
"season_starts_on": "2026-10-01",
"season_ends_on": "2026-12-31",
"season_videos_published": 3,
"season_videos_target": 9,
"season_posts": 4,
"season_plays": 58400,
"posts_read": 4,
"season_plays_posts_measured": 4,
"average_likes_per_video": 785,
"average_shares_per_video": 106,
"average_creator_followers": 13070,
"estimated_new_guests": 24,
"estimated_new_guests_note": "Estimate from video engagement data. Not a commitment.",
"commitment": {
"videos": {
"value": 58400,
"target": 60000,
"status": "met"
},
"average_creator_followers": {
"value": 58400,
"target": 60000,
"status": "met"
},
"season_plays": {
"value": 58400,
"target": 60000,
"status": "met"
},
"average_likes_per_video": {
"value": 58400,
"target": 60000,
"status": "met"
},
"average_shares_per_video": {
"value": 58400,
"target": 60000,
"status": "met"
},
"first_visit": {
"value": "2026-10-03",
"target": "2026-10-06",
"status": "met"
}
},
"measured_at": "2026-11-09T02:00:00Z",
"final": false
}
}

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

{
"error": {
"code": "unauthorized"
}
}

location_not_found. No store of this key carries that partner_location_id.

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

{
"error": {
"code": "unauthorized"
}
}

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

{
"error": {
"code": "unauthorized"
}
}