# Builderly API reference

Base URL: http://smartman.max-media.io
Generated from the running server on 2026-11-09T17:13:29.513Z. Every mounted route is listed with the access it needs, the parameters its handler reads and the data models it uses.

## Authentication

Send `Authorization: Bearer <token>` where a route needs a token. Add `?ionic=true` to get JSON from routes that also render pages.

- **Admin token** (`admin`): Bearer token of a site admin (Authorization: Bearer <token>).
- **User token** (`user`): Bearer token of a signed-in user of the site.
- **Optional user** (`optional-user`): Works without a token; a user token personalises the answer.
- **User with access** (`user-priv`): A signed-in user whose plan grants access to the item.
- **Page access** (`page-priv`): Pages limited to some users check the token when one is sent.
- **Webhook signature** (`webhook`): Called by a provider; verified by its signature.
- **reCAPTCHA** (`recaptcha`): Needs a reCAPTCHA token from the site form.
- **System** (`system`): Internal - called by the platform itself.

### For AI assistants: getting a token

Public endpoints (Access: Public) need no token. Everything else - changing the site, or reading its orders, bookings, customers and other private data - needs the site owner's API token.

You cannot create a token yourself, and you must not ask for the owner's password. Ask the user for a token instead - you can send them this message as it is:

> To work with your site through its API, I need an API token from you:
> 1. Sign in to your Builderly admin: https://admin.max-media.io
> 2. Open Developers > API reference (or go straight to https://admin.max-media.io/tabs/site-builder/api-docs).
> 3. Press "Generate token", copy the token and paste it here.
> The token acts as you, so only share it in this chat. You can cancel it at any time by signing out of all devices.

Then send it with every request as `Authorization: Bearer <token>`, and add `?ionic=true` to get JSON. Calls go to the site's own address (its domain), not to the reference's.

The token acts as the user: say what you will change and wait for their yes before any request that creates, changes or deletes something, never repeat the token back, and never put it in a link or a file you share.

## Status codes

| Code | Name | Meaning |
| --- | --- | --- |
| 200 | OK | It worked. The answer is the object or list asked for. |
| 201 | Created | The object was created. Some endpoints send it back; others send an empty body. |
| 202 | Accepted | The work was started and finishes in the background - for example a video being processed ({ "status": "processing" }). Check back on the object. |
| 204 | No Content | It worked, and there is nothing to send back - for example after removing a staff member. |
| 301 | Moved Permanently | The address changed; follow the Location header. |
| 400 | Bad Request | The request was refused as sent: a required field is missing, a value has the wrong type or fails validation. The body says what - often as plain text. |
| 401 | Unauthorized | No token, or one that is invalid or signed out. Without ?ionic=true, some endpoints answer this with the HTML login page instead of JSON. |
| 402 | Payment Required | The content needs a subscription: the user has no price plan that unlocks it. |
| 403 | Forbidden | The token is valid but may not do this - the record belongs to someone else, or the user is not an admin. AI builder endpoints also answer 403 when the account is out of credits. |
| 404 | Not Found | No object with that ID or URL slug, or no such endpoint. |
| 409 | Conflict | It clashes with the current state: the item is already being processed, a version is already applied, or an AI plan or preview is no longer available. |
| 410 | Gone | It existed but is no longer there - for example a comment already deleted on the social network. |
| 412 | Precondition Failed | A rule the request must meet is not met - for example push notifications of the same type at least 48 hours apart. |
| 418 | I'm a teapot | An account confirmation or password reset link was used with an email that does not match it. |
| 421 | Misdirected Request | The domain is not a Builderly site. Call the site's own address. |
| 422 | Unprocessable Content | The request was understood but could not be done - for example the AI could not read the website it was asked to clone. The message says what to try instead. |
| 429 | Too Many Requests | Slow down: the site's request limit was reached, an AI chat already has a request running, or the hourly limit of AI search answers is used up. Wait and retry. |
| 500 | Internal Server Error | Something failed on the server. Retrying later may work; if it keeps failing, the request may be one the endpoint does not handle. |
| 502 | Bad Gateway | A service the request depends on failed - for example the address a redirect forwards to. |
| 503 | Service Unavailable | Used by the lead form when an order is below its minimum value, not only for outages: read the message. |

Errors do not share one shape: depending on the endpoint the body is plain text, { "error": "..." }, { "message": "..." } or empty. Rely on the status code, and show the body to the user as the reason.

## Endpoints

### SEO & analytics

How the site is found and measured: SEO keywords, meta titles and descriptions, redirects, tracking codes and visit statistics.

#### Activity Log

##### List the activity log filters
`GET /activity-log-filters`
The action and entity values actually present, for the filter menus. Only values that occur, so no filter comes back empty.
- Access: Admin token
- Returns: a list of ActivityLog objects.
- Status codes: 200, 401, 500
- Models: ActivityLog

##### List all activity logs
`GET /activity-logs`
List activity log entries, newest first. Answers { results, limit, skip, has_more }, paged with ?skip and ?limit (capped). Filters: ?action, ?entity, ?entity_id, ?user, ?email, ?kind, ?search, ?from and ?to.
- Access: Admin token
- Query:
  - `limit` (string): How many results to return.
  - `skip` (string): How many results to skip - for paging.
- Returns: a list of ActivityLog objects.
- Status codes: 200, 401, 500
- Models: ActivityLog

##### Export activity logs
`GET /activity-logs-export`
The current selection as CSV. The same filters as /activity-logs, capped at a limit.
- Access: Admin token
- Query:
  - `limit` (string): How many results to return.
- Returns: the ActivityLog object.
- Status codes: 200, 401, 500
- Models: ActivityLog

##### Retrieve an activity log
`GET /activity-logs/:id`
One entry, including the full recorded payload. 404 when there is no such record.
- Access: Admin token
- Path:
  - `id` (string): The ID of the activity log.
- Returns: the ActivityLog object.
- Status codes: 200, 401, 404, 500
- Models: ActivityLog

#### Ga

##### Connect the Google Analytic
`POST /ga/connect`
Lists the Google Analytics accounts and properties of a Google sign-in (accessToken). Answers { hasAccount, accounts }. The token is used once and not stored.
- Access: User token
- Status codes: 200, 400, 401, 500

##### Create a Google Analytic
`POST /ga/create`
Creates or picks a Google Analytics property and puts its tag on the site. Uses the site's domain and currency. Every page is rendered again with the tag.
- Access: User token
- Body:
  - `property` (string): The Google Analytic's property.
  - `accountName` (string): The Google Analytic's account name.
  - `currencyCode` (string): The Google Analytic's currency code.
  - `propertyName` (string): The Google Analytic's property name.
  - `timeZone` (string): The Google Analytic's time zone.
  - `replaceTag` (string): The Google Analytic's replace tag.
- Status codes: 200, 400, 401, 500
- Models: MyContact, PaymentMethod

##### Disconnect the Google Analytic
`POST /ga/disconnect`
Unlinks Google Analytics and removes its tag from the site. Every page is rendered again without the tag. The Analytics property itself is not touched. Answers { connected: false }.
- Access: User token
- Status codes: 200, 401, 500
- Models: MyContact, Tracking

##### List all Google Analytics
`GET /ga/events`
Events by name over ?range, from Google Analytics. The same answers when not linked as /ga/report.
- Access: User token
- Query:
  - `range` (string): Only Google Analytics with this range.
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### List all Google Analytics
`GET /ga/pages`
Most viewed pages over ?range, from Google Analytics. The same answers when not linked as /ga/report.
- Access: User token
- Query:
  - `range` (string): Only Google Analytics with this range.
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### Retrieve the Google Analytic
`GET /ga/realtime`
Visitors on the site right now, from Google Analytics. The last 30 minutes, by minute. Cached for a minute.
- Access: User token
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### Report the Google Analytic
`GET /ga/report`
Visitors and events per day over ?range, from Google Analytics (cached). ?range picks the period. Answers { connected: false } when not linked, and noAccess when the platform lost access to the property. Answers are cached.
- Access: User token
- Query:
  - `range` (string): Only Google Analytics with this range.
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### Change the status of a Google Analytic
`GET /ga/status`
Whether Google Analytics is linked and its tag is on the site. Answers { connected } with the property when linked.
- Access: User token
- Status codes: 200, 401, 500
- Models: MyContact, Tracking

#### Gmb

##### List all Google Business Profiles
`GET /gmb/categories`
Business Profile categories matching ?q, for a region and language. ?accessToken is the owner's Google token.
- Access: User token
- Query:
  - `accessToken` (string): Only Google Business Profiles with this access token.
  - `regionCode` (string): Only Google Business Profiles with this region code.
  - `languageCode` (string): Only Google Business Profiles with this language code.
  - `q` (string): The words to search for.
- Status codes: 200, 400, 401, 500

##### Connect the Google Business Profile
`POST /gmb/connect`
Lists the Google Business Profile locations of a Google sign-in (accessToken). Answers { hasBusiness, locations, accountEmail }. The token is used once and not stored.
- Access: User token
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### Create a Google Business Profile
`POST /gmb/create`
Creates Business Profile locations (locations) for the business. 400 when the Google account has no Business Profile account. Answers 201 { locations }.
- Access: User token
- Body:
  - `locations` (string): The Google Business Profile's locations.
- Status codes: 201, 400, 401, 500
- Models: MyContact

##### Disconnect the Google Business Profile
`POST /gmb/disconnect`
Unlinks the Business Profile from the site; the profile itself stays. Answers { connected: false }.
- Access: User token
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### Import the Google Business Profile
`POST /gmb/import`
Imports a location's address, hours, services and pictures into the site. Only what is asked: importServices, importHours, importAddress, importEmail; services go into collectionId. Answers what was imported.
- Access: User token
- Body:
  - `serviceItems` (string): The Google Business Profile's service items.
  - `storefrontAddress` (string): The Google Business Profile's storefront address.
  - `regularHours` (string): The Google Business Profile's regular hours.
  - `location` (string): The Google Business Profile's location.
  - `importServices` (string): The Google Business Profile's import services.
  - `collectionId` (string): The Google Business Profile's collection id.
  - `importHours` (string): The Google Business Profile's import hours.
  - `importAddress` (string): The Google Business Profile's import address.
  - `email` (string): An email address.
  - `importEmail` (string): The Google Business Profile's import email.
- Status codes: 200, 400, 401, 500
- Models: OriginAddress, Collection, MyContact, Service

##### Create a Google Business Profile
`POST /gmb/select`
Links one Business Profile location to the site (location). Answers { connected, gmb_location }.
- Access: User token
- Body:
  - `location` (string): The Google Business Profile's location.
- Status codes: 200, 400, 401, 500
- Models: MyContact

##### Change the status of a Google Business Profile
`GET /gmb/status`
Whether a Business Profile location is linked to the site. Answers { connected } with the location when linked.
- Access: User token
- Status codes: 200, 401, 500
- Models: MyContact

#### Gsc

##### Retrieve the Search Console
`GET /gsc/breakdown`
Search Console results by query, page, country or device (?dimension). ?dimension: query, page, country or device.
- Access: User token
- Query:
  - `range` (string): Only Search Consoles with this range.
  - `type` (string): Only Search Consoles with this type.
  - `dimension` (string): Only Search Consoles with this dimension.
- Status codes: 200, 400, 401, 500
- Models: MyContact, Tracking

##### Connect the Search Console
`POST /gsc/connect`
Verifies the site in Search Console and adds it (accessToken). Puts the verification meta tag on the site, verifies it and adds the sitemap. Answers { connected, siteUrl, reporting }.
- Access: User token
- Status codes: 200, 400, 401, 409, 500
- Models: ClientMachine, MyContact, Tracking

##### Disconnect the Search Console
`POST /gsc/disconnect`
Unlinks Search Console and removes its verification tag. The site stays in the owner's Search Console. Answers { connected: false }.
- Access: User token
- Status codes: 200, 401, 500
- Models: Tracking

##### Retrieve the Search Console
`GET /gsc/performance`
Clicks, impressions and positions over ?range, from Search Console (cached). ?range picks the period, ?type the search type. Answers { connected: false } when not linked.
- Access: User token
- Query:
  - `range` (string): Only Search Consoles with this range.
  - `type` (string): Only Search Consoles with this type.
- Status codes: 200, 400, 401, 500
- Models: MyContact, Tracking

##### List all Search Consoles
`GET /gsc/sites`
Whether Google Search Console is linked and verified for the site. Answers { connected } with the site's Search Console address when linked.
- Access: User token
- Status codes: 200, 401, 500
- Models: MyContact, Tracking

#### Keyword

##### List all keywords
`GET /keywords`
The SEO keywords. Answers an array of every keyword.
- Access: Admin token
- Returns: a list of Keyword objects.
- Status codes: 200, 401, 500
- Models: Keyword

##### Retrieve a keyword
`GET /keywords/:id`
One SEO keyword. 404 when there is no such keyword.
- Access: Admin token
- Path:
  - `id` (string): The ID of the keyword.
- Returns: the Keyword object.
- Status codes: 200, 401, 404, 500
- Models: Keyword

#### Keyword Blacklist

##### Retrieve the keyword blacklist
`GET /keyword-blacklist`
Words not allowed in posts and comments. Answers the record's id and words.
- Access: User token
- Returns: the KeywordBlacklist object.
- Status codes: 200, 401, 500
- Models: KeywordBlacklist

##### Create a keyword blacklist
`POST /keyword-blacklist`
Creates a blacklist record. Answers 201 with no body.
- Access: User token
- Returns: the KeywordBlacklist object.
- Status codes: 201, 400, 401, 500
- Models: KeywordBlacklist

##### Update a keyword blacklist
`PATCH /keyword-blacklist/:id`
Updates a blacklist record. Fields outside the allowed list are silently ignored. Answers the updated record, or 404.
- Access: User token
- Path:
  - `id` (string): The ID of the keyword blacklist.
- Returns: the KeywordBlacklist object.
- Status codes: 200, 400, 401, 404, 500
- Models: KeywordBlacklist

##### Delete a keyword blacklist
`DELETE /keyword-blacklist/:id`
Deletes a blacklist record. Answers the deleted record, or 404. Records that point to it are not changed.
- Access: User token
- Path:
  - `id` (string): The ID of the keyword blacklist.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: KeywordBlacklist

#### Meta

##### List all metas
`GET /metas`
Every page's meta tags. Reads no token.
- Access: Public
- Returns: a list of Meta objects.
- Status codes: 200, 500
- Models: Meta

##### Create a meta
`POST /metas`
Creates a page's meta tags. Answers 201 with the record. Pages get theirs automatically when created, so this is for pages without one.
- Access: User token
- Returns: the Meta object.
- Status codes: 201, 400, 401, 500
- Models: Meta

##### Retrieve a meta
`GET /metas/:id`
One page's meta tags. 404 when there is no such record.
- Access: Public
- Path:
  - `id` (string): The ID of the meta.
- Returns: the Meta object.
- Status codes: 200, 404, 500
- Models: Meta

#### Pixel Data

##### List all conversions days
`GET /conversions-by-days/:days`
Each conversion by date over the last days. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of).
- Access: User token
- Path:
  - `days` (string): The conversions day's days.
