# Builderly API reference

Base URL: http://hristovtintdetailng.com
Generated from the running server on 2026-11-09T17:13:29.278Z. 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

### Marketing & notifications

Reaching the site's users: push notifications, newsletters, automations and QR codes.

#### Advertisment

##### Create an ad
`POST /ads`
Creates an ad. Answers 201 with no body.
- Access: Admin token
- Status codes: 201, 400, 401, 500
- Models: Advertisment

##### Retrieve an ad
`GET /ads/:id`
One ad. 404 when there is no such record.
- Access: Admin token
- Path:
  - `id` (string): The ID of the ad.
- Status codes: 200, 401, 404, 500
- Models: Advertisment

##### Update an ad
`PATCH /ads/:id`
Updates an ad. Answers the ad.
- Access: Admin token
- Path:
  - `id` (string): The ID of the ad.
- Status codes: 200, 400, 401, 500
- Models: Advertisment

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

#### Alert

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

##### Create an alert
`POST /alerts`
Creates an alert. Answers 201 with no body.
- Access: Admin token
- Status codes: 201, 400, 401, 500

##### Retrieve an alert
`GET /alerts/:id`
One alert. 404 when there is no such record.
- Access: Admin token
- Path:
  - `id` (string): The ID of the alert.
- Returns: the Alert object.
- Status codes: 200, 401, 404, 500
- Models: Alert

#### Automation

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

##### Create an automation
`POST /automations`
Creates an automation (a webhook called on an event). Answers 201 with no body.
- Access: Admin token
- Returns: the Automation object.
- Status codes: 201, 400, 401, 500
- Models: Automation

##### Retrieve an automation
`GET /automations/:id`
One automation. 404 when there is no such record.
- Access: Admin token
- Path:
  - `id` (string): The ID of the automation.
- Returns: the Automation object.
- Status codes: 200, 401, 404, 500
- Models: Automation

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

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

##### List all models
`GET /get-model/:model`
An example entry of a model and its schema, to map an automation's fields. The newest entry, with its references filled in, shows what an automation's payload looks like.
- Access: Admin token
- Path:
  - `model` (string): The model's model.
- Status codes: 200, 401, 500

#### Connected Account

##### List all connected accounts
`GET /connected-accounts`
Accounts the signed-in user manages. Answers { connectedAccounts, accounts_that_authorized_me }.
- Access: User token
- Returns: a list of ConnectedAccount objects.
- Status codes: 200, 401, 500
- Models: ConnectedAccount

##### Retrieve a connected accounts on behalf of
`GET /connected-accounts-by-on-behalf-of/:id`
The connection to an account the signed-in user manages, by that account. Answers the managed account. 404 when there is no connection.
- Access: User token
- Path:
  - `id` (string): The ID of the connected accounts on behalf of.
- Status codes: 200, 401, 404, 500
- Models: ConnectedAccount

##### Retrieve a connected accounts on behalf of
`GET /connected-accounts-on-behalf-of/:id`
The connection that lets a user manage the signed-in user's account. 404 when there is no connection.
- Access: User token
- Path:
  - `id` (string): The ID of the connected accounts on behalf of.
- Status codes: 200, 401, 404, 500
- Models: ConnectedAccount

##### Change the status of a connected account
`PATCH /connected-accounts-status/:id`
Accepts or refuses an account connection, and sets what it may do. Fields outside the allowed list are silently ignored. Answers the updated record, or 404.
- Access: User token
- Path:
  - `id` (string): The ID of the connected account.
- Returns: the ConnectedAccount object.
- Status codes: 200, 400, 401, 403, 404, 500
- Models: ConnectedAccount

##### Retrieve a connected account
`GET /connected-accounts/:id`
One account connection. 404 when there is no such connection.
- Access: User token
- Path:
  - `id` (string): The ID of the connected account.
- Returns: the ConnectedAccount object.
- Status codes: 200, 401, 404, 500
- Models: ConnectedAccount

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

##### Delete a connected account
`DELETE /connected-accounts/:id`
Deletes an account connection. Either side can end it. 403 "Unauthorized." for anyone else.
- Access: User token
- Path:
  - `id` (string): The ID of the connected account.
- Returns: an empty answer on success.
- Status codes: 200, 401, 403, 404, 500
- Models: ConnectedAccount

##### List all connected accounts
`GET /my-connected-accounts`
Users who manage the signed-in user's account. Answers an array.
- Access: User token
- Returns: a list of ConnectedAccount objects.
- Status codes: 200, 401, 500
- Models: ConnectedAccount

##### Send an account connection request
`POST /send-account-connection-request`
Asks another user (email) for access to manage their account. Answers 201 with the pending connection; the other user accepts it with PATCH /connected-accounts-status/:id.
- Access: User token
- Body:
  - `email` (string): An email address.
- Status codes: 201, 400, 401, 500
- Models: User, ConnectedAccount

#### Instagram

##### Retrieve the instagram
`GET /get-instagram`
Pictures of a public Instagram profile (?profile). Answers { instaMedias, profilePic }. Reads no token.
- Access: Public
- Query:
  - `profile` (string): Only instagrams with this profile.
  - `first` (string): Only instagrams with this first.
- Status codes: 200, 500

#### Push Notification

##### Create a push notification
`POST /push-notification`
Creates a push notification. 412 when one was sent to the same audience in the last 48 hours. Answers 201.
- Access: Admin token
- Body:
  - `title` (string): The notification's heading.
  - `body` (string): The notification's text.
  - `image` (string): Picture shown with it.
  - `sendTo` (string): The push notification's send to.
  - `type` (string): Push, system, both.
  - `url` (string): The push notification's URL slug, as in its address on the site.
- Returns: the PushNotification object.
- Status codes: 201, 400, 401, 412, 500
- Models: PushNotification, MyContact, PushToken, UserEngagementNotification

##### Retrieve the push notification info
`GET /push-notification-info`
Get a summary info of push notifications. Answers an array of every record.
- Access: Admin token
- Status codes: 200, 401, 500
- Models: PushToken

##### Retrieve the push notification
`GET /push-notification/timer`
How long until another push notification may be sent to ?sendTo (one every 48 hours). Answers { text } for the admin to show.
- Access: Admin token
- Query:
  - `sendTo` (string): Only push notifications with this send to.
- Returns: the PushNotification object.
- Status codes: 200, 401, 500
- Models: PushNotification

#### Push Token

##### Retrieve the push token
`GET /push-token`
Devices registered for push notifications. Answers an array of every record.
- Access: Admin token
- Returns: the PushToken object.
- Status codes: 200, 401, 500
- Models: PushToken

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

## Objects

### Advertisment

- `name`: String, required - Internal name of the ad.
- `media`: ObjectId - Media.id of the ad's picture.
- `alt`: String - Alternative text of the picture.
- `link`: String - Where clicking the ad leads.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Alert

- `type`: String, required - INFO = 0; WARNING = 1; DANGER = 2;.
- `heading`: String, required - What is the alert about.
- `message`: String, required - Alert message.
- `meta_id`: ObjectId, → Meta - Meta.id.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Automation

- `title`: String, required - Name of the automation.
- `webhook_url`: String, required - The URL called when the event happens.
- `event_type`: String, required - The event that triggers the call (new order, new booking...).
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

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

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

### PushNotification

- `title`: String, required - The notification's heading.
- `body`: String - The notification's text.
- `image`: String - Picture shown with it.
- `send_to`: String - Who it goes to (all users, a segment...).
- `type`: String - Push, system, both.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### PushToken

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

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