Factuarea APIDevelopers

Tiempo imputado a tareas

Imputa tiempo a las tareas a mano o con un temporizador, consulta el resumen de tiempo de un proyecto y convierte las horas facturables en un borrador de factura, y por qué no es el fichaje de jornada.

El tiempo imputado a una tarea mide el trabajo dedicado a ella, para que veas adónde van las horas y puedas facturarlas. Lo imputas a mano, como un periodo cerrado, o con un temporizador que corre hasta que lo detienes, y un proyecto convierte sus horas facturables en un borrador de factura.

No es el registro de jornada. Una imputación de tiempo de tarea pertenece al módulo tasks: usa los scopes tasks:*, sus eventos son task_time_entry.* y sus operaciones viven bajo /v1/tasks/{task}/time-entries y /v1/task-timers. Los fichajes del módulo de control horario (/v1/time-entries, time_entries:*, el módulo control_horario) son el registro legal de jornada encadenado por hash: otro recurso, con su propio registro. Las horas imputadas a una tarea nunca aparecen en ese registro, ni en sus balances, ni en los cierres mensuales, ni en las exportaciones de nómina. Consulta Control horario.

Imputar tiempo a mano

POST /v1/tasks/{task}/time-entries imputa un periodo cerrado de trabajo:

curl -X POST https://api.factuarea.com/v1/tasks/$TASK_ID/time-entries \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "started_at": "2026-09-28T09:00:00+02:00",
    "ended_at": "2026-09-28T11:00:00+02:00",
    "description": "Payment gateway integration",
    "billable": true
  }'
  • started_at y ended_at son ISO 8601 con zona horaria. El periodo debe terminar después de empezar, durar como máximo 24 horas y no empezar con más de un día de adelanto; si no, la llamada devuelve 422 invalid_time_entry_period. Una imputación con inicio y fin iguales es válida y dura cero segundos.
  • description es opcional, de hasta 1000 caracteres. billable vale true por defecto.
  • La autoría es siempre de quien tiene la credencial.
  • Las imputaciones pueden solaparse: es trabajo que atribuyes a tareas, no un fichaje.

La imputación se devuelve con su duration_seconds, is_running y, una vez facturada, el invoice_id y el invoiced_at de la factura que la incluye.

El temporizador

En lugar de escribir un periodo, arranca un temporizador cuando empiezas y detenlo cuando terminas:

# Arrancarlo en una tarea (sin cuerpo)
curl -X POST https://api.factuarea.com/v1/tasks/$TASK_ID/timer/start \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"

# ¿Qué está corriendo ahora? `data` es null si no hay nada
curl https://api.factuarea.com/v1/task-timers/current \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"

# Detenerlo, en la tarea en que corra
curl -X POST https://api.factuarea.com/v1/task-timers/stop \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"
  • Un temporizador por usuario y empresa. Arrancar otro mientras uno corre, en cualquier tarea, devuelve 409 task_timer_already_running y deja intacto el que estaba en marcha. Un usuario con un temporizador en otra empresa puede arrancar uno aquí.
  • Un temporizador en marcha es una imputación con ended_at: null e is_running: true.
  • Detenerlo fija el fin en el instante actual y devuelve la imputación cerrada. Sin temporizador en marcha devuelve 422 task_timer_not_running.
  • Un temporizador que lleva más de 24 horas corriendo se cierra exactamente a las 24 horas de su inicio, así que uno olvidado nunca bloquea el siguiente.
  • El temporizador pertenece a quien tiene la credencial, así que GET /v1/task-timers/current muestra el suyo y nunca el de otra persona.

Editar y borrar imputaciones

PUT /v1/tasks/{task}/time-entries/{time_entry} es parcial y cambia started_at, ended_at, description y billable. En una imputación en marcha solo puedes cambiar la descripción y la marca de facturable: detén el temporizador para cerrarla.

Cuando una imputación se incluye en una factura queda bloqueada: editarla o borrarla devuelve 422 task_time_entry_invoiced hasta que se borre el borrador de factura. DELETE .../time-entries/{time_entry} es permanente y necesita el scope tasks:delete y una Idempotency-Key; borrar una imputación en marcha cancela el temporizador.

GET /v1/tasks/{task}/time-entries lista las imputaciones de una tarea, de la más reciente a la más antigua y con paginación por cursor.

Resumen de tiempo de un proyecto

GET /v1/projects/{project}/time-summary responde cuánto tiempo ha consumido un proyecto, opcionalmente entre from y to (fechas en la zona horaria de la empresa):

