# 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

### Users & staff

Users are the people with an account on the site: customers, staff members who take bookings, and admins. A user signs in with an email and password and gets a token for the API.

#### Professional Account

##### Create a professional account
`POST /professional-account`
Asks for a professional account for the signed-in user. Answers 201; it waits for review. 403 when the site puts professional pages behind a plan the user lacks; 402 when the user already has one.
- Access: User token
- Returns: the ProfessionalAccount object.
- Status codes: 201, 400, 401, 402, 403, 500
- Models: SocialModeSettings, ProfessionalAccount

##### List all professional account pages
`GET /professional-account-pages/:model`
Professional accounts that offer a kind of item, with their ratings. Answers { users, filters, advanced_filters, originAddresses }.
- Access: Optional user
- Path:
  - `model` (string): The professional account page's model.
- Query:
  - `collection` (string): Only results in this collection.
  - `origin_address` (string): Only professional account pages with this origin address.
- Status codes: 200, 404, 500
- Models: PaymentMethod, Collection, ProfessionalAccount, OriginAddress

##### List all professional accounts
`GET /professional-account-preview/:user`
A professional account's shareable page. Server-rendered with meta tags, for link previews. Cached for an hour.
- Access: Public
- Path:
  - `user` (string): Id of user, who has created the account.
- Returns: a list of ProfessionalAccount objects.
- Status codes: 200, 403, 404, 500
- Models: ProfessionalAccount

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

##### Delete a professional account
`DELETE /professional-account/:id`
Deletes a professional account. 403 when it is another user's. Answers 201.
- Access: User token
- Path:
  - `id` (string): The ID of the professional account.
- Returns: an empty answer on success.
- Status codes: 201, 401, 403, 404, 500
- Models: ProfessionalAccount

##### List all professional accounts
`GET /professional-account/:user`
A user's professional account with its services, staff and ratings. 404 when there is none; 403 when it is not approved or the user is disabled.
- Access: Optional user
- Path:
  - `user` (string): Id of user, who has created the account.
- Returns: a list of ProfessionalAccount objects.
- Status codes: 200, 403, 404, 500
- Models: ProfessionalAccount

#### User

##### Retrieve the account confirmation
`GET /account-confirmation`
The page that asks the user to confirm their email. Shown after signing up on the website.
- Access: Optional user
- Status codes: 200
- Models: MyContact

##### Block a block user
`PATCH /block-user/:id`
Blocks or unblocks a user for the signed-in user. Calling it again unblocks. Blocking also removes the follows between the two users, both ways. Answers 201.
- Access: User token
- Path:
  - `id` (string): The ID of the block user.
- Returns: the User object.
- Status codes: 201, 400, 401, 404, 500
- Models: User

##### List all blocked users
`GET /blocked-users`
Users the signed-in user blocked. Each with name, handle, avatar and whether verified.
- Access: User token
- Returns: a list of User objects.
- Status codes: 200, 401, 500
- Models: User

##### List all booking schedule full months
`GET /booking-schedule-full-month/:date`
Every booking of the user's services in the month of a date. Bookings are matched by the date format they are stored in (e.g. 2026-8-4).
- Access: Optional user, User token
- Path:
  - `date` (string): A date (YYYY-MM-DD).
- Status codes: 200, 401, 500
- Models: Service, Booking, UserLockedHours

##### List all booking schedule months
`GET /booking-schedule-month/:date`
The user's booking schedule for the month of a date: bookings and locked hours per day. One entry per day of the month, with that day's bookings and the hours that cannot be booked, for the calendar view.
- Access: Optional user, User token
- Path:
  - `date` (string): A date (YYYY-MM-DD).
- Status codes: 200, 401, 500
- Models: Service, Booking, UserLockedHours

##### List all booking schedule weeks
`GET /booking-schedule-week/:date&:direction`
The user's booking schedule for the week of a date, or the week before or after (direction). Weeks run Sunday to Saturday.
- Access: Optional user, User token
- Path:
  - `date` (string): A date (YYYY-MM-DD).
  - `direction` (string): The booking schedule week's direction.
- Status codes: 200, 401, 500
- Models: Service, Booking, UserLockedHours

##### Update the disable user
`PATCH /disable-user`
Disables the signed-in user's account; it is deleted after 90 days. Signs the user out everywhere, hides the account and sets it to be deleted 90 days later (delete_date).
- Access: User token
- Status codes: 200, 401, 500

##### Retrieve the followers email
`GET /followers-email`
Emails of the signed-in user's followers. Only the emails.
- Access: User token
- Status codes: 200, 401, 500
- Models: User

##### Generate a 2auth token with AI
`GET /generate-2auth-token`
Makes a two-factor secret for the signed-in user and answers its QR code. Answers 201 { dataUrl, outpauth_url }: the QR code to scan into an authenticator app. Two-factor stays off until PATCH /verify-token accepts a code.
- Access: User token
- Status codes: 201, 400, 401, 500
- Models: MyContact, User

##### List all user bookings
`GET /new-user-bookings`
Bookings of the user's services made after ?newer_than. Polled by the admin to show new bookings as they come in.
- Access: Optional user, User token
- Query:
  - `newer_than` (string): Only user bookings with this newer than.
- Returns: a list of Booking objects.
- Status codes: 200, 401, 500
- Models: Service, Booking

##### Retrieve the password reset
`GET /password-reset`
The page to ask for a password reset. Renders the form; it calls GET /users/send-password-reset/:email.
- Access: Optional user
- Status codes: 200
- Models: MyContact

##### Reset a reset password
`GET /reset-password/:email&:validation_code`
The page that sets a new password from a reset link. Redirects to the not-found page when the code does not match the email.
- Access: Optional user
- Path:
  - `email` (string): An email address.
  - `validation_code` (string): The reset password's validation code.
- Status codes: 200, 400, 500
- Models: MyContact

##### Retrieve the signup
`GET /signup`
The sign-up page. Renders the form; it posts to POST /users.
- Access: Optional user
- Status codes: 200
- Models: MyContact

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

##### Retrieve an u
`GET /u/:handle`
A user's public profile page; with /:id, a conversation with them. Redirects to the profile in the app; the website has no profile page of its own.
- Access: Optional user
- Path:
  - `handle` (string): The u's handle.
- Status codes: 200, 500
- Models: MyContact

##### Delete user addresses
`DELETE /user-address/:index`
Removes one of the signed-in user's saved addresses. index is the address's position in other_address, from 0.
- Access: User token
- Path:
  - `index` (string): The user address's index.
- Returns: an empty answer on success.
- Status codes: 200, 401, 500

##### List all user ads
`GET /user-ads`
Ads to show a user (?handle or ?user): products and services of other users, in social mode. Products and services of other users who boosted them, skipping users the viewer blocked. Each ad shown is counted and its owner may be notified.
- Access: Optional user
- Query:
  - `handle` (string): Only user ads with this handle.
  - `user` (string): Only user ads with this user.
- Status codes: 200, 404, 500
- Models: User, ProfessionalAccount, SocialModeSettings, Product, Service, BlogPost, PricePlan, Program, Subscription, Media, UserEngagementNotification

##### List all user attributions
`GET /user-attributions`
Revenue attributed to the signed-in user, in total and by month. Answers { total_revenue } rounded to 2 decimals.
- Access: User token
- Status codes: 200, 401, 500
- Models: AttributedRevenue

##### List all user attributions
`GET /user-attributions/:days`
Revenue attributed to the signed-in user over the last days. Answers { current_period_revenue } rounded to 2 decimals.
- Access: User token
- Path:
  - `days` (string): The user attribution's days.
- Status codes: 200, 401, 500
- Models: AttributedRevenue

##### Retrieve the user blog post
`GET /user-blogpost`
One of the user's own blog posts for its editor (?id), in social mode. Answers the post with the categories its editor needs.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user blog post.
- Returns: the BlogPost object.
- Status codes: 200, 401
- Models: BlogPost, Collection

##### Retrieve the user booking
`GET /user-booking`
One booking of the user's services (?id) with its customer and attached records. 403 when the booking is not for one of the user's services.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user booking.
- Returns: the Booking object.
- Status codes: 200, 401, 403, 500
- Models: Booking, Service, ConnectedAccount, User

##### Search user bookings
`GET /user-bookings-search/:args`
Bookings of the user's services matching a search. Matches the customer's name, phone number or email (any case), newest first, with each booking's service.
- Access: User token
- Path:
  - `args` (string): The user booking's args.
- Returns: a list of Booking objects.
- Status codes: 200, 401, 500
- Models: Service, Booking

##### List all user bookings
`GET /user-bookings/:skip`
Bookings of the user's services, a page at a time, sorted by ?sortBy and ?sortOrder. Ten at a time. Each booking comes with its service.
- Access: Optional user, User token
- Path:
  - `skip` (string): How many results to skip - for paging.
- Query:
  - `sortBy` (string): The order of the results.
  - `sortOrder` (string): Only user bookings with this sort order.
- Returns: a list of Booking objects.
- Status codes: 200, 401, 500
- Models: Service, Booking

##### Update the user churned booking
`PATCH /user-churned-booking`
Marks a booking's customer as churned (?booking_id). Used by the follow-up flow after a booking. 403 when the booking is not for one of the user's services.
- Access: Optional user, User token
- Query:
  - `booking_id` (string): Only user churned bookings with this booking id.
- Returns: the Booking object.
- Status codes: 200, 401, 403, 500
- Models: Booking

##### Confirm a user booking
`PATCH /user-confirm-booking`
Confirms a booking (?booking_id). Answers the booking with its service and staff member. 403 when the booking is not for one of the user's services.
- Access: Optional user, User token
- Query:
  - `booking_id` (string): Only user bookings with this booking id.
- Returns: the Booking object.
- Status codes: 200, 401, 403, 500
- Models: Booking

##### Retrieve the user confirmation mail
`GET /user-confirmation-mail`
Sends the signed-in user the email confirmation again. Answers with no body.
- Access: User token
- Status codes: 200, 401, 500

##### Search user confirmed bookings
`GET /user-confirmed-bookings-search/:args`
Confirmed bookings matching a search. Matches the customer's name, phone number or email, newest first.
- Access: User token
- Path:
  - `args` (string): The user confirmed booking's args.
- Returns: a list of Booking objects.
- Status codes: 200, 401, 500
- Models: Service, Booking

##### List all user confirmed bookings
`GET /user-confirmed-bookings/:skip`
Confirmed bookings of the user's services, a page at a time. Ten at a time, sorted by ?sortBy and ?sortOrder.
- Access: Optional user, User token
- Path:
  - `skip` (string): How many results to skip - for paging.
- Query:
  - `sortBy` (string): The order of the results.
  - `sortOrder` (string): Only user confirmed bookings with this sort order.
- Returns: a list of Booking objects.
- Status codes: 200, 401, 500
- Models: Service, Booking

##### List all user current bookings
`GET /user-current-bookings`
Today's and upcoming bookings of the user's services. At most 100.
- Access: Optional user, User token
- Query:
  - `sortBy` (string): The order of the results.
  - `sortOrder` (string): Only user current bookings with this sort order.
- Returns: a list of Booking objects.
- Status codes: 200, 401, 500
- Models: Service, Booking

##### Update the user did not answer booking
`PATCH /user-did-not-answer-booking`
Records that the booking's customer did not answer the call (?booking_id). Counts the attempt on the booking (call_attempts, last_call_attempt). 403 when the booking is not for one of the user's services.
- Access: Optional user, User token
- Query:
  - `booking_id` (string): Only user did not answer bookings with this booking id.
- Returns: the Booking object.
- Status codes: 200, 401, 403, 500
- Models: Booking

##### List all user dynamic models
`GET /user-dynamic-models`
Custom models the signed-in user can use, with their records. Answers { dynamic_models, user_input_models }.
- Access: User token
- Returns: a list of DynamicModel objects.
- Status codes: 200, 401, 500
- Models: DynamicModel, Model

##### Retrieve a user dynamic model
`GET /user-dynamic-models/:id`
One custom model. Only its name and fields. 404 when there is no such model.
- Access: User token
- Path:
  - `id` (string): The ID of the user dynamic model.
- Returns: the DynamicModel object.
- Status codes: 200, 401, 404, 500
- Models: DynamicModel

##### Retrieve a user follower
`GET /user-followers/:id&:skip`
A user's followers, a page at a time. Answers { users, count }.
- Access: Public
- Path:
  - `id` (string): The ID of the user follower.
  - `skip` (string): How many results to skip - for paging.
- Status codes: 200, 500
- Models: User

##### Retrieve a user following
`GET /user-following/:id&:skip`
Who a user follows, a page at a time. Answers { users, count }.
- Access: Public
- Path:
  - `id` (string): The ID of the user following.
  - `skip` (string): How many results to skip - for paging.
- Status codes: 200, 500
- Models: User

##### Retrieve a user handle
`GET /user-handle/:handle`
The user with a handle, or 404 when it is free. Answers { _id } of the user who has the handle, or null when it is free: used to check a handle before saving it.
- Access: Public
- Path:
  - `handle` (string): The user handle's handle.
- Status codes: 200, 500
- Models: User

##### Retrieve the user inbox
`GET /user-inbox`
The signed-in user's conversations, newest first, or those of an account they manage (?on_behalf_of). Each conversation with its other members and the record it is about. 403 for an account the user may not message for.
- Access: User token
- Query:
  - `on_behalf_of` (string): Only user inboxes with this on behalf of.
- Status codes: 200, 401, 403, 404, 500
- Models: ConnectedAccount, Message, User, Product, Service, BlogPost

##### List all user invoices
`GET /user-invoices`
The signed-in user's Stripe invoices. Read from Stripe and formatted for display.
- Access: User token
- Status codes: 200, 401, 500

##### Retrieve the user lead from booking
`GET /user-lead-from-booking`
The customer of a booking (?id) with their orders and other bookings. With the customer's orders, newest first, and their bookings with each service.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user lead from booking.
- Returns: the Booking object.
- Status codes: 200, 401, 500
- Models: Booking, Order, Lead, Service

##### Retrieve a user mention
`GET /user-mention/:handle`
Users whose handle starts with the text, for @mentions. An empty list for an empty search.
- Access: User token
- Path:
  - `handle` (string): The user mention's handle.
- Status codes: 200, 401, 500
- Models: User

##### Retrieve the user order
`GET /user-order`
One order of the user's own store (?id), in social mode. Only orders of the signed-in user's own store. Answers the order with its customer and their earlier orders.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user order.
- Returns: the Order object.
- Status codes: 200, 401, 500
- Models: Order, Lead, Product, Program

##### List all user payment methods
`GET /user-payment-method/:payment_method`
One of the user's saved Stripe payment methods. Read from Stripe. 404 when Stripe has no such method.
- Access: Optional user, User token
- Path:
  - `payment_method` (string): The user payment method's payment method.
- Status codes: 200, 401, 404, 500

##### List all user payments
`GET /user-payments`
The signed-in user's payment settings and the site's payment terms, with the Stripe account's capabilities. With the Stripe account's status when card payment is set up, and the merchant agreement page when there is none yet.
- Access: User token
- Status codes: 200, 401, 500
- Models: UserPaymentSettings, PaymentMethod, SocialModeSettings, AboutPage, MyContact

##### Retrieve the user price plan
`GET /user-price-plan/`
The signed-in user's price plans. The plans the user subscribes to.
- Access: User token
- Returns: the PricePlan object.
- Status codes: 200, 401, 500
- Models: User, PricePlan

##### Retrieve the user product
`GET /user-product`
One of the user's own products for its editor (?id), in social mode. Answers the product with the categories and origin addresses its editor needs, for the app with ?ionic.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user product.
- Returns: the Product object.
- Status codes: 200, 401, 500
- Models: Product, Media, Collection, OriginAddress

