Presupuestos
Un presupuesto es una propuesta económica que envías a un cliente antes de
emitir la factura correspondiente. Tiene líneas de detalle, totales, condiciones
de pago y un ciclo de vida con estados (pending, accepted, rejected,
closed).
Cuando el cliente acepta el presupuesto, lo normal es convertirlo en factura.
La conversión en sí no es una operación de esta API: se hace desde la
interfaz. El presupuesto convertido refleja la factura resultante en su
related cuando se consulta.
Estados
content.main.baseState controla el estado declarado del presupuesto. Es lo
que tú marcas desde el propio documento:
pending— presupuesto enviado o en negociación, sin decisión.accepted— el cliente lo ha aceptado.rejected— el cliente lo ha rechazado.closed— cerrado sin esperar respuesta (por ejemplo, plazo vencido).
El estado efectivo que ves en la interfaz puede no coincidir con baseState
si existen documentos relacionados. Por ejemplo, un presupuesto accepted que
se ha convertido en factura aparece como facturado, aunque su baseState
siga siendo accepted.
Campos derivados que se rellenan típicamente al cambiar baseState:
acceptedDate,acceptedBy— quién aceptó y cuándo.rejectedDate,rejectedBy— equivalente para rechazos.
Estos campos no son obligatorios al crear el presupuesto.
Factura proforma
Un presupuesto puede marcarse como factura proforma con
content.main.isProforma: true. Una factura proforma es un documento previo a
la factura definitiva que se presenta al cliente con apariencia de factura,
pero sin efectos fiscales reales. Es habitual en escenarios como pagos
anticipados, exportaciones o aprobaciones internas del cliente que exigen un
documento con formato de factura antes de emitir la definitiva.
A nivel del sistema, una factura proforma sigue siendo un presupuesto: usa
los mismos endpoints, mismos estados (baseState) y la misma estructura de
líneas y totales. Solo cambia su presentación:
- Nombre del PDF generado — usa el prefijo “proforma” (o el configurado en la plantilla del documento) en vez de “presupuesto”.
- Plantilla de email al enviarlo — usa la plantilla
email_proforma(con asunto y cuerpo propios) en vez deemail_estimate. Configura ambas plantillas en los ajustes de la empresa si quieres mensajes distintos para presupuestos y proformas. - Etiquetado interno — aparece como “proforma” en los listados de la app y en los nombres de fichero, no como “presupuesto”.
isProforma no implica cambios fiscales: no genera asientos contables, no
se reporta a VeriFactu/TicketBAI y no consume serie de facturación. Para emitir
la factura real al cliente, crea un nuevo documento de tipo invoice cuando
corresponda.
Estructura del presupuesto
Forma común a los documentos de venta de FacturaDirecta:
content.type— siempre"estimate".content.uuid— identificador inmutable.content.main— datos del documento (contacto, fechas, divisa, líneas, totales, condiciones, plantilla). Puede incluirowner, el usuario responsable del presupuesto cuando trabajas con roles personalizados.content.attachments— adjuntos vinculados (ver Adjuntos).content.meta— metadatos internos.
En respuestas, además, en el nivel raíz: tags, creationDate,
modificationDate, related.
Si creas el presupuesto con OAuth y no envías owner, la API asigna
como responsable al usuario autenticado. Si usas una apiKey, queda sin
responsable salvo que envíes owner en el body.
content.main.customFields es un mapa de valores indexado por el ID estable
cfi_<uuid v4> de cada campo personalizado. Las claves
deben corresponder a definiciones existentes. También se aceptan definiciones
borradas para conservar presupuestos históricos; un ID desconocido o con
formato incorrecto produce 400 Bad Request.
Líneas de detalle
content.main.lines es un array. Cada línea requiere text, quantity y
unitPrice. Otros campos relevantes:
discountodiscountRate— descuento absoluto o porcentual.tax— array de identificadores de impuesto (TaxId) que aplican a la línea. Los IDs se obtienen del catálogo de ventas de la empresa conGET /{companyId}/settings/taxes/sales. Pueden aplicarse varios impuestos a una misma línea, típicamente IVA + retención de IRPF. Ver Impuestos para el modelo completo (catálogos, autorepercutidos, agregado en el documento).
En los ejemplos de esta página:
- Los UUIDs (
con_2c4f8e21-…,est_8d3b6c14-…,upl_6f8e9b42-…) son ilustrativos. Cada empresa tiene los suyos; sustitúyelos por los identificadores reales que devuelve la API en cada caso.- Los IDs de impuestos (
S_IVA_21,S_IRPF_15) son los del catálogo por defecto del sistema. Pueden variar por empresa o comunidad fiscal; recupera el catálogo real conGET /{companyId}/settings/taxes/sales.
lineTotal— total de la línea; la API lo calcula si lo omites.document— ID del producto del catálogo si la línea proviene de uno.account— cuenta contable de la línea; por defecto se toma de la cuenta asociada al producto o, en su defecto, la de ventas de la empresa.
Importes y totales. Los totales del documento (total, totalBeforeTaxes,
linesTotal, taxes) se calculan a partir de las líneas. Conviene dejarlos
vacíos al crear o actualizar y leerlos de la respuesta. Enviarlos manualmente
solo está justificado para importaciones que fijan totales históricos.
taxIncludedPrices: true indica que unitPrice ya incluye IVA. Por defecto es
false. Cambia el cálculo de taxes y total.
Por defecto el documento se trata como presupuesto. Para marcarlo como
factura proforma, pon content.main.isProforma: true (ver
Factura proforma).
Enlace a la aplicación
Las respuestas que devuelven un presupuesto incluyen webUrl junto al resto de
los datos. En los listados, cada elemento de items lleva su propio enlace.
webUrl abre la ficha del elemento en la aplicación web de FacturaDirecta.
Puedes mostrarlo como enlace en tu integración sin construir rutas internas.
El navegador pedirá iniciar sesión con un usuario que tenga acceso a la
empresa. Es un campo opcional y no es un endpoint de la API: trátalo como una
URL para el usuario, no como una URL a la que enviar $ACCESS_TOKEN.
Operaciones
- Lista de presupuestos
- Crear presupuesto
- Obtener un presupuesto
- Actualizar presupuesto
- Borrar presupuesto
- Actualizar etiquetas de presupuesto
- Enviar presupuesto por correo
- Generar el presupuesto en PDF
- Adjuntos
Lista de presupuestos
GET /{companyId}/estimates devuelve los presupuestos de la empresa, paginados.
Parámetros de consulta principales:
search— búsqueda aproximada en el texto del presupuesto (título, líneas, notas) y en el nombre de su cliente: todas las palabras, sin distinguir acentos ni mayúsculas (ver Búsqueda).minDate,maxDate— rango de fechas (YYYY-MM-DD).series,formattedSeries— serie de numeración (en formato canónico o como aparece al usuario).minNumber,maxNumber— rango de número de documento.contact— ID de contacto.hasContact—true/falsepara filtrar con o sin contacto.minTotal,maxTotal— rango de importe total.currency— código ISO 4217 (EUR,USD…).country— código país ISO 3166-1 Alpha-2.emails— buscar por destinatario.allTheseTags,anyOfTheseTags— filtros por etiquetas concretas.hasTags—truedevuelve solo presupuestos con al menos una etiqueta yfalse, solo presupuestos sin etiquetas.sortBy— campo de orden.related— recursos a expandir.
Ver Paginación para los parámetros comunes
(offset, limit, hasMore).
Ejemplo de respuesta JSON
{
"pagination": { "offset": 0, "limit": 50, "total": 42 },
"items": [
{
"content": {
"type": "estimate",
"uuid": "est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c",
"main": {
"title": "Presupuesto 2026/0041 — Acme Diseño",
"baseState": "pending",
"docNumber": "2026/0041",
"series": "default",
"date": "2026-05-03",
"dueDate": "2026-06-02",
"contact": "con_2c4f8e21-7b3a-4d9c-9e1f-a8b7c6d5e4f3",
"currency": "EUR",
"lines": [
{
"text": "Diseño de identidad corporativa",
"quantity": 1,
"unitPrice": 1800.00,
"tax": ["S_IVA_21"]
}
],
"linesTotal": 1800.00,
"totalBeforeTaxes": 1800.00,
"taxes": [
{
"id": "S_IVA_21",
"base": 1800.00,
"amount": 378.00,
"companyCurrencyBase": 1800.00,
"companyCurrencyAmount": 378.00
}
],
"total": 2178.00
}
},
"tags": ["q2-2026"],
"creationDate": "2026-05-03T09:12:00.000Z",
"modificationDate": "2026-05-03T09:12:00.000Z"
}
]
}Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates?minDate=2026-01-01&limit=50"Crear presupuesto
POST /{companyId}/estimates crea un presupuesto.
Parámetros del body:
content.type— siempre"estimate".content.main— campos del documento.lineses lo importante; los totales se calculan a partir de ellas.tags(opcional).
Notas:
language(opcional): idioma en que se imprime y se envía el documento, como código ISO 639-1 (es,ca,en…). Si se omite, el del contacto al asignarlo y, si no tiene, el idioma base de la plantilla. Solo tiene efecto si la plantilla tiene ese idioma.- Si
contactapunta a un ID existente, sus datos fiscales y de envío se toman de ese contacto. seriesydocNumberse asignan automáticamente si no los envías, según la numeración configurada para presupuestos.- La respuesta es el presupuesto creado completo, en el formato de Obtener un presupuesto.
Ejemplo de request JSON
{
"content": {
"type": "estimate",
"main": {
"contact": "con_2c4f8e21-7b3a-4d9c-9e1f-a8b7c6d5e4f3",
"date": "2026-05-03",
"dueDate": "2026-06-02",
"currency": "EUR",
"lines": [
{
"text": "Diseño de identidad corporativa",
"quantity": 1,
"unitPrice": 1800.00,
"tax": ["S_IVA_21"]
}
]
}
},
"tags": ["q2-2026"]
}Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{
"content": {
"type": "estimate",
"main": {
"contact": "con_2c4f8e21-7b3a-4d9c-9e1f-a8b7c6d5e4f3",
"date": "2026-05-03",
"currency": "EUR",
"lines": [
{ "text": "Diseño de identidad corporativa", "quantity": 1, "unitPrice": 1800.00, "tax": ["S_IVA_21"] }
]
}
}
}' \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates"Obtener un presupuesto
GET /{companyId}/estimates/{id} devuelve un presupuesto por ID.
Parámetros:
related(opcional) — recursos relacionados a expandir, por ejemploinvoicespara ver si el presupuesto ha derivado en factura.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c?related=invoices"Actualizar presupuesto
PUT /{companyId}/estimates/{id} sustituye el contenido del presupuesto.
Las líneas se reemplazan por las que envíes y los campos opcionales que no envíes se
eliminan. Los campos obligatorios que no envíes conservan su valor, igual que docNumber
y meta, que no cambian. Lo que FacturaDirecta rellena al crear (account, dueDate,
fiscalPosition, theme…) se rellena igual al actualizar si no lo envías. Si no envías
exchangeRate, se conserva el anterior mientras no cambien ni la moneda ni la fecha; si
cambia alguna de las dos, se toma el tipo de cambio de la nueva fecha.
Para cambiar el estado del documento, envía el contacto y las líneas
inalterados junto con el nuevo baseState (y, si aplica, acceptedDate /
rejectedDate).
Restricciones:
- Si el presupuesto ya está convertido en una factura, las modificaciones
pueden estar limitadas o producir efectos secundarios. Antes de actualizar
un
accepted, consulta surelated.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
-d '@estimate.json' \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c"Borrar presupuesto
DELETE /{companyId}/estimates/{id} elimina un presupuesto.
Restricciones. No se puede borrar un presupuesto que ya esté vinculado a
una factura emitida. La API devuelve 409 Conflict con el detalle del documento
que bloquea el borrado.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c"Actualizar etiquetas de presupuesto
PUT /{companyId}/estimates/{id}/tags reemplaza el conjunto de etiquetas sin
tocar el resto del contenido.
Ejemplo de request JSON
{
"tags": ["q2-2026", "agencia", "prioridad-alta"]
}Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
-d '{"tags":["q2-2026","agencia","prioridad-alta"]}' \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c/tags"Enviar presupuesto por correo
PUT /{companyId}/estimates/{id}/send envía el presupuesto por correo
electrónico. Los destinatarios, asunto y cuerpo se toman de la plantilla
configurada para presupuestos; los campos del body permiten sobreescribirlos
puntualmente.
Parámetros del body (todos opcionales):
to,cc,bcc— listas de destinatarios; sobrescriben los valores de la plantilla.from— remitente; debe ser una dirección autorizada en la empresa.subject— asunto.html— cuerpo del email en HTML.
Si no envías body, se usa enteramente la plantilla del presupuesto.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
-d '{"to":["compras@acme.es"],"subject":"Presupuesto 2026/0041"}' \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c/send"Generar el presupuesto en PDF
PUT /{companyId}/estimates/{id}/pdf genera una URL temporal con el
presupuesto en PDF.
Parámetros del body:
mode(opcional) —"attachment"(URL para descargar como adjunto, por defecto),"inline"(visualización en línea) o"print"(URL HTML que carga el PDF y lo envía a imprimir).
La URL devuelta es válida solo durante el periodo indicado en la respuesta.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
-d '{"mode":"inline"}' \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c/pdf"Adjuntos
Un presupuesto puede tener varios adjuntos vinculados (PDFs de referencia,
documentación técnica, etc.). Los adjuntos no se suben en el body del
presupuesto: primero se crean con POST /uploads y después se vinculan al
presupuesto con POST /estimates/{id}/attachments enviando los uploadIds.
Una vez vinculados, los adjuntos viven dentro del recurso y se pueden listar o eliminar de forma independiente.
Listar adjuntos
GET /{companyId}/estimates/{id}/attachments devuelve los adjuntos vinculados
al presupuesto.
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c/attachments"Vincular adjuntos
POST /{companyId}/estimates/{id}/attachments añade adjuntos al presupuesto a
partir de uploads previos.
Parámetros del body:
uploadIds— array de identificadoresupl_<uuid>obtenidos conPOST /uploads. Mínimo uno.
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"uploadIds":["upl_6f8e9b42-1d3c-4a7f-b2e4-9c1d5e7f3a6b","upl_7a9b0c53-2e4d-4b8a-a3f5-0d2e6f8a4b7c"]}' \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c/attachments"Eliminar un adjunto
DELETE /{companyId}/estimates/{id}/attachments/{attachmentIndex} elimina un
adjunto del presupuesto. attachmentIndex es la posición del adjunto en el
array (basada en cero).
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE \
"https://app.facturadirecta.com/api/$COMPANY_ID/estimates/est_8d3b6c14-2f5e-4a7b-b0c8-1d2e3f4a5b6c/attachments/0"Versiones
GET /{companyId}/estimates/{id}/versions lista las versiones de el presupuesto: su alta, cada
modificación, su eliminación y su recuperación, con quién y cuándo, aunque se haya eliminado.
GET /{companyId}/estimates/{id}/versions/{versionId} devuelve la copia de una versión, en el
mismo formato que GET /{companyId}/estimates/{id}, y los cambios respecto a la versión anterior.
Sirven para ver qué se cambió y recuperar datos: ver
Versiones de documentos.
Errores comunes
400—minDateomaxDatees una fecha que no existe, como2026-02-30. Ver Fechas que no existen.400 ValidationError— faltacontact, o líneas conquantityounitPriceinválidos.400 ValidationError—baseStatecon valor no admitido.409 Conflict— borrado o modificación incompatible con un documento relacionado (típicamente, factura ya emitida).409 Conflict—seriesodocNumberduplicado en la empresa.
Ver Errores y validaciones para el formato general de respuestas de error.
Endpoints
| Método | Path | operationId | Scopes | Descripción |
|---|---|---|---|---|
| GET | /{companyId}/estimates | getEstimates | estimates:read | Lista de presupuestos |
| GET | /{companyId}/estimates/{id} | getEstimate | estimates:read | Obtener un presupuesto |
| GET | /{companyId}/estimates/{id}/attachments | getEstimateAttachments | estimates:read | Listar adjuntos de un presupuesto |
| GET | /{companyId}/estimates/{id}/versions | getEstimateVersions | estimates:read | Versiones de el presupuesto |
| GET | /{companyId}/estimates/{id}/versions/{versionId} | getEstimateVersion | estimates:read | Versión de el presupuesto |
| POST | /{companyId}/estimates | createEstimate | estimates:write | Crear presupuesto |
| POST | /{companyId}/estimates/{id}/attachments | addEstimateAttachments | estimates:write | Vincular adjuntos a un presupuesto |
| PUT | /{companyId}/estimates/{id} | updateEstimate | estimates:write | Actualizar presupuesto |
| PUT | /{companyId}/estimates/{id}/pdf | createEstimatePDF | estimates:read | Generar el presupuesto en formato PDF |
| PUT | /{companyId}/estimates/{id}/send | sendEstimate | estimates:write | Enviar presupuesto por correo electrónico |
| PUT | /{companyId}/estimates/{id}/tags | updateEstimateTags | estimates:write | Actualizar etiquetas de presupuesto |
| DELETE | /{companyId}/estimates/{id} | deleteEstimate | estimates:write | Borrar presupuesto |
| DELETE | /{companyId}/estimates/{id}/attachments/{attachmentIndex} | deleteEstimateAttachment | estimates:write | Eliminar adjunto de un presupuesto |
Scopes
estimates:read— Lectura de presupuestos.estimates:write— Modificación de presupuestos.