# Builderly API reference

Base URL: http://nd.max-media.io
Generated from the running server on 2026-11-05T11:35:42.616Z. 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

### Design & components

The site's look: the theme (colours, fonts, dark mode), header, footer, popups and reusable custom components built with HTML, CSS and JS.

#### Custom Component

##### List all custom components
`GET /custom-components`
Returns the site's custom components, newest first unless a sort is given.
- Access: Public
- Returns: a list of CustomComponent objects.
- Status codes: 200, 500
- Models: CustomComponent

##### Create a custom component
`POST /custom-components`
Create new custom_component.
- Access: Admin token
- Returns: the CustomComponent object.
- Status codes: 201, 400, 401, 500
- Models: CustomComponent

##### Retrieve a custom component
`GET /custom-components/:id`
Returns one custom component, found by its ID.
- Access: Public
- Path:
  - `id` (string): The ID of the custom component.
- Returns: the CustomComponent object.
- Status codes: 200, 404, 500
- Models: CustomComponent

##### Update a custom component
`PATCH /custom-components/:id`
Update CustomComponent by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the custom component.
- Returns: the CustomComponent object.
- Status codes: 200, 400, 401, 404, 500
- Models: CustomComponent

##### Delete a custom component
`DELETE /custom-components/:id`
Delete CustomComponent record by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the custom component.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: CustomComponent

#### Custom Font

##### Retrieve the custom font
`GET /custom-font`
Returns the custom font.
- Access: Admin token
- Returns: the CustomFont object.
- Status codes: 200, 401, 500
- Models: CustomFont

##### Create a custom font
`POST /custom-font`
Import a Google font. Takes `{ query }` — a family name, a Google. Fonts URL, a <link> tag or a `font-family:` declaration — and          resolves its real weights against Google's font metadata. The older          `{ family, link }` body still works unchanged.
- Access: Admin token
- Body:
  - `query` (string): The custom font's query.
- Returns: the CustomFont object.
- Status codes: 200, 201, 400, 401, 500
- Models: CustomFont

##### Retrieve a custom font
`GET /custom-font/:id`
Returns one custom font, found by its ID.
- Access: Admin token
- Path:
  - `id` (string): The ID of the custom font.
- Returns: the CustomFont object.
- Status codes: 200, 401, 404, 500
- Models: CustomFont

##### Update a custom font
`PATCH /custom-font/:id`
Update CustomFont by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the custom font.
- Returns: the CustomFont object.
- Status codes: 200, 400, 401, 404, 500
- Models: CustomFont

##### Delete a custom font
`DELETE /custom-font/:id`
Deletes the custom font. This cannot be undone.
- Access: Admin token
- Path:
  - `id` (string): The ID of the custom font.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: CustomFont

##### Retrieve the font catalogue
`GET /font-catalogue`
Every font the theme picker may offer — the built-in library plus. this tenant's own imports, in one shape.
- Access: Admin token
- Status codes: 200, 401, 500
- Models: CustomFont

##### Search google fonts
`GET /google-fonts/search`
Typeahead over the whole Google Fonts library, for the admin's font. picker. `q` is whatever the user has typed so far.
- Access: Admin token
- Query:
  - `q` (string): The words to search for.
- Status codes: 200, 401, 500

#### Editor

##### Add an add locale
`POST /add-locale`
Add an add locale.
- Access: Public
- Body:
  - `locale` (string): The add locale's locale.
- Status codes: 200

##### Retrieve the 404
`GET /get-404`
Returns the 404.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the app scss
`GET /get-app-scss`
Returns the app scss.
- Access: Public
- Status codes: 200

##### Retrieve the blog
`GET /get-blog`
Returns the blog.
- Access: Admin token
- Status codes: 200, 401

##### List all blogs
`GET /get-blogs`
Returns the site's blogs, newest first unless a sort is given.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the bs css
`GET /get-bs-css`
Returns the bs css.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the cart
`GET /get-cart`
Returns the cart.
- Access: Admin token
- Status codes: 200, 401