##### List all user products
`GET /user-products`
A user's products page (?user), in social mode. Rendered with the seller's products.
- Access: Optional user
- Query:
  - `user` (string): Only user products with this user.
- Returns: a list of Product objects.
- Status codes: 200, 500
- Models: Product, User, Media

##### Retrieve the user program
`GET /user-program`
One of the user's own programs for its editor (?id), in social mode. Answers { program, categories, topics }.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user program.
- Returns: the Program object.
- Status codes: 200, 401, 500
- Models: Program, Collection

##### Retrieve the user service
`GET /user-service`
One of the user's own services for its editor (?id), in social mode. Answers the service with the staff, categories and origin addresses its editor needs. 403 when it is not the user's, or an account they manage.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user service.
  - `on_behalf_of` (string): Only user services with this on behalf of.
- Returns: the Service object.
- Status codes: 200, 401, 403
- Models: Service, ConnectedAccount, User, Collection, OriginAddress

##### List all user services
`GET /user-services`
The signed-in user's services. Services the user is a staff member of.
- Access: User token
- Returns: a list of Service objects.
- Status codes: 200, 401, 500
- Models: Service

##### Retrieve the user shipping
`GET /user-shipping`
One of the user's own delivery settings (?id), in social mode. 404 when it is not the user's.
- Access: Optional user, User token
- Query:
  - `id` (string): The ID of the user shipping.
- Returns: the Shipping object.
- Status codes: 200, 401, 500
- Models: Shipping

##### Retrieve the user staff
`GET /user-staff`
The page of the user's own staff, in social mode. The page; it loads the staff itself.
- Access: Optional user, User token
- Status codes: 200, 401

##### Update a user token
`PATCH /user-tokens/:id`
Signs a restricted user out everywhere (clears their tokens). Does nothing unless the user is restricted.
- Access: User token
- Path:
  - `id` (string): The ID of the user token.
- Status codes: 200, 400, 401, 404, 500
- Models: User

##### Retrieve a user
`GET /user/add_staff/:owner_id&:validation_code`
Accepts a staff invitation and adds the signed-in user to the owner's staff. Opened from the invitation email; a wrong code goes to the not-found page.
- Access: User token
- Path:
  - `owner_id` (string): User.id of the admin who added this user.
  - `validation_code` (string): Code sent to confirm the email.
- Returns: the User object.
- Status codes: 200, 401, 500
- Models: User, MyContact, Publish

##### Update your user
`PATCH /user/me/password`
Changes the signed-in user's password, checking the current one. Send password (the current one) and new_password. 401 "Password not valid" when the current one is wrong.
- Access: User token
- Status codes: 200, 401, 500

##### Delete a user
`DELETE /user/remove_admin/:id`
Removes an administrator; ?deleteQuery=0 also deletes everything they made. Without deleteQuery=0 the admin's products, services, media and bookings stay. 403 for removing yourself. Answers 204.
- Access: Admin token
- Path:
  - `id` (string): The ID of the user.
- Query:
  - `deleteQuery` (string): Only users with this delete query.
- Returns: an empty answer on success.
- Status codes: 204, 401, 403, 500
- Models: User, Product, Service, Media, Booking, Order, Shipping

##### Delete a user
`DELETE /user/remove_staff/:id`
Removes a staff member of the user's account; ?deleteQuery=0 also deletes everything they made. Without deleteQuery=0 the staff member's products, services, media and bookings stay with the account. 403 for removing yourself or an admin. Answers 204.
- Access: User token
- Path:
  - `id` (string): The ID of the user.
- Query:
  - `deleteQuery` (string): Only users with this delete query.
- Returns: an empty answer on success.
- Status codes: 204, 401, 403, 500
- Models: User, Product, Service, Media, Booking, Order, Shipping

##### Create a user
`POST /user/send_staff_email`
Invites someone (email) to be staff of the user's account, or of one they manage (on_behalf_of). The invitation email carries a link to GET /user/add_staff. 403 when the user may not manage that account's staff.
- Access: Optional user, User token
- Body:
  - `on_behalf_of` (string): The user's on behalf of.
  - `email` (string): An email address.
- Status codes: 200, 401, 403, 500
- Models: ConnectedAccount

##### Create a user
`POST /users`
Signs a visitor up: creates the user, emails the confirmation and answers the user with a token. Answers 201 with { token } for the app; a website sign-up is redirected to /account-confirmation instead. The confirmation email carries the code GET /users/confirm checks. 400 when the email is taken or a field is invalid.
- Access: Public
- Returns: the User object.
- Status codes: 201, 400, 500
- Models: User

##### Create a users admin
`POST /users-admin`
Signs an administrator in to another site's account by email, creating that user when missing (can_edit), and answers a token. Used by the platform admin to open a customer's site: the user is found by email, or created with the given can_edit rights, and a fresh token is answered with 201.
- Access: Admin token
- Body:
  - `email` (string): An email address.
  - `name` (string): The users admin's name.
  - `can_edit` (string): The users admin's can edit.
- Status codes: 201, 400, 401, 500
- Models: User

##### Update a user
`PATCH /users/:id`
Updates any user (admin). For administrators. Answers the updated user, or 404. Fields outside the allowed list are ignored.
- Access: Admin token
- Path:
  - `id` (string): The ID of the user.
- Returns: the User object.
- Status codes: 200, 400, 401, 404, 500
- Models: User

##### Confirm the user
`GET /users/confirm/:email&:validation_code`
Confirms a user's email with the code they were sent and signs them in. Opened from the confirmation email: marks the email confirmed and redirects to the account page signed in. A wrong code answers 400.
- Access: Public
- Path:
  - `email` (string): An email address.
  - `validation_code` (string): Code sent to confirm the email.
- Returns: the User object.
- Status codes: 200, 400, 418, 500
- Models: User

##### Retrieve the user
`GET /users/is-logged`
Whether the visitor is signed in; refreshes their location from their IP when it is older than a week. Answers { user }, or 401 when the token is missing or no longer valid. The location lookup uses the visitor's IP and runs at most once a week.
- Access: Optional user, User token
- Status codes: 200, 401, 500

##### Sign in
`POST /users/login`
Signs a user in with email and password (or an existing token) and answers the user, a token and their active subscriptions. Answers { user, token }. With two-factor sign-in on, the first call answers 401 { needs_token: true } and the call is repeated with the code in token; a wrong code answers 401 "Invalid verification code.". 400 for a wrong email or password.
- Access: Public
- Body:
  - `email` (string): An email address.
- Returns: the User object.
- Status codes: 200, 400, 401, 500
- Models: User, PricePlan

##### Sign out
`POST /users/logout`
Signs out: removes the token used for the call. Only the token in the Authorization header is removed; the user's other devices stay signed in.
- Access: User token
- Status codes: 200, 401, 500

##### Retrieve your user
`GET /users/me`
The signed-in user with the site's settings, their orders and the programs they bought. Renders the account page on the website, or JSON for the app with ?ionic. In social mode the website sends the user to the app instead, signed in with their latest token.
- Access: Optional user, User token
- Query:
  - `skip_transactions_check` (string): Only users with this skip transactions check.
- Returns: the User object.
- Status codes: 200, 401, 404, 500
- Models: MyContact, SocialModeSettings, Publish, Order, Program, Ticket, Event, QrCode, Donation, Product, BlogPost, PricePlan, Subscription, User, Service, Shipping, Booking, PaymentMethod, ProfessionalAccount

##### Update your user
`PATCH /users/me`
Updates the signed-in user's own profile (name, address, saved items, two-factor and other allowed fields). Fields outside the allowed list are silently ignored, and the two-factor fields can never be set here (use GET /generate-2auth-token and PATCH /verify-token). Answers the updated user without its two-factor secret.
- Access: User token
- Body:
  - `saved_products` (string): The user's saved products.
  - `saved_programs` (string): The user's saved programs.
  - `saved_blogposts` (string): The user's saved blog posts.
  - `saved_services` (string): The user's saved services.
- Status codes: 200, 400, 401, 500

##### Delete your user
`DELETE /users/me`
Deletes the signed-in user's account and everything they own. Deletes the account at once and emails the user a cancellation. Answers the deleted user. Use PATCH /disable-user for the 90-day grace period instead.
- Access: User token
- Returns: an empty answer on success.
- Status codes: 200, 401, 500
- Models: ProfessionalAccount

##### Retrieve your user
`GET /users/me/avatar`
The signed-in user's profile picture. Answers the image bytes, or 404 when the user has no picture.
- Access: User token
- Status codes: 200, 401, 404, 500
- Models: Media

##### Create a user
`POST /users/me/avatar`
Uploads the signed-in user's profile picture (avatar, form field). Multipart upload; the picture is resized and stored as a media record. Redirects to the account page when done.
- Access: User token
- Status codes: 200, 400, 401

##### Delete your user
`DELETE /users/me/avatar`
Removes the signed-in user's profile picture. Deletes the media record too.
- Access: User token
- Returns: an empty answer on success.
- Status codes: 200, 401
- Models: Media

##### Retrieve your user
`GET /users/me/delete`
The account deletion page. Asks to confirm before DELETE /users/me.
- Access: User token
- Status codes: 200, 400, 401, 500

##### Retrieve your user
`GET /users/me/transactions`
The signed-in user's payments: Stripe invoices, payment intents and subscriptions. Read live from Stripe, so it is as current as Stripe is and takes a moment. 404 when the user has no Stripe customer yet.
- Access: Optional user, User token
- Query:
  - `skip_transactions_check` (string): Only users with this skip transactions check.
- Status codes: 200, 401, 404, 500
- Models: PaymentMethod, PricePlan

##### Retrieve the user
`GET /users/on-behalf-of`
The account the signed-in user manages for someone else (?on_behalf_of), with its orders. The same as /users/me, for an account the signed-in user has been given access to. 404 when there is no such connection.
- Access: Optional user, User token
- Query:
  - `on_behalf_of` (string): Only users with this on behalf of.
  - `skip_transactions_check` (string): Only users with this skip transactions check.
- Returns: the User object.
- Status codes: 200, 401, 404, 500
- Models: MyContact, ConnectedAccount, Order, Product, Program, User, BlogPost, PricePlan, Subscription, Service, Shipping, Booking, PaymentMethod, Post, UserPaymentSettings, SocialModeSettings

##### List all users
`GET /users/send-password-reset/:email`
Emails a password reset link to the user. Answers 201 when the email was sent, 400 when no user has that email.
- Access: Public
- Path:
  - `email` (string): An email address.
- Returns: a list of User objects.
- Status codes: 201, 400, 500
- Models: User

##### Verify a token
`PATCH /verify-token`
Checks a two-factor code (token) and turns two-factor sign-in on when it is right. Answers { verified }.
- Access: User token
- Status codes: 200, 400, 401, 500
- Models: User

#### User Engagement Notification

##### List all user engagement notifications
`GET /latest-user-engagement-notifications/:users`
The signed-in user's latest notifications. The newest 5.
- Access: User token
- Path:
  - `users` (string): The user engagement notification's users.
- Returns: a list of UserEngagementNotification objects.
- Status codes: 200, 401, 500
- Models: UserEngagementNotification, Post, Group

##### List all user engagement notifications
`GET /new-user-engagement-notifications`
The signed-in user's unseen notifications. Answers { notifications_count, messages_count }, for the badges.
- Access: User token
- Returns: a list of UserEngagementNotification objects.
- Status codes: 200, 401, 500
- Models: UserEngagementNotification

##### Update the seen message notification
`PATCH /seen-my-message-notification`
Marks the signed-in user's message notifications seen. Answers the notifications marked.
- Access: User token
- Status codes: 200, 401, 500
- Models: UserEngagementNotification

##### Update the seen notification
`PATCH /seen-my-notifications`
Marks the signed-in user's notifications seen. Answers the notifications marked.
- Access: User token
- Status codes: 200, 401, 500
- Models: UserEngagementNotification

##### List all system user engagement notifications
`GET /system-user-engagement-notifications`
System notifications for the signed-in user. Newest first.
- Access: User token
- Returns: a list of UserEngagementNotification objects.
- Status codes: 200, 401, 500
- Models: UserEngagementNotification

##### List all user engagement notifications
`GET /user-engagement-notifications`
The signed-in user's notifications. The newest 50, with the post, comment or item each is about, skipping blocked users.
- Access: User token
- Returns: a list of UserEngagementNotification objects.
- Status codes: 200, 401, 500
- Models: UserEngagementNotification, Post, Group

##### List all user engagement notifications
`GET /user-engagement-notifications/:skip&:users`
The signed-in user's notifications, a page at a time. Skips users the viewer blocked.
- Access: User token
- Path:
  - `skip` (string): How many results to skip - for paging.
  - `users` (string): The user engagement notification's users.
- Returns: a list of UserEngagementNotification objects.
- Status codes: 200, 401, 500
- Models: UserEngagementNotification

#### User Privilege

##### List all user privileges
`GET /user-privileges`
Who can see each kind of content (sign-in, subscription). Answers an array of every record.
- Access: Public
- Status codes: 200, 500

##### Create a user privilege
`POST /user-privileges`
Creates a content access setting. A site has one; update it with PATCH instead. Answers 201.
- Access: Admin token
- Status codes: 201, 400, 401, 500

##### Retrieve a user privilege
`GET /user-privileges/:id`
The content access settings by id. 404 when there is no such record.
- Access: Public
- Path:
  - `id` (string): The ID of the user privilege.
- Status codes: 200, 404, 500

##### Update a user privilege
`PATCH /user-privileges/:id`
Updates a content access setting. Fields outside the allowed list are silently ignored. Answers the updated record, or 404.
- Access: Admin token
- Path:
  - `id` (string): The ID of the user privilege.
- Status codes: 200, 400, 401, 404, 500

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

#### User Report

##### List all mini app reports
`GET /mini-app-reports/:skip`
Reports of mini apps, a page at a time. Answers { userReports, count }.
- Access: User token
- Path:
  - `skip` (string): How many results to skip - for paging.
- Status codes: 200, 400, 401, 500
- Models: UserReport

##### Create a user report
`POST /user-report`
Creates an user report. Answers 201 with no body.
- Access: User token
- Returns: the UserReport object.
- Status codes: 201, 400, 401, 500
- Models: UserReport

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

##### List all user reports
`GET /user-reports/:skip&:limit`
Reports of posts, users and comments, a page at a time. Answers reported posts, comments and users, and content flagged by the blacklist, with counts.
- Access: User token
- Path:
  - `skip` (string): How many results to skip - for paging.
  - `limit` (string): How many results to return.
- Returns: a list of UserReport objects.
- Status codes: 200, 401, 500
- Models: UserReport, KeywordBlacklist, Post

#### AI builder

##### Create a staff member with AI
`POST /create-staff-member`
Create a staff member from a prompt, written by the AI builder.
- Access: Admin token
- Body:
  - `prompt` (string): What the AI should do with the staff member, in plain words - any language.
  - `chatId` (string): The AI chat this request belongs to; its history and language carry over. Leave it out to start a new chat.
  - `aiVersion` (string): Which version of the AI builder to use; leave it out for the current one.
  - `item_id` (string): The ID of the staff member to change.
- Status codes: 200, 401, 500
- Models: ChatMessage

##### Create a staff schedule with AI
`POST /create-staff-schedule`
Create a staff schedule from a prompt, written by the AI builder.
- Access: Admin token
- Body:
  - `prompt` (string): What the AI should do with the staff schedule, in plain words - any language.
  - `chatId` (string): The AI chat this request belongs to; its history and language carry over. Leave it out to start a new chat.
  - `aiVersion` (string): Which version of the AI builder to use; leave it out for the current one.
  - `item_id` (string): The ID of the staff schedule to change.
