# Builderly API reference

Base URL: http://bulgariandebateassociation.max-media.io
Generated from the running server on 2026-11-09T16:55:30.339Z. 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

### Invoices

Invoices and price quotes the site issues for orders and subscriptions, generated from the invoice settings (business details, taxes, numbering).

#### Invoice

##### Retrieve the can alter invoice sequence
`GET /can_alter_invoice_sequence`
Return boolean if invoice sequence can be alteerd. Answers { can_alter_invoice, can_alter_price_quote }: the starting numbers can only change before the first invoice or quote is issued.
- Access: Admin token
- Status codes: 200, 401, 500
- Models: Invoice, PriceQuote

##### Retrieve a download invoice
`GET /download-invoice/:id/:translate/:filename`
Download invoice. Answers the PDF; translate picks the second language. Reads no token.
- Access: Public
- Path:
  - `id` (string): The ID of the download invoice.
  - `translate` (string): The download invoice's translate.
  - `filename` (string): The download invoice's filename.
- Status codes: 200, 400, 500

##### Delete an invoice
`DELETE /invoices/:id`
Deletes an invoice; only the last one can be deleted, so numbering stays continuous. 400 when it is not the last one. Answers the deleted invoice.
- Access: Admin token
- Path:
  - `id` (string): The ID of the invoice.
- Returns: an empty answer on success.
- Status codes: 200, 400, 401, 404, 500
- Models: Invoice, PriceQuote

#### Invoice Settings

##### List all invoice settings
`GET /invoice-settings`
The invoice settings. The site's one record.
- Access: Admin token
- Returns: a list of InvoiceSettings objects.
- Status codes: 200, 401, 500
- Models: InvoiceSettings

##### Create an invoice setting
`POST /invoice-settings`
Creates an invoice settings record. A site has one; update it with PATCH instead.
- Access: Admin token
- Returns: the InvoiceSettings object.
- Status codes: 201, 400, 401, 500
- Models: InvoiceSettings

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

##### Update an invoice setting
`PATCH /invoice-settings/:id`
Updates an invoice settings record. Applies to invoices issued from now on; issued ones keep the details they were made with. Answers the settings, or 404.
- Access: Admin token
- Path:
  - `id` (string): The ID of the invoice setting.
- Returns: the InvoiceSettings object.
- Status codes: 200, 400, 401, 404, 500
- Models: Invoice, InvoiceSettings

#### Nra Audit

##### Retrieve the NRA audit file
`GET /nra-audit-file`
The audit file itself, as a windows-1251 XML attachment. For the Bulgarian revenue agency (НАП). 400 with the reasons when the period is invalid, settings are missing or a sale cannot be reported.
- Access: Admin token
- Query:
  - `month` (string): Only NRA audit files with this month.
  - `year` (string): Only NRA audit files with this year.
- Status codes: 200, 400, 401, 500

##### Retrieve the NRA audit summary
`GET /nra-audit-summary`
Dry run - what the file would contain, without producing it. Takes the same period as the file. Answers its totals and the errors that would stop it. 400 for an invalid period.
- Access: Admin token
- Query:
  - `month` (string): Only NRA audit summaries with this month.
  - `year` (string): Only NRA audit summaries with this year.
- Status codes: 200, 400, 401, 500

##### List all NRA settings
`GET /nra-settings`
Current NRA audit-file settings, with the default payment map. With the default payment code map, for fields not yet set.
- Access: Admin token
- Status codes: 200, 401, 500

##### Create a NRA setting
`POST /nra-settings`
Create or update the tenant's NRA audit-file settings. Answers the saved settings.
- Access: Admin token
- Status codes: 200, 400, 401, 500

#### Recurring Invoice

##### List all recurring invoices
`GET /recurring-invoices`
All recurring invoices, the next due first. Answers an array of every record.
- Access: Admin token
- Returns: a list of RecurringInvoice objects.
- Status codes: 200, 401, 500
- Models: RecurringInvoice

