Factuarea APIDevelopers

Proyectos y tareas

Proyectos con clave y columnas de tablero, tareas con posición, etiquetas, comentarios, relaciones, campos personalizados, vínculos con documentos y adjuntos: la API de gestión del trabajo bajo /v1/projects y /v1/tasks.

Factuarea incluye un módulo de tareas nativo: proyectos con un tablero de columnas y tareas que se pueden vincular a las facturas, los presupuestos, los contactos y el resto de documentos de tu empresa. La API lo expone bajo /v1/projects, /v1/tasks, /v1/task-labels, /v1/task-timers, /v1/users, /v1/notifications y /v1/agenda. Cada operación es también una tool MCP y un comando del CLI.

Las tareas necesitan el módulo tasks, que incluyen todos los planes, y los scopes granulares projects:read|write|delete, tasks:read|write|delete, users:read y notifications:read|write. Emitir una key con esos scopes para una empresa sin el módulo se rechaza con scope_not_allowed_by_plan. Los scopes projects:delete y tasks:delete son solo de API key: un consentimiento OAuth nunca los concede. Consulta Scopes y operaciones irreversibles.

Proyectos y claves

Un proyecto agrupa tareas y es dueño del tablero en el que viven. Su clave del proyecto —una letra mayúscula seguida de hasta nueve letras mayúsculas o dígitos, como DEV— prefija la clave de cada tarea: DEV-1, DEV-2… Las claves son únicas en tu empresa, sin distinguir mayúsculas y contando los proyectos archivados. Una clave que ya está en uso devuelve 409 project_key_in_use.

curl -X POST https://api.factuarea.com/v1/projects \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Web redesign",
    "key": "WEB",
    "icon": "rocket",
    "description": "Storefront redesign and follow-up fixes."
  }'

El proyecto se crea con sus columnas de tablero por defecto y se devuelve con sus estadísticas de tareas (total_tasks, completed_tasks, completion_percentage y next_due_on).

  • GET /v1/projects lista los proyectos en el orden en que los muestra la app. Los proyectos archivados quedan fuera salvo que pases include_archived=true.
  • POST /v1/projects/find-by-key resuelve un proyecto a partir de su clave (WEB), sin distinguir mayúsculas y esté archivado o no. Es una lectura: no necesita Idempotency-Key.
  • PUT /v1/projects/{project} es parcial. Cambiar la key conserva la anterior como alias, así que las tareas siguen respondiendo a sus claves antiguas. Aquí también viven los valores de facturación por defecto para facturar el tiempo imputado: consulta Tiempo imputado a tareas.
  • POST /v1/projects/{project}/archive y .../unarchive son reversibles: un proyecto archivado sale de los listados por defecto y deja de aceptar tareas nuevas (422 project_archived), pero todo sigue siendo consultable.
  • DELETE /v1/projects/{project} es permanente y se lleva consigo las tareas, los comentarios, los adjuntos y el tiempo imputado del proyecto.

Columnas y estado del tablero

Una tarea siempre está en uno de tres estados de tablero:

statusDónde está la tareacolumn_id
plannedEl backlog: pendiente de planificarnull
activeEn una columna del tableroLa columna
archivedArchivada, fuera del tableronull

planned y archived son estados virtuales, no columnas, y sus nombres están reservados: una columna no puede usarlos como slug (422 column_slug_reserved).

Un proyecto nuevo recibe cuatro columnas —por hacer, en curso, en revisión y hecho— con el nombre en el idioma de quien lo crea y los slugs canónicos to-do, in-progress, in-review y done. Solo la última es una columna final (is_final: true): mover una tarea a una columna final la completa (se fija completed_at) y sacarla de ella la reabre.

  • POST /v1/projects/{project}/columns añade una columna al final del tablero. Su slug se deriva del nombre y es único en el proyecto (409 column_slug_in_use). color es una clave de la paleta (gray, red, orange, amber, green, teal, blue, cyan, violet o pink) o un código hexadecimal.
  • PUT .../columns/{column} es parcial. Convertir una columna en final completa las tareas que contiene; volver a quitárselo las reabre.
  • PUT .../columns/reorder recibe column_ids con todas las columnas del proyecto exactamente una vez, en el orden nuevo.
  • Las columnas se devuelven como una lista simple, sin paginación.