- Status codes: 200, 401, 500
- Models: ChatMessage

##### Generate a staff with AI
`POST /generate-staff`
Use it to create a new staff member or team member account.
- Access: Admin token
- Body:
  - `prompt` (string): What the AI should do with the staff, in plain words - any language.
  - `chatId` (string): The AI chat this request belongs to; its history and language carry over. Leave it out to start a new chat.
- Status codes: 200, 401, 500

##### Generate a staff schedule with AI
`POST /generate-staff-schedule`
Use it to lock or block time slots in a staff member's schedule.
- Access: Admin token
- Body:
  - `prompt` (string): What the AI should do with the staff schedule, in plain words - any language.
  - `chatId` (string): The AI chat this request belongs to; its history and language carry over. Leave it out to start a new chat.
- Status codes: 200, 401, 500

## Objects

### AboutPage

A page built in the editor or by the AI builder. Its content is in containers: each container is a full-width section with columns, and each column has components, laid out on a 12-column grid by their size.

- `requiresLogin`: Boolean, default false - Only signed-in users can see the page.
- `requiresSubscription`: Boolean, default false - Only subscribers of one of price_plan_ids can see the page.
- `price_plan_ids`: String[] - The price plans whose subscribers can see the page, with requiresSubscription.
- `title`: String, required - The page's title, shown in the browser tab and in the admin.
- `url`: String, required - The page's address on the site: /<url>. Unique.
- `redirectUrl`: String - When set, visitors who open the page are sent to this address instead.
- `legal_kind`: String - For legal pages: which document it is, in English (Privacy Policy, Terms of Service...).
- `isPartial`: Boolean, default false - A part of other pages (a banner, a block inside a product page), not a page of its own.
- `showTo`: String, default "0" - Who sees the page: "0" everyone, "1" signed-in users only, "2" visitors who are not signed in.
- `showHeader`: Boolean, default true - Show the site's header on the page.
- `showFooter`: Boolean, default true - Show the site's footer on the page.
- `ai_context_v2`: Mixed - Legacy, no longer written: the AI context is built on demand. Old copies are not selected and are removed by npm run migrate:strip-about-page-ai-context.
- `ai_surfaces_v2`: Mixed - The editable regions the AI page modifier found on the page last time it read it; written by the AI builder.
- `ai_overview`: String - A short summary of the page the AI builder keeps for its own use.
- `ai_generation_metadata`: Mixed - How the AI builder generated the page (mode, prompt, timings); written by the AI builder.
- `containers`: Object[] - The page's content: sections, each with columns of components.
  - `isFluid`: Boolean, default false
  - `parallaxEnabled`: Boolean
  - `parallaxAmount`: Number
  - `parallaxZoom`: Number
  - `continuousEnabled`: Boolean, default false
  - `continuousEffect`: String, default "none"
  - `continuousDuration`: Number, default 2400
  - `continuousIntensity`: Number, default 4
  - `backgroundImage`: String
  - `backgroundSize`: String
  - `backgroundPosition`: String
  - `backgroundRepeat`: String
  - `backgroundVideo`: String
  - `backgroundColor`: String
  - `backgroundGradient.enabled`: Boolean, default false
  - `backgroundGradient.type`: String
  - `backgroundGradient.degrees`: Number
  - `backgroundGradient.radialShape`: String
  - `backgroundGradient.radialPosition`: String
  - `backgroundGradient.colors`: Object[]
    - `color`: String
    - `percentage`: Number
    - `_id`: ObjectId
  - `backgroundGradient.css`: String
  - `backgroundParallax`: Boolean, default false
  - `minHeight`: Number
  - `minHeightMobile`: Number
  - `padding_top.value`: String, default ""
  - `padding_top.unit`: String, default "px"
  - `padding_top.mobile_value`: String, default ""
  - `padding_top.mobile_unit`: String, default "px"
  - `padding_right.value`: String, default ""
  - `padding_right.unit`: String, default "px"
  - `padding_right.mobile_value`: String, default ""
  - `padding_right.mobile_unit`: String, default "px"
  - `padding_bottom.value`: String, default ""
  - `padding_bottom.unit`: String, default "px"
  - `padding_bottom.mobile_value`: String, default ""
  - `padding_bottom.mobile_unit`: String, default "px"
  - `padding_left.value`: String, default ""
  - `padding_left.unit`: String, default "px"
  - `padding_left.mobile_value`: String, default ""
  - `padding_left.mobile_unit`: String, default "px"
  - `allowOffset`: Boolean, default false
  - `offsetX`: Number, default 0
  - `offsetY`: Number, default 0
  - `offsetMobileX`: Number, default 0
  - `offsetMobileY`: Number, default 0
  - `zIndex`: Number, default 0
  - `wrap_reverse`: Boolean, default false
  - `borderRadius`: Number, default 0
  - `marginX`: Number, default 0
  - `editorName`: String
  - `horizontalScroll`: Boolean, default false
  - `horizontalScrollWidth`: Number, default 100
  - `overflowX`: String, default "hidden"
  - `columns`: Object[]
    - `size`: String
    - `hoverGroup`: Boolean
    - `parallaxEnabled`: Boolean
    - `parallaxAmount`: Number
    - `parallaxZoom`: Number
    - `continuousEnabled`: Boolean, default false
    - `continuousEffect`: String, default "none"
    - `continuousDuration`: Number, default 2400
    - `continuousIntensity`: Number, default 4
    - `sticky`: Boolean, default false
    - `justify`: String
    - `align`: String
    - `onHoverActions`: Boolean, default false
    - `onHoverTransition`: Number, default 0.3
    - `backgroundColor`: String
    - `backgroundGradient.enabled`: Boolean, default false
    - `backgroundGradient.type`: String
    - `backgroundGradient.degrees`: Number
    - `backgroundGradient.radialShape`: String
    - `backgroundGradient.radialPosition`: String
    - `backgroundGradient.colors`: Object[]
      - `color`: String
      - `percentage`: Number
      - `_id`: ObjectId
    - `backgroundGradient.css`: String
    - `backgroundColorOnHover`: String
    - `innerBackgroundColor`: String
    - `innerBackgroundGradient.enabled`: Boolean, default false
    - `innerBackgroundGradient.type`: String
    - `innerBackgroundGradient.degrees`: Number
    - `innerBackgroundGradient.radialShape`: String
    - `innerBackgroundGradient.radialPosition`: String
    - `innerBackgroundGradient.colors`: Object[]
      - `color`: String
      - `percentage`: Number
      - `_id`: ObjectId
    - `innerBackgroundGradient.css`: String
    - `innerBackgroundColorOnHover`: String
    - `backgroundImage`: String
    - `backgroundSize`: String
    - `backgroundPosition`: String
    - `backgroundRepeat`: String
    - `backgroundVideo`: String
    - `paddingX`: Number, default 0
    - `paddingXOnHover`: Number, default 0
    - `paddingY`: Number, default 0
    - `paddingYOnHover`: Number, default 0
    - `innerPaddingX`: Number, default 0
    - `innerPaddingXOnHover`: Number, default 0
    - `innerPaddingY`: Number, default 0
    - `allowOffset`: Boolean, default false
    - `offsetX`: Number, default 0
    - `offsetY`: Number, default 0
    - `offsetMobileX`: Number, default 0
    - `offsetMobileY`: Number, default 0
    - `zIndex`: Number, default 0
    - `innerPaddingYOnHover`: Number, default 0
    - `paddingOptions`: String
    - `paddingOptionsOnHover`: String
    - `innerPaddingOptions`: String
    - `borderOptions`: String
    - `borderOptionsOnHover`: String
    - `card`: Boolean, default false
    - `borderRadius`: Number, default 0
    - `borderRadiusOnHover`: Number, default 0
    - `borderType`: String, default "none"
    - `borderTypeOnHover`: String, default "none"
    - `borderWidth`: Number, default 0
    - `borderWidthOnHover`: Number, default 0
    - `borderColor`: String, default ""
    - `borderColorOnHover`: String, default ""
    - `components`: Object[]
      - `type`: String
      - `size`: String, default "12"
      - `sticky`: Boolean, default false
      - `paddingX`: Number, default 0
      - `paddingY`: Number, default 0
      - `allowOffset`: Boolean, default false
      - `offsetX`: Number, default 0
      - `offsetY`: Number, default 0
      - `offsetMobileX`: Number, default 0
      - `offsetMobileY`: Number, default 0
      - `zIndex`: Number, default 0
      - `position`: String, one of static | relative | absolute | fixed | sticky, default "static"
      - `top.value`: String, default "0"
      - `top.unit`: String, default "px"
      - `top.mobile_value`: String, default ""
      - `top.mobile_unit`: String, default "px"
      - `left.value`: String, default "0"
      - `left.unit`: String, default "px"
      - `left.mobile_value`: String, default ""
      - `left.mobile_unit`: String, default "px"
      - `right.value`: String, default "0"
      - `right.unit`: String, default "px"
      - `right.mobile_value`: String, default ""
      - `right.mobile_unit`: String, default "px"
      - `bottom.value`: String, default "0"
      - `bottom.unit`: String, default "px"
      - `bottom.mobile_value`: String, default ""
      - `bottom.mobile_unit`: String, default "px"
      - `custom_measurements`: Boolean, default false
      - `edit_type`: String, default "simple"
      - `custom_width.value`: Mixed
      - `custom_width.unit`: String, default "px"
      - `custom_width.mobile_value`: Mixed
      - `custom_width.mobile_unit`: String, default "px"
      - `custom_min_width.value`: Mixed
      - `custom_min_width.unit`: String, default "px"
      - `custom_min_width.mobile_value`: Mixed
      - `custom_min_width.mobile_unit`: String, default "px"
      - `custom_max_width.value`: Mixed
      - `custom_max_width.unit`: String, default "px"
      - `custom_max_width.mobile_value`: Mixed
      - `custom_max_width.mobile_unit`: String, default "px"
      - `custom_height.value`: Mixed
      - `custom_height.unit`: String, default "px"
      - `custom_height.mobile_value`: Mixed
      - `custom_height.mobile_unit`: String, default "px"
      - `custom_min_height.value`: Mixed
      - `custom_min_height.unit`: String, default "px"
      - `custom_min_height.mobile_value`: Mixed
      - `custom_min_height.mobile_unit`: String, default "px"
      - `custom_max_height.value`: Mixed
      - `custom_max_height.unit`: String, default "px"
      - `custom_max_height.mobile_value`: Mixed
      - `custom_max_height.mobile_unit`: String, default "px"
      - `object_fit`: String, default "none"
      - `aspect_ratio.custom`: Boolean, default false
      - `aspect_ratio.ratio`: String, default ""
      - `min_height`: Number, default 0
      - `margin_left.value`: Mixed
      - `margin_left.unit`: String, default "px"
      - `margin_left.mobile_value`: Mixed
      - `margin_left.mobile_unit`: String, default "px"
      - `margin_right.value`: Mixed
      - `margin_right.unit`: String, default "px"
      - `margin_right.mobile_value`: Mixed
      - `margin_right.mobile_unit`: String, default "px"
      - `margin_top.value`: Mixed
      - `margin_top.unit`: String, default "px"
      - `margin_top.mobile_value`: Mixed
      - `margin_top.mobile_unit`: String, default "px"
      - `margin_bottom.value`: Mixed
      - `margin_bottom.unit`: String, default "px"
      - `margin_bottom.mobile_value`: Mixed
      - `margin_bottom.mobile_unit`: String, default "px"
      - `padding_left.value`: Mixed
      - `padding_left.unit`: String, default "px"
      - `padding_left.mobile_value`: Mixed
      - `padding_left.mobile_unit`: String, default "px"
      - `padding_right.value`: Mixed
      - `padding_right.unit`: String, default "px"
      - `padding_right.mobile_value`: Mixed
      - `padding_right.mobile_unit`: String, default "px"
      - `padding_top.value`: Mixed
      - `padding_top.unit`: String, default "px"
      - `padding_top.mobile_value`: Mixed
      - `padding_top.mobile_unit`: String, default "px"
      - `padding_bottom.value`: Mixed
      - `padding_bottom.unit`: String, default "px"
      - `padding_bottom.mobile_value`: Mixed
      - `padding_bottom.mobile_unit`: String, default "px"
      - `border_left.color`: String
      - `border_left.width.value`: Mixed
      - `border_left.width.unit`: String, default "px"
      - `border_left.style`: String
      - `border_right.color`: String
      - `border_right.width.value`: Mixed
      - `border_right.width.unit`: String, default "px"
      - `border_right.style`: String
      - `border_top.color`: String
      - `border_top.width.value`: Mixed
      - `border_top.width.unit`: String, default "px"
      - `border_top.style`: String
      - `border_bottom.color`: String
      - `border_bottom.width.value`: Mixed
      - `border_bottom.width.unit`: String, default "px"
      - `border_bottom.style`: String
      - `border_top_left_radius.value`: Mixed
      - `border_top_left_radius.unit`: String, default "px"
      - `border_top_right_radius.value`: Mixed
      - `border_top_right_radius.unit`: String, default "px"
      - `border_bottom_left_radius.value`: Mixed
      - `border_bottom_left_radius.unit`: String, default "px"
      - `border_bottom_right_radius.value`: Mixed
      - `border_bottom_right_radius.unit`: String, default "px"
      - `custom_border_radius.value`: Number
      - `custom_border_radius.unit`: String, default "px"
      - `specific_border_radius`: Boolean, default false
      - `box_shadows`: Object[]
      - `mix_blend_mode`: String, one of normal | multiply | screen | overlay | darken | lighten | color-dodge | color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity, default "normal"
      - `paddingOptions`: String
      - `backgroundColor`: String
      - `backgroundGradient.enabled`: Boolean, default false
      - `backgroundGradient.type`: String
      - `backgroundGradient.degrees`: Number
      - `backgroundGradient.radialShape`: String
      - `backgroundGradient.radialPosition`: String
      - `backgroundGradient.colors`: Object[]
      - `backgroundGradient.css`: String
      - `card`: Boolean, default false
      - `borderRadius`: Number, default 0
      - `borderType`: String, default "none"
      - `borderWidth`: Number, default 0
      - `borderColor`: String, default ""
      - `borderOptions`: String
      - `showOnMobile`: Boolean, default true
      - `showOnDesktop`: Boolean, default true
      - `icon`: String
      - `iconSettings.size`: Number, default 40
      - `iconSettings.color`: String, default "var(--ion-color-primary)"
      - `heading`: String
      - `subHeading`: String
      - `heading_alignment`: String
      - `innerHTML`: String
      - `innerCSS`: String
      - `innerJS`: String
      - `lineHeight`: String, default "normal"
      - `medias`: Object[]
      - `products`: ObjectId[], → Product
      - `product_gallery.design_layout`: String, default ""
      - `product_gallery.mode`: String, default "card"
      - `product_gallery.columns`: Number, default 3
      - `product_gallery.placeholderItems`: Object[]
      - `product_gallery.placeholderPlateColor`: String, default ""
      - `product_gallery.showName`: Boolean, default true
      - `product_gallery.showPrice`: Boolean, default true
      - `product_gallery.showDescription`: Boolean, default false
      - `product_gallery.showBrand`: Boolean, default false
      - `product_gallery.showRibbon`: Boolean, default false
      - `product_gallery.showRating`: Boolean, default false
      - `product_gallery.showCart`: Boolean, default false
      - `product_gallery.showLink`: Boolean, default false
      - `product_gallery.linkLabel`: String, default "View product"
      - `product_gallery.imageAspectRatio`: String, default "1/1"
      - `product_gallery.imageHeight`: Number, default 260
      - `product_gallery.imageRadius`: Number, default 20
      - `product_gallery.imageObjectFit`: String, default "cover"
      - `product_gallery.cardBackgroundColor`: String, default "var(--ion-card-background, #ffffff)"
      - `product_gallery.cardBorderRadius`: Number, default 28
      - `product_gallery.cardBorderWidth`: Number, default 0
      - `product_gallery.cardBorderColor`: String, default "transparent"
      - `product_gallery.cardPaddingX`: Number, default 20
      - `product_gallery.cardPaddingY`: Number, default 20
      - `product_gallery.gap`: Number, default 24
      - `product_gallery.boxShadowColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.22)"
      - `product_gallery.boxShadowOffsetY`: Number, default 20
      - `product_gallery.boxShadowBlurRadius`: Number, default 40
      - `product_gallery.boxShadowSpreadRadius`: Number, default -22
      - `product_gallery.fieldBackground`: String, default "transparent"
      - `product_gallery.hairlineColor`: String, default "transparent"
      - `product_gallery.hairlineWidth`: Number, default 0
      - `product_gallery.maxWidth`: Number, default 0
      - `product_gallery.scrimGradient`: String, default ""
      - `product_gallery.align`: String, default "left"
      - `product_gallery.accentColor`: String, default "var(--ion-color-primary, #3880ff)"
      - `product_gallery.nameColor`: String, default "var(--ion-text-color, #1e293b)"
      - `product_gallery.nameFontSize`: String, default "1em"
      - `product_gallery.nameFontWeight`: String, default "700"
      - `product_gallery.nameFontFamily`: String, default ""
      - `product_gallery.nameTransform`: String, default "none"
      - `product_gallery.priceColor`: String, default "var(--ion-color-primary, #3880ff)"
      - `product_gallery.priceFontSize`: String, default "0.94em"
      - `product_gallery.priceFontWeight`: String, default "600"
      - `product_gallery.priceFontFamily`: String, default ""
      - `product_gallery.priceFontStyle`: String, default "normal"
      - `product_gallery.metaColor`: String, default "rgba(var(--ion-text-color-rgb, 30,41,59), 0.66)"
      - `product_gallery.titlePosition`: String, default "bottom"
      - `product_gallery.imageSide`: String, default "left"
      - `product_gallery.imagePadding`: Number, default 0
      - `product_gallery.boxShadowOffsetX`: Number, default 0
      - `product_gallery.descFontSize`: String, default "13px"
      - `product_gallery.descFontWeight`: String, default "400"
      - `product_gallery.animation`: String, default "none"
      - `product_gallery.animationDuration`: Number, default 0
      - `product_gallery.animationDelay`: Number, default 0
      - `product_gallery.showCustomFields`: Boolean, default false
      - `product_gallery.cardDesign`: String, default ""
      - `product_gallery.carouselLoop`: Boolean, default false
      - `product_gallery.carouselControls`: Boolean, default false
      - `product_gallery.customCss`: String, default ""
      - `services`: ObjectId[], → Service
      - `service_gallery.design_layout`: String, default ""
      - `service_gallery.mode`: String, default "card"
      - `service_gallery.columns`: Number, default 3
      - `service_gallery.placeholderItems`: Object[]
      - `service_gallery.placeholderPlateColor`: String, default ""
      - `service_gallery.showTitle`: Boolean, default true
      - `service_gallery.showPrice`: Boolean, default true
      - `service_gallery.showDescription`: Boolean, default false
      - `service_gallery.showDuration`: Boolean, default false
      - `service_gallery.durationLabel`: String, default "min"
      - `service_gallery.showImage`: Boolean, default true
      - `service_gallery.showLink`: Boolean, default false
      - `service_gallery.linkLabel`: String, default "View service"
      - `service_gallery.imageAspectRatio`: String, default "1/1"
      - `service_gallery.imageHeight`: Number, default 260
      - `service_gallery.imageRadius`: Number, default 20
      - `service_gallery.imageObjectFit`: String, default "cover"
      - `service_gallery.cardBackgroundColor`: String, default "var(--ion-card-background, #ffffff)"
      - `service_gallery.cardBorderRadius`: Number, default 28
      - `service_gallery.cardBorderWidth`: Number, default 0
      - `service_gallery.cardBorderColor`: String, default "transparent"
      - `service_gallery.cardPaddingX`: Number, default 20
      - `service_gallery.cardPaddingY`: Number, default 20
      - `service_gallery.gap`: Number, default 24
      - `service_gallery.boxShadowColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.22)"
      - `service_gallery.boxShadowOffsetY`: Number, default 20
      - `service_gallery.boxShadowBlurRadius`: Number, default 40
      - `service_gallery.boxShadowSpreadRadius`: Number, default -22
      - `service_gallery.fieldBackground`: String, default "transparent"
      - `service_gallery.hairlineColor`: String, default "transparent"
      - `service_gallery.hairlineWidth`: Number, default 0
      - `service_gallery.rowRuleColor`: String, default "transparent"
      - `service_gallery.rowRuleWidth`: Number, default 0
      - `service_gallery.maxWidth`: Number, default 0
      - `service_gallery.scrimGradient`: String, default ""
      - `service_gallery.align`: String, default "left"
      - `service_gallery.accentColor`: String, default "var(--ion-color-primary, #3880ff)"
      - `service_gallery.titleColor`: String, default "var(--ion-text-color, #1e293b)"
      - `service_gallery.titleFontSize`: String, default "1em"
      - `service_gallery.titleFontWeight`: String, default "700"
      - `service_gallery.titleFontFamily`: String, default ""
      - `service_gallery.titleTransform`: String, default "none"
      - `service_gallery.priceColor`: String, default "var(--ion-color-primary, #3880ff)"
      - `service_gallery.priceFontSize`: String, default "0.94em"
      - `service_gallery.priceFontWeight`: String, default "600"
      - `service_gallery.priceFontFamily`: String, default ""
      - `service_gallery.priceFontStyle`: String, default "normal"
      - `service_gallery.metaColor`: String, default "rgba(var(--ion-text-color-rgb, 30,41,59), 0.66)"
      - `service_gallery.titlePosition`: String, default "bottom"
      - `service_gallery.imageSide`: String, default "left"
      - `service_gallery.imagePadding`: Number, default 0
      - `service_gallery.boxShadowOffsetX`: Number, default 0
      - `service_gallery.descFontSize`: String, default "13px"
      - `service_gallery.descFontWeight`: String, default "400"
      - `service_gallery.animation`: String, default "none"
      - `service_gallery.animationDuration`: Number, default 0
      - `service_gallery.animationDelay`: Number, default 0
      - `service_gallery.showCustomFields`: Boolean, default false
      - `service_gallery.cardDesign`: String, default ""
      - `service_gallery.carouselLoop`: Boolean, default false
      - `service_gallery.carouselControls`: Boolean, default false
      - `service_gallery.customCss`: String, default ""
      - `blog_gallery.design_layout`: String, default ""
      - `blog_gallery.mode`: String, default "card"
      - `blog_gallery.columns`: Number, default 3
      - `blog_gallery.leadLayout`: String, default "beside"
      - `blog_gallery.leadWidth`: Number, default 58
      - `blog_gallery.placeholderItems`: Object[]
      - `blog_gallery.placeholderPlateColor`: String, default ""
      - `blog_gallery.showTitle`: Boolean, default true
      - `blog_gallery.showExcerpt`: Boolean, default false
      - `blog_gallery.showDate`: Boolean, default true
      - `blog_gallery.showImage`: Boolean, default true
      - `blog_gallery.showLink`: Boolean, default false
      - `blog_gallery.linkLabel`: String, default "Read more"
      - `blog_gallery.showCustomFields`: Boolean, default false
      - `blog_gallery.imageAspectRatio`: String, default "1/1"
      - `blog_gallery.imageHeight`: Number, default 260
      - `blog_gallery.imageRadius`: Number, default 20
      - `blog_gallery.imageObjectFit`: String, default "cover"
      - `blog_gallery.imagePadding`: Number, default 0
      - `blog_gallery.imageSide`: String, default "left"
      - `blog_gallery.cardBackgroundColor`: String, default "var(--ion-card-background, #ffffff)"
      - `blog_gallery.cardBorderRadius`: Number, default 28
      - `blog_gallery.cardBorderWidth`: Number, default 0
      - `blog_gallery.cardBorderColor`: String, default "transparent"
      - `blog_gallery.cardPaddingX`: Number, default 20
      - `blog_gallery.cardPaddingY`: Number, default 20
      - `blog_gallery.gap`: Number, default 24
      - `blog_gallery.boxShadowColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.22)"
      - `blog_gallery.boxShadowOffsetX`: Number, default 0
      - `blog_gallery.boxShadowOffsetY`: Number, default 20
      - `blog_gallery.boxShadowBlurRadius`: Number, default 40
      - `blog_gallery.boxShadowSpreadRadius`: Number, default -22
      - `blog_gallery.fieldBackground`: String, default "transparent"
      - `blog_gallery.hairlineColor`: String, default "transparent"
      - `blog_gallery.hairlineWidth`: Number, default 0
      - `blog_gallery.rowRuleColor`: String, default "transparent"
      - `blog_gallery.rowRuleWidth`: Number, default 0
      - `blog_gallery.maxWidth`: Number, default 0
      - `blog_gallery.scrimGradient`: String, default ""
      - `blog_gallery.align`: String, default "left"
      - `blog_gallery.accentColor`: String, default "var(--ion-color-primary, #3880ff)"
      - `blog_gallery.titleColor`: String, default "var(--ion-text-color, #1e293b)"
      - `blog_gallery.titleFontSize`: String, default "1em"
      - `blog_gallery.titleFontWeight`: String, default "700"
      - `blog_gallery.titleFontFamily`: String, default ""
      - `blog_gallery.titleTransform`: String, default "none"
      - `blog_gallery.dateColor`: String, default "var(--ion-color-primary, #3880ff)"
      - `blog_gallery.dateFontSize`: String, default "0.81em"
      - `blog_gallery.dateFontWeight`: String, default "600"
      - `blog_gallery.dateFontFamily`: String, default ""
      - `blog_gallery.dateFontStyle`: String, default "normal"
      - `blog_gallery.metaColor`: String, default "rgba(var(--ion-text-color-rgb, 30,41,59), 0.66)"
      - `blog_gallery.excerptFontSize`: String, default "0.88em"
      - `blog_gallery.excerptFontWeight`: String, default "400"
      - `blog_gallery.excerptFontFamily`: String, default ""
      - `blog_gallery.titlePosition`: String, default "bottom"
      - `blog_gallery.animation`: String, default "none"
      - `blog_gallery.animationDuration`: Number, default 0
      - `blog_gallery.animationDelay`: Number, default 0
      - `blog_gallery.cardDesign`: String, default ""
      - `blog_gallery.customCss`: String, default ""
      - `multi_booking.layout`: String, default "chips"
      - `multi_booking.columns`: Number, default 3
      - `multi_booking.pickerBackground`: String, default "transparent"
      - `multi_booking.gap`: Number, default 10
      - `multi_booking.align`: String, default "left"
      - `multi_booking.showPrice`: Boolean, default false
      - `multi_booking.showDuration`: Boolean, default false
      - `multi_booking.showDescription`: Boolean, default false
      - `multi_booking.showImage`: Boolean, default false
      - `multi_booking.itemPaddingX`: Number, default 18
      - `multi_booking.itemPaddingY`: Number, default 10
      - `multi_booking.itemRadius`: Number, default 100
      - `multi_booking.itemBorderWidth`: Number, default 0
      - `multi_booking.itemBorderColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.12)"
      - `multi_booking.itemBackground`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.10)"
      - `multi_booking.itemTextColor`: String, default "var(--ion-text-color, inherit)"
      - `multi_booking.itemSubTextColor`: String, default "var(--ion-color-medium, rgba(0,0,0,0.55))"
      - `multi_booking.selectedBackground`: String, default "var(--ion-color-primary)"
      - `multi_booking.selectedTextColor`: String, default "var(--ion-color-primary-contrast, #ffffff)"
      - `multi_booking.selectedSubTextColor`: String, default "rgba(var(--ion-color-primary-contrast-rgb, 255,255,255), 0.75)"
      - `multi_booking.selectedBorderColor`: String, default "var(--ion-color-primary)"
      - `multi_booking.hoverBackground`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.18)"
      - `multi_booking.titleFontSize`: Number, default 14
      - `multi_booking.titleFontWeight`: String, default "500"
      - `multi_booking.subFontSize`: Number, default 13
      - `multi_booking.dividerColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.12)"
      - `multi_booking.dividerWidth`: Number, default 1
      - `multi_booking.autoScroll`: Boolean, default true
      - `multi_booking.cardBackground`: String, default "var(--ion-card-color, #ffffff)"
      - `multi_booking.cardRadius`: Number, default 28
      - `multi_booking.cardBorderWidth`: Number, default 0
      - `multi_booking.cardBorderColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.12)"
      - `multi_booking.cardMaxWidth`: Number, default 820
      - `multi_booking.cardLayout`: String, default "stack"
      - `multi_booking.splitWidth`: Number, default 340
      - `multi_booking.shadowColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.18)"
      - `multi_booking.shadowOffsetY`: Number, default 20
      - `multi_booking.shadowBlur`: Number, default 40
      - `multi_booking.shadowSpread`: Number, default -22
      - `multi_booking.sectionPaddingX`: Number, default 40
      - `multi_booking.sectionPaddingY`: Number, default 32
      - `multi_booking.sectionDividerColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.12)"
      - `multi_booking.sectionDividerWidth`: Number, default 1
      - `multi_booking.showStepLabels`: Boolean, default true
      - `multi_booking.serviceStepLabel`: String, default "Step 1 — Service"
      - `multi_booking.dayStepLabel`: String, default "Step 2 — Day"
      - `multi_booking.staffStepLabel`: String, default "Step 3 — Staff member"
      - `multi_booking.timeStepLabel`: String, default "Step 4 — Time"
      - `multi_booking.stepLabelColor`: String, default "var(--ion-color-medium, rgba(0,0,0,0.55))"
      - `multi_booking.stepLabelSize`: Number, default 13
      - `multi_booking.stepLabelWeight`: String, default "700"
      - `multi_booking.stepLabelSpacing`: Number, default 0.04
      - `multi_booking.stepLabelUppercase`: Boolean, default true
      - `multi_booking.dayCount`: Number, default 6
      - `multi_booking.dayLayout`: String, default "strip"
      - `multi_booking.dayBorderColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.15)"
      - `multi_booking.dayShape`: String, default "circle"
      - `multi_booking.daySize`: Number, default 64
      - `multi_booking.dayGap`: Number, default 10
      - `multi_booking.dayShowWeekday`: Boolean, default false
      - `multi_booking.dayBackground`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.10)"
      - `multi_booking.dayTextColor`: String, default "var(--ion-text-color, inherit)"
      - `multi_booking.daySelectedBackground`: String, default "var(--ion-color-primary)"
      - `multi_booking.daySelectedTextColor`: String, default "var(--ion-color-primary-contrast, #ffffff)"
      - `multi_booking.dayDisabledOpacity`: Number, default 0.35
      - `multi_booking.timeGap`: Number, default 10
      - `multi_booking.timeRadius`: Number, default 100
      - `multi_booking.timeBorderWidth`: Number, default 0
      - `multi_booking.timeBorderColor`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.15)"
      - `multi_booking.timeSelectedBorderColor`: String, default "var(--ion-color-primary)"
      - `multi_booking.timePaddingX`: Number, default 18
      - `multi_booking.timePaddingY`: Number, default 10
      - `multi_booking.timeBackground`: String, default "rgba(var(--ion-color-primary-rgb, 56,128,255), 0.10)"
      - `multi_booking.timeTextColor`: String, default "var(--ion-text-color, inherit)"
      - `multi_booking.timeSelectedBackground`: String, default "var(--ion-color-primary)"
      - `multi_booking.timeSelectedTextColor`: String, default "var(--ion-color-primary-contrast, #ffffff)"
      - `multi_booking.buttonText`: String, default "Confirm my booking"
      - `multi_booking.buttonBackground`: String, default "var(--ion-color-primary)"
      - `multi_booking.buttonTextColor`: String, default "var(--ion-color-primary-contrast, #ffffff)"
      - `multi_booking.buttonRadius`: Number, default 100
      - `multi_booking.buttonPaddingY`: Number, default 16
      - `multi_booking.buttonFontSize`: Number, default 15
      - `multi_booking.buttonFontWeight`: String, default "700"
      - `multi_booking.buttonFullWidth`: Boolean, default true
      - `blogposts`: ObjectId[], → BlogPost
      - `videos`: ObjectId[], → Video
      - `price_plans`: ObjectId[], → PricePlan
      - `href`: String, default "#"
      - `router_link`: String
      - `buttonOptions.fill`: String
      - `buttonOptions.expand`: String
      - `buttonOptions.size`: String
      - `buttonOptions.color`: String
      - `buttonOptions.class`: String
      - `buttonOptions.customColor`: String
      - `buttonOptions.customColorContrast`: String
      - `buttonOptions.customColorHover`: String
      - `buttonOptions.hoverRoll`: Boolean
      - `buttonOptions.fontWeight`: Number
      - `buttonOptions.letterSpacing`: Number
      - `buttonOptions.fontSize`: Number, default 14
      - `buttonOptions.borderRadius`: Number, default 6
      - `buttonOptions.customColorA`: String
      - `buttonOptions.customColorB`: String
      - `buttonOptions.customColorC`: String
      - `buttonOptions.custom_measurements`: Boolean, default false
      - `buttonOptions.height.value`: String
      - `buttonOptions.height.unit`: String
      - `buttonOptions.width.value`: String
      - `buttonOptions.width.unit`: String
      - `carousel.showArrows`: Boolean, default true
      - `carousel.showIndicators`: Boolean, default true
      - `carousel.height`: Number, default 90
      - `carousel.automaticHeight`: Boolean, default true
      - `carousel.carouselMedias`: Object[]
      - `map`: String
      - `contactForm.name`: String
      - `contactForm.email`: String
      - `contactForm.subject`: String
      - `contactForm.body`: String
      - `contactForm.button`: String
      - `contactForm.hideNewsletter`: Boolean
      - `contactForm.placeholders.name`: String
      - `contactForm.placeholders.email`: String
      - `contactForm.placeholders.subject`: String
      - `contactForm.placeholders.body`: String
      - `contactForm.style.backgroundColor`: String
      - `contactForm.style.textColor`: String
      - `contactForm.style.accentColor`: String
      - `contactForm.style.border.color`: String
      - `contactForm.style.border.width.value`: Mixed
      - `contactForm.style.border.width.unit`: String
      - `contactForm.style.border.style`: String
      - `contactForm.style.borderRadius.value`: Mixed
      - `contactForm.style.borderRadius.unit`: String
      - `contactForm.style.padding.value`: Mixed
      - `contactForm.style.padding.unit`: String
      - `contactForm.style.labelFontSize.value`: Mixed
      - `contactForm.style.labelFontSize.unit`: String
      - `contactForm.style.consentFontSize.value`: Mixed
      - `contactForm.style.consentFontSize.unit`: String
      - `contactForm.style.inputBackgroundColor`: String
      - `contactForm.style.inputTextColor`: String
      - `contactForm.style.placeholderColor`: String
      - `contactForm.style.inputFocusColor`: String
      - `contactForm.style.inputFontSize.value`: Mixed
      - `contactForm.style.inputFontSize.unit`: String
      - `contactForm.style.inputPadding.value`: Mixed
      - `contactForm.style.inputPadding.unit`: String
      - `contactForm.style.textareaMinHeight.value`: Mixed
      - `contactForm.style.textareaMinHeight.unit`: String
      - `contactForm.style.inputMargin.value`: Mixed
      - `contactForm.style.inputMargin.unit`: String
      - `contactForm.style.inputBorder.color`: String
      - `contactForm.style.inputBorder.width.value`: Mixed
      - `contactForm.style.inputBorder.width.unit`: String
      - `contactForm.style.inputBorder.style`: String
      - `contactForm.style.inputBorderRadius.value`: Mixed
      - `contactForm.style.inputBorderRadius.unit`: String
      - `contactForm.style.buttonBackgroundColor`: String
      - `contactForm.style.buttonTextColor`: String
      - `contactForm.style.buttonAlign`: String
      - `contactForm.style.buttonFontSize.value`: Mixed
      - `contactForm.style.buttonFontSize.unit`: String
      - `contactForm.style.buttonBorder.color`: String
      - `contactForm.style.buttonBorder.width.value`: Mixed
      - `contactForm.style.buttonBorder.width.unit`: String
      - `contactForm.style.buttonBorder.style`: String
      - `contactForm.style.buttonBorderRadius.value`: Mixed
      - `contactForm.style.buttonBorderRadius.unit`: String
      - `contactForm.style.buttonWidth.value`: Mixed
      - `contactForm.style.buttonWidth.unit`: String
      - `contactForm.additional`: Object[]
      - `instagram.columns`: Number
      - `instagram.first`: Number
      - `instagram.skip`: Number
      - `instagram.showInfo`: Boolean
      - `instagram.gridType`: Number
      - `instagram.profile`: String
      - `facebook.url`: String
      - `facebook.width`: String
      - `facebook.height`: String
      - `animation`: String, default "none"
      - `animationDuration`: Number, default 0
      - `animationStrength`: Number
      - `parallaxEnabled`: Boolean
      - `parallaxAmount`: Number
      - `parallaxZoom`: Number
      - `textReveal`: String
      - `animationDelay`: Number, default 0
      - `animationReplay`: String, default "once"
      - `animationEasing`: String, default "power3.out"
      - `animationBreakpoint`: String, default "all"
      - `scrollScrubEnabled`: Boolean, default false
      - `scrollScrubAxis`: String, default "y"
      - `scrollScrubDistance`: Number, default 80
      - `motionOrigin`: String, default "center center"
      - `hoverEnabled`: Boolean, default false
      - `hoverEffect`: String, default "none"
      - `hoverDuration`: Number, default 240
      - `hoverIntensity`: Number, default 4
      - `continuousEnabled`: Boolean, default false
      - `continuousEffect`: String, default "none"
      - `continuousDuration`: Number, default 2400
      - `continuousIntensity`: Number, default 4
      - `statefulEnabled`: Boolean, default false
      - `statefulEffect`: String, default "none"
      - `statefulDuration`: Number, default 260
      - `statefulStagger`: Number, default 60
      - `transform.enabled`: Boolean, default false
      - `transform.translateX.value`: Number, default 0
      - `transform.translateX.unit`: String, default "px"
      - `transform.translateY.value`: Number, default 0
      - `transform.translateY.unit`: String, default "px"
      - `transform.scaleX`: Number, default 1
      - `transform.scaleY`: Number, default 1
      - `transform.rotate`: Number, default 0
      - `transform.rotateX`: Number, default 0
      - `transform.rotateY`: Number, default 0
      - `transform.skewX`: Number, default 0
      - `transform.skewY`: Number, default 0
      - `transform.perspective`: Number, default 0
      - `transform.originX`: String, default "center"
      - `transform.originY`: String, default "center"
      - `opacity`: Mixed
      - `transitionDuration`: Mixed
      - `transitionEasing`: String
      - `states`: Mixed
      - `useIframe`: Boolean, default false
      - `popup.text`: String
      - `popup.backgroundColor`: String
      - `popup.fullScreen`: Boolean, default false
      - `popup.about_page`: ObjectId, → AboutPage
      - `custom_component.html`: String
      - `custom_component.compiled_html`: String
      - `custom_component.css`: String
      - `custom_component.compiled_css`: String
      - `custom_component.js`: String
      - `custom_component.iframe`: Boolean, default false
      - `custom_component.variables`: Object[]
      - `hoverable_media.before_hover_media.media`: ObjectId, → Media
      - `hoverable_media.before_hover_media.gcs_url`: String
      - `hoverable_media.before_hover_media.vimeo_uri`: String
      - `hoverable_media.before_hover_media.vimeo_picture`: String
      - `hoverable_media.before_hover_media.youtube_url`: String
      - `hoverable_media.before_hover_media.vimeo_url`: String
      - `hoverable_media.before_hover_media.href`: String
      - `hoverable_media.before_hover_media.router_link`: String
      - `hoverable_media.before_hover_media.thumbnail`: String
      - `hoverable_media.before_hover_media.autoplay`: Boolean, default false
      - `hoverable_media.before_hover_media.loop`: Boolean, default false
      - `hoverable_media.before_hover_media.show_controls`: Boolean, default true
      - `hoverable_media.after_hover_media.media`: ObjectId, → Media
      - `hoverable_media.after_hover_media.gcs_url`: String
      - `hoverable_media.after_hover_media.vimeo_uri`: String
      - `hoverable_media.after_hover_media.vimeo_picture`: String
      - `hoverable_media.after_hover_media.youtube_url`: String
      - `hoverable_media.after_hover_media.vimeo_url`: String
      - `hoverable_media.after_hover_media.href`: String
      - `hoverable_media.after_hover_media.router_link`: String
      - `hoverable_media.after_hover_media.thumbnail`: String
      - `hoverable_media.after_hover_media.autoplay`: Boolean, default false
      - `hoverable_media.after_hover_media.loop`: Boolean, default false
      - `hoverable_media.after_hover_media.show_controls`: Boolean, default true
      - `collapsible_container`: Object[]
      - `collapsible_container_settings.enable_customization`: Boolean, default false
      - `collapsible_container_settings.title_color`: String
      - `collapsible_container_settings.title_color_checked`: String
      - `collapsible_container_settings.title_background`: String
      - `collapsible_container_settings.title_background_checked`: String
      - `collapsible_container_settings.title_font_size`: String
      - `collapsible_container_settings.title_border_radius`: String
      - `collapsible_container_settings.title_border_color`: String
      - `collapsible_container_settings.title_border_width`: String
      - `collapsible_container_settings.body_color`: String
      - `collapsible_container_settings.body_background`: String
      - `collapsible_container_settings.body_border_radius`: String
      - `collapsible_container_settings.body_border_color`: String
      - `collapsible_container_settings.body_border_width`: String
      - `collapsible_container_settings.body_font_size`: String
      - `collapsible_container_settings.icon_color`: String
      - `collapsible_container_settings.icon_glyph_color`: String
      - `collapsible_container_settings.icon_background_color`: String
      - `quiz.title`: String
      - `quiz.header`: String
      - `quiz.questions`: Object[]
      - `quiz.score_results`: Object[]
      - `quiz.show_right_answers`: Boolean, default false
      - `quiz.mutliple_choice`: Boolean, default false
      - `partners.defaultCollection`: String, default ""
      - `partners.defaultView`: String, default "locations"
      - `scroll_sequence.media`: ObjectId, → Media
      - `scroll_sequence.scroll_length`: Number, default 3
      - `scroll_sequence.fit`: String, one of cover | contain, default "cover"
      - `scroll_sequence.background_color`: String, default "#000000"
      - `scroll_sequence.overlay_color`: String, default ""
      - `scroll_sequence.overlay_opacity`: Number, default 0
      - `scroll_sequence.rows_over`: Boolean, default true
      - `scroll_sequence.rows_effect`: String, one of slide | pop, default "slide"
      - `scroll_sequence.snap_points`: Number[]
      - `scroll_sequence.snap_scroll_speed`: Number, default 1.5
      - `scroll_sequence.snap_down`: Boolean, default true
      - `scroll_sequence.snap_up`: Boolean, default false
      - `scroll_sequence.stop_momentum`: Boolean, default false
      - `smart_search.placeholder`: String, default ""
      - `smart_search.kinds`: String[]
      - `smart_search.collections`: String[]
      - `smart_search.items`: Object[]
      - `smart_search.showKindFilter`: Boolean, default true
      - `smart_search.showPriceFilter`: Boolean, default false
      - `smart_search.showDateFilter`: Boolean, default false
      - `smart_search.showSort`: Boolean, default true
      - `smart_search.dateMode`: String, one of created | updated | availability, default "created"
      - `smart_search.layout`: String, one of grid | list, default "grid"
      - `smart_search.columns`: Number, default 3
      - `smart_search.perPage`: Number, default 12
      - `smart_search.instant`: Boolean, default true
      - `smart_search.showImages`: Boolean, default true
      - `smart_search.showPrices`: Boolean, default true
      - `smart_search.showInitial`: Boolean, default false
      - `smart_search.showAnswer`: Boolean, default false
      - `countdown.targetDate`: String, default ""
      - `countdown.expiredText`: String, default "Offer has ended"
      - `countdown.hideOnExpire`: Boolean, default false
      - `countdown.textColor`: String, default ""
      - `countdown.boxColor`: String, default ""
      - `countdown.align`: String, one of  | left | center | right, default ""
      - `swiper.slides`: Object[]
      - `swiper.autoplay`: Boolean, default false
      - `swiper.loop`: Boolean, default false
      - `swiper.show_controls`: Boolean, default true
      - `swiper.dynamic_bullets`: Boolean, default false
      - `swiper.pagination`: Boolean, default true
      - `dynamicField`: String
      - `useDynamicField`: Boolean, default false
      - `text_auto_slider.speed`: Number
      - `text_auto_slider.aspect_ratio`: String
      - `text_auto_slider.text_color`: String
      - `text_auto_slider.background_color`: String
      - `text_auto_slider.delimiter_color`: String
      - `text_auto_slider.direction`: String
      - `text_auto_slider.width`: Number
      - `text_auto_slider.font_size`: Number
      - `text_auto_slider.text_transform`: String, one of none | uppercase, default "none"
      - `text_auto_slider.texts`: Object[]
      - `image_auto_slider.speed`: Number
      - `image_auto_slider.aspect_ratio`: String
      - `image_auto_slider.direction`: String
      - `image_auto_slider.width`: Number
      - `image_auto_slider.medias`: Object[]
      - `image_dragger.aspect_ratio`: String
      - `image_dragger.media_1.media`: ObjectId, → Media
      - `image_dragger.media_1.gcs_url`: String
      - `image_dragger.media_1.vimeo_uri`: String
      - `image_dragger.media_1.vimeo_picture`: String
      - `image_dragger.media_1.vimeo_url`: String
      - `image_dragger.media_1.youtube_url`: String
      - `image_dragger.media_2.media`: ObjectId, → Media
      - `image_dragger.media_2.gcs_url`: String
      - `image_dragger.media_2.vimeo_uri`: String
      - `image_dragger.media_2.vimeo_picture`: String
      - `image_dragger.media_2.vimeo_url`: String
      - `image_dragger.media_2.youtube_url`: String
      - `image_dragger.media_2.title`: String
      - `image_dragger.media_2.body`: String
      - `image_dragger.media_2.textColor`: String
      - `image_dragger.media_2.href`: String
      - `image_dragger.media_2.router_link`: String
      - `_id`: ObjectId
    - `sections`: Object[]
      - `position`: String, one of static | relative | absolute | fixed | sticky, default "static"
      - `overflow`: String, one of visible | hidden | scroll | auto, default "visible"
      - `editorName`: String
      - `top.value`: String, default "0"
      - `top.unit`: String, default "px"
      - `top.mobile_value`: String, default ""
      - `top.mobile_unit`: String, default "px"
      - `left.value`: String, default "0"
      - `left.unit`: String, default "px"
      - `left.mobile_value`: String, default ""
      - `left.mobile_unit`: String, default "px"
      - `right.value`: String, default "0"
      - `right.unit`: String, default "px"
      - `right.mobile_value`: String, default ""
      - `right.mobile_unit`: String, default "px"
      - `bottom.value`: String, default "0"
      - `bottom.unit`: String, default "px"
      - `bottom.mobile_value`: String, default ""
      - `bottom.mobile_unit`: String, default "px"
      - `display`: String, one of block | inline | flex, default "block"
      - `flex_direction`: String, one of row | row-reverse | column | column-reverse, default "row"
      - `flex_direction_mobile`: String, default ""
      - `backdropFilter`: String, default ""
      - `justify`: String, one of start | end | center | space-between | space-around | stretch, default "start"
      - `justify_mobile`: String, default ""
      - `align`: String, one of start | end | center | space-between | space-around | stretch, default "start"
      - `align_mobile`: String, default ""
      - `animation`: String, default "none"
      - `animationDuration`: Number, default 0
      - `animationStrength`: Number
      - `parallaxEnabled`: Boolean
      - `parallaxAmount`: Number
      - `parallaxZoom`: Number
      - `animationDelay`: Number, default 0
      - `animationReplay`: String, default "once"
      - `animationEasing`: String, default "power3.out"
      - `animationBreakpoint`: String, default "all"
      - `scrollScrubEnabled`: Boolean, default false
      - `scrollScrubAxis`: String, default "y"
      - `scrollScrubDistance`: Number, default 80
      - `motionOrigin`: String, default "center center"
      - `hoverEnabled`: Boolean, default false
      - `hoverEffect`: String, default "none"
      - `hoverDuration`: Number, default 240
      - `hoverIntensity`: Number, default 4
      - `continuousEnabled`: Boolean, default false
      - `continuousEffect`: String, default "none"
      - `continuousDuration`: Number, default 2400
      - `continuousIntensity`: Number, default 4
      - `statefulEnabled`: Boolean, default false
      - `statefulEffect`: String, default "none"
      - `statefulDuration`: Number, default 260
      - `statefulStagger`: Number, default 60
      - `transform.enabled`: Boolean, default false
      - `transform.translateX.value`: Number, default 0
      - `transform.translateX.unit`: String, default "px"
      - `transform.translateY.value`: Number, default 0
      - `transform.translateY.unit`: String, default "px"
      - `transform.scaleX`: Number, default 1
      - `transform.scaleY`: Number, default 1
      - `transform.rotate`: Number, default 0
      - `transform.rotateX`: Number, default 0
      - `transform.rotateY`: Number, default 0
      - `transform.skewX`: Number, default 0
      - `transform.skewY`: Number, default 0
      - `transform.perspective`: Number, default 0
      - `transform.originX`: String, default "center"
      - `transform.originY`: String, default "center"
      - `opacity`: Mixed
      - `transitionDuration`: Mixed
      - `transitionEasing`: String
      - `states`: Mixed
      - `hoverGroup`: Boolean
      - `flex_wrap`: String, one of nowrap | wrap | wrap-reverse, default "wrap"
      - `flex_wrap_mobile`: String, default ""
      - `width.value`: String, default ""
      - `width.unit`: String, default "px"
      - `width.mobile_value`: String, default ""
      - `width.mobile_unit`: String, default "px"
      - `min_width.value`: String, default ""
      - `min_width.unit`: String, default "px"
      - `min_width.mobile_value`: String, default ""
      - `min_width.mobile_unit`: String, default "px"
      - `max_width.value`: String, default ""
      - `max_width.unit`: String, default "px"
      - `max_width.mobile_value`: String, default ""
      - `max_width.mobile_unit`: String, default "px"
      - `height.value`: String, default ""
      - `height.unit`: String, default "px"
      - `height.mobile_value`: String, default ""
      - `height.mobile_unit`: String, default "px"
      - `min_height.value`: String, default ""
      - `min_height.unit`: String, default "px"
      - `min_height.mobile_value`: String, default ""
      - `min_height.mobile_unit`: String, default "px"
      - `max_height.value`: String, default ""
      - `max_height.unit`: String, default "px"
      - `max_height.mobile_value`: String, default ""
      - `max_height.mobile_unit`: String, default "px"
      - `object_fit`: String
      - `aspect_ratio.custom`: Boolean, default false
      - `aspect_ratio.ratio`: String, default ""
      - `margin_left.value`: String, default "0"
      - `margin_left.unit`: String, default "px"
      - `margin_left.mobile_value`: String, default ""
      - `margin_left.mobile_unit`: String, default "px"
      - `margin_right.value`: String, default "0"
      - `margin_right.unit`: String, default "px"
      - `margin_right.mobile_value`: String, default ""
      - `margin_right.mobile_unit`: String, default "px"
      - `margin_top.value`: String, default "0"
      - `margin_top.unit`: String, default "px"
      - `margin_top.mobile_value`: String, default ""
      - `margin_top.mobile_unit`: String, default "px"
      - `margin_bottom.value`: String, default "0"
      - `margin_bottom.unit`: String, default "px"
      - `margin_bottom.mobile_value`: String, default ""
      - `margin_bottom.mobile_unit`: String, default "px"
      - `padding_left.value`: String, default "0"
      - `padding_left.unit`: String, default "px"
      - `padding_left.mobile_value`: String, default ""
      - `padding_left.mobile_unit`: String, default "px"
      - `padding_right.value`: String, default "0"
      - `padding_right.unit`: String, default "px"
      - `padding_right.mobile_value`: String, default ""
      - `padding_right.mobile_unit`: String, default "px"
      - `padding_top.value`: String, default "0"
      - `padding_top.unit`: String, default "px"
      - `padding_top.mobile_value`: String, default ""
      - `padding_top.mobile_unit`: String, default "px"
      - `padding_bottom.value`: String, default "0"
      - `padding_bottom.unit`: String, default "px"
      - `padding_bottom.mobile_value`: String, default ""
      - `padding_bottom.mobile_unit`: String, default "px"
      - `border_left.style`: String, default "none"
      - `border_left.color`: String
      - `border_left.width.value`: String, default "0"
      - `border_left.width.unit`: String, default "px"
      - `border_right.style`: String, default "none"
      - `border_right.color`: String
      - `border_right.width.value`: String, default "0"
      - `border_right.width.unit`: String, default "px"
      - `border_top.style`: String, default "none"
      - `border_top.color`: String
      - `border_top.width.value`: String, default "0"
      - `border_top.width.unit`: String, default "px"
      - `border_bottom.style`: String, default "none"
      - `border_bottom.color`: String
      - `border_bottom.width.value`: String, default "0"
      - `border_bottom.width.unit`: String, default "px"
      - `border_top_left_radius.value`: String, default "0"
      - `border_top_left_radius.unit`: String, default "px"
      - `border_top_right_radius.value`: String, default "0"
      - `border_top_right_radius.unit`: String, default "px"
      - `border_bottom_left_radius.value`: String, default "0"
      - `border_bottom_left_radius.unit`: String, default "px"
      - `border_bottom_right_radius.value`: String, default "0"
      - `border_bottom_right_radius.unit`: String, default "px"
      - `border_radius.value`: String, default "0"
      - `border_radius.unit`: String, default "px"
      - `specific_border_radius`: Boolean, default false
      - `box_shadows`: Object[]
      - `backgroundColor`: String
      - `backgroundGradient.enabled`: Boolean, default false
      - `backgroundGradient.type`: String
      - `backgroundGradient.degrees`: Number
      - `backgroundGradient.radialShape`: String
      - `backgroundGradient.radialPosition`: String
      - `backgroundGradient.colors`: Object[]
      - `backgroundGradient.css`: String
      - `backgroundVideo`: String
      - `backgroundImage`: String
      - `backgroundSize`: String
      - `backgroundPosition`: String
      - `backgroundRepeat`: String
      - `showOnMobile`: Boolean, default true
      - `showOnDesktop`: Boolean, default true
      - `components`: Object[]
      - `sections`: Object[]
      - `_id`: ObjectId
    - `_id`: ObjectId
  - `ai_meta`: Mixed
  - `_id`: ObjectId
- `suitability_price_plans`: ObjectId[], → PricePlan - PricePlan ids.
- `isSuitable`: Boolean - Set per request, not stored: whether the signed-in user's price plans match the page's suitability plans.
- `archived`: Boolean, default false - Hidden from the site and the admin's page list without being deleted.
- `archivedAt`: Date - When the page was archived.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### AttributedRevenue

- `value`: Number, required - Amount of revenue attributed to the owner, in the site's currency.
- `owner_id`: ObjectId, required, → User - User.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### BlogPost

An article on the site's blog.

- `title`: String, required - Title of blogpost.
- `url`: String, required - Generated from title, no need to set it manually.
- `static_url`: String - A fixed address kept when the post's url changes, so old links keep working.
- `header`: String - Short header of blogpost.
- `description`: String, required - Body text of blogpost.
- `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
  - `thumbnail`: String
  - `vimeo_uri`: String
  - `vimeo_picture`: String
  - `vimeo_url`: String
  - `youtube_url`: String
  - `youtube_picture`: String
  - `_id`: ObjectId