##### List all contacts
`GET /get-contacts`
Returns the site's contacts, newest first unless a sort is given.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the css
`GET /get-css`
Returns the css.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the footer
`GET /get-footer`
Returns the footer.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the footer css
`GET /get-footer-css`
Returns the footer css.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the header
`GET /get-header`
Returns the header.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the header css
`GET /get-header-css`
Returns the header css.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the index
`GET /get-index`
Returns the index.
- Access: Admin token
- Status codes: 200, 401

##### List all locales
`GET /get-locales`
Returns the site's locales, newest first unless a sort is given.
- Access: Public
- Returns: a list of Locales objects.
- Status codes: 200, 404, 500
- Models: Locales

##### Retrieve the main css
`GET /get-main-css`
Returns the main css.
- Access: Admin token
- Status codes: 200, 401

##### List all partners
`GET /get-partners`
Returns the site's partners, newest first unless a sort is given.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the payment
`GET /get-payment`
Returns the payment.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the product
`GET /get-product`
Returns the product.
- Access: Admin token
- Status codes: 200, 401

##### List all products
`GET /get-products`
Returns the site's products, newest first unless a sort is given.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the service
`GET /get-service`
Returns the service.
- Access: Admin token
- Status codes: 200, 401

##### List all services
`GET /get-services`
Returns the site's services, newest first unless a sort is given.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the store
`GET /get-store`
Returns the store.
- Access: Admin token
- Status codes: 200, 401

##### Retrieve the theme
`GET /get-theme`
Returns the theme.
- Access: Public
- Status codes: 200, 400, 404, 500

##### Retrieve the vlog
`GET /get-vlog`
Returns the vlog.
- Access: Admin token
- Status codes: 200, 401

##### List all vlogs
`GET /get-vlogs`
Returns the site's vlogs, newest first unless a sort is given.
- Access: Admin token
- Status codes: 200, 401

##### Set a 404
`POST /set-404`
Set a 404.
- Access: Admin token
- Body:
  - `content` (string): The 404's content.
- Status codes: 200, 401

##### Set a blog
`POST /set-blog`
Set a blog.
- Access: Admin token
- Body:
  - `content` (string): The blog's content.
- Status codes: 200, 401

##### Set blogs
`POST /set-blogs`
Set blogs.
- Access: Admin token
- Body:
  - `content` (string): The blog's content.
- Status codes: 200, 401

##### Set bs css
`POST /set-bs-css`
Set bs css.
- Access: Admin token
- Body:
  - `content` (string): The bs css's content.
- Status codes: 200, 401

##### Set a cart
`POST /set-cart`
Set a cart.
- Access: Admin token
- Body:
  - `content` (string): The cart's content.
- Status codes: 200, 401

##### Set contacts
`POST /set-contacts`
Set contacts.
- Access: Admin token
- Body:
  - `content` (string): The contact's content.
- Status codes: 200, 401

##### Set a css
`POST /set-css`
Set a css.
- Access: Admin token
- Body:
  - `content` (string): The css's content.
- Status codes: 200, 401

##### Set a footer
`POST /set-footer`
Set a footer.
- Access: Admin token
- Body:
  - `content` (string): The footer's content.
- Status codes: 200, 401

##### Set a footer css
`POST /set-footer-css`
Set a footer css.
- Access: Admin token
- Body:
  - `content` (string): The footer css's content.
- Status codes: 200, 401

##### Set a header
`POST /set-header`
Set a header.
- Access: Admin token
- Body:
  - `content` (string): The header's content.
- Status codes: 200, 401

##### Set a header css
`POST /set-header-css`
Set a header css.
- Access: Admin token
- Body:
  - `content` (string): The header css's content.
- Status codes: 200, 401

##### Set an index
`POST /set-index`
Set an index.
- Access: Admin token
- Body:
  - `content` (string): The index's content.
- Status codes: 200, 401