Borrar una columna con tareas

Borrar una columna es permanente, y una columna con tareas necesita un destino para ellas. Indica la columna de destino del mismo proyecto en el parámetro de query move_to_column_id:

curl -X DELETE \
  "https://api.factuarea.com/v1/projects/$PROJECT_ID/columns/$COLUMN_ID?move_to_column_id=$OTHER_COLUMN_ID" \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

En una sola transacción las tareas pasan al final de la columna de destino, en su orden, cada una emite su evento task.status_changed y la columna se borra. Sin move_to_column_id, una columna que aún tiene tareas devuelve 409 column_has_tasks y no cambia nada; un destino que no existe, que es de otro proyecto o que es la propia columna que se borra devuelve 422 invalid_move_target_column. Una columna vacía no necesita destino. La operación es irreversible, así que Idempotency-Key es obligatoria.

Tareas, claves y tablero

project_id y title son los únicos campos obligatorios de POST /v1/tasks. Una tarea nace en la primera columna de su proyecto salvo que envíes un column_id o un status virtual. Los campos opcionales son description (Markdown), priority (none, low, medium, high o urgent; none por defecto), start_on y due_on (YYYY-MM-DD; un start_on posterior a due_on devuelve 422 invalid_task_schedule), assignee_id (un miembro de tu empresa), label_ids, custom_fields y entity_link.

curl -X POST https://api.factuarea.com/v1/tasks \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "0193a4f2-7c20-7a11-8b52-4d6e8f0a2c01",
    "title": "Call the customer about the checkout demo",
    "priority": "high",
    "due_on": "2026-10-15",
    "assignee_id": "0193a4f2-6b1c-7d3e-8a41-2c5e7f9a1b02",
    "label_ids": ["0193a4f2-9a64-7e55-8f96-8b0c2d4e6a02"],
    "custom_fields": { "0193a4f2-7e42-7c33-8d74-6f8a0b2c4e01": 4 },
    "entity_link": { "type": "quote", "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a4d" }
  }'

La tarea se devuelve con su clave (DEV-16), su number en el proyecto, su status de tablero y su column_id, sus etiquetas, los valores de sus campos personalizados y contadores de subtareas, comentarios y adjuntos. El número solo crece: una tarea borrada nunca libera su número para reutilizarlo.

Resolver una tarea por su clave

La gente habla de DEV-12, no de un UUID. POST /v1/tasks/find-by-key recibe { "key": "DEV-12" }, sin distinguir mayúsculas, y devuelve la tarea. Las claves anteriores siguen funcionando: una tarea movida de DEV-12 a otro proyecto, o cuyo proyecto cambió de clave, se sigue encontrando con la clave antigua. Una clave mal formada devuelve 422 invalid_task_key y una desconocida 404 task_not_found. El filtro q de la búsqueda también acepta una clave.

GET /v1/tasks busca en todos los proyectos:

curl "https://api.factuarea.com/v1/tasks?project_id=$PROJECT_ID&status=active&assignee_id=me&sort=due_on&limit=50" \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"

Los filtros son q, project_id, status, column_id, priority, assignee_id (el UUID de un miembro o me), label_id, due_before, due_after y completed. sort admite created_at, updated_at, due_on, priority o number, con el prefijo - para el orden descendente.