- `published`: Boolean, default true - True if not set.
- `owner_id`: ObjectId, → User - User.id.
- `connected_account_owner_id`: ObjectId, → User - User.id.
- `collection_id`: ObjectId, → Collection - Collection, to which the blog post belongs.
- `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 - Reference to AboutPage model, shown at the bottom of the post page.
- `suitability_price_plans`: ObjectId[], → PricePlan - A list of references to PricePlan model, marks post as suitable for users with those plans.
- `isSuitable`: Boolean - Set per request, not stored: whether the signed-in user's price plans match the post's suitability plans.
- `reference_id`: String - Id of the record the post was made from (an import or a clone).
- `wildcard_url`: Mixed - The wildcard route this post answers on, when it has one.
- `likes`: ObjectId[], → User - User ids.
- `views`: ObjectId[], → User - User ids.
- `total_views`: Number, default 0 - How many times the post was opened.
- `saves`: ObjectId[], → User - User ids.
- `times_showed`: Number, default 0 - How many times the post was shown in a list.
- `requiresLogin`: Boolean, default false - Only signed-in users can read the post.
- `requiresSubscription`: Boolean, default false - Only subscribers of the post's price plans can read it.
- `price_plan_ids`: String[] - A list of price plan id strings that grant access to this post.
- `_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