##### Create a recurring invoice
`POST /recurring-invoices`
Creates a recurring invoice; its first run is the start date, or the next one after now. 400 "start_date is required". Answers 201 with it.
- Access: Admin token
- Returns: the RecurringInvoice object.
- Status codes: 201, 400, 401, 500
- Models: RecurringInvoice

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

##### Update a recurring invoice
`PATCH /recurring-invoices/:id`
Updates a recurring invoice; a schedule change, or switching it on, reschedules it. Answers it, or 404.
- Access: Admin token
- Path:
  - `id` (string): The ID of the recurring invoice.
- Returns: the RecurringInvoice object.
- Status codes: 200, 400, 401, 404, 500
- Models: RecurringInvoice

##### Delete a recurring invoice
`DELETE /recurring-invoices/:id`
Deletes a recurring invoice; the quotes and invoices it already made stay. Answers the deleted record, or 404. Records that point to it are not changed.
- Access: Admin token
- Path:
  - `id` (string): The ID of the recurring invoice.
- Returns: an empty answer on success.
- Status codes: 200, 401, 404, 500
- Models: RecurringInvoice

##### Create a recurring invoice
`POST /recurring-invoices/:id/run`
Creates a recurring invoice from the fields sent. auto_send), outside the schedule, which it leaves as it is.
- Access: Admin token
- Path:
  - `id` (string): The ID of the recurring invoice.
- Returns: the RecurringInvoice object.
- Status codes: 201, 400, 401, 404, 500
- Models: RecurringInvoice

## Objects

### Invoice

- `stripeNumber`: String - Invoice number we get from Stripe (foreign key).
- `is_credit_note`: Boolean, default false - This document is a credit note for an earlier invoice.
- `credit_note_invoice_number`: String - Number of the invoice the credit note corrects.
- `credit_note_invoice_date`: String - Date of the invoice the credit note corrects.
- `is_debit_note`: Boolean, default false - This document is a debit note for an earlier invoice.
- `debit_note_invoice_number`: String - Number of the invoice the debit note adds to.
- `debit_note_invoice_date`: String - Date of the invoice the debit note adds to.
- `number`: Number - Our invoice number.
- `stripeInvoiceId`: String - Id of invoice stripe gives us.
- `has_price_quote`: Boolean, default false - Flag which shows if we created invoice from price quote.
- `customer_name`: String - Name of customer.
- `customer_address`: String - Address of customer.
- `customer_postal_code`: String - Postal code of customer.
- `customer_city`: String - City of customer.
- `customer_country`: String - Country of customer.
- `customer_phone`: String - Phone of customer.
- `customer_email`: String - Email of customer.
- `customer_tax_id`: String - Tax id of customer.
- `customer_vat_id`: String - Customer's VAT number.
- `customer_responsible_official`: String - Person responsible on the customer's side.
- `customer_organization_name`: String - Customer's company name.
- `billing_customer_address`: String - Address of billed customer.
- `billing_customer_postal_code`: String - Postal code billed of customer.
- `billing_customer_city`: String - City of billed customer.
- `billing_customer_country`: String - Country of billed customer.
- `billing_customer_phone`: String - Phone of billed customer.
- `subtotal`: Number - Invoice subtotal.
- `amount`: Number - Invoice amount.
- `day_of_issue`: String - Day of issue of invoice.
- `paid_on`: String - Day the invoice was paid (day_of_issue when empty).
- `foreign`: Boolean - Flag which shows if invoice is from foreign to company country.
- `home_tax`: Number, default 0 - Home country tax amount.
- `foreign_tax`: Number, default 0 - Foreign country tax amount.
- `items`: Object[] - Array of sold products which contains their name, cost, quantity and discount.
  - `id`: String
  - `name`: String
  - `qty`: Number
  - `unit_price`: Number
  - `discount`: Number
  - `amount`: Number
  - `_id`: ObjectId