Estado, posición y movimiento

  • POST /v1/tasks/{task}/status mueve una tarea a una column_id de su proyecto o a un status virtual, al final del destino.
  • POST /v1/tasks/{task}/reposition la coloca en una posición exacta: un index (0 es el primero) o una vecina, before_task_id o after_task_id, y opcionalmente otra columna en la misma llamada.
  • POST /v1/tasks/{task}/move la envía a otro proyecto. La tarea recibe allí una clave nueva y sigue respondiendo a la anterior; los valores de campos personalizados que el destino no define se descartan.
  • POST /v1/tasks/{task}/duplicate la copia al final de la misma columna. La copia conserva descripción, prioridad, fechas, etiquetas, valores de campos personalizados y persona asignada; los comentarios, la actividad, las imputaciones de tiempo y los vínculos no se copian.
  • POST /v1/tasks/{task}/assign y .../unassign fijan y quitan la persona asignada. Consulta los ids de los miembros con GET /v1/users; un usuario que no es miembro devuelve 422 task_assignee_not_member.

Editar y borrar

PUT /v1/tasks/{task} es parcial: solo cambian los campos que envías, y un null explícito vacía description, start_on, due_on y assignee_id. priority y title no pueden ser null.

DELETE /v1/tasks/{task} es permanente. Se lleva consigo los comentarios, los adjuntos, las relaciones y las imputaciones de tiempo de la tarea, y es irreversible: Idempotency-Key es obligatoria.

Operaciones masivas

Tres operaciones actúan sobre hasta 200 tareas a la vez, todo o nada: POST /v1/tasks/bulk-status, POST /v1/tasks/bulk-update (prioridad, persona asignada, fecha de vencimiento y una etiqueta que añadir o quitar) y POST /v1/tasks/bulk-delete. Las tres exigen una Idempotency-Key. Una selección mayor devuelve 422 bulk_task_selection_too_large; las tareas que ya no existen se omiten y el resultado indica cuántas han cambiado. Consulta Operaciones en lote.

Etiquetas, comentarios, relaciones y campos personalizados

Las etiquetas de tarea viven en un catálogo por empresa y no tienen relación con las etiquetas de los documentos: consulta Etiquetas y campos personalizados para estas últimas. Una etiqueta tiene un name, único en tu empresa sin distinguir mayúsculas (409 task_label_name_in_use), y un color de la paleta o un código hexadecimal. El catálogo lista cada etiqueta con su tasks_count: cuántas tareas la llevan, incluidas las archivadas. POST /v1/tasks/{task}/labels añade una etiqueta a una tarea y DELETE .../labels/{label} la quita; borrar una etiqueta del catálogo la quita de todas las tareas.

Los comentarios son Markdown, de 1 a 10 000 caracteres. Las menciones a miembros de la empresa notifican a las personas mencionadas; las menciones a cualquier otra persona se ignoran. El author de un comentario tiene un type: user, external (sincronizado desde una forja de código), imported o automation. Solo quien lo escribió puede editar un comentario, y los sincronizados o importados no se pueden editar (422 task_comment_not_editable); pueden borrarlo quien lo escribió y los roles owner y admin de la empresa.

Las relaciones unen dos tareas de la empresa como subtask, blocks o related. Una tarea no puede relacionarse consigo misma (422 task_self_relation), una relación que cerraría un ciclo se rechaza (422 task_relation_cycle) y un duplicado devuelve 409 task_relation_exists. El listado muestra cada relación desde el punto de vista de la tarea de la ruta, mediante direction: parent, child, blocks, blocked_by o related. Borrar una relación deja intactas las dos tareas.

Los campos personalizados de tarea se definen por proyecto, con un type de text, number, date, dropdown, boolean o multiselect, y no son los campos personalizados de los documentos. Un campo obligatorio necesita un valor por defecto no vacío, que reciben las tareas existentes. Fija los valores al crear la tarea, con el mapa custom_fields (id del campo a valor), o más tarde con PUT /v1/tasks/{task}/custom-fields/{field}; null vacía un campo opcional. Un valor que no encaja con el tipo devuelve 422 invalid_custom_field_value, y una definición que se contradice, o una edición que dejaría huérfanos valores existentes, 422 invalid_custom_field_definition. Borrar una definición borra sus valores en todas las tareas del proyecto.