### ChatMessage

- `chat_id`: ObjectId, required, → ChatHistory - ChatHistory.id.
- `role`: String, one of user | model - One of: user, model.
- `text`: String - The message's text.
- `target_url`: String - Admin page the message links to.
- `action`: String, one of RESPONSE | REDIRECT | OBJECT_RESPONSE | ERROR | CLARIFY | PROPOSED_ACTION - One of: RESPONSE, REDIRECT, OBJECT_RESPONSE, ERROR, CLARIFY, PROPOSED_ACTION.
- `options`: String[] - Quick replies offered under the message.
- `data.object`: Mixed
- `data.object_type`: String
- `data.edit_summary`: Mixed
- `data.edit_diff`: Mixed
- `data.undo_record`: Mixed
- `data.hero_animation_offer`: Mixed
- `data.preview_state`: String
- `data.pending_credit_cost`: Number
- `data.target_restore`: Mixed
- `data.media_request`: Mixed
- `data.item_request`: Mixed
- `data.reference_request`: Mixed
- `data.section_options`: Mixed
- `data.section_blueprint`: Mixed
- `data.section_style_options`: Mixed
- `data.section_style_blueprint`: Mixed
- `data.section_role_picker`: Mixed
- `data.small_section_regeneration_options`: Mixed
- `data.small_section_regeneration_target`: Mixed
- `data.small_section_regeneration_prompt`: String
- `data.selected_small_section_action`: Mixed
- `data.component_regeneration_input`: Mixed
- `data.selected_section_role`: Mixed
- `data.selected_section_option`: Mixed
- `data.selected_section_style`: Mixed
- `data.section_options_target`: Mixed
- `data.section_options_prompt`: String
- `data.style_options_target`: Mixed
- `data.style_options_prompt`: String
- `data.previous_container`: Mixed
- `data.preserved_custom_components`: Mixed[]
- `data.selection_request`: Mixed
- `data.proposed_action`: Mixed
- `data.plan_result`: Mixed
- `data.parsed_intent`: Mixed
- `data.parsed_intent_version`: Number
- `data.parsed_intent_at`: Date
- `data.item_id`: ObjectId
- `data.design_archetype`: String
- `data.design_palette`: Mixed
- `data.out_of_credits`: Boolean
- `data.site_wide_edit`: Mixed
- `data.redesign`: Mixed
- `medias`: Object[] - Pictures attached to the message.
  - `media`: ObjectId, → Media
  - `gcs_url`: String
  - `gemini_uri`: String
  - `gemini_interaction_id`: String
  - `_id`: ObjectId