- `grounds_for_transaction`: String - Legal grounds for the transaction (e.g. a VAT exemption).
- `description_of_transaction`: String - What the transaction is for.
- `place_of_transaction`: String - Where the transaction took place.
- `payment`: String - How it is paid (cash, bank transfer, card).
- `dateDue`: String - Date the invoice must be paid by.
- `invoice_settings.number`: Number
- `invoice_settings.price_quote_number`: String
- `invoice_settings.bic`: String
- `invoice_settings.swift`: String
- `invoice_settings.tax_id`: String
- `invoice_settings.vat_id`: String
- `invoice_settings.logo`: ObjectId
- `invoice_settings.business_name`: String
- `invoice_settings.business_name_translated`: String
- `invoice_settings.responsible_official`: String
- `invoice_settings.responsible_official_translated`: String
- `invoice_settings.business_email`: String
- `invoice_settings.company_id`: String
- `invoice_settings.business_address`: String
- `invoice_settings.business_address_translated`: String
- `invoice_settings.business_phone_number`: String
- `invoice_settings.business_country`: String
- `invoice_settings.business_country_translated`: String
- `invoice_settings.footer`: String
- `invoice_settings.footer_translated`: String
- `invoice_settings.foreign_tax`: Number, default 0
- `invoice_settings.home_tax`: Number, default 0
- `invoice_settings.currency_symbol`: String
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### InvoiceSettings

The business details, numbering and taxes the site's invoices are issued with.

- `number`: Number - Invoice starting number.
- `price_quote_number`: String - Price quote starting number.
- `bic`: String - Bic of bank account.
- `swift`: String - Swift of bank account.
- `tax_id`: String - The business's tax identification number.
- `vat_id`: String - The business's VAT number.
- `logo`: ObjectId - Id of media used as logo on invoices.
- `business_name`: String - Name of bussines.
- `business_name_translated`: String - Name of bussines.
- `responsible_official`: String - Responsible official.
- `responsible_official_translated`: String - Responsible official.
- `business_email`: String - Email of bussines.
- `company_id`: String - Id of company.
- `business_address`: String - Address of business.
- `business_address_translated`: String - Address of business.
- `business_phone_number`: String - Phone number of business.
- `business_country`: String - Country of business.
- `business_country_translated`: String - Country of business.
- `footer`: String - Footer text placed at bottom of invoice.
- `footer_translated`: String - Footer text placed at bottom of invoice.
- `foreign_tax`: Number, default 0 - Tax which is applied to foreign to business countries customers.
- `home_tax`: Number, default 0 - Tax which is applied to the home country customers.
- `currency_symbol`: String - Currency symbol printed on invoices.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### PriceQuote

- `customer_name`: String - Name of customer.
- `customer_address`: String - Address of customer.
- `customer_postal_code`: String - Postal code of customer.
- `customer_city`: String - City of customer.
- `customer_country`: String - Country of customer.
- `customer_phone`: String - Phone of customer.
- `customer_email`: String - Email of customer.
- `customer_tax_id`: String, required - Tax id of customer.
- `customer_vat_id`: String - Customer's VAT number.
- `customer_responsible_official`: String, required - Person responsible on the customer's side.
- `customer_organization_name`: String - Customer's company name.
- `billing_customer_address`: String - Address of billed customer.
- `billing_customer_postal_code`: String - Postal code billed of customer.
- `billing_customer_city`: String - City of billed customer.
- `billing_customer_country`: String - Country of billed customer.
- `billing_customer_phone`: String - Phone of billed customer.
- `subtotal`: Number - Invoice subtotal.
- `amount`: Number - Invoice amount.
- `day_of_issue`: String - Day of issue of invoice.
- `number`: Number - The quote's number.
- `foreign`: Boolean - Flag which shows if invoice is from foreign to company country.
- `home_tax`: Number, default 0 - Home country tax amount.
- `foreign_tax`: Number, default 0 - Foreign country tax amount.
- `items`: Object[] - Array of sold products which contains their name, cost, quantity and discount.
  - `id`: String
  - `name`: String
  - `qty`: Number
  - `unit_price`: Number
  - `discount`: Number
  - `amount`: Number
  - `_id`: ObjectId