Una tarea puede apuntar al resto de Factuarea. El vocabulario de entidades vinculables es cerrado: invoice, quote, proforma, delivery_note, purchase_invoice, recurring_invoice, contact, product y employee.

  • Al crearla, entity_link vincula la tarea en la misma transacción. Si la entidad no existe, es de otra empresa o su módulo no es accesible, la llamada devuelve 404 linked_entity_not_found y la tarea no se crea.
  • Después, POST /v1/tasks/{task}/entity-links la vincula; vincular la misma entidad otra vez devuelve el vínculo existente. Un vínculo con una entidad que se borró sigue en el listado con available: false.
  • Desde la entidad, GET /v1/tasks/linked?entity_type=invoice&entity_id=… lista las tareas vinculadas a una factura, un presupuesto o cualquier otra entidad, con las archivadas marcadas.
  • Los enlaces externos —POST /v1/tasks/{task}/external-links— adjuntan una dirección http o https sin más. Los enlaces que reflejan una issue, una pull request o una rama de una forja de código (GitHub, GitLab o Gitea) los mantiene la integración.

Adjuntos y enlaces de subida

POST /v1/tasks/{task}/attachments sube un fichero como multipart/form-data. El máximo es de 10 MB por fichero y el tipo se comprueba por contenido, nunca por extensión: imágenes (PNG, JPEG, GIF, WebP, HEIC, AVIF), PDF, documentos de Word, Excel y PowerPoint, texto y hojas de cálculo OpenDocument, texto plano, CSV, Markdown y ZIP. target coloca el fichero en un comentario nuevo (comment, el valor por defecto) o al final de la descripción (description), y note pasa a ser el texto del comentario. Los ficheros cuentan para la cuota de almacenamiento del plan (402 storage_quota_exceeded cuando está llena) y la subida necesita una Idempotency-Key.

Para recibir una foto desde un móvil, o un fichero de alguien sin cuenta, crea un enlace de subida con POST /v1/tasks/{task}/upload-links. El enlace es de un solo uso, caduca a los 30 minutos y su url se muestra solo en esa respuesta. Una vez usado o caducado responde 410 task_upload_link_expired.

Los adjuntos se listan, se consultan y se descargan por tarea, y DELETE .../attachments/{attachment} elimina el fichero para siempre y libera su almacenamiento.

Actividad

GET /v1/tasks/{task}/activities devuelve el registro de actividad, de la más reciente a la más antigua: cambios de estado y de columna, ediciones con los campos cambiados, asignaciones, etiquetas, comentarios, relaciones, adjuntos y tiempo imputado, cada uno con su actor (user, api_key, external o system). Las entradas no tienen id, así que el cursor es opaco: devuelve el next_cursor como starting_after sin tocarlo.

Paginación, actualizaciones parciales y errores

  • Paginación por cursor. Los listados de proyectos, tareas, etiquetas, comentarios, imputaciones de tiempo, usuarios, notificaciones y actividad devuelven { data, has_more, next_cursor }; pasa next_cursor como starting_after para la página siguiente. Las columnas, las definiciones de campos personalizados, las relaciones, los vínculos y los adjuntos son cortos y se devuelven como una lista simple. Consulta Paginación.
  • PUT es parcial en todas partes: los campos omitidos conservan su valor y un null explícito vacía los opcionales.
  • Idempotencia. Las nueve operaciones irreversibles, las operaciones masivas, la importación y la subida de ficheros exigen una Idempotency-Key; cualquier otra escritura la acepta. Consulta Idempotencia.
  • Errores. Cada error de tareas tiene un código estable, listado en Códigos de error de Tareas.

Algunas partes del módulo existen solo en la app y no tienen operación en la API: las integraciones con forjas de código y herramientas de chat, los feeds iCal (consulta la guía del feed iCal), el tablero público de solo lectura, el fondo del proyecto, el orden de los proyectos y las preferencias de notificación.

Siguientes pasos

En esta página

¿Te echamos una mano?Contactar con soporte