- `products`: ObjectId[], → Product - Product ids.
- `services`: ObjectId[], → Service - Service ids.
- `blogposts`: ObjectId[], → BlogPost - BlogPost ids.
- `programs`: ObjectId[], → Program - Program ids.
- `suggestions`: Object[] - Next steps suggested under the message.
  - `text`: String
  - `route`: String
  - `item_id`: ObjectId
  - `medias`: Mixed[]
  - `picture`: ObjectId
  - `_id`: ObjectId
- `is_system`: Boolean, default false - Written by the platform, not by the owner or the AI.
- `_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

### Donation

A fundraising campaign.

- `enabled`: Boolean, default false - The campaign accepts donations.
- `has_shippable_items`: Boolean, default false - Donors get something shipped, so an address is asked for.
- `medias`: Object[] - The campaign's pictures.
  - `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
- `url`: String, required - Generated from name, no need to set it manually.
- `static_url`: String - A fixed address kept when the url changes.
- `title`: String, required - Name of the campaign, required.
- `description`: String, required - Full body text describing the campaign and its goals, in HTML format, required.
- `about_page`: ObjectId, → AboutPage - AboutPage.id.
- `target_amount.enabled`: Boolean, default false
- `target_amount.amount`: Number
- `predefined_amounts.enabled`: Boolean, default false
- `predefined_amounts.amounts`: Object[]
  - `title`: String, required
  - `description`: String
  - `amount`: Number, required
  - `_id`: ObjectId
- `collection_id`: ObjectId, → Collection - Reference to a Collection with name starting with 'donation-category/', optional.
- `topics`: Object[] - Causes a donor can choose to give to.
  - `collection_id`: ObjectId, → Collection
  - `_id`: ObjectId
- `owner_id`: ObjectId, → User - User.id.
- `options`: Object[] - Purchasable add-on option groups for the donation (e.g. "Include a gift", "Select a reward tier").
  - `name`: String, required
  - `options`: Object[]
    - `option`: String, required
    - `match_to_collection`: ObjectId, → Collection
    - `quantity`: Number
    - `badge`: String
    - `option_specific_media`: ObjectId, → Media
    - `_id`: ObjectId
  - `_id`: ObjectId
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### DynamicModel

A custom data model the site defines: its fields and who can read and write its records.

