Órdenes de compra
Una orden de compra registra un encargo en firme a un proveedor antes de la recepción de la mercancía y su facturación. Tiene líneas de detalle, totales y condiciones como el resto de documentos de compra, con una diferencia clave: cada línea tiene su propio estado (pendiente de recibir, recibida o cancelada), y el estado de la orden se calcula a partir de ellas.
Cuando la mercancía se recibe, lo habitual es convertir la orden en factura de compra. La conversión no es una operación de esta API: se hace desde la interfaz. El gasto resultante conserva el enlace con la orden a través del campo origin de sus líneas.
La orden de compra es además el lado que manda en la coordinación con el pedido de cliente: los vínculos línea a línea se crean desde aquí y los estados se propagan desde aquí. Ver Flujo de pedidos y órdenes de compra.
En los ejemplos de esta página los UUIDs (pur_…, con_…, upl_…) son ilustrativos: sustitúyelos por los identificadores reales de tu empresa. Los IDs de impuestos (P_IVA_21_SV) son los del catálogo por defecto; recupera los tuyos con GET /{companyId}/settings/taxes/purchases y consulta Impuestos.
Disponibilidad por plan
Las órdenes de compra y los pedidos forman parte del Módulo Inventario. Están incluidos en el plan Diamante y se pueden contratar como módulo en Bronce, Plata y Oro. En el plan Gratis no están disponibles.
Sin esa disponibilidad, las operaciones de escritura (crear, actualizar, etiquetar y borrar) responden 403 Forbidden con el código plan_limit_exceeded y el mensaje «Los pedidos de cliente y las órdenes de compra no están disponibles en tu plan». Las operaciones de lectura no fallan: devuelven lo que haya.
Estados
Estado de la orden (calculado)
content.main.state es el estado de la orden y es de solo lectura en la práctica: FacturaDirecta lo recalcula en cada guardado a partir del estado de las líneas, con esta prioridad:
pending— alguna línea está pendiente de recibir.received— sin líneas pendientes y alguna línea recibida.canceled— todas las líneas están canceladas.
Si envías main.state en un create o un update, el valor se ignora y se sustituye por el calculado. Para cambiar el estado de la orden, cambia el estado de sus líneas.
Como en los pedidos, las líneas vacías (sin texto ni importe) no cuentan, y una orden sin líneas con contenido queda en pending.
Estado de línea
content.main.lines[].state es escribible y admite estos valores:
pending— pendiente de recibir.received— recibida.canceled— cancelada.
Las líneas nuevas sin state se crean como pending. Cambiar el estado de una línea vinculada a un pedido de cliente modifica también el pedido: ver Flujo de pedidos y órdenes de compra.
Identidad de las líneas
Cada línea tiene un id estable que la identifica dentro de la orden. FacturaDirecta lo genera si no lo envías.
Al actualizar una orden las líneas se sustituyen por las del body, con esta regla: una línea que incluya un id ya existente conserva su identidad (y con ella los vínculos que esa línea tenga con otros documentos); una línea sin id se trata como línea nueva. Si actualizas órdenes por API, conserva los id que devolvió la API en las líneas que no quieras recrear.
Los id deben ser únicos dentro del documento: dos líneas con el mismo id se rechazan con 400.
Estructura de la orden de compra
content.type— siempre"purchaseOrder".content.uuid— identificador inmutable, prefijopur_.content.main— datos del documento (proveedor, fechas, divisa, líneas, totales, plantilla).content.attachments— adjuntos vinculados (ver Adjuntos).content.meta— metadatos internos.
Dentro de content.main son obligatorios docNumber y lines. Campos con comportamiento propio:
Campo | Significado |
| El proveedor. Los impuestos y las cuentas contables se resuelven con el catálogo de compras. |
| Estado de la orden. Calculado; se ignora al escribir. |
| Fecha de recepción prevista de la mercancía. |
| Almacén del documento a efectos de stock. Si no lo indicas se usa el almacén por defecto de la empresa. |
| Valores de campos personalizados del documento. |
| Datos fiscales de la contraparte. |
A diferencia del pedido de cliente, la orden de compra no tiene owner.
En respuestas, además, en el nivel raíz: tags, creationDate, modificationDate y related. related solo transporta los objetos que pidas con el parámetro related (hoy, definiciones de impuestos): no contiene los documentos en los que se haya convertido la orden.
Líneas de detalle
content.main.lines es un array. Cada línea requiere text, quantity y unitPrice. Además de los campos comunes a los documentos de compra (discount/discountRate, tax, document, account, lineTotal), las líneas de la orden añaden:
id— identidad estable de la línea (ver Identidad de las líneas).state— estado de la línea (ver Estado de línea).client— ID del contacto cliente para el que se compra esa línea (trazabilidad de compras bajo pedido de cliente).clientOrder,clientOrderLine— vínculo con el pedido de cliente y con la línea concreta que origina esta línea. Este es el lado desde el que se crea el vínculo: al guardar la orden, FacturaDirecta completa el vínculo recíproco en el pedido y propaga el estado. Para que el vínculo se acepte, el proveedor de la línea de pedido debe coincidir con el proveedor de la orden, y el producto y la cantidad deben ser los mismos en las dos líneas.
Si omites tax en una línea, FacturaDirecta resuelve el impuesto por defecto a partir del producto, del proveedor y de la posición fiscal del documento.
Las líneas con producto deben llevar quantity mayor que cero, y ese producto debe tener activada la faceta de compra (purchases).
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.
Operaciones
Lista de órdenes de compra
GET /{companyId}/purchaseOrders devuelve las órdenes activas de la empresa, paginadas.
Parámetros de consulta específicos:
state— estado de la orden:pending,receivedocanceled. Repite el parámetro para incluir varios estados.minDate/maxDate— fecha de la orden (YYYY-MM-DD), inclusive.series— serie sin aplicar el formato de año (##o####).formattedSeries— serie ya formateada.minNumber/maxNumber— número secuencial, inclusive.contact— proveedor de la orden. Admite varios valores.hasContact—falsepara obtener las órdenes sin contacto asociado.minTotal/maxTotal— importe total.currency— moneda (ISO 4217).country— país de la dirección fiscal del proveedor (ISO 3166-1 alpha-2).emails— búsqueda parcial en los correos del documento, insensible a mayúsculas y acentos; todas las palabras deben coincidir.allTheseTags— la orden debe llevar todas las etiquetas indicadas.anyOfTheseTags— basta con una de las etiquetas indicadas.hasTags—truepara recibir solo órdenes sin ninguna etiqueta.sortBy— orden de los resultados. Valores:date,series,formattedSeries,number,total,currency,country,creationDate,modificationDate. Prefija con-para orden descendente y repite el parámetro para ordenar por varios criterios.related— datos adicionales. Único valor disponible:taxIds, que devuelve enrelated.objectslas definiciones de los impuestos usados.
Parámetros globales aceptados:
Acepta además los parámetros estándar offset, limit, minCreationDate, maxCreationDate, minModificationDate, maxModificationDate y el header accept-version. Ver Paginación y Autenticación.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders?state=pending&sortBy=-date&limit=50"
Crear orden de compra
POST /{companyId}/purchaseOrders crea una orden de compra.
Parámetros del body:
content(obligatorio) — la orden.content.typedebe ser"purchaseOrder"ycontent.maindebe llevardocNumberylines.tags(opcional) — etiquetas iniciales de la orden.
Notas:
Si no envías
content.uuid, la API asigna uno con prefijopur_. Si lo envías y ya existe, responde409 Conflict.El
statede la orden se calcula desde las líneas: lo que envíes enmain.statese descarta.Para abastecer líneas de pedido, indica
clientOrderyclientOrderLineen cada línea. Al guardar, esas líneas de pedido pasan aordered.
Parámetros globales aceptados: accept-version.
Ejemplo de request JSON
Contenido mínimo (ejemplo minimal del openapi). Las líneas se crean pendientes de recibir, así que la orden queda pending:
{ "content": { "type": "purchaseOrder", "main": { "docNumber": { "series": "OC" }, "contact": "con_7b1d2c93-4e5f-4a6b-8c7d-9e0f1a2b3c4d", "currency": "EUR", "lines": [ { "quantity": 1, "unitPrice": 100, "tax": ["P_IVA_21_SV"], "text": "Descripción del artículo a comprar" } ] } }}
Con estado por línea (ejemplo conEstadosDeLinea). Todas las líneas están recibidas, así que la orden queda received:
{ "content": { "type": "purchaseOrder", "main": { "docNumber": { "series": "OC" }, "contact": "con_7b1d2c93-4e5f-4a6b-8c7d-9e0f1a2b3c4d", "currency": "EUR", "lines": [ { "quantity": 2, "unitPrice": 50, "tax": ["P_IVA_21_SV"], "text": "Artículo ya recibido del proveedor", "state": "received" }, { "quantity": 1, "unitPrice": 75, "tax": ["P_IVA_21_SV"], "text": "Otro artículo ya recibido", "state": "received" } ] } }}
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \ -d '@purchaseOrder.json' \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders"
Obtener una orden de compra
GET /{companyId}/purchaseOrders/{id} devuelve una orden por ID.
Parámetros de consulta específicos:
related—taxIdspara recibir enrelated.objectslas definiciones de los impuestos usados en la orden.
Parámetros globales aceptados: accept-version.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10?related=taxIds"
Actualizar orden de compra
PUT /{companyId}/purchaseOrders/{id} sustituye el contenido completo de la orden. No es un PATCH: lo que no envíes se pierde.
Parámetros del body:
content(obligatorio) — la orden completa. Si incluyeuuid, debe coincidir con el de la ruta.syncContactData(opcional) — contrue, actualiza dirección (address,country,zipcode) ycounterparta partir del contacto demain.contact. No toca correos, posición fiscal, vencimiento ni cuenta contable.tagsytagsOperation(opcionales) — etiquetas y operación a aplicar (add,removeoreplace).
Notas:
Conserva los
idde las líneas que no quieras recrear.Cada guardado vuelve a propagar los estados a los pedidos vinculados, que se guardan también y emiten su propio
client_order.updated.
Parámetros globales aceptados: accept-version.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \ -d '@purchaseOrder.json' \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10"
Borrar orden de compra
DELETE /{companyId}/purchaseOrders/{id} borra la orden. El borrado es recuperable desde la interfaz; el documento queda con archived: true y emite el evento purchase_order.archived.
Al borrarla, las líneas de pedido que abastecía vuelven a pending y quedan desvinculadas. Los vínculos se conservan del lado de la orden para poder rehacerlos si se recupera.
Parámetros globales aceptados: accept-version.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10"
Actualizar etiquetas
PUT /{companyId}/purchaseOrders/{id}/tags cambia solo las etiquetas, sin tocar el contenido de la orden.
Parámetros del body (ambos obligatorios):
tags— array de etiquetas.tagsOperation—add,removeoreplace.
Parámetros globales aceptados: accept-version.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \ -d '{"tags":["reposicion"],"tagsOperation":"add"}' \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10/tags"
Enviar la orden por correo
PUT /{companyId}/purchaseOrders/{id}/send envía la orden al proveedor por correo electrónico. Los destinatarios, el asunto y el cuerpo se toman de la plantilla del tema; los campos del body permiten sobreescribirlos.
Parámetros del body (todos opcionales):
to,cc,bcc— listas de destinatarios; sustituyen a los valores demain.emails,main.emailsCcymain.emailsBccdel documento.from— remitente; debe ser una dirección dada de alta en la empresa.subject— asunto.html— cuerpo del mensaje en HTML.
Debe haber al menos un destinatario. Si no se puede determinar ninguno, o si la empresa no tiene remitentes configurados, la respuesta es 409 Conflict.
Parámetros globales aceptados: accept-version.
Copy as cURL
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \ -d '{"to":["pedidos@proveedor.es"],"subject":"Orden de compra OC-2026-08"}' \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10/send"
Generar la orden en PDF
PUT /{companyId}/purchaseOrders/{id}/pdf genera una URL temporal con la orden en PDF.
Parámetros del body:
mode—"attachment"(descarga como adjunto),"inline"(visualización en línea) o"print"(URL HTML que carga el PDF y lo envía a imprimir). Un valor ausente o distinto de esos tres devuelve400.
La respuesta lleva url, filename y availableUntil; en modo print añade urlPdf. La URL es válida hasta la fecha de availableUntil (tres días).
Parámetros globales aceptados: accept-version.
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/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10/pdf"
Adjuntos
Una orden de compra puede tener hasta 10 adjuntos. Los adjuntos no se suben en el body de la orden: primero se crean con POST /uploads y después se vinculan enviando sus uploadIds.
Listar adjuntos
GET /{companyId}/purchaseOrders/{id}/attachments devuelve los adjuntos vinculados a la orden.
Parámetros globales aceptados: accept-version.
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10/attachments"
Vincular adjuntos
POST /{companyId}/purchaseOrders/{id}/attachments añade adjuntos a la orden a partir de uploads previos.
Parámetros del body:
uploadIds(obligatorio) — array no vacío de identificadoresupl_<uuid>obtenidos conPOST /uploads.
Si la suma de adjuntos existentes y nuevos supera 10, la respuesta es 400 con el código attachments_limit_exceeded.
Parámetros globales aceptados: accept-version.
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \ -d '{"uploadIds":["upl_8a2c1234-1234-4123-8123-123456789012"]}' \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10/attachments"
Eliminar un adjunto
DELETE /{companyId}/purchaseOrders/{id}/attachments/{attachmentIndex} elimina un adjunto. attachmentIndex es su posición en el array, empezando en cero; un valor no entero o negativo devuelve 400.
Parámetros globales aceptados: accept-version.
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE \ "https://app.facturadirecta.com/api/$COMPANY_ID/purchaseOrders/pur_9f8e7d66-5c4b-4a39-8271-6e5d4c3b2a10/attachments/0"
Numeración
Las órdenes de compra usan sus propias series de numeración, configurables en los ajustes de la empresa. Si no indicas docNumber.number al crear, se asigna el siguiente número de la serie. Las series con ## o #### se expanden con el año en docNumber.formattedSeries.
Concurrencia
Los guardados y borrados de órdenes de compra de una misma empresa se serializan: cada uno puede tocar los pedidos que abastece, y dos a la vez decidirían la propagación sobre una foto obsoleta. Si ya hay 20 escrituras de órdenes en curso en la misma empresa, la siguiente responde 429 Too Many Requests. Si cargas órdenes en lote, hazlo en serie o con poca concurrencia y reintenta ante un 429.
Webhooks
Los cambios en órdenes de compra emiten purchase_order.created, purchase_order.updated, purchase_order.archived y purchase_order.unarchived. Ver Webhooks.
Cada guardado o borrado que afecte a pedidos vinculados emite además un client_order.updated por cada pedido afectado.
Errores comunes
400— el documento tiene referencias que no existen (proveedor, producto, método de pago o plantilla).400— dos líneas con el mismoid, vínculo con pedido incompleto (documento vinculado y línea vinculada deben ir juntos) o dos líneas apuntando a la misma línea de pedido (el vínculo es 1:1).400— la línea de pedido a la que apuntas no existe, ya está vinculada a otra orden de compra, tiene otro proveedor, otro producto u otra cantidad. Si necesitas comprar unidades adicionales, añade una línea de reposición independiente en vez de cambiar la cantidad de la línea vinculada.400— línea con producto yquantitymenor o igual que cero.400— producto sin las preferencias de compra activadas.400con códigoattachments_limit_exceeded— se supera el máximo de adjuntos del documento.403— el plan no incluye pedidos ni órdenes de compra (ver Disponibilidad por plan), o faltan scopes.404— la orden no existe en la empresa indicada.409—content.uuidya existe al crear, o no hay destinatario ni remitente al enviar por correo.429— ya hay 20 escrituras de órdenes en curso en la misma empresa (ver Concurrencia).
Ver Errores y validaciones para el formato general.
Referencia exhaustiva
Esta página cubre los matices funcionales y los casos típicos. Para la referencia exhaustiva de todos los campos del body y la respuesta, consulta el Swagger UI o el openapi crudo.
Endpoints
Método | Path | operationId | Scopes | Descripción |
GET |
|
|
| Lista de órdenes de compra |
GET |
|
|
| Obtener una orden de compra |
GET |
|
|
| Listar adjuntos de una orden de compra |
POST |
|
|
| Crear orden de compra |
POST |
|
|
| Vincular adjuntos a una orden de compra |
PUT |
|
|
| Actualizar orden de compra |
PUT |
|
|
| Generar la orden de compra en formato PDF |
PUT |
|
|
| Enviar orden de compra por correo electrónico |
PUT |
|
|
| Actualizar etiquetas de orden de compra |
DELETE |
|
|
| Borrar orden de compra |
DELETE |
|
|
| Eliminar adjunto de una orden de compra |
Scopes
purchaseOrders:read— Lectura de órdenes de compra.purchaseOrders:write— Modificación de órdenes de compra.