- Query:
  - `on_behalf_of` (string): Only conversions days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, PixelData

##### List all conversions graph days
`GET /conversions-graph-by-days/:days`
Conversions per day over the last days, for a chart. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of).
- Access: User token
- Path:
  - `days` (string): The conversions graph day's days.
- Query:
  - `on_behalf_of` (string): Only conversions graph days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, PixelData

##### List all conversions table days
`GET /conversions-table-by-days/:days`
Conversions by event over the last days, as a table. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of).
- Access: User token
- Path:
  - `days` (string): The conversions table day's days.
- Query:
  - `on_behalf_of` (string): Only conversions table days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, PixelData

##### Count event days
`GET /event-count-by-days/:days`
How many pixel events happened per day over the last days. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of). Answers { events, count }.
- Access: User token
- Path:
  - `days` (string): The event day's days.
- Query:
  - `on_behalf_of` (string): Only event days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, PixelData

##### List all pages and screens days
`GET /pages-and-screens-by-days/:days`
The most viewed pages over the last days. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of).
- Access: User token
- Path:
  - `days` (string): The pages and screens day's days.
- Query:
  - `on_behalf_of` (string): Only pages and screens days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, MyContact, PixelData

##### List all pages and screens graph days
`GET /pages-and-screens-graph-by-days/:days`
Page views per day over the last days, for a chart. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of).
- Access: User token
- Path:
  - `days` (string): The pages and screens graph day's days.
