Skip to main content

Generate PDFs

MCP Tool: generate_pdf​

Profile: core

Generates a PDF by combining a template with data from a record.

Parameters​

ParameterTypeRequiredDescription
templateIdstringYesID of the record in pdf_templates
recordIdstringNoID of the record with the data
entityNamestringNoEntity name. If omitted when using recordId, resolved from the template's entidad_origen field.
dataobjectNoAdditional or override data. Keys = template field names
storebooleanNoSave the PDF to storage. Default: true
updateFieldstringNoRecord field where to save the PDF reference. Default: pdf_documento

Generation Flow​

  1. Finds the template by templateId
  2. If recordId is provided without entityName, resolves entity from template.entidad_origen (fallback added in v1.17.0)
  3. Fetches the record from the entity
  4. Maps the fields: the template name must match the record fieldKey
  5. If data is provided, it is merged (override) over the record data
  6. Fields of type table receive array[][] input (not stringified) so pdfme renders them correctly
  7. Generates the PDF
  8. If store=true, saves it to file storage
  9. If updateField is defined, updates that field of the record with the PDF link

Example: Invoice PDF​

generate_pdf({
templateId: "uuid-de-la-plantilla",
recordId: "uuid-de-la-factura",
entityName: "facturas",
updateField: "pdf_documento"
})

Example: PDF with recordId only (entity resolved from template)​

When the PDF designer dialog passes recordId but not entityName, the backend resolves the entity automatically from the template definition:

generate_pdf({
templateId: "uuid-de-la-plantilla",
recordId: "uuid-de-la-factura"
})

Example: PDF with Custom Data​

generate_pdf({
templateId: "uuid-de-la-plantilla",
data: {
empresa: "Mi Empresa S.A.",
fecha: "18/02/2026",
total: "$15,000.00"
}
})

Example: Record PDF with Extra Data​

generate_pdf({
templateId: "uuid-de-la-plantilla",
recordId: "uuid-de-la-factura",
entityName: "facturas",
data: {
pie_pagina: "Gracias por su compra"
}
})

Response​

Returns the metadata of the generated file (URL, size, etc.) or the PDF in base64 if store=false.

Notes​

  • Field names matter: the name in the template JSON must be exactly the same as the entity's fieldKey
  • Data in data overrides record data if both exist for the same field
  • For calculated fields or fixed text not in the record, use the data parameter
  • Table fields receive array[][] input. Each inner array is a row; each element is a cell value

Table plugin​

The PDF designer (frontend) and generator (backend) support the table plugin from @pdfme/schemas.

In the designer​

Drag a Table element from the sidebar onto the canvas. Configure columns, header row, and column widths in the properties panel.

In the generator​

A field of type table expects its input as an array of arrays:

{
"items_table": [
["Description", "Qty", "Unit Price", "Total"],
["Widget A", "2", "$10.00", "$20.00"],
["Widget B", "1", "$50.00", "$50.00"]
]
}

The first row is typically the header. pdfme renders borders, column widths, and row styling based on the template configuration.


Upload PDFs to Knowledge Base​

Binary PDF files can be uploaded directly to the knowledge base via multipart upload. The document is ingested, chunked, and made available for RAG search.

Endpoint​

POST /api/knowledge/documents/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data

Fields​

FieldTypeRequiredDescription
fileFileYesPDF file. Must be application/pdf. Maximum 20 MB
titlestringNoDocument title. Defaults to the filename

Example​

curl -X POST \
-H "Authorization: Bearer <token>" \
-F "file=@invoice.pdf" \
-F "title=Q1 Invoice" \
https://api.fyso.dev/api/knowledge/documents/upload

Response​

{
"success": true,
"data": {
"id": "uuid",
"title": "Q1 Invoice",
"status": "ingested",
"createdAt": "2026-02-24T00:00:00Z"
}
}

Error responses​

StatusCause
400Missing file field or invalid MIME type (only application/pdf accepted)
401 / 403Missing or invalid authentication
413File exceeds 20 MB limit

Notes​

  • The endpoint converts the binary buffer to base64 and delegates to documentService.ingestDocument, which handles text extraction, chunking, and embedding generation
  • After upload, the document is immediately searchable via POST /api/knowledge/search
  • JSON-based ingestion (POST /api/knowledge/documents) remains unchanged — this endpoint adds multipart support without affecting the existing flow