##### Set locales
`POST /set-locales`
Set locales.
- Access: Admin token
- Body:
  - `content` (string): The locale's content.
- Status codes: 200, 401

##### Set a main css
`POST /set-main-css`
Set a main css.
- Access: Admin token
- Body:
  - `content` (string): The main css's content.
- Status codes: 200, 401

##### Set partners
`POST /set-partners`
Set partners.
- Access: Admin token
- Body:
  - `content` (string): The partner's content.
- Status codes: 200, 401

##### Set a payment
`POST /set-payment`
Set a payment.
- Access: Admin token
- Body:
  - `content` (string): The payment's content.
- Status codes: 200, 401

##### Set a product
`POST /set-product`
Set a product.
- Access: Admin token
- Body:
  - `content` (string): The product's content.
- Status codes: 200, 401

##### Set products
`POST /set-products`
Set products.
- Access: Admin token
- Body:
  - `content` (string): The product's content.
- Status codes: 200, 401

##### Set a service
`POST /set-service`
Set a service.
- Access: Admin token
- Body:
  - `content` (string): The service's content.
- Status codes: 200, 401

##### Set services
`POST /set-services`
Set services.
- Access: Admin token
- Body:
  - `content` (string): The service's content.
- Status codes: 200, 401

##### Set a store
`POST /set-store`
Set a store.
- Access: Admin token
- Body:
  - `content` (string): The store's content.
- Status codes: 200, 401

##### Set a theme
`POST /set-theme`
Set a theme.
- Access: Admin token
- Body:
  - `content` (string): The theme's content.
- Status codes: 200, 401

##### Set a vlog
`POST /set-vlog`
Set a vlog.
- Access: Admin token
- Body:
  - `content` (string): The vlog's content.
- Status codes: 200, 401

##### Set vlogs
`POST /set-vlogs`
Set vlogs.
- Access: Admin token
- Body:
  - `content` (string): The vlog's content.
- Status codes: 200, 401

#### Index Component

##### List all index components
`GET /index-components`
Returns the site's index components, newest first unless a sort is given.
- Access: Admin token
- Returns: a list of IndexComponent objects.
- Status codes: 200, 401, 500
- Models: IndexComponent

##### Create an index component
`POST /index-components`
Create new indexComponent.
- Access: Admin token
- Returns: the IndexComponent object.
- Status codes: 201, 400, 401, 500
- Models: IndexComponent

##### Retrieve an index component
`GET /index-components/:id`
Returns one index component, found by its ID.
- Access: Admin token
- Path:
  - `id` (string): The ID of the index component.
- Returns: the IndexComponent object.
- Status codes: 200, 401, 404, 500
- Models: IndexComponent

##### Update an index component
`PATCH /index-components/:id`
Update IndexComponent by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the index component.
- Returns: the IndexComponent object.
- Status codes: 200, 400, 401, 404, 500
- Models: IndexComponent

##### Delete an index component
`DELETE /index-components/:id`
Delete IndexComponent record by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the index component.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: IndexComponent

#### Popup

##### Retrieve the popup
`GET /popup`
Returns the popup.
- Access: Admin token
- Returns: the Popup object.
- Status codes: 200, 401, 500
- Models: Popup

##### Create a popup
`POST /popup`
Create new popup.
- Access: Admin token
- Returns: the Popup object.
- Status codes: 201, 400, 401, 500
- Models: Popup

##### Retrieve a popup
`GET /popup/:id`
Returns one popup, found by its ID.
- Access: Admin token
- Path:
  - `id` (string): The ID of the popup.
- Returns: the Popup object.
- Status codes: 200, 401, 404, 500
- Models: Popup

#### Wildcard

##### Retrieve a g
`GET /g/:url(*)`
Returns one g, found by its URL slug.
- Access: Public
- Path:
  - `url` (string): The g's URL slug, as in its address on the site.
- Status codes: 200, 404, 500, 502
- Models: Wildcard

##### List all wildcards
`GET /wildcards`
Returns the site's wildcards, newest first unless a sort is given.
- Access: Admin token
- Query:
  - `authenticated` (string): Only wildcards with this authenticated.