- Query:
  - `on_behalf_of` (string): Only pages and screens graph days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: MyContact, ConnectedAccount, User, PixelData

##### Count sessions days
`GET /sessions-count-by-days/:days`
Sessions and their length per day over the last days. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of). Answers { sessions }.
- Access: User token
- Path:
  - `days` (string): The sessions day's days.
- Query:
  - `on_behalf_of` (string): Only sessions days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, PixelData

##### Count user days
`GET /user-count-by-days/:days`
Visitors per day over the last days. From the site's own pixel. 403 "Unauthorized" for an account the user may not manage (?on_behalf_of). Answers { users, count }.
- Access: User token
- Path:
  - `days` (string): The user day's days.
- Query:
  - `on_behalf_of` (string): Only user days with this on behalf of.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount, User, PixelData

#### Report

##### List all item rating over times
`GET /item-rating-over-time/:from&:to`
Ratings of chosen items over time. Answers { datasets, averageRating, totalRatings } for ?itemsString.
- Access: Admin token
- Path:
  - `from` (string): The item rating over time's from.
  - `to` (string): The item rating over time's to.
- Query:
  - `split` (string): Only item rating over times with this split.
  - `itemsString` (string): Only item rating over times with this items string.
- Status codes: 200, 401, 500
- Models: Rating

##### Report bookings over time
`GET /report-bookings-over-time/:from&:to`
Bookings per service between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The bookings over time's from.
  - `to` (string): The bookings over time's to.
- Query:
  - `split` (string): Only bookings over times with this split.
  - `services` (string): Only bookings over times with this services.
- Status codes: 200, 401, 500
- Models: Service, Booking, Order

##### Report clicks over time
`GET /report-clicks-over-time/:from&:to`
Clicks per link between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The clicks over time's from.
  - `to` (string): The clicks over time's to.
- Status codes: 200, 401, 500
- Models: Click

##### Report a coupon over time
`GET /report-coupon-over-time/:from&:to`
Use of chosen coupons (?coupons) between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The coupon over time's from.
  - `to` (string): The coupon over time's to.
- Query:
  - `split` (string): Only coupon over times with this split.
  - `coupons` (string): Only coupon over times with this coupons.
- Status codes: 200, 401, 500
- Models: Coupon, Order

##### Report an interaction over time
`GET /report-interaction-over-time/:from&:to`
Visitor interaction per day between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd. Reads no token.
- Access: Public
- Path:
  - `from` (string): The interaction over time's from.
  - `to` (string): The interaction over time's to.
- Status codes: 200, 500
- Models: Traffic

##### Report an item over time
`GET /report-item-over-time/:from&:to`
Sales of chosen products (?ids) per day between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The item over time's from.
  - `to` (string): The item over time's to.
- Query:
  - `split` (string): Only item over times with this split.
  - `ids` (string): Only item over times with this ids.
- Status codes: 200, 401, 500
- Models: Product, Order

##### Report an item sales over time
`GET /report-item-sales-over-time/:from&:to`
Sales per product between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The item sales over time's from.
  - `to` (string): The item sales over time's to.
- Status codes: 200, 401, 500
- Models: Order, Product

##### Report a newsletter over time
`GET /report-newsletter-over-time/:from&:to`
New newsletter subscribers per day between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The newsletter over time's from.
  - `to` (string): The newsletter over time's to.
- Status codes: 200, 401, 500
- Models: NewsletterContact

##### Report a payment methods revenue over time
`GET /report-payment-methods-revenue-over-time/:from&:to`
Revenue per payment method between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The payment methods revenue over time's from.
  - `to` (string): The payment methods revenue over time's to.
- Query:
  - `split` (string): Only payment methods revenue over times with this split.
  - `payments` (string): Only payment methods revenue over times with this payments.
- Status codes: 200, 401, 500
- Models: Order

##### Report a price plan over time
`GET /report-priceplan-over-time/:from&:to`
New subscriptions per plan between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The price plan over time's from.
  - `to` (string): The price plan over time's to.
- Query:
  - `split` (string): Only price plan over times with this split.
  - `price_plans` (string): Only price plan over times with this price plans.
- Status codes: 200, 401, 500
- Models: PricePlan, Subscription

##### Report a push over time
`GET /report-push-over-time/:from&:to`
New push subscribers per day between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The push over time's from.
  - `to` (string): The push over time's to.
- Status codes: 200, 401, 500
- Models: PushToken

##### Report sales over time
`GET /report-sales-over-time/:from&:to`
Sales per day between two dates (yyyy-mm-dd). Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The sales over time's from.
  - `to` (string): The sales over time's to.
- Status codes: 200, 401, 500
- Models: Order

##### Report a shipping over time
`GET /report-shipping-over-time/:from&:to`
Orders per delivery method between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The shipping over time's from.
  - `to` (string): The shipping over time's to.
- Query:
  - `split` (string): Only shipping over times with this split.
  - `shippings` (string): Only shipping over times with this shippings.
- Status codes: 200, 401, 500
- Models: Order

##### Report a traffic over time
`GET /report-traffic-over-time/:from&:to`
Sessions and page views per day between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The traffic over time's from.
  - `to` (string): The traffic over time's to.
- Status codes: 200, 401, 500
- Models: Traffic

##### Report users over time
`GET /report-users-over-time/:from&:to`
New users per day between two dates. Renders the report page; with ?ionic answers its data as JSON. Dates are yyyy-mm-dd.
- Access: Admin token
- Path:
  - `from` (string): The users over time's from.
  - `to` (string): The users over time's to.
- Status codes: 200, 401, 500
- Models: User

##### List all user item rating over times
`GET /user-item-rating-over-time/:from&:to`
Ratings of the user's items of a kind (?type) over time. 404 "No ratings found". Answers the series with the average to 2 decimals.
- Access: Admin token
- Path:
  - `from` (string): The user item rating over time's from.
  - `to` (string): The user item rating over time's to.
- Query:
  - `charAt` (string): Only user item rating over times with this char at.
  - `slice` (string): Only user item rating over times with this slice.
  - `type` (string): Only user item rating over times with this type.
- Status codes: 200, 401, 404, 500
- Models: Model, Rating

#### Tracking

##### List all trackings
`GET /trackings`
The site's tracking scripts. Answers an array of every record.
- Access: Public
- Returns: a list of Tracking objects.
- Status codes: 200, 500
- Models: Tracking

##### Create a tracking
`POST /trackings`
Creates a tracking script. Every page is rendered again with the script. Answers 201.
- Access: Admin token
- Returns: the Tracking object.
- Status codes: 201, 400, 401, 500
- Models: Tracking

##### Retrieve a tracking
`GET /trackings/:id`
One tracking script. 404 when there is no such record.
- Access: Public
- Path:
  - `id` (string): The ID of the tracking.