- `name`: String - Name of the custom model.
- `fields`: Object[] - Recursive reference for nesting fields,.
  - `name`: String, required
  - `type`: String
  - `required`: Boolean
  - `default`: Mixed
  - `validations.minLength`: String
  - `validations.maxLength`: String
  - `patchable`: Boolean, default true
  - `ref`: String
  - `ref_value_field`: String, default "_id"
  - `ref_text_field`: String, default "_id"
  - `depends_on`: String
  - `populate`: Boolean
  - `wysiwyg`: Boolean
  - `fields`: Mixed[]
  - `show_field_in_cms_table`: Boolean, default true
  - `enumerator_values`: Object[]
    - `value`: String
    - `_id`: ObjectId
  - `_id`: ObjectId
- `auth.create`: Boolean, default true
- `auth.read`: Boolean, default false
- `auth.update`: Boolean, default true
- `auth.delete`: Boolean, default true
- `ownership_settings.enable_ownership_identification`: Boolean, default false
- `ownership_settings.ownership_based_auth`: String, one of none | owner | admin, default "none"
- `ownership_settings.profile_use`: Boolean, default false
- `routers.post.replace_all`: Boolean, default false
- `routers.post.code`: String
- `routers.get.replace_all`: Boolean, default false
- `routers.get.code`: String
- `routers.get_one.replace_all`: Boolean, default false
- `routers.get_one.code`: String
- `routers.patch.replace_all`: Boolean, default false
- `routers.patch.code`: String
- `routers.delete.replace_all`: Boolean, default false
- `routers.delete.code`: String
- `attach_in`: Object[], → [object Object] - Where its records can be attached (bookings, orders...).
  - `ref`: String
  - `ref_value_field`: String, default "_id"
  - `ref_text_field`: String, default "_id"
  - `user_input`: Boolean, default false
  - `_id`: ObjectId
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Event

A ticketed event at a venue.

- `name`: String, required - Name of the event.
- `venue`: ObjectId, required, → Venue - Venue.id.
- `description`: String, required - About the event.
- `medias`: Object[] - The event's pictures.
  - `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
- `dates`: Object[] - When it takes place, one entry per date.
  - `date`: Date, required
  - `seating_plan.id`: ObjectId, required, → SeatingPlan
  - `seating_plan.sections`: Object[], required
    - `subsections`: Object[], required
      - `rows`: Object[], required
      - `edit`: Boolean, required
      - `widest_column`: Number, required
      - `justify`: String, required
      - `left`: Number
      - `top`: Number
    - `section_type`: String, required
    - `name`: String, required
    - `top`: Number
    - `left`: Number
    - `color`: String
    - `premium_color`: String
    - `rotation`: Number
    - `tier`: Number, default 0
    - `max_seats`: Number
    - `tickets`: ObjectId[], → Ticket
  - `_id`: ObjectId
- `tier_1.name`: String
- `tier_1.price`: Number
- `tier_2.name`: String
- `tier_2.price`: Number
- `tier_3.name`: String
- `tier_3.price`: Number
- `tier_4.name`: String
- `tier_4.price`: Number
- `tier_5.name`: String
- `tier_5.price`: Number
- `tier_6.name`: String
- `tier_6.price`: Number
- `tier_7.name`: String
- `tier_7.price`: Number
- `tier_8.name`: String
- `tier_8.price`: Number
- `tier_9.name`: String
- `tier_9.price`: Number
- `tier_10.name`: String
- `tier_10.price`: Number
- `tier_11.name`: String
- `tier_11.price`: Number
- `tier_12.name`: String
- `tier_12.price`: Number
- `tier_13.name`: String
- `tier_13.price`: Number
- `tier_14.name`: String
- `tier_14.price`: Number
- `tier_15.name`: String
- `tier_15.price`: Number
- `owner_id`: ObjectId, required, → User - User.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Group

- `type`: String, required - Public / private;.
- `avatar`: ObjectId, → Media - Media.id.
- `cover`: ObjectId, → Media - Media.id.
- `name`: String, required - The group's name.
- `handle`: String, required - The group's unique @handle.
- `bio`: String - About the group.
- `participants`: ObjectId[], → User - User ids.
- `owner_id`: ObjectId, required, → User - User.id.
- `who_can_post`: String, default "all" - All, admin.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### KeywordBlacklist

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

### Lead

- `seq`: Number, default 0 - Running number of the customer.
- `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 - 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 - Customer's tax number.
- `vat_id`: String - Customer's VAT number.
- `notes`: String - Notes kept on the customer.
- `products`: String[] - Product ids the customer bought.
- `products_obj`: Object[] - The products bought, as they were when ordered.
  - `product_id`: ObjectId, → Product
  - `name`: String
  - `options`: String
  - `price`: Number
  - `quantity`: Number
  - `_id`: ObjectId
- `programs`: String[] - Program ids the customer bought.
- `programs_obj`: Object[] - The programs bought, as they were when ordered.
  - `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.
  - `donation_id`: ObjectId, → Donation
  - `name`: String
  - `options`: String
  - `price`: Number
  - `quantity`: Number
  - `_id`: ObjectId
- `lifetime_value`: Number, default 0 - Everything the customer has spent.
- `last_order_value`: Number - Value of the customer's last order.
- `services`: ObjectId[], → Service - Service ids.
- `stripe_id`: String - The customer's id in Stripe.
- `delivery_method`: String - The customer's last delivery method.
- `shipping_option`: String, one of address | office, default "address" - One of: address, office.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Media

An uploaded image, video or file.

- `file`: Buffer - (buffer) base64 image data.
- `file_path`: String - The bytes in Cloud Storage instead of `file` (utils/media-store.js): the object - named by the bytes' sha256, so identical pictures share one - and that hash.
- `alt`: String - Img alt (same as filename if not specified).
- `filename`: String - Name of the stored file.
- `filetype`: String - MIME type of the file.
- `vimeo_uri`: String - The video's Vimeo id, for videos hosted there.
- `vimeo_picture`: String - Thumbnail Vimeo made.
- `duration`: Number - Length of a video in seconds.
- `vimeo_url`: String - Link to the video on Vimeo.
- `youtube_url`: String - Link to the video on YouTube.
- `youtube_picture`: String - Thumbnail of the YouTube video.
- `thumbnail`: String - Small preview of the file.
- `gcs_url`: String - The file's address in cloud storage.
- `gcs_480_30_url`: String - The video transcoded to 480p.
- `gcs_720_30_url`: String - The video transcoded to 720p.
- `gcs_1080_30_url`: String - The video transcoded to 1080p.
- `picture_gcs_url`: String - The picture's address in cloud storage.
- `transcode_status`: String, default "not_started" - 'not_started' | 'pending' | 'error' | 'completed'.
- `owner_id`: ObjectId, → User - User id of owner.
- `sequence.status`: String
- `sequence.started_at`: Date
- `sequence.updated_at`: Date
- `sequence.step`: String
- `sequence.done`: Number
- `sequence.total`: Number
- `sequence.ext`: String
- `sequence.trim_start`: Number
- `sequence.trim_end`: Number
- `sequence.build_id`: String
- `sequence.previous_base`: String
- `sequence.frame_count`: Number
- `sequence.fps`: Number
- `sequence.width`: Number
- `sequence.height`: Number
- `sequence.desktop_path`: String
- `sequence.mobile_path`: String
- `sequence.portrait_path`: String
- `sequence.poster`: String
- `sequence.error`: String
- `source_url`: String - Site-clone real-asset reuse: the original URL this Media was downloaded from (asset-fetcher.js). Lets repeated/duplicate clone runs reuse the same stored asset instead of re-downloading it.
- `source_framing`: String - How a downloaded picture was prepared before it was stored (asset-fetcher.js FRAMING): a copy made before the frame its site baked in was taken off is not reused for one made after.
- `origin`: String - 'ai' for images the AI builder generated (validators.js). The site-readiness checklist counts the items still showing one, so people know which photos to replace with their own. Unset on uploads and on media created before it.
- `width`: Number - Displayed size of an image file (utils/image-size.js), so pages can give the <img> width/height and reserve its space before it loads. Set on save; older media by scripts/backfill-media-size.js.
- `height`: Number - Height of the picture in pixels.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Message

- `sender_id`: ObjectId, required, → User - User.id of sender is automatically set from auth.
- `receiver_id`: ObjectId, required, → User - User.id of receiver.
- `product_id`: ObjectId, → Product - Product.id of product, that the message is about.
- `service_id`: ObjectId, → Service - Service.id.
- `isOpened`: Boolean, default false - The recipient has read it.
- `blogpost_id`: ObjectId, → BlogPost - BlogPost.id.
- `isDirectMessage`: Boolean, default false - Between two users, not in a group.
- `message`: Object[] - Message.
  - `from`: ObjectId, required, → User
  - `text`: String, required
  - `createdAt`: String
  - `sent`: Boolean, default false
  - `seen`: Boolean, default false
  - `seen_by`: ObjectId[], → User
  - `postId`: ObjectId, → Post
  - `userId`: ObjectId, → User
  - `medias`: Object[]
    - `media`: ObjectId, → Media
    - `vimeo_uri`: String
    - `vimeo_picture`: String
    - `vimeo_url`: String
    - `youtube_url`: String
    - `youtube_picture`: String
    - `gcs_url`: String
    - `_id`: ObjectId
  - `isSystem`: Boolean, default false
  - `groupId`: ObjectId, → Group
  - `_id`: ObjectId
- `isGroup`: Boolean, default false - A group conversation.
- `group_users`: ObjectId[], → User - Keeps the messages after user leaves the group.
- `current_group_users`: ObjectId[], → User - Update when user leaves or joins.
- `users_nicknames`: Object[] - Nicknames members set for each other in the conversation.
  - `nickname`: String
  - `user`: ObjectId, → User
  - `_id`: ObjectId
- `group_avatar`: ObjectId, → Media - Media.id.
- `group_name`: String - Name of the group conversation.
- `delete_chat`: Object[] - Users who deleted the conversation for themselves, and when.
  - `isDeleted`: Boolean, default false
  - `user`: ObjectId, → User
  - `createdAt`: Date
  - `_id`: ObjectId
- `program_id`: ObjectId, → Program - Program.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### 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

### 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

### Post

- `posted_by`: ObjectId, required, → User - User.id.
- `repost_of`: ObjectId, → Post - Post.id.
- `connected_account_posted_by`: ObjectId, → User - User.id.
- `text`: String - The post's text.
- `title`: String - The post's title.
- `likes`: ObjectId[], → User - User ids.
- `shares`: Object[] - Who shared it, and when.
  - `from`: ObjectId, → User
  - `to`: ObjectId, → User
  - `_id`: ObjectId
- `views`: ObjectId[], → User - User ids.
- `comments`: ObjectId[], → Comment - Comment ids.
- `medias`: Object[] - Pictures and videos of the post.
  - `media`: ObjectId, → Media
  - `vimeo_uri`: String
  - `vimeo_picture`: String
  - `vimeo_url`: String
  - `youtube_url`: String
  - `youtube_picture`: String
  - `gcs_url`: String
  - `gcs_480_30_url`: String
  - `gcs_720_30_url`: String
  - `gcs_1080_30_url`: String
  - `duration`: Number
  - `transcode_status`: String, default "not_started"
  - `_id`: ObjectId
- `thumbnail.media`: ObjectId, → Media
- `keywords`: String[] - Words it is found by.
- `emotion`: String - Positive, neutral, negative.
- `political_spectrum`: String - Far left, left, far right, right, middle.
- `explicit`: String - Yes, no, middle.
- `harmful`: String - Yes, no, maybe.
- `propaganda`: String - Yes, no, middle.
- `advertisement`: String - Yes, no, maybe.
- `engaging`: String - Yes, no, maybe.
- `language`: String - Language of the post.
- `interests`: String[] - From Google Segments.
- `app_category`: String[] - From Google Segments.
- `user_profile`: String[] - Profiles the post is shown to.
- `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,.
- `isAdvertisment`: Boolean, default false - A paid ad.
- `saves`: ObjectId[], → User - User ids.
- `expirable`: Boolean, default false - Disappears after a while.
- `exclusive`: Boolean, default false - Only for subscribers.
- `price_plans`: ObjectId[], → PricePlan - PricePlan ids.
- `targeting.keywords`: String[]
- `targeting.language`: String[]
- `targeting.interests`: String[]
- `targeting.app_category`: String[]
- `targeting.user_economics`: String[]
- `targeting.user_education`: String[]
- `targeting.marital_status`: String[]
- `targeting.age`: String[]
- `targeting.sex`: String[]
- `targeting.isCpc`: Boolean, default false
- `targeting.cost_per_click`: Number, default 0
- `targeting.cost_per_mile`: Number, default 0
- `targeting.daily_budget`: Number, default 0
- `targeting.duration`: Number, default 0
- `targeting.outer_link.text`: String
- `targeting.outer_link.url`: String
- `targeting.locations`: Object[]
  - `type`: String, one of Point
  - `coordinates`: Number[]
  - `_id`: ObjectId
- `targeting.total`: Number, default 0
- `targeting.created_on`: Date
- `targeting.inner_link.text`: String
- `targeting.inner_link.profile_segment`: String
- `targeting.total_clicks`: Number, default 0
- `targeting.unique_clicks`: ObjectId[], → User
- `targeting.campaign_type`: String
- `targeting.related_videos`: ObjectId[], → Post
- `mentions`: ObjectId[], → User - User ids.
- `total_views`: Number, default 0 - How many times it was opened.
- `times_showed`: Number, default 0 - How many times it was shown in a feed.
- `attached_to`: ObjectId, → Post - Post.id.
- `attached_to_cta_text`: String - Text of the post's call-to-action button.
- `poll.question`: String
- `poll.answers`: Object[]
  - `text`: String
  - `users`: ObjectId[], → User
  - `_id`: ObjectId
- `isBlacklist`: Boolean, default false - Contains blacklisted words.
- `isReviewed`: Boolean, default false - A moderator reviewed it.
- `custom_link.heading`: String
- `custom_link.url`: String
- `embeded_link.og:image`: String
- `embeded_link.og:site_name`: String
- `embeded_link.og:title`: String
- `embeded_link.og:url`: String
- `posted_in`: ObjectId, → Group - Group.id.
- `attached_to_service`: ObjectId, → Service - Service.id.
- `attached_to_product`: ObjectId, → Product - Product.id.
- `attached_to_blogpost`: ObjectId, → BlogPost - BlogPost.id.
- `attached_to_program`: ObjectId, → Program - Program.id.
- `attached_to_priceplans`: Boolean, default false - Only subscribers of the attached price plans see it.
- `isWhitelisted`: Boolean, default false - Allowed past moderation.
- `attached_to_group`: ObjectId, → Group - Group.id.
- `reach`: ObjectId[], → User - User ids.
- `showAds`: Boolean, default true - The author allows ads next to it.
- `adminShowAds`: Boolean, default true - The admin allows ads next to it.
- `isAddReviewed`: Boolean, default false - The ad was reviewed.
- `reposts`: ObjectId[], → Post - Post ids.
- `original_post`: ObjectId, → Post - The first reposted post.
- `isHidden`: Boolean, default false - Hidden by a moderator.
- `dislikes`: ObjectId[], → User - User ids.
- `frames`: Object[] - The frames of a story.
  - `media`: ObjectId, → Media
  - `timestamp`: Number
  - `_id`: ObjectId