- `grounds_for_transaction`: String - Legal grounds for the transaction.
- `description_of_transaction`: String - What it is for.
- `place_of_transaction`: String - Where it takes place.
- `payment`: String - How it would be paid.
- `dateDue`: String - Date the quote is valid until.
- `invoice_id`: ObjectId, → invoice - Id of invoice created from this price quote.
- `invoice_settings.number`: Number
- `invoice_settings.price_quote_number`: String
- `invoice_settings.bic`: String
- `invoice_settings.swift`: String
- `invoice_settings.tax_id`: String
- `invoice_settings.vat_id`: String
- `invoice_settings.logo`: ObjectId
- `invoice_settings.business_name`: String
- `invoice_settings.business_name_translated`: String
- `invoice_settings.responsible_official`: String
- `invoice_settings.responsible_official_translated`: String
- `invoice_settings.business_email`: String
- `invoice_settings.company_id`: String
- `invoice_settings.business_address`: String
- `invoice_settings.business_address_translated`: String
- `invoice_settings.business_phone_number`: String
- `invoice_settings.business_country`: String
- `invoice_settings.business_country_translated`: String
- `invoice_settings.footer`: String
- `invoice_settings.footer_translated`: String
- `invoice_settings.foreign_tax`: Number, default 0
- `invoice_settings.home_tax`: Number, default 0
- `invoice_settings.currency_symbol`: String
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date

### RecurringInvoice

- `title`: String, default "" - Name of the recurring invoice.
- `active`: Boolean, default true - It keeps issuing invoices.
- `auto_send`: Boolean, default false - Each invoice is emailed to the customer when issued.
- `interval_count`: Number, default 1 - How many interval_units pass between two invoices.
- `interval_unit`: String, one of day | week | month | year, default "month" - One of: day, week, month, year.
- `start_date`: Date, required - First date an invoice is issued.
- `end_date`: Date - Last date an invoice may be issued; empty for no end.
- `due_days`: Number, default 0 - Days after the issue date the invoice is due (0: the same day).
- `next_run_at`: Date - When the next invoice is issued.
- `customer_name`: String - Customer's name, printed on each quote and invoice.
- `customer_address`: String - Customer's address.
- `customer_postal_code`: String - Customer's postal code.
- `customer_city`: String - Customer's city.
- `customer_country`: String - Customer's country.
- `customer_phone`: String - Customer's phone.
- `customer_email`: String - Customer's email, where invoices are sent.
- `customer_tax_id`: String - Customer's tax number.
- `customer_vat_id`: String - Customer's VAT number.
- `customer_responsible_official`: String - Person responsible on the customer's side.
- `customer_organization_name`: String - Customer's company name.
- `billing_customer_address`: String - Billing address, when different.
- `billing_customer_postal_code`: String - Billing postal code.
- `billing_customer_city`: String - Billing city.
- `billing_customer_country`: String - Billing country.
- `billing_customer_phone`: String - Billing phone.
- `foreign`: Boolean, default false - The customer is abroad, so the foreign tax rate applies.
- `items`: Object[] - What is invoiced each time: name, quantity, price.
  - `id`: String
  - `name`: String
  - `qty`: Number, default 1
  - `unit_price`: Number, default 0
  - `discount`: Number, default 0
  - `_id`: ObjectId
- `payment`: String - How it is paid.
- `grounds_for_transaction`: String - Legal grounds for the transaction.
- `description_of_transaction`: String - What it is for.
- `place_of_transaction`: String - Where it takes place.
- `runs`: Number, default 0 - How many invoices it has issued.
- `last_run_at`: Date - When the last invoice was issued.
- `last_price_quote_id`: ObjectId - PriceQuote.id of the last quote issued.
- `last_invoice_id`: ObjectId - UserInvoice.id of the last invoice issued.
- `last_error`: String - Why the last run failed, if it did.
- `_id`: ObjectId
- `updatedAt`: Date
- `createdAt`: Date
