Menu

API reference · CRM

Quotes

crm · quotes · 13 operations

GET/v1/crm/quotes/config

Get the quote configuration

crm.quotes.config.get

ReadIdempotentSince 2026-11-01

Returns the quote configuration of the CRM: the templates (layout, accent color, intro text, attached pages, which one is the default), the number prefix and the next number, the default validity in days, the number format and decimals, the issuer data printed on the document and the three footer texts. Never empty: an organization that never saved a template gets the synthetic template named 'Estándar' (id __default) with its brand color, and it stays when another template is created.

Scope
crm:read
Permission
View the module
MCP tool
crm_quotes_config_getOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.config.get".

Declared cost: up to 1 reads and 0 writes per call (they count against the daily quota).

Parameters

No parameters.

Response

templatesarray<object>
number_prefixstring
next_numbernumber

Next correlative number the first emission of a deal takes.

number_paddingnumber

Digits of the number (4 → 0042).

default_validity_daysnumber
number_formatenum | null

Values: auto, dot_comma, comma_dot

decimalsnumber | null
issuerobject | null

Issuer data printed on the document; legal_name is printed as issuer.name in crm.quotes.export.

footer_leftstring | null
footer_centerstring | null
footer_rightstring | null
updated_atnumber | null

Last change of the stored configuration, epoch ms (absent while nothing was ever saved).

updated_by_idstring | null

Errors

Example

curl "https://api.mb-suite.com/v1/crm/quotes/config" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/crm/quotes/config" \
  -H "Authorization: Bearer $MB_TEST_KEY"
PATCH/v1/crm/quotes/config

Update the quote numbering, issuer and footer

crm.quotes.config.update

WriteIdempotentSince 2026-11-01

Updates any of: the number prefix, the next number (it never goes back: the stored one wins if it is higher, so numbers already emitted are never reused), the default validity in days, the number format (auto, dot_comma, comma_dot) and decimals (0 or 2), the issuer data (replaced as a whole) and the three footer texts (an empty string leaves that position blank; {{numero}} prints the quote number). Fields not sent are kept. Returns the next number in force. Templates are managed with crm.quotes.templates.*. Requires manage_quote_config (managers and admins).

Scope
crm:write
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_config_updateOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.config.update".

Declared cost: up to 1 reads and 1 writes per call (they count against the daily quota).

Parameters

number_prefixstringbodyoptional

Printed prefix of the quote number, up to 24 characters (for example 'COT-2026-').

next_numberintegerbodyoptional

Next correlative number; it never goes back: the stored one wins if it is higher.

default_validity_daysintegerbodyoptional

Default validity of a quote in days (1 to 365); each emission can change it.

number_formatenumbodyoptional

Thousands and decimal separators of the amounts: auto (by the document language), dot_comma (1.234,56) or comma_dot (1,234.56).

Values: auto, dot_comma, comma_dot

decimals0 | 2bodyoptional

Decimals of the amounts: 0 or 2.

issuerobjectbodyoptional

The issuer printed on the document, replaced as a whole (fields not sent are left empty).

footer_leftstringbodyoptional

Left footer text; an empty string leaves it blank; {{numero}} prints the quote number.

footer_centerstringbodyoptional

Center footer text; an empty string leaves it blank; {{numero}} prints the quote number.

footer_rightstringbodyoptional

Right footer text; an empty string leaves it blank; {{numero}} prints the quote number.

Response

next_numbernumber

Errors

Example

curl -X PATCH "https://api.mb-suite.com/v1/crm/quotes/config" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X PATCH "https://api.mb-suite.com/v1/crm/quotes/config" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/quotes/templates

Create or replace a quote template

crm.quotes.templates.save

WriteSince 2026-11-01

Creates a quote template (without template.id) or replaces the whole template with that id (fields not sent, like intro_text, are left empty; an id that does not exist answers quote_template_not_found): name, layout (classic, modern or compact), accent color (#rrggbb), optional intro text, the ordered ids of the attached pages (from crm.quotes.pages.list, up to 20; one that does not exist answers quote_page_not_found) and whether it is the default (marking it unmarks the others; one template is always the default). In an organization that never saved a template the synthetic 'Estándar' (id __default) stays next to the new one. Returns the template id. A template is the design every quote uses: a deal's quote (its lines and totals) is built with crm.deals.update_quote and emitted with crm.quotes.emit. Requires manage_quote_config.

Scope
crm:write
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_templates_saveOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.templates.save".

Declared cost: up to 1 reads and 1 writes per call (they count against the daily quota).

Parameters

templateobjectbodyrequired

The whole template: a replace overwrites every field (what is not sent is left empty).

Response

template_idstring

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "template": {}
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "template": {}
}'
POST/v1/crm/quotes/templates/{template_id}/delete

Delete a quote template

crm.quotes.templates.delete

IrreversibleSince 2026-11-01

Deletes a quote template for good: templates have no trash, so it cannot be restored (quotes already emitted keep their PDF and their snapshot). If it was the default, the first remaining template becomes the default; when none remains, the synthetic 'Estándar' (id __default) comes back, and that one alone cannot be deleted (quote_template_last). The dry run names the template and which one becomes the default. Confirm with the user first. Requires manage_quote_config.

Needs confirmation: first dry_run: true (preview and confirm_token, valid 10 minutes and for one run), then the same body with confirm_token. In a few operations only with certain data: the description says when. Why and how: Dry run and confirm_token.

Scope
crm:write and “Allow deletions” (crm:delete in OAuth)
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_templates_deleteOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.templates.delete".

Declared cost: up to 2 reads and 1 writes per call (they count against the daily quota).

Parameters

template_idstringpathrequired

The template's id, from crm.quotes.config.get (templates[].id); __default is the synthetic 'Estándar' template.

Response

oktrue

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates/{template_id}/delete" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "dry_run": true
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates/{template_id}/delete" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "dry_run": true
}'
POST/v1/crm/quotes/templates/{template_id}/default

Make a quote template the default

crm.quotes.templates.set_default

WriteIdempotentSince 2026-11-01

Marks a template as the default one (the others stop being default): it is the template a new emission uses when none is chosen; also the synthetic 'Estándar' (id __default). Idempotent. Requires manage_quote_config.

Scope
crm:write
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_templates_set_defaultOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.templates.set_default".

Declared cost: up to 2 reads and 1 writes per call (they count against the daily quota).

Parameters

template_idstringpathrequired

The template's id, from crm.quotes.config.get (templates[].id); __default is the synthetic 'Estándar' template.

Response

oktrue

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates/{template_id}/default" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates/{template_id}/default" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/quotes/templates/{template_id}/duplicate

Duplicate a quote template

crm.quotes.templates.duplicate

WriteSince 2026-11-01

Copies a template with all its settings and pages under the name '<name> (copia)', never as the default, and returns the id of the copy. Requires manage_quote_config.

Scope
crm:write
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_templates_duplicateOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.templates.duplicate".

Declared cost: up to 2 reads and 1 writes per call (they count against the daily quota).

Parameters

template_idstringpathrequired

The template's id, from crm.quotes.config.get (templates[].id); __default is the synthetic 'Estándar' template.

Response

template_idstring

Id of the copy.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates/{template_id}/duplicate" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/templates/{template_id}/duplicate" \
  -H "Authorization: Bearer $MB_TEST_KEY"
GET/v1/crm/quotes/pages

List the quote attachment pages

crm.quotes.pages.list

ReadIdempotentSince 2026-11-01

Lists the attachment pages that templates can append at the end of a quote (terms of sale, payment methods…), ordered by title, with their size; with include_content, also their sanitized HTML. Paginated by cursor (limit up to 50). Templates reference them by id in page_ids.

Scope
crm:read
Permission
View the module
MCP tool
crm_quotes_pages_listOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.pages.list".

Declared cost: up to 52 reads and 0 writes per call (they count against the daily quota).

Parameters

limitintegerqueryoptional

Pages per call, 1 to 50 (default 20).

Default: 20

cursorstringqueryoptional

next_cursor of the previous page.

include_contentbooleanqueryoptional

Include each page's sanitized HTML in content_html (default false: only title, size and dates).

Default: false

Response

dataarray<object>
has_moreboolean
next_cursorstring

Errors

Example

curl "https://api.mb-suite.com/v1/crm/quotes/pages" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/crm/quotes/pages" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/quotes/pages

Create a quote attachment page

crm.quotes.pages.create

WriteSince 2026-11-01

Creates an attachment page (title up to 160 characters and its rich-text HTML, sanitized when saved: scripts and event attributes are removed) that templates can append at the end of a quote; add its id to a template with crm.quotes.templates.save. Returns the page id. It is not the quote itself: a deal's quote (its lines and totals) is built with crm.deals.update_quote and its PDF is emitted with crm.quotes.emit. Requires manage_quote_config.