- `privacy`: String, required, one of everyone | followers | private, default "everyone" - One of: everyone, followers, private.
- `isPinned`: Boolean, default false - Pinned to the top of the author's profile.
- `_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

### ProfessionalAccount

- `user`: ObjectId, required, → User - Id of user, who has created the account.
- `show.services`: Boolean, default false
- `show.staff_members`: Boolean, default false
- `show.blogposts`: Boolean, default false
- `show.programs`: Boolean, default false
- `show.products`: Boolean, default false
- `show.events`: Boolean, default false
- `show.price_plans`: Boolean, default false
- `show.posts`: Boolean, default false
- `reviewed`: Boolean, default false - A moderator reviewed the request.
- `approved`: Boolean, default false - The account was approved as professional.
- `cover`: ObjectId, → Media - Media.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Program

An online course: weeks of days, each day a list of steps.

- `title`: String - Name of the program, required.
- `url`: String, required - Generated from title, no need to set it manually.
- `static_url`: String - A fixed address kept when the url changes.
- `header`: String - Short tagline or subtitle shown in listings, optional.
- `body`: String - Full program description in HTML format, optional.
- `medias`: Object[] - The program's pictures.
  - `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
- `video`: ObjectId, → Video - Video.id.
- `about_page`: ObjectId, → AboutPage - AboutPage.id.
- `weeks`: Object[] - A list of week objects, required.
  - `isCompleted`: Mixed
  - `progress`: Mixed
  - `title`: String
  - `days`: Object[]
    - `isCompleted`: Mixed
    - `progress`: Mixed
    - `title`: String
    - `steps`: Object[]
      - `title`: String, required
      - `body`: String, required
      - `video`: ObjectId, → Video
      - `medias`: Object[]
      - `about_page`: ObjectId, → AboutPage
      - `timer`: Number, default 0
      - `_id`: ObjectId
    - `_id`: ObjectId
  - `_id`: ObjectId
- `suitability_price_plans`: ObjectId[], → PricePlan - A list of PricePlan ids, marks program as suitable for users with those plans.
- `isSuitable`: Boolean - Set per request, not stored: whether the signed-in user's price plans match the program's suitability plans.
- `popup.title`: String
- `popup.points`: String[]
- `price`: Number, default 0 - Price in the user's currency, default 0.
- `collection_id`: ObjectId, → Collection - Reference to a Collection with name starting with 'program-category/', required.
- `topics`: Object[] - Topics it covers.
  - `collection_id`: ObjectId, → Collection
  - `_id`: ObjectId
- `owner_id`: ObjectId, required, → User - User.id.
- `connected_account_owner_id`: ObjectId, → User - User.id.
- `ribbon`: String - Short badge text shown on the card (e.g. "New", "Best seller"), optional.
- `striked`: String - Original price shown as strikethrough next to the real price, optional.
- `isConsistent`: Boolean, default false - Every week has the same structure.
- `isAcademic`: Boolean, default true - Free-order course, not weeks and days: progress is not tied to a week and day.
- `wildcard_url`: Mixed - The wildcard route it answers on, when it has one.
- `reviewed`: Boolean - A moderator reviewed it.
- `approved`: Boolean - Approved to be listed.
- `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.
- `requiresLogin`: Boolean, default false - Only signed-in users can see it.
- `requiresSubscription`: Boolean, default false - Only subscribers can see it.
- `price_plan_ids`: String[] - A list of price plan id strings that grant access to this program.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Publish

- `web`: Boolean - The site is published on the web.
- `ios`: Boolean - Published as an iOS app.
- `android`: Boolean - Published as an Android app.
- `pwaSwitch`: String - Install-as-app prompt: '0' off, '1' on.
- `android_app_id`: String - The Android app's package id.
- `ios_app_id`: String - The iOS app's App Store id.
- `_id`: ObjectId

### QrCode

- `ticket`: ObjectId, required, → Ticket - Ticket.id.
- `status`: String, one of used | not-used, default "not-used" - One of: used, not-used.
- `_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

### Shipping

- `region`: String, required - The region this delivery setting is for.
- `has_store_pickup`: Boolean, default false - Customers can pick the order up at the pickup point instead of having it delivered.
- `pickup_title`: String - Name of the pickup point.
- `pickup_address`: String - Address of the pickup point.
- `pickup_available`: String - When pickup is possible.
- `pickup_instructions`: String - What customers should know about pickup.
- `delivery`: Object[] - The delivery options offered in this region, each { name, estimated_delivery_time, fixed_rate (its price), has_free_delivery, free_delivery_requirement }. Free delivery over an amount: has_free_delivery true and free_delivery_requirement the minimum order total (threshold) above which it costs nothing. Send the whole list: it replaces the old one.
  - `name`: String
  - `estimated_delivery_time`: String
  - `fixed_rate`: Number
  - `rate_per_total`: Number
  - `rate_per_unit`: Number
  - `has_free_delivery`: Boolean, default false
  - `free_delivery_requirement`: Number, default 0
  - `delivery_days`: Number, default 3
  - `hasIntegration`: Boolean, default true
  - `has_time_window`: Boolean, default false
  - `available_from`: String
  - `available_to`: String
  - `timezone`: String
  - `_id`: ObjectId
- `owner_id`: ObjectId, required, → User - User.id.
- `connected_account_owner_id`: ObjectId, → User - User.id.
- `min_order_value`: Number, default 0 - Smallest order delivery is offered for.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### SocialModeSettings

The switches for the site's social app features: feed, posts, groups, chat, marketplace.

- `social_mode`: Boolean, default false - The site runs as a social network (feed, profiles).
- `allow_products`: Boolean, default false - Users can sell products.
- `allow_services`: Boolean, default false - Users can offer services.
- `allow_services_stp`: Boolean, default false - Users can take service payments themselves.
- `allow_blogposts`: Boolean, default false - Users can write blog posts.
- `allow_programs`: Boolean, default false - Users can sell programs.
- `allow_programs_stp`: Boolean, default false - Users can take program payments themselves.
- `allow_posts`: Boolean, default false - Users can post to the feed.
- `allow_ai`: Boolean, default false - AI features are on for users.
- `allow_bites`: Boolean, default false - Short videos are on.
- `allow_long_videos`: Boolean, default false - Long videos are on.
- `allow_explore`: Boolean, default false - The explore page is on.
- `allow_online_payments`: Boolean, default false - Users can take online payments.
- `allow_price_plans`: Boolean, default false - Users can sell subscriptions.
- `allow_boosting_posts`: Boolean, default false - Users can pay to boost posts.
- `allow_single_ai`: Boolean, default false - Users get the single-chat AI.
- `merchant_agreement`: ObjectId, → AboutPage - AboutPage.id.
- `verification_popup`: ObjectId, → AboutPage - AboutPage.id.
- `commission`: Number - Platform commission on users' sales, in percent.
- `home_page`: String, default "home" - What opens first (feed, store, about page...).
- `navigation_pages.bites`: Boolean, default true
- `navigation_pages.long_videos`: Boolean, default true
- `navigation_pages.vouchers`: Boolean, default true
- `navigation_pages.store`: Boolean, default true
- `navigation_pages.programs`: Boolean, default true
- `navigation_pages.services`: Boolean, default true
- `navigation_pages.blogposts`: Boolean, default true
- `navigation_pages.subscription`: Boolean, default true
- `navigation_pages.playlists`: Boolean, default true
- `navigation_pages.partners`: Boolean, default true
- `navigation_pages.contacts`: Boolean, default true
- `navigation_pages.tracker`: Boolean, default true
- `navigation_pages.more`: Boolean, default true
- `navigation_pages.claims`: Boolean, default true
- `navigation_pages.miniapps`: Boolean, default false
- `navigation_pages.events`: Boolean, default false
- `navigation_pages.professional_pages`: Boolean, default false
- `allow_google_login`: Boolean, default true - Sign in with Google is on.
- `use_cdn_for_medias`: Boolean, default false - Pictures and videos load from cdn_for_medias.
- `cdn_for_medias`: String - CDN address for media.
- `use_cdn_for_microservices`: Boolean, default false - Microservices are called through cdn_for_microservices.
- `cdn_for_microservices`: String - CDN address for microservices.
- `cdn_for_sockets`: String - Address of the socket server.
- `paywall.store.has_paywall`: Boolean, default false
- `paywall.store.priceplans`: ObjectId[], → PricePlan
- `paywall.programs.has_paywall`: Boolean, default false
- `paywall.programs.priceplans`: ObjectId[], → PricePlan
- `paywall.services.has_paywall`: Boolean, default false
- `paywall.services.priceplans`: ObjectId[], → PricePlan
- `paywall.blogposts.has_paywall`: Boolean, default false
- `paywall.blogposts.priceplans`: ObjectId[], → PricePlan
- `paywall.subscription.has_paywall`: Boolean, default false
- `paywall.subscription.priceplans`: ObjectId[], → PricePlan
- `paywall.post.has_paywall`: Boolean, default false
- `paywall.post.priceplans`: ObjectId[], → PricePlan
- `paywall.groups.has_paywall`: Boolean, default false
- `paywall.groups.priceplans`: ObjectId[], → PricePlan
- `paywall.professional_pages.has_paywall`: Boolean, default false
- `paywall.professional_pages.priceplans`: ObjectId[], → PricePlan
- `allow_chat`: Boolean, default true - Users can message each other.
- `allow_in_app_notifications`: Boolean, default true - In-app notifications are on.
- `dashboard_pages.following`: Boolean, default true
- `dashboard_pages.recent`: Boolean, default true
- `dashboard_pages.threads`: Boolean, default true
- `dashboard_pages.long_videos`: Boolean, default true
- `dashboard_pages.groups`: Boolean, default true
- `dashboard_pages.about_pages`: Boolean, default true
- `dashboard_pages.mini_apps`: Boolean, default true
- `dashboard_pages.blogposts`: Boolean, default true
- `dashboard_pages.products`: Boolean, default true
- `dashboard_pages.services`: Boolean, default true
- `dashboard_pages.price_plans`: Boolean, default true
- `dashboard_pages.programs`: Boolean, default true
- `dashboard_pages.claims`: Boolean, default true
- `dashboard_pages.bites`: Boolean, default true
- `dashboard_pages.playlists`: Boolean, default true
- `dashboard_pages.partners`: Boolean, default true
- `dashboard_pages.contacts`: Boolean, default true
- `dashboard_pages.tracker`: Boolean, default true
- `dashboard_pages.vouchers`: Boolean, default true
- `dashboard_pages.explore`: Boolean, default true
- `feed_menus`: String, default "grid" - Grid, row.
- `allow_miniapps`: Boolean, default false - Mini apps are on.
- `about_pages.groups`: ObjectId, → AboutPage
- `user_groups`: Boolean, default true - Users can create groups.
- `allow_professional_pages`: Boolean, default false - Professional accounts get their own pages.
- `allow_professional_account_registration`: Boolean, default false - Users can apply for a professional account.
- `locations_map.enabled`: Boolean, default false
- `use_companion_bookings`: Boolean, default false - Bookings are handled by the companion app.
- `confirm_bookings_call`: Boolean, default false - The AI phone agent calls to confirm bookings.
- `require_professional_account.services`: Boolean, default false
- `require_professional_account.products`: Boolean, default false
- `require_professional_account.programs`: Boolean, default false
- `require_professional_account.blogposts`: Boolean, default false
- `require_professional_account.subscriptions`: Boolean, default false
- `hide_feed_menus`: Boolean, default false - Feed menus are hidden.
- `_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

### Ticket

- `event`: ObjectId, required, → Event - Event.id.
- `date`: Number, required - Index of the event date.
- `section`: Number - Index of the section.
- `subsection`: Number - Index of the subsection.
- `row`: Number - Index of the row.
- `seat`: Number - Index of the seat.
- `row_index_formated`: Number - Row number as shown to the buyer.
- `seat_index_formated`: Number - Seat number as shown to the buyer.
- `lead_id`: ObjectId, → Lead - Lead.id.
- `socket_id`: String - The buyer's live connection, while the seat is held.
- `tier.name`: String
- `tier.price`: Number
- `status`: String, one of frozen | waiting-for-payment | paid | frozen-by-admin | bought-by-admin, default "frozen" - One of: frozen, waiting-for-payment, paid, frozen-by-admin, bought-by-admin.
- `expiration_time`: Date, required - When a held seat is released if not paid.
- `qr_code`: ObjectId, → QrCode - QrCode.id.
- `_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

### UserEngagementNotification

- `type`: String - Liked_post, commented, liked_comment, replied_to, mentioned, sent_message, search, followed, profile_visit, system, group_request_received, group_request_accepted, activity_boost.
- `title`: String, required - The notification's heading.
- `body`: String - The notification's text.
- `owner_id`: ObjectId, → User - User.id.
- `from`: ObjectId, → User - User.id.
- `post`: ObjectId, → Post - Post.id.
- `group`: ObjectId, → Group - Group.id.
- `sendToAll`: Boolean, default false - Goes to every user.
- `comment`: ObjectId, → Comment - Comment.id.
- `is_received`: Boolean, default false - Delivered to the user.
- `is_seen`: Boolean, default false - The user saw it.
- `url`: String - Where tapping it leads.
- `image`: String - Picture shown with it.
- `service`: ObjectId, → Service - Service.id.
- `product`: ObjectId, → Product - Product.id.
- `blogpost`: ObjectId, → BlogPost - BlogPost.id.
- `program`: ObjectId, → Program - Program.id.
- `booking`: ObjectId, → Booking - Booking.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### UserLockedHours

- `user`: ObjectId, required - User.id of the staff member.
- `locked_ranges`: Object[] - Date and time ranges the staff member cannot be booked.
  - `start`: Date
  - `end`: Date
  - `_id`: ObjectId
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### UserPaymentSettings

- `has_card`: Boolean, default false - Card payment is offered.
- `card_locale`: String, default "Pay with credit card" - Label of the card option.
- `email`: String - Email for payments.
- `country`: String - Country for payments.
- `agreedToTerms`: Boolean, default false - The user accepted the payment terms.
- `agreedToTermsAt`: String - When they accepted them.
- `merchant_id`: String - 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 - PayPal id.
- `owner_id`: ObjectId, required - User.id the settings belong to.
- `number`: Number - Next invoice number.
- `price_quote_number`: String - Next quote number.
- `bic`: String - BIC printed on invoices.
- `swift`: String - SWIFT printed on invoices.
- `tax_id`: String - Tax number.
- `vat_id`: String - VAT number.
- `logo`: ObjectId - Logo printed on invoices.
- `business_name`: String - Business name on invoices.
- `business_name_translated`: String - Business name in the second language.
- `responsible_official`: String - Responsible person on invoices.
- `responsible_official_translated`: String - The same in the second language.
- `business_email`: String - Business email on invoices.
- `company_id`: String - Company registration number.
- `business_address`: String - Business address on invoices.
- `business_address_translated`: String - The same in the second language.
- `business_phone_number`: String - Business phone on invoices.
- `business_country`: String - Business country on invoices.
- `business_country_translated`: String - The same in the second language.
- `footer`: String - Footer text of invoices.
- `footer_translated`: String - The same in the second language.
- `foreign_tax`: Number, default 0 - Tax rate for customers abroad, in percent.
- `home_tax`: Number, default 0 - Tax rate for home customers, in percent.
- `_id`: ObjectId

### UserReport

- `user`: ObjectId, required, → User - User.id.
- `post`: ObjectId, → Post - Post.id.
- `reason`: String, required - Spam, scam, illegal-activity, sexually-explicit, violence, impersonation, not-like.
- `reported_user`: ObjectId, → User - User.id.
- `comment`: ObjectId, → Comment - Comment.id.
- `reply`: ObjectId - The moderator's answer.
- `seen`: Boolean, default false - A moderator has seen it.
- `miniApp`: ObjectId, → MiniApp - MiniApp.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date