{
  "data": {
    "object": "project_time_summary",
    "project_id": "0193a4f2-7c20-7a11-8b52-4d6e8f0a2c01",
    "from": "2026-09-01",
    "to": "2026-09-30",
    "total_seconds": 36900,
    "billable_seconds": 33300,
    "invoiced_seconds": 9900,
    "pending_seconds": 23400,
    "by_task": [
      {
        "task_id": "0193a4f2-8f53-7d44-8e85-7a9b1c3d5f12",
        "key": "DEV-12",
        "title": "Integrate the payment gateway in the checkout",
        "total_seconds": 22500,
        "billable_seconds": 22500,
        "invoiced_seconds": 9900,
        "pending_seconds": 12600
      }
    ],
    "by_user": [
      {
        "user_id": "0193a4f2-6b1c-7d3e-8a41-2c5e7f9a1b01",
        "name": "Ana Pérez",
        "total_seconds": 22500,
        "billable_seconds": 22500
      }
    ]
  }
}

pending_seconds es lo que aún puedes facturar: el tiempo facturable que todavía no se ha facturado. Los temporizadores en marcha quedan fuera de todos los totales.

Facturar las horas

Un proyecto convierte sus horas facturables en un borrador de factura para su contacto de facturación. Deben estar definidos en el proyecto, con PUT /v1/projects/{project} o en la app:

  • un contacto de facturación (billing_contact_id) que pueda recibir facturas de venta;
  • un precio: una tarifa por hora (billing_hourly_rate) o un producto de facturación (billing_product_id), cuyo precio para ese contacto se usa cuando no hay tarifa.

Sin ellos, la llamada devuelve 422 task_time_not_invoiceable e indica qué falta.

Elige las horas con entry_ids (hasta 500 imputaciones) o con un period (from y to, inclusivos, por la fecha de inicio de las imputaciones) —nunca las dos cosas— y una grouping: per_task da una línea por tarea, per_entry una línea por imputación y single_line una sola línea con el total. Solo cumplen los requisitos las imputaciones del proyecto cerradas, facturables y aún sin facturar.

Primero, la vista previa. Aplica las mismas comprobaciones y no crea nada:

curl -X POST https://api.factuarea.com/v1/projects/$PROJECT_ID/time-invoices/preview \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "period": { "from": "2026-09-01", "to": "2026-09-30" }, "grouping": "per_task" }'

La vista previa lista el cliente, las líneas (cantidad en horas, unidad HUR, precio e importe antes de impuestos), los totales en segundos y en horas, las imputaciones que se facturarían y los warnings. Después crea la factura con el mismo cuerpo:

curl -X POST https://api.factuarea.com/v1/projects/$PROJECT_ID/time-invoices \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "period": { "from": "2026-09-01", "to": "2026-09-30" }, "grouping": "per_task" }'
{
  "data": {
    "id": "0193a4f2-c3fd-7bee-8c8f-7e9f1a3b5d01",
    "object": "task_time_invoice",
    "project_id": "0193a4f2-7c20-7a11-8b52-4d6e8f0a2c01",
    "invoice_id": "0193a4f2-c3fd-7bee-8c8f-7e9f1a3b5d10",
    "grouping": "per_task",
    "status": "draft"
  }
}
  • Exige invoices:write, no un scope de proyectos: la operación crea una factura. Una credencial con solo projects:write recibe 403 insufficient_scope. La vista previa es una lectura y necesita projects:read.
  • La factura es un borrador. Nunca se emite, se envía ni se registra ante la AEAT por sí sola; la terminas con la API de facturas. Se aplican las reglas normales de las facturas: si el plan ha agotado sus facturas, la llamada devuelve 402 limit_exceeded y no se crea nada.
  • Todo o nada. En una transacción se crea la factura y se marcan las imputaciones como facturadas. Si falla cualquier paso, no queda ninguna imputación marcada.
  • Los reintentos son seguros. Repetir la petición con la misma Idempotency-Key, o con el mismo batch_id, devuelve la misma factura. Dos peticiones a la vez sobre las mismas imputaciones producen una sola factura; la otra recibe task_time_entry_invoiced.
  • Borrar el borrador libera las horas. Vuelven a estar pendientes. Emitir, enviar, cobrar o anular la factura no las libera.

Eventos

Las imputaciones emiten task_time_entry.created (también al arrancar un temporizador), task_time_entry.updated (también al detenerlo), task_time_entry.deleted y task_time_entry.invoiced, uno por cada imputación de un lote facturado. Consulta Eventos de tareas.

Siguientes pasos

En esta página

¿Te echamos una mano?Contactar con soporte