These endpoints are public — no authentication required. Use them from the quote builder SPA or any external integration.
All endpoints in this page are rate limited to 60 requests per minute .
POST /api/quotes/save-draft
Validates and persists a quote with status draft. Use this to save progress before the client finalises their selection. A unique reference number is generated automatically in the format COT-XXXXXX.
Request body
Client contact information. Full name of the client. Maximum 255 characters.
Valid email address. Maximum 255 characters.
Company or organisation name. Optional.
Contact phone number. Optional.
client.additional_requirements
Free-text field for any extra requirements the client wants to communicate. Optional.
Array of selected quote block objects. May be empty for drafts. Show Block item properties
ID of the source QuoteBlock. Optional — omit for custom line items.
Display name of the line item.
Description of the service.
Block type (e.g., generic, hourly, fixed). Defaults to generic.
Quantity of units. Defaults to 1.
Estimated hours for this item.
Unit price. Stored as unit_price on the QuoteItem record.
Total price for this line item (unit price × quantity).
Additional block configuration. Stored as data on the QuoteItem record.
Quote totals. Grand total. Must be a non-negative number.
Total estimated hours across all blocks.
Response
Unique quote reference in the format COT-XXXXXX.
Human-readable confirmation message.
Example
curl --request POST \
https://your-domain.com/api/quotes/save-draft \
--header "Content-Type: application/json" \
--data '{
"client": {
"name": "Ana García",
"email": "ana@example.com",
"company": "Acme Corp",
"phone": "+1 555 0100"
},
"blocks": [
{
"id": 10,
"name": "Landing Page",
"description": "Single-page marketing site",
"type": "fixed",
"quantity": 1,
"hours": 40,
"base_price": 1500.00,
"total_price": 1500.00
}
],
"summary": {
"subtotal": 1500.00,
"tax": 285.00,
"total": 1785.00,
"hours": 40
}
}'
200 — success
422 — validation error
{
"success" : true ,
"reference" : "COT-64A3F2B1C9D" ,
"message" : "Cotización guardada como borrador"
}
{
"success" : false ,
"errors" : {
"client.name" : [ "The client.name field is required." ],
"client.email" : [ "The client.email field must be a valid email address." ],
"summary.total" : [ "The summary.total field is required." ]
}
}
POST /api/quotes/submit
Validates, persists, and finalises a quote. Sets status to sent and records sent_at. Generates a PDF and stores it at storage/app/public/quotes/{reference}.pdf. Returns a URL to the stored PDF.
Unlike save-draft, the blocks array must contain at least one item .
Request body
Same structure as POST /api/quotes/save-draft with one additional constraint:
Must contain at least one block (min:1).
Response
Unique quote reference in the format COT-XXXXXX.
Public URL to the generated PDF file (served from storage/).
Human-readable confirmation message.
Example
curl --request POST \
https://your-domain.com/api/quotes/submit \
--header "Content-Type: application/json" \
--data '{
"client": {
"name": "Ana García",
"email": "ana@example.com",
"company": "Acme Corp",
"phone": "+1 555 0100"
},
"blocks": [
{
"id": 10,
"name": "Landing Page",
"description": "Single-page marketing site",
"type": "fixed",
"quantity": 1,
"hours": 40,
"base_price": 1500.00,
"total_price": 1500.00
}
],
"summary": {
"subtotal": 1500.00,
"tax": 285.00,
"total": 1785.00,
"hours": 40
}
}'
200 — success
422 — validation error
500 — server error
{
"success" : true ,
"reference" : "COT-64A3F2B1C9D" ,
"pdf_url" : "/storage/quotes/COT-64A3F2B1C9D.pdf" ,
"message" : "Cotización enviada exitosamente"
}
{
"success" : false ,
"errors" : {
"blocks" : [ "The blocks field must contain at least 1 items." ]
}
}
{
"success" : false ,
"message" : "Error al procesar la cotización. Por favor, intenta nuevamente."
}
POST /api/quotes/generate-pdf
Generates and streams a PDF for the provided quote data. The quote is not saved to the database. Use this to preview or download a PDF without creating a quote record.
Request body
Same structure as POST /api/quotes/save-draft .
Response
Returns the PDF file as a binary download.
Header Value Content-Typeapplication/pdfContent-Dispositionattachment; filename="cotizacion.pdf"
This endpoint returns a file, not JSON. Handle the response as a binary blob in your client.
Example
curl --request POST \
https://your-domain.com/api/quotes/generate-pdf \
--header "Content-Type: application/json" \
--output cotizacion.pdf \
--data '{
"client": {
"name": "Ana García",
"email": "ana@example.com"
},
"blocks": [
{
"name": "Landing Page",
"hours": 40,
"base_price": 1500.00,
"total_price": 1500.00
}
],
"summary": {
"subtotal": 1500.00,
"tax": 285.00,
"total": 1785.00
}
}'
GET /api/health
Health check endpoint for monitoring and uptime checks. No authentication required and not subject to the standard rate limits.
Response
Always "healthy" when the application is running.
Current server time in ISO 8601 format.
Example
curl https://your-domain.com/api/health
{
"status" : "healthy" ,
"timestamp" : "2024-01-15T10:30:00.000000Z"
}