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/projectslista los proyectos en el orden en que los muestra la app. Los proyectos archivados quedan fuera salvo que pasesinclude_archived=true.POST /v1/projects/find-by-keyresuelve un proyecto a partir de su clave (WEB), sin distinguir mayúsculas y esté archivado o no. Es una lectura: no necesitaIdempotency-Key.PUT /v1/projects/{project}es parcial. Cambiar lakeyconserva 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}/archivey.../unarchiveson reversibles: un proyecto archivado sale de los listados por defecto y deja de aceptar tareas nuevas (422project_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:
status | Dónde está la tarea | column_id |
|---|---|---|
planned | El backlog: pendiente de planificar | null |
active | En una columna del tablero | La columna |
archived | Archivada, fuera del tablero | null |
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}/columnsañade una columna al final del tablero. Suslugse deriva del nombre y es único en el proyecto (409column_slug_in_use).colores una clave de la paleta (gray,red,orange,amber,green,teal,blue,cyan,violetopink) 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/reorderrecibecolumn_idscon 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.
Buscar
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}/statusmueve una tarea a unacolumn_idde su proyecto o a unstatusvirtual, al final del destino.POST /v1/tasks/{task}/repositionla coloca en una posición exacta: unindex(0 es el primero) o una vecina,before_task_idoafter_task_id, y opcionalmente otra columna en la misma llamada.POST /v1/tasks/{task}/movela 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}/duplicatela 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}/assigny.../unassignfijan y quitan la persona asignada. Consulta los ids de los miembros conGET /v1/users; un usuario que no es miembro devuelve 422task_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.
Vínculos con documentos, contactos y otras herramientas
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_linkvincula 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 404linked_entity_not_foundy la tarea no se crea. - Después,
POST /v1/tasks/{task}/entity-linksla 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 conavailable: 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ónhttpohttpssin 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 }; pasanext_cursorcomostarting_afterpara 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. PUTes parcial en todas partes: los campos omitidos conservan su valor y unnullexplí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
entradas manuales, el temporizador y cómo convertir las horas facturables en un borrador de factura.
suscríbete desde una app de calendario a las tareas de un proyecto o a las tuyas.
los 21 eventos de tareas, comentarios, tiempo imputado y proyectos.
crea, mueve, asigna y comenta tareas desde una regla.
la misma superficie como tools para un agente.
proyectos, tareas y tiempo desde tu terminal.
cada código con su causa y qué hacer.