- Returns: the Tracking object.
- Status codes: 200, 404, 500
- Models: Tracking

##### Update a tracking
`PATCH /trackings/:id`
Updates a tracking script. Fields outside the allowed list are silently ignored. Answers the updated record, or 404.
- Access: Admin token
- Path:
  - `id` (string): The ID of the tracking.
- Returns: the Tracking object.
- Status codes: 200, 400, 401, 404, 500
- Models: Tracking

##### Delete a tracking
`DELETE /trackings/:id`
Deletes a tracking script. Answers the deleted record, or 404. Records that point to it are not changed.
- Access: Admin token
- Path:
  - `id` (string): The ID of the tracking.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: Tracking

## Objects

### ActivityLog

- `actor.user`: ObjectId, → User
- `actor.email`: String
- `actor.name`: String
- `actor.kind`: String, one of admin | customer | guest | system, default "guest"
- `action`: String, required - What happened, in domain terms: create, update, delete, order, add_to_cart, login, login_failed, logout, ... See ACTIONS in utils/activity-log.js.
- `entity`: String - What it happened to. `entity` is a model name ('Product'); `label` is the human-readable name captured at write time, so the log still reads correctly after the underlying record is renamed or deleted.
- `entity_id`: String - Id of the record the action changed.
- `label`: String - What was done, in words ("Updated product").
- `method`: String - Where it came from, for tracing an entry back to a specific request.
- `path`: String - The API path that was called.
- `status`: Number - The HTTP status the call answered with.
- `changes`: Mixed - The fields the call sent, as they were written.
- `ip`: String - IP address the call came from.
- `user_agent`: String - Browser or client that made the call.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Booking

One appointment a client booked for a service.

- `date`: String - Booking date.
- `date_iso`: Date - The booked date as an ISO string.
- `depart_date`: String - End date of a stay (date-range bookings).
- `depart_date_iso`: Date - End date as an ISO string.
- `price`: Number - What the booking costs.
- `time`: String - Booking time.
- `local_time`: String - The booked time in the customer's time zone.
- `isLastHour`: Boolean - The booking took the day's last free slot, so the day is marked fully booked.
- `organization_name`: String - For invoicing.
- `name`: String, required - Customer's full name.
- `firstname`: String - Customer's first name.
- `lastname`: String - Customer's last name.
- `email`: String, required - Customer's email.
- `phone_number`: String, required - Customer's phone number.
- `address`: String, required - Customer's address.
- `city`: String, required - Customer's city.
- `state`: String - Customer's state or region.
- `country`: String, required - Customer's country.
- `zip_code`: String, required - Customer's postal code.
- `tax_identification_number`: String - For invoicing.
- `notes`: String - What the customer wrote with the booking.
- `service_id`: ObjectId, → Service - Id of booked service.
- `staff_member`: ObjectId, → User - Booked staff member.
- `coupon`: ObjectId - Applied coupon.
- `discount_value`: Number, default 0 - Discount value of service with applied coupon.
- `finalized`: Boolean, default false - The booking went through (payment done or not needed).
- `confirmed`: Boolean, default false - The business confirmed the booking.
- `confirmed_timestamp`: Date - When it was confirmed.
- `week_reminder_sent`: Boolean - The reminder a week before was sent.
- `day_reminder_sent`: Boolean - The reminder a day before was sent.
- `status`: String - Follow-up outcome with the customer: other, churnet, not_upsell or upsell.
- `upsell`: ObjectId, → Order - Order.id.
- `staffmember_notes`: String - Notes the staff member keeps on the booking.
- `rating_mail_sent`: Boolean, default false - The email asking for a rating was sent.
- `call_attempts`: Number, default 0 - How many times the AI phone agent called about it.
- `last_call_attempt`: Date - When the last call was made.
- `attached_dynamic_models`: Object[] - Records of custom models attached to the booking.
  - `model`: ObjectId, → DynamicModel
  - `document`: ObjectId
  - `_id`: ObjectId
- `beds24_booking_id`: String - The booking's id in Beds24, when synced.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Click

- `url`: String - The link that was clicked.
- `ip`: String - IP address of the visitor who clicked.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### ClientMachine

- `domain`: String, required
- `instance_group`: String
- `port`: Number, required
- `name`: String
- `isPremium`: Boolean, default false
- `access_level`: Number, default 0
- `premium_domain`: String
- `premium_domain_parked`: Boolean, default false
- `subscription_id`: String
- `hasSSL`: Boolean, default false
- `isDeleted`: Boolean, default false
- `agreedToTerms`: Boolean, default false
- `agreedToTermsAt`: String
- `cancel.isPending`: Boolean, default false
- `cancel.timestamp`: Date
- `hasRunningCampaign`: Boolean, default false
- `transfer_ns`: String[]
- `pending_domain_transfer`: Boolean, default false
- `domain_transfer_complete`: Boolean, default false
- `isSuspended`: Boolean, default false
- `suspended_at`: Date
- `replica_sets`: Object[]
  - `instance_group`: String
  - `port`: Number, required
  - `_id`: ObjectId
- `defaultUser`: ObjectId
- `onboard_type`: String, default "generic"
- `completed_payment`: Boolean, default false
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Collection

A group or filter of items; the prefix of its name is its kind (product/, grouping/, service/, blogpost/...).

- `name`: String, required - Written "<kind>/<Name>": the prefix is where it shows - product/ (a store category), service/ (a service category), blogpost/, program-category/, donation-category/; filters: grouping/ (in a product category), calendar-filter/ (on the booking page). "service/Deep cleaning". A name without a prefix shows nowhere.
- `parent_collection`: ObjectId, → Collection - Collection.id of the parent collection.
- `picture`: ObjectId, → Media - Media.id.
- `about_page`: ObjectId, → AboutPage - Reference to AboutPage.
- `match_to_option`: Boolean, default false - Matches all products which have an option with match_to_collection true.
- `is_color`: Boolean, default false - Used for products with color options.
- `color`: String - Used to visually show the color on the page when is_color is true.
- `position`: Number - Order among collections of the same kind; lower first.
- `items`: ObjectId[] - Array<Product.id> deprecated.
- `thumbnail`: ObjectId, → Media - Media.id, shown on the store cards instead of picture.
- `_id`: ObjectId

### ConnectedAccount

- `on_behalf_of`: ObjectId, required, → User - The profile that gives authority to other user to alter his account.
- `user_account`: ObjectId, required, → User - The account which will receive certain privileges over over the account of the authorizer.
- `status`: String, default "pending" - State of the connection (connected, expired...).
- `is_authorized_to.create_posts`: Boolean, default false
- `is_authorized_to.send_messages`: Boolean, default false
- `is_authorized_to.answer_delete_comments`: Boolean, default false
- `is_authorized_to.access_engagements`: Boolean, default false
- `is_authorized_to.access_boosted_posts`: Boolean, default false
- `is_authorized_to.access_analytics`: Boolean, default false
- `is_authorized_to.alter_profile_settings`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_products`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_services`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_blogposts`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_price_plans`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_programs`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_orders`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_bookings`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_subscriptions`: Boolean, default false
- `is_authorized_to.catalogue_access.alter_purchases`: Boolean, default false
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Coupon

A discount code for checkout.