Scope
crm:write
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_pages_createOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.pages.create".

Declared cost: up to 0 reads and 1 writes per call (they count against the daily quota).

Parameters

titlestringbodyrequired

Page title, up to 160 characters.

content_htmlstringbodyrequired

Rich-text HTML of the page; it is sanitized when saved (scripts and event attributes are removed).

Response

page_idstring

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/pages" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "TITLE",
  "content_html": "CONTENT_HTML"
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/pages" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "TITLE",
  "content_html": "CONTENT_HTML"
}'
PATCH/v1/crm/quotes/pages/{page_id}

Update a quote attachment page

crm.quotes.pages.update

WriteIdempotentSince 2026-11-01

Changes the title and/or the HTML content (sanitized when saved) of an attachment page; with neither it answers no_changes. Quotes already emitted keep the PDF they were issued with. Requires manage_quote_config.

Scope
crm:write
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_pages_updateOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.pages.update".

Declared cost: up to 1 reads and 1 writes per call (they count against the daily quota).

Parameters

page_idstringpathrequired

An attachment page's id, from crm.quotes.pages.list.

titlestringbodyoptional

New title, up to 160 characters.

content_htmlstringbodyoptional

New rich-text HTML; it is sanitized when saved.

Response

oktrue

Errors

Example

curl -X PATCH "https://api.mb-suite.com/v1/crm/quotes/pages/{page_id}" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X PATCH "https://api.mb-suite.com/v1/crm/quotes/pages/{page_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/quotes/pages/{page_id}/delete

Delete a quote attachment page

crm.quotes.pages.delete

IrreversibleSince 2026-11-01

Deletes an attachment page for good and removes it from every template that used it: pages have no trash, so it cannot be restored (quotes already emitted keep their PDF). The dry run names the page and the templates it leaves. Confirm with the user first. Requires manage_quote_config.

Needs confirmation: first dry_run: true (preview and confirm_token, valid 10 minutes and for one run), then the same body with confirm_token. In a few operations only with certain data: the description says when. Why and how: Dry run and confirm_token.

Scope
crm:write and “Allow deletions” (crm:delete in OAuth)
Permission
Edit in the module · CRM action: manage_quote_config
MCP tool
crm_quotes_pages_deleteOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.pages.delete".

Declared cost: up to 3 reads and 2 writes per call (they count against the daily quota).

Parameters

page_idstringpathrequired

An attachment page's id, from crm.quotes.pages.list.

Response

oktrue

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/pages/{page_id}/delete" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "dry_run": true
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/crm/quotes/pages/{page_id}/delete" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "dry_run": true
}'
POST/v1/crm/deals/{deal_id}/quote/emit

Emit the quote PDF of a deal

crm.quotes.emit

WriteSince 2026-11-01

Emits the deal's quote as a PDF (rendered by MB Suite's PDF service) and returns its download URL and number. The first emission reserves the next number for the deal; later emissions of the same deal reuse it and add a new row to its history (crm.quotes.emissions.list). Options: template (one that does not exist answers quote_template_not_found), which of its pages to include (only among the template's: quote_page_not_in_template otherwise), document language (es, en, pt-BR), number format and decimals, validity in days and a note for this emission. The deal must have line items (crm.deals.update_quote); see the document first with crm.quotes.export. When the PDF service is not available it answers pdf_unavailable (503) and nothing is emitted: retry in a few seconds. Not idempotent. Requires edit_deal on the deal.

Scope
crm:write
Permission
Edit in the module
MCP tool
crm_quotes_emitOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.emit".

Declared cost: up to 26 reads and 6 writes per call (they count against the daily quota). Touches an external platform (pdf): it counts against the external operations quota.

Parameters

deal_idstringpathrequired

The deal's id, from crm.deals.list.

localeenumbodyrequired

Language of the document: es, en or pt-BR.

Values: es, en, pt-BR

validity_daysintegerbodyrequired

Validity of this quote in days (1 to 365); crm.quotes.config.get has the default.

template_idstringbodyoptional

Template to use (default: the default one). The template's id, from crm.quotes.config.get (templates[].id); __default is the synthetic 'Estándar' template.

include_page_idsarray<string>bodyoptional

Which of the template's attachment pages to include (ids from the template's page_ids); omit it for all of them. A page the template does not have answers quote_page_not_in_template.