- Returns: a list of Wildcard objects.
- Status codes: 200, 401, 500
- Models: Wildcard

##### Create a wildcard
`POST /wildcards`
Create new wildcard.
- Access: Admin token
- Returns: the Wildcard object.
- Status codes: 201, 400, 401, 500
- Models: Wildcard

##### Retrieve a wildcard
`GET /wildcards/:id`
Returns one wildcard, found by its ID.
- Access: Admin token
- Path:
  - `id` (string): The ID of the wildcard.
- Returns: the Wildcard object.
- Status codes: 200, 401, 404, 500
- Models: Wildcard

##### Update a wildcard
`PATCH /wildcards/:id`
Update Wildcard by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the wildcard.
- Returns: the Wildcard object.
- Status codes: 200, 400, 401, 404, 500
- Models: Wildcard

##### Delete a wildcard
`DELETE /wildcards/:id`
Delete Wildcard record by id.
- Access: Admin token
- Path:
  - `id` (string): The ID of the wildcard.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: Wildcard

#### AI builder

##### Create a popup with AI
`POST /create-new-popup`
Create a popup from a prompt, written by the AI builder.
- Access: User token
- Body:
  - `prompt` (string): What the AI should do with the popup, 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 popup to change.
- Status codes: 200, 401, 500
- Models: ChatMessage

##### Generate a popup with AI
`POST /generate-popup`
Use it to create or set up a site popup or modal.
- Access: User token
- Body:
  - `prompt` (string): What the AI should do with the popup, 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

### ChatMessage

- `chat_id`: ObjectId, required, → ChatHistory
- `role`: String, one of user | model
- `text`: String
- `target_url`: String
- `action`: String, one of RESPONSE | REDIRECT | OBJECT_RESPONSE | ERROR | CLARIFY | PROPOSED_ACTION
- `options`: String[]
- `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[]
  - `media`: ObjectId, → Media
  - `gcs_url`: String
  - `gemini_uri`: String
  - `gemini_interaction_id`: String
  - `_id`: ObjectId
- `products`: ObjectId[], → Product
- `services`: ObjectId[], → Service
- `blogposts`: ObjectId[], → BlogPost
- `programs`: ObjectId[], → Program
- `suggestions`: Object[]
  - `text`: String
  - `route`: String
  - `item_id`: ObjectId
  - `medias`: Mixed[]
  - `picture`: ObjectId
  - `_id`: ObjectId
- `is_system`: Boolean, default false
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### CustomComponent

- `name`: String
- `html`: String
- `compiled_html`: String
- `css`: String
- `compiled_css`: String
- `js`: String
- `variables`: Object[]
  - `value`: String
  - `_id`: ObjectId
- `iframe`: Boolean, default false
- `media`: ObjectId, → Media
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### CustomFont

- `family`: String, required
- `link`: String, required
- `name`: String
- `weights`: String
- `italics`: String[]
- `subsets`: String[]
- `generic`: String
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### IndexComponent

- `type`: String
- `position`: Number
- `about_page`: String
- `isFluid`: Boolean, default false
- `isAppComponent`: Boolean, default false
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Locales

- `locales_object`: Mixed
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Popup

A popup shown on the site, with the landing page behind its accept button.

- `title`: String, required - Internal admin label for this popup (e.g. "Welcome discount", "Newsletter signup", "Cookie consent").
- `body`: ObjectId, required, → AboutPage - The full landing page the user sees after clicking accept.
- `decline_button_text`: String, required - Text on the dismiss button (e.g. "No thanks", "Maybe later", "Close").
- `accept_button_text`: String, required - Text on the primary CTA button of the popup modal (e.g. "Sign up", "Learn more", "Claim offer").
- `accept_button_link`: String
- `wide_modal`: Boolean, default false - True for wider popup modal, false (default) for compact.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### Wildcard

- `url`: String
- `points_to`: String
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date