- `code`: String, required - Coupon code.
- `name`: String, required - Coupon name (not shown to end user).
- `fixed_discount`: Number - Fixed amount of discount.
- `percentage_discount`: Number - Discount in percent, e.g. 90 for 90% off.
- `shipping_discount`: Number - Shipping discount discount.
- `sale_discount`: Number - Sale discount discount.
- `quantity_discount.buy`: Number
- `quantity_discount.get`: Number
- `apply_to_all_orders`: Boolean - The coupon works on any order.
- `apply_to_all_products`: Boolean - The coupon works on every product.
- `apply_to_product`: String - The NAME of the one product the coupon works on, exactly as the product is named (not its id): the cart matches it against product names.
- `apply_to_event`: String - The NAME of the one event the coupon works on, exactly as the event is named.
- `apply_to_all_events`: Boolean - The coupon works on every event.
- `apply_to_collection`: String - The full NAME of the one category the coupon works on ("product/Candles"), not its id: the cart matches it against category names.
- `apply_to_minimum_subtotal`: Number - Minimum total amount.
- `start_date`: Date - When the coupon starts working; now when left out.
- `end_date`: Date - When it stops working, unless no_end_date is set.
- `no_end_date`: Boolean, default false - The coupon never expires; end_date is ignored.
- `limit_uses`: Number - How many times the coupon can be used in all; null (the default) for unlimited.
- `uses`: Number, default 0 - How many times it has been used (do not set).
- `_id`: ObjectId

### Keyword

An SEO keyword the site targets.

- `word`: String, required - The search phrase the site wants to rank for.
- `_id`: ObjectId

### KeywordBlacklist

- `keyword`: String[] - Words that are not allowed in posts and comments.
- `_id`: ObjectId

### Meta

The site's default meta title, description and name for search results.

- `title`: String - Title shown in search results and link previews.
- `url`: String, required - The page the tags are for.
- `description`: String - Description shown in search results and link previews.
- `site_name`: String - Site name shown in link previews.
- `image`: ObjectId - Picture shown in link previews.
- `_id`: ObjectId

### Model

- `name`: String, required
- `make`: ObjectId, → Make
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### MyContact

The site's name and contact details.

- `zip_code`: String, required - Postal/ZIP code.
- `city`: String, required - The city where the business is located.
- `address`: String, required - The street address.
- `contact`: String - Html format.
- `email`: String, required - The public contact email address.
- `google_app`: String - Link to the business's app on Google Play.
- `workhours`: String - Opening hours as text.
- `logo`: ObjectId - Media.id.
- `site_name`: String, required - The business/site name shown publicly.
- `domain`: String, required - The site's own domain.
- `stock_domain`: String - The platform subdomain the site always answers on.
- `isMarket`: Boolean, required, default false - The site is a marketplace.
- `forbidden_collections`: Object[] - Array of {collection_id}.
  - `collection_id`: ObjectId, → Collection
  - `_id`: ObjectId
- `isInit`: Boolean, default false - The site was set up from a template.
- `template`: String, default "0000" - The template the site was made from.
- `lang`: String - 2-letter language code (e.g. "en", "fr", "de").
- `allowedComponents.services`: Boolean, default true
- `allowedComponents.products`: Boolean, default true
- `allowedComponents.blogposts`: Boolean, default true
- `allowedComponents.programs`: Boolean, default true
- `favicon`: ObjectId - Media.id of the browser tab icon.
- `cacheEnabled`: Boolean - Pages are cached for faster loading.
- `has_completed_startup_prompt`: Boolean, default true - The owner went through the first AI prompt.
- `gmb_location`: String - The Google Business Profile location linked to the site.
- `ga_property`: String - The Google Analytics property linked to the site.
- `site_generated_at`: Date - When the AI builder first built this site (a plan that made the homepage). Written once (runPlan); starts the admin's 15-minute launch offer.
- `admin_first_opened_at`: Date - When the owner first opened the admin; with admin_last_opened_at it tells "never opened it" from "opened it and left".
- `admin_last_opened_at`: Date - When the owner last opened the admin.
- `admin_in_app_browser`: Boolean - The owner last opened the admin inside an app's browser.
- `domain_suggestions`: Mixed - Domain names suggested to the owner, kept so they are not suggested again.
- `_id`: ObjectId

### NewsletterContact

- `name`: String, required - Subscriber's name.
- `age`: Number - Subscriber's age.
- `email`: String, required - Subscriber's email.
- `city`: String - Subscriber's city.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Order

A completed purchase.

- `organization_name`: String - Customer's company name.
- `firstname`: String, required - Customer's first name.
- `lastname`: String, required - Customer's last name.
- `email`: String, required - Customer's email.
- `phone_number`: String, required - Customer's phone number.
- `address`: String, required - Delivery address.
- `city`: String, required - Delivery city.
- `state`: String - Delivery state or region.
- `country`: String, required - Delivery country.
- `zip_code`: String, required - Delivery postal code.
- `tax_identification_number`: String - Customer's tax number, for an invoice.
- `notes`: String - What the customer wrote with the order.
- `products`: String[] - Product ids ordered.
- `products_obj`: Object[] - The products ordered, as they were then: options, quantity and price.
  - `product_id`: ObjectId, → Product
  - `name`: String
  - `options`: String
  - `price`: Number
  - `quantity`: Number
  - `_id`: ObjectId
- `programs`: String[] - Program ids ordered.
- `programs_obj`: Object[] - The programs ordered, as they were then.
  - `program_id`: ObjectId, → Program
  - `title`: String
  - `price`: Number
  - `_id`: ObjectId
- `tickets`: ObjectId[], → Ticket - Ticket ids.
- `donations`: ObjectId[], → Donation - Donation ids.
- `donations_obj`: Object[] - The donations made with the order.
  - `donation_id`: ObjectId, → Donation
  - `name`: String
  - `options`: String
  - `price`: Number
  - `quantity`: Number
  - `_id`: ObjectId
- `value`: Number - Total of the order.
- `finalized`: Boolean, default false - Checkout was completed.
- `fulfilled`: Boolean, default false - The order was sent or handed over.
- `paid`: Boolean, default false - The order is paid.
- `delivery_method`: String - How it is delivered (courier, office, pickup...).
- `payment_method`: String - How it is paid (card, cash, invoice, PayPal).
- `shipping_cost`: Number - What delivery costs.
- `coupon_code`: String - The coupon used.
- `owner_id`: ObjectId, → User - User.id.
- `reference_id`: String - The order's id at the payment provider.
- `rating_mail_sent`: Boolean, default false - The email asking for a rating was sent.
- `shipping_label`: String - The courier's shipment label.
- `shipping_option`: String, one of address | office, default "address" - One of: address, office.
- `shipping_message`: String - The courier's last status message.
- `shipping_office`: String - The courier office it is delivered to.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### OriginAddress

An address deliveries and venues start from - a shop, warehouse or office.

- `title`: String, required - Name of the address ("Warehouse").
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### PaymentMethod

- `has_cash`: Boolean, default false - Cash on delivery is offered.
- `cash_locale`: String, default "Pay by cash" - Label of the cash option.
- `cash_instructions`: String - Instructions shown for cash payment.
- `cash_increase`: Number, default 0 - Extra charged for cash payment.
- `has_card`: Boolean, default false - Card payment is offered.
- `card_locale`: String, default "Pay with credit card" - Label of the card option.
- `email`: String - The business's email for payments.
- `country`: String - The business's country for payments.
- `has_invoicing`: Boolean, default false - Payment by invoice is offered.
- `invoice_locale`: String, default "Pay via invoice" - Label of the invoice option.
- `invoicing_instructions`: String - Instructions shown for paying by invoice.
- `currency`: String, required - Currency prices are in.
- `agreedToTerms`: Boolean, default false - The owner accepted the payment terms.
- `agreedToTermsAt`: String - When the owner accepted them.
- `merchant_id`: String - The business's merchant id at the card processor.
- `has_paypal`: Boolean, default false - PayPal is offered.
- `paypal_increase`: Number, default 0 - Extra charged for PayPal.
- `paypal_id`: String - The business's PayPal id.
- `lock_currency`: Boolean, default false - Visitors cannot switch the currency.
- `commission_percentage`: Number, default 4.4 - The platform's commission on payments.
- `two_currencies`: Boolean, default false - Prices are shown in a second currency too.
- `second_currency`: String - The second currency.
- `calculate_rate`: Boolean, default false - The second price is converted at the current rate.
- `currency_rate`: Number - Fixed rate for the second currency, when not calculated.
- `_id`: ObjectId

### PixelData

- `id`: String - Id of the site the event came from.
- `uid`: String - Id of the visitor (cookie).
- `ev`: String - The event (pageload, purchase...).
- `ed.currency`: String
- `ed.value`: Number
- `ed.payment_type`: String
- `ed.coupon`: String
- `ed.items`: Object[]
  - `item_id`: String
  - `item_name`: String
  - `affiliation`: String
  - `coupon`: String
  - `discount`: Number
  - `index`: Number
  - `item_brand`: String
  - `item_category`: String
  - `item_category2`: String
  - `item_category3`: String
  - `item_category4`: String
  - `item_category5`: String
  - `item_list_id`: String
  - `item_list_name`: String
  - `item_variant`: String
  - `location_id`: String
  - `price`: Number
  - `quantity`: Number
  - `_id`: ObjectId
- `ed.shipping_tier`: String
- `ed.virtual_currency_name`: String
- `ed.group_id`: String
- `ed.level_name`: String
- `ed.success`: Boolean
- `ed.level`: Number
- `ed.character`: String
- `ed.method`: String
- `ed.score`: Number
- `ed.transaction_id`: String
- `ed.shipping`: Number
- `ed.tax`: Number
- `ed.search_term`: String
- `ed.content_type`: String
- `ed.content_id`: String
- `ed.creative_name`: String
- `ed.creative_slot`: String
- `ed.promotion_id`: String
- `ed.promotion_name`: String
- `ed.achievement_id`: String
- `v`: String - Version of the tracking script.
- `dl`: String - The page's address.
- `rl`: String - The referring address.
- `ts`: String - When the event happened.
- `de`: String - The page's character encoding.
- `sr`: String - Screen resolution.
- `vp`: String - Viewport size.
- `cd`: String - Screen colour depth.
- `dt`: String - The page's title.
- `bn`: String - Browser name and version.
- `md`: String - Whether the device is mobile.
- `ua`: String - User agent.
- `tz`: String - Visitor's time zone offset in minutes.
- `utm_source`: String - UTM source of the visit.
- `utm_medium`: String - UTM medium.
- `utm_term`: String - UTM term.
- `utm_content`: String - UTM content.
- `utm_campaign`: String - UTM campaign.
- `utm_source_platform`: String - UTM source platform.
- `utm_creative_format`: String - UTM creative format.
- `utm_marketing_tactic`: String - UTM marketing tactic.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### PricePlan

A recurring membership plan.

- `name`: String, required - The plan's name.
- `description`: String - What the plan gives.
- `statement_descriptor`: String, required - Short description of product.
- `plan_features`: Object[] - The plan's features, listed on its card.
  - `feature_type`: String
  - `feature_name`: String
  - `feature_value`: String
  - `_id`: ObjectId
- `price`: Number, required - Price per period.
- `recurring_options.interval`: String, required
- `recurring_options.interval_count`: Number, required
- `link`: String, required - Stripe payment page link.
- `image`: ObjectId, → Media - Media.id.
- `price_id`: String, required - Id of stripe price object.
- `payment_link_id`: String, required - Id of string payment page link.
- `free_trial_days`: Number, default 0 - Days free before the first payment.
- `billing_address_collection`: String, default "auto" - Wheter to collect billing information.
- `owner_id`: ObjectId, → User - User.id.
- `times_showed`: Number, default 0 - How many times it was shown.
- `views`: ObjectId[], → User - User ids.
- `total_views`: Number, default 0 - How many times it was opened.
- `disabled`: Boolean, default false - Cannot be subscribed to.
- `ribbon`: String - Label on the card ("Popular").
- `linked_plans`: ObjectId[], → PricePlan - PricePlan ids.
- `is_hidden`: Boolean, default false - Not listed on the site.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Product

An item the store sells, with its price, images, options and delivery details.

- `name`: String, required - Name of product.
- `url`: String, required - Generated from name, no need to set it manually.
- `static_url`: String - A fixed address kept when the url changes, so old links keep working.
- `ribbon`: String - Short label shown on the product's card, e.g. "New" or "-20%".
- `striked`: String - The old price, shown crossed out next to price: for a sale ("was 12, now 9") set price to 9 and striked to "12". Empty for no sale.
- `price`: Number, required - Price of the product in the site's currency.
- `description`: String - Description of product in html format.
- `product_informations`: Object[] - Extra details listed on the product page, each { name, description } ("Material": "Soy wax").
  - `name`: String, required
  - `description`: String, required
  - `_id`: ObjectId
- `product_options`: Object[] - The choices a buyer makes (Size, Colour): each { name, options: [{ option }] }. An option's text may carry a price change in brackets, "Large (+5)", added to price. Changing the options rebuilds the product's stock lines.
  - `name`: String, required
  - `options`: Object[]
    - `option`: String, required
    - `match_to_collection`: ObjectId, → Collection
    - `quantity`: Number
    - `badge`: String
    - `option_specific_media`: ObjectId, → Media
    - `_id`: ObjectId
  - `informations`: Object[]
    - `name`: String
    - `description`: String
    - `_id`: ObjectId
  - `_id`: ObjectId
- `published`: Boolean, default true - Shown on the site. False hides it from the store and lists without deleting it.
- `available_for_purchase`: Boolean, default true - The whole product can be bought; false stops every option of it. One option sold out ("the white mug ran out") is that option's stock line: quantity 0, tracked.
- `medias`: Object[] - Array of {media}.
  - `media`: ObjectId, → Media
  - `gcs_url`: String
  - `gcs_480_30_url`: String
  - `gcs_720_30_url`: String
  - `gcs_1080_30_url`: String
  - `duration`: Number
  - `vimeo_uri`: String
  - `vimeo_picture`: String
  - `vimeo_url`: String
  - `youtube_url`: String
  - `youtube_picture`: String
  - `thumbnail`: String
  - `_id`: ObjectId
- `collection_id`: ObjectId, → Collection - Collection.id.
- `grouping`: Object[] - The grouping/ filters it appears under inside its category: each { collection_id }.
  - `collection_id`: ObjectId, → Collection
  - `_id`: ObjectId
- `owner_id`: ObjectId, required, → User - User.id.
- `connected_account_owner_id`: ObjectId, → User - User.id.
- `qty`: Number, default 1 - Not the stock: nothing reads it as stock. Stock is kept per option in stock lines (Inventory): read GET /inventory/:product_id/:option, set it with PATCH /inventory/:id {quantity}.
- `origin_address`: String - Name of the address, taken from OriginAdress model, used for filtering.
- `selected`: Boolean, default false - Featured: the home page's highlighted products block shows these first.
- `custom_1`: String - Custom defined field 1.
- `custom_2`: String - Custom defined field 2.
- `custom_3`: String - Custom defined field 3.
- `about_page`: ObjectId, → AboutPage - Reference to AboutPage model, shown in product page.
- `is_digital`: Boolean, default false - Delivered as a download, not shipped.
- `digital_contents`: Object[] - The files a buyer gets.
  - `content`: ObjectId, → DigitalContent
  - `option`: String
  - `_id`: ObjectId
- `suitability_price_plans`: ObjectId[], → PricePlan - PricePlan ids: a signed-in user with one of them sees the product as suitable (isSuitable).
- `isSuitable`: Boolean - Set per request, not stored: whether the signed-in user's price plans match the product's suitability plans.
- `brand`: String - Name of the product brand.
- `brand_logo`: ObjectId, → Media - Logo of the brand, reference to Media model.
- `weight`: Number, default 0 - Weight of the product in kg, for delivery.
- `height`: Number, default 0 - Height of the product in cm, for delivery.
- `length`: Number, default 0 - Length of the product in cm, for delivery.
- `width`: Number, default 0 - Width of the product in cm, for delivery.
- `delivery_type`: String, default "parcel" - Used for delivery, default is parcel, allowed values are books, bulk, letter, parcel or parcel_letter.
- `reference_id`: String - Id of the record it was made from (an import or a clone).
- `secondary_cta.show`: Boolean, default false
- `secondary_cta.title`: String
- `secondary_cta.webUrl`: String
- `secondary_cta.appUrl`: String
- `wildcard_url`: Mixed - The wildcard route the product answers on, when it has one.
- `sku`: Mixed - Stock keeping unit code, when the product has one.
- `reviewed`: Boolean - A moderator reviewed it (marketplace).
- `approved`: Boolean - Approved to be listed (marketplace).
- `expired`: Boolean, default false - Past expires_on and no longer listed.
- `expires_on`: Date - When the listing expires.
- `expire_reminder_sent`: Boolean, default false - The owner was reminded it expires.
- `likes`: ObjectId[], → User - User ids.
- `views`: ObjectId[], → User - User ids.
- `total_views`: Number, default 0 - How many times it was opened.
- `saves`: ObjectId[], → User - User ids.
- `times_showed`: Number, default 0 - How many times it was shown in a list.
- `requiresLogin`: Boolean, default false - Only signed-in users can see it.
- `requiresSubscription`: Boolean, default false - Only subscribers can see it.
- `price_plan_ids`: String[] - Reference to PricePlan ids.
- `linked_products`: Object[] - List of products that are shown for quick add to cart in the product page.
  - `product`: ObjectId, → Product
  - `option`: String
  - `_id`: ObjectId
- `attached_priceplans.name`: String
- `attached_priceplans.priceplans`: ObjectId[], → PricePlan
- `about_section`: ObjectId, → AboutPage - Reference to AboutPage model, shown below the add to cart button.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### PushToken

- `user`: String - User.id the device belongs to.
- `is_admin`: Boolean, default false - The device belongs to an admin, for admin notifications.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Rating

- `email`: String, required - Email of who rated.
- `text`: String - The review's text.
- `medias`: Object[] - Pictures added to the review.
  - `media`: ObjectId, → Media
  - `_id`: ObjectId
- `stars`: Number, required - Rating from 1 to 5.
- `product`: ObjectId, → Product - Product.id.
- `service`: ObjectId, → Service - Service.id.
- `program`: ObjectId, → Program - Program.id.
- `price_plan`: ObjectId, → PricePlan - PricePlan.id.
- `name`: String - Name of who rated.
- `miniapp`: ObjectId, → MiniApp - MiniApp.id.
- `staff_member`: ObjectId, → User - User.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Service

A bookable service: its duration, price, the staff who perform it and when it can be booked.

- `title`: String, required - Title of service.
- `url`: String, required - Generated from title, no need to set it manually.
- `static_url`: String - A fixed address kept when the url changes, so old links keep working.
- `header`: String - Short header of service.
- `description`: String - Body text of service.
- `bookable`: Boolean, default true - True if not set.
- `expirable`: Boolean, default false - The listing expires.
- `confirm_bookings`: Boolean, default false - Bookings wait for the business to confirm them.
- `show_notes`: Boolean, default false - Customers can write a note when booking.
- `minutes_delete_bookings`: Number - Number of minutes before the booking expires before being confirmed and is set 'expirable:true'.
- `medias`: Object[] - Attached media objects with ids.
  - `media`: ObjectId, → Media
  - `gcs_url`: String
  - `gcs_480_30_url`: String
  - `gcs_720_30_url`: String
  - `gcs_1080_30_url`: String
  - `duration`: Number
  - `vimeo_uri`: String
  - `vimeo_picture`: String
  - `vimeo_url`: String
  - `youtube_url`: String
  - `youtube_picture`: String
  - `thumbnail`: String
  - `_id`: ObjectId
- `collection_id`: ObjectId, → Collection - Collection, to which the blog post belongs.
- `price`: Number - The price of the service in the globally set currency.
- `online_payment`: Boolean, default false - Bookings are paid online.
- `book_by_date`: Boolean, default false - Whole days are booked, not time slots.
- `book_date_range`: Boolean, default false - A range of days is booked (a stay).
- `start_date`: Date - Date.
- `end_date`: Date - Date.
- `day_offset`: Number, default 0 - How many days ahead of today booking opens; 0 allows today.
- `is_recurring`: Boolean, default false - The service repeats on a schedule.
- `max_participants`: Number, required - How many people can book one slot.
- `session_duration`: Number, required - Length of a slot in minutes.
- `time_between_sessions`: Number, default 0 - Break added after each slot, in minutes.
- `discount`: Object[] - Discounts by number of sessions booked.
  - `days`: Number
  - `per_total_price`: Number
  - `fixed_price`: Number
  - `per_day`: Number
  - `_id`: ObjectId
- `monday.active`: Boolean, default false
- `monday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `tuesday.active`: Boolean, default false
- `tuesday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `wednesday.active`: Boolean, default false
- `wednesday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `thursday.active`: Boolean, default false
- `thursday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `friday.active`: Boolean, default false
- `friday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `saturday.active`: Boolean, default false
- `saturday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `sunday.active`: Boolean, default false
- `sunday.hours`: Object[]
  - `start`: String
  - `end`: String
  - `_id`: ObjectId
- `address`: String - Where is the service performed.
- `staff_member`: ObjectId[], → User - [User.id].
- `owner_id`: ObjectId, → User - User.id.
- `connected_account_owner_id`: ObjectId, → User - User.id.
- `timezone`: Number, default false - Time zone offset the slots are in, in hours.
- `choose_timezone`: Boolean - Customers pick the time zone slots are shown in.
- `origin_address`: String - OriginAddress.id where the service is given.
- `selected`: Boolean, default false - False if not set.
- `custom_1`: String - Custom defined field 1.
- `custom_2`: String - Custom defined field 2.
- `custom_3`: String - Custom defined field 3.
- `about_page`: ObjectId, → AboutPage - AboutPage.id.
- `show_only_about_page`: Boolean, default false - The service page shows only its attached page.
- `suitability_price_plans`: ObjectId[], → PricePlan - PricePlan ids.
- `isSuitable`: Boolean - Set per request, not stored: whether the signed-in user's price plans match the service's suitability plans.
- `booking_only`: Boolean - If the booking page should not show a header and footer.
- `dates_disabled`: String[] - Closed days: dates on which the service cannot be booked (a holiday, a day off). Add a date here to close it.
- `dates_booked`: String[] - Days that are fully booked.
- `receipt_about_page`: ObjectId, → AboutPage - AboutPage.id.
- `wildcard_url`: Mixed - The wildcard route it answers on, when it has one.
- `locked_hours`: Date[] - Hours that cannot be booked.
- `reviewed`: Boolean - A moderator reviewed it (marketplace).
- `approved`: Boolean - Approved to be listed (marketplace).
- `likes`: ObjectId[], → User - User ids.
- `views`: ObjectId[], → User - User ids.
- `total_views`: Number, default 0 - How many times it was opened.
- `saves`: ObjectId[], → User - User ids.
- `times_showed`: Number, default 0 - How many times it was shown in a list.
- `analytics_locales.google_event_custom_title`: String, default "schedule"
- `analytics_locales.facebook_event_custom_title`: String, default "Schedule"
- `analytics_locales.tiktok_event_custom_title`: String
- `analytics_locales.linkedin_event_custom_title`: String
- `analytics_locales.chatgpt_event_custom_title`: String
- `email_text`: String - The text the client will receive inside the email.
- `calendar_description`: String - The text the client will see when adding the appointment inside their calendar.
- `requiresLogin`: Boolean, default false - Only signed-in users can see it.
- `requiresSubscription`: Boolean, default false - Only subscribers of price_plan_ids can see it.
- `price_plan_ids`: String[] - Price plans whose subscribers can see it, with requiresSubscription.
- `calendar_filter`: Object[] - Filters shown on the booking calendar.
  - `collection_id`: ObjectId, → Collection
  - `_id`: ObjectId
- `locked_ranges`: Object[] - Date and time ranges that cannot be booked.
  - `start`: Date
  - `end`: Date
  - `_id`: ObjectId
- `connected_services`: ObjectId[], → Service - Service ids.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Subscription

- `stripe_subscription_id`: String - Id of stripe substring object.
- `user_id`: ObjectId, required, → User - Id of user who subscribet to price plan.
- `status`: Number, default 0 - 1 active, 0 cancelled or unpaid.
- `payment_intent_id`: String - Id of stripe payment intend object.
- `price_plan`: ObjectId, required, → PricePlan - Id of the subscribed price plan.
- `rating_mail_sent`: Boolean, default false - The email asking for a rating was sent.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Tracking

- `title`: String - Name of the script ("Google Tag Manager").
- `script`: String, required - The script added to the site.
- `prefix`: String - Id or prefix the script uses.
- `place_in_body`: Boolean, default false - Added to the page body instead of the head.
- `external_tracker_id`: String - E.g. pixel id.
- `external_tracker_integration`: String - E.g. Meta Conversion API.
- `event_map`: Map - Maps our canonical event names onto platform-specific identifiers. Only needed by platforms that will not accept a free-form event name: LI -> { "Purchase": "12345678" } (LinkedIn Campaign Manager conversion ids) CG -> { "SecondaryCTA": "custom" } (overrides for the built-in ChatGPT map).
- `_id`: ObjectId

### Traffic

- `session_id`: String - The visitor's session.
- `page_views`: Number - Pages viewed in the session.
- `site_session`: Number, default 0 - Website sessions.
- `app_session`: Number, default 0 - App sessions.
- `last_url`: String - Last page viewed.
- `path`: String[] - Pages viewed, in order.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### User

A person with an account on the site - customer, staff member or admin.

- `name`: String - Display name.
- `email`: String, required - Email, used to sign in.
- `avatar`: ObjectId - Media.id of the profile picture.
- `social_avatar`: String - Profile picture from a social sign-in.
- `isAdmin`: Boolean, default false - Can use the admin.
- `isStaff`: Boolean, default false - A staff member who can be booked.
- `owner_id`: ObjectId - User.id of the admin who added this user.
- `organization_name`: String - Company name.
- `firstname`: String - First name.
- `lastname`: String - Last name.
- `phone_number`: String - Phone number.
- `address`: String - Address.
- `city`: String - City.
- `state`: String - State or region.
- `country`: String - Country.
- `zip_code`: String - Postal code.
- `tax_identification_number`: String - Tax number.
- `notes`: String - Notes kept on the user.
- `isConfirmed`: Boolean, default false - The email was confirmed.
- `number_of_sales`: Number, default 0 - How many sales the user made (marketplace).
- `stripe_id`: String - The user's id in Stripe.
- `paypal_id`: String - The user's PayPal id.
- `access_level`: Number - Admin permission level; 0 is full access.
- `can_edit.site`: Boolean, default true
- `can_edit.crm`: Boolean, default true
- `can_edit.store`: Boolean, default true
- `can_edit.payments`: Boolean, default true
- `can_edit.staff`: Boolean, default true
- `validation_code`: String - Code sent to confirm the email.
- `price_plans`: ObjectId[], → PricePlan - PricePlan ids.
- `emotion`: String - Positive, neutral, negative.
- `political_spectrum`: String - Far left, left, far right, right, middle.
- `language`: Mixed - Multiple objects inside - key: value - example - "EN": 5 (5 being the weight);.
- `interests`: Mixed - Multiple objects inside - key: value - example - "hobby": 5 (5 being the weight);.
- `app_category`: Mixed - Multiple objects inside - key: value - example - "hobby": 5 (5 being the weight);.
- `user_profile`: Mixed - Multiple objects inside - key: value - example - "intelligent": 5 (5 being the weight);.
- `user_economics`: String - Low, middle, high.
- `user_education`: String - Low, middle, high.
- `marital_status`: String - Single, married.
- `age`: String - 0-18, 18-25, 25-30, 30-35, 35-45, 45-60.
- `sex`: String - Male - female.
- `attractiveness`: String - Low, medium, high.
- `following`: ObjectId[], → User - User ids.
- `followers`: ObjectId[], → User - User ids.
- `handle`: String - Unique @handle.
- `saved_posts`: ObjectId[], → Post - Post ids.
- `blocked_users`: ObjectId[], → User - User ids.
- `blocked_by`: ObjectId[], → User - User ids.
- `bio`: String - About the user.
- `wallet`: Number, default 0 - Balance in the user's wallet.
- `ip_location.city`: String
- `ip_location.continent_name`: String
- `ip_location.country_name`: String
- `ip_location.country_subdivision`: String
- `ip_location.location_latitude`: Number
- `ip_location.location_longitude`: Number
- `ip_location.last_updated`: Date
- `ip_location.ip_address`: String
- `ip_location.zip_code`: String
- `ip_location.dialing_code`: String
- `location`: Embedded - The user's chosen location.
  - `type`: String, one of Point
  - `coordinates`: Number[]
  - `_id`: ObjectId
- `checkout_recovery_at`: Date - When we last emailed them about a Premium checkout they left (utils/checkout-recovery).
- `search_history`: String[] - What the user searched for.
- `isRestricted`: Boolean, default false - Restricted by a moderator.
- `isMonetized`: Boolean, default false - Earns from their content.
- `monetization_request.isRequested`: Boolean, default false
- `monetization_request.requested_on`: Date
- `sentFollowersEmail`: Date - When the followers summary email was last sent.
- `isShadowbanned`: Boolean, default false - Their content is hidden from others without telling them.
- `custom_url`: Object[] - Custom addresses for their profile.
  - `heading`: String
  - `url`: String
  - `_id`: ObjectId
- `isWhitelisted`: Boolean, default false - Skips moderation.
- `isReviewedWhitelist`: Boolean, default false - The whitelist request was reviewed.
- `advertiser_id`: String - Id as an advertiser.
- `selected_events`: String[] - Events the user follows.
- `profile_feed_style`: String, default "list" - How their profile feed looks (grid, list).
- `hidden_users`: ObjectId[], → User - User ids whose posts are hidden from this user's feed.
- `isVerified`: Boolean, default false - Shows the verified badge.
- `saved_products`: ObjectId[], → Product - Product ids the user saved.
- `saved_programs`: ObjectId[], → Program - Program ids the user saved.
- `saved_blogposts`: ObjectId[], → Blogpots - BlogPost ids the user saved.
- `saved_services`: ObjectId[], → Service - Service ids the user saved.
- `last_used_miniapps`: ObjectId[], → MiniApp - MiniApp ids.
- `has_disabled_seen`: Boolean, default false - Read receipts are off.
- `other_address`: Object[] - Other saved addresses.
  - `firstname`: String
  - `lastname`: String
  - `email`: String
  - `phone_number`: String
  - `address`: String
  - `city`: String
  - `state`: String
  - `country`: String
  - `zip_code`: String
  - `_id`: ObjectId
- `is_disabled`: Boolean, default false - The account is disabled.
- `delete_date`: Date - When the account will be deleted.
- `trial_price_plans`: Object[] - Price plans the user is trying, and until when.
  - `end_date`: Date
  - `start_date`: Date
  - `price_plan`: ObjectId, → PricePlan
  - `_id`: ObjectId
- `lastActivity`: Date - When the user was last active.
- `attached_dynamic_models`: Object[] - Records of custom models attached to the user.
  - `model`: ObjectId, → DynamicModel
  - `document`: ObjectId
  - `_id`: ObjectId
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date