number_formatenumbodyoptional

Separators for this emission (default: the configuration's).

Values: auto, dot_comma, comma_dot

decimals0 | 2bodyoptional

Decimals for this emission, 0 or 2 (default: the configuration's).

notestringbodyoptional

A note printed on this emission only, up to 1000 characters.

Response

emission_idstring
pdf_urlstring

Download link of the PDF.

number_formattedstring

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/deals/{deal_id}/quote/emit" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "locale": "es",
  "validity_days": 1
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset. In the practice organization this operation is not simulated (it reaches another platform): it answers 409 sandbox_external_unavailable.

GET/v1/crm/deals/{deal_id}/quote/emissions

List the quote emissions of a deal

crm.quotes.emissions.list

ReadIdempotentSince 2026-11-01

Returns the emissions of the deal's quote, newest first, paginated by cursor (limit up to 50, default 20): number, language, validity, totals, currency, the template used, who emitted it and a fresh download URL of its PDF; with include_content, also the frozen content (issuer, client, line items, intro and footer). deal_not_found when the deal does not exist or the seller's scope hides it.

Scope
crm:read
Permission
View the module
MCP tool
crm_quotes_emissions_listOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.emissions.list".

Declared cost: up to 53 reads and 0 writes per call (they count against the daily quota).

Parameters

deal_idstringpathrequired

The deal's id, from crm.deals.list.

limitintegerqueryoptional

Emissions per call, 1 to 50 (default 20), newest first.

Default: 20

cursorstringqueryoptional

next_cursor of the previous page.

include_contentbooleanqueryoptional

Include each emission's frozen content (issuer, client, line_items, intro_text, footer); default false: number, dates, template, totals and the PDF link.

Default: false

Response

dataarray<object>
has_moreboolean
next_cursorstring

Errors

Example

curl "https://api.mb-suite.com/v1/crm/deals/{deal_id}/quote/emissions" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/crm/deals/{deal_id}/quote/emissions" \
  -H "Authorization: Bearer $MB_TEST_KEY"
GET/v1/crm/deals/{deal_id}/quote

Get the quote document of a deal

crm.quotes.export

ReadIdempotentSince 2026-11-01

Builds the deal's quote document from its current state, exactly what the emission preview shows: issuer (name is the configuration's legal_name, the logo as an absolute URL), client (company and primary person), line items and totals, currency, the number it has (or the next one, is_preview_number), validity, template layout and color, the attached pages (sanitized HTML) and the footer. Optional template (quote_template_not_found when it does not exist), pages (only among the template's: quote_page_not_in_template otherwise) and language. It writes nothing and does not reserve a number: use crm.quotes.emit for the PDF. Not found if the deal does not exist or the seller's scope hides it.

Scope
crm:read
Permission
View the module
MCP tool
crm_quotes_exportOn the full surface; on the compact one, mb_execute_operation with id: "crm.quotes.export".

Declared cost: up to 26 reads and 0 writes per call (they count against the daily quota).

Parameters

deal_idstringpathrequired

The deal's id, from crm.deals.list.

template_idstringqueryoptional

Template to build it with (default: the default one). The template's id, from crm.quotes.config.get (templates[].id); __default is the synthetic 'Estándar' template.

include_page_idsarray<string>queryoptional

Which of the template's attachment pages to include (ids from the template's page_ids); omit it for all of them. A page the template does not have answers quote_page_not_in_template.

localeenumqueryoptional

Language of the document: es (default), en or pt-BR.

Values: es, en, pt-BR

Response

localestring
number_formattedstring
is_preview_numberboolean

true when the deal has no number yet: the one shown is the next one, reserved only by crm.quotes.emit.

issue_datenumber
validity_daysnumber
valid_untilnumber
issuerobject
clientobject | null
line_itemsarray<object>
totalsobject
currencystring
template_idstring
layoutstring
accent_colorstring
pagesarray<object>
footerobject
number_formatenum | null

Values: auto, dot_comma, comma_dot

decimalsnumber | null
intro_textstring | null
notestring | null

Errors

Example

curl "https://api.mb-suite.com/v1/crm/deals/{deal_id}/quote" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/crm/deals/{deal_id}/quote" \
  -H "Authorization: Bearer $MB_TEST_KEY"