API de Harmony

Lee los datos de tu organización desde tus propios sistemas, sin pasar por la interfaz. Es una API de sólo lectura: ningún endpoint escribe, y una clave filtrada expone información pero nunca altera tu operación.

https://harmony.report/api/v1 · openapi.json — impórtalo en Postman, Insomnia o un generador de clientes.

Autenticación

Un super administrador emite las claves desde Ajustes → API. La clave se muestra una sola vez: Harmony guarda su huella, no la clave. Si se pierde, se revoca y se emite otra.

curl https://harmony.report/api/v1/me \
  -H "Authorization: Bearer hk_live_tu_clave"

La API es de servidor a servidor: no responde a peticiones desde un navegador. Una clave en el código de un frontend es una clave pública.

El mes es la unidad de consulta

Turnos, novedades, asignaciones y registros financieros se piden por mes, con period=YYYY-MM, y el parámetro es obligatorio. No hay rango de fechas: Harmony organiza la operación por período mensual, que es también la unidad con la que se cierra el mes. Cada turno vuelve con su fecha completa en date.

Paginación

limit va de 1 a 5.000 (50 por defecto). Para volumen conviene subirlo: las novedades de un mes son miles, y a 5.000 por página son unas pocas peticiones contra el mismo límite por minuto. La respuesta trae nextCursor: mientras no sea null, hay más páginas. Es la única señal de fin — nunca el tamaño de data.

Expansiones

Las cuatro rutas por identificador —cliente, sede, puesto y persona— aceptan include: una lista de secciones separadas por comas que llegan en la misma respuesta. Sirve para no encadenar una petición por cada pieza de la programación.

curl "https://harmony.report/api/v1/points/{id}?period=2026-08&include=area,customer,assignments,workers,shifts,incidents,elsewhere" \
  -H "Authorization: Bearer hk_live_tu_clave"

Esa sola petición trae el puesto, su sede, su cliente, quién está asignado, quién está programado —con assigned para distinguirlos—, los turnos y las novedades del mes, y dónde más está esa gente.

Tres reglas que conviene saber antes de escribir la primera llamada. Sin include la respuesta no cambia; con él, el recurso viene dentro de un sobre —{ point: …, shifts: [] }— junto a las secciones pedidas. Las secciones que viven en un mes exigen period, y pedirlas sin él es un 400, no un mes por defecto. Y cada sección tiene un tope de 3.000 elementos —y elsewhere consulta como mucho 150 personas—: si se alcanza, su nombre aparece en truncated. Para volumen la vía no es ésta sino la ruta plana con cursor, que pagina hasta 5.000 por página; las expansiones componen una vista, no exportan.

Endpoints

GET/me

Devuelve la organización de la clave, su alcance y el límite de peticiones. Útil como primera llamada para comprobar que la clave funciona.

Petición

curl "https://harmony.report/api/v1/me" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "key": {
    "name": "Integración de nómina",
    "prefix": "hk_live_a1b2c3",
    "createdAt": "2026-09-07T15:04:00.000Z",
    "lastUsedAt": "2026-09-07T15:41:12.000Z",
    "expiresAt": null
  },
  "organization": {
    "id": "p57fazjfjmde4egmkz0xh6b51982enz0",
    "name": "Seguridad Andina"
  },
  "scope": {
    "type": "organization",
    "workspaceIds": null,
    "unreachableWorkspaceIds": []
  },
  "rateLimit": {
    "limit": 60,
    "windowSeconds": 60
  }
}
GET/workspaces

Los espacios que la clave alcanza. Una clave de organización los devuelve todos; una acotada, sólo los suyos.

Petición

curl "https://harmony.report/api/v1/workspaces" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j",
      "name": "Operación Bogotá",
      "active": true,
      "createdAt": "2026-01-15T14:02:11.000Z"
    }
  ],
  "nextCursor": null
}

Campos de Workspace

idstringIdentificador de Convex.
namestringNombre del espacio.
activebooleanSi está activo.
createdAtstringCreación, ISO 8601.
GET/customers

Los clientes de la organización. Con una clave acotada a espacios, workspaceId es obligatorio: no hay índice que recorra varios espacios en una sola página.

Parámetros

workspaceIdstringsegún alcanceEspacio del que listar los clientes.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/customers" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "name": "Centro Comercial Andino",
      "identifier": "900123456-7",
      "code": "CC-AND",
      "workspaceId": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j",
      "idle": false,
      "active": true,
      "hasForm": true,
      "createdAt": "2026-02-03T09:11:00.000Z"
    }
  ],
  "nextCursor": null
}

Campos de Customer

idstringIdentificador de Convex.
namestringRazón social del cliente.
identifierstringNIT o documento.
workspaceIdstringEspacio al que pertenece.
idlebooleanSuspendido temporalmente.
activebooleanSi está activo.
hasFormbooleanTiene ficha de formulario.
createdAtstringCreación, ISO 8601.
GET/customers/{id}

Un cliente por su identificador. Responde 404 si no existe o si está fuera del alcance de la clave: no se distingue, para no confirmar la existencia de datos ajenos. Con include devuelve la programación del cliente completa —sedes, puestos, personal, turnos y novedades del mes— en una sola petición.

Parámetros

idstring · rutaobligatorioIdentificador del cliente.
includestringopcionalSecciones que añadir a la respuesta, separadas por comas. Sin este parámetro la respuesta no cambia; con él, el recurso pasa a venir dentro de un sobre junto a las secciones pedidas.
periodstringopcionalMes a consultar, YYYY-MM. Obligatorio en cuanto se expande algo que vive en un mes; sin él esas expansiones responden 400.

Expansiones · include

workspaceEl espacio de trabajo al que pertenece.
areasLas sedes del cliente.
pointsLos puestos que cuelgan.
workerspide periodLas personas asignadas y las programadas, cada una con assigned: true | false. Alguien puede cubrir un puesto sin estar asignado, y alguien asignado puede no tener ni un turno.
assignmentspide periodLas asignaciones del período.
shiftspide periodLos turnos del período.
incidentspide periodLas novedades del período. Cada una lleva además fields: sus detalles, las respuestas al formulario de novedades de la organización, como [{ fieldId, label, value }] en el orden del formulario, sólo con lo respondido y visible, y con value ya legible (la etiqueta de una lista, fechas DD/MM/AAAA, importes en pesos). Sin formulario, fields es [].
positionsLos cargos referidos por los registros, sin repetir.
categoriesLas categorías de novedad referidas, sin repetir.

Petición

curl "https://harmony.report/api/v1/customers/j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "id": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
  "name": "Centro Comercial Andino",
  "identifier": "900123456-7",
  "code": "CC-AND",
  "workspaceId": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j",
  "idle": false,
  "active": true,
  "hasForm": true,
  "createdAt": "2026-02-03T09:11:00.000Z"
}

Campos de Customer

idstringIdentificador de Convex.
namestringRazón social del cliente.
identifierstringNIT o documento.
workspaceIdstringEspacio al que pertenece.
idlebooleanSuspendido temporalmente.
activebooleanSi está activo.
hasFormbooleanTiene ficha de formulario.
createdAtstringCreación, ISO 8601.
GET/areas/{id}

Una sede por su identificador, con lo que cuelga de sus puestos. Los turnos y las novedades cuelgan del puesto y no de la sede, así que expandirlos cuesta una consulta por puesto: una sede de más de 50 responde 400 y hay que pedir sus puestos uno a uno.

Parámetros

idstring · rutaobligatorioIdentificador de la sede.
includestringopcionalSecciones que añadir a la respuesta, separadas por comas. Sin este parámetro la respuesta no cambia; con él, el recurso pasa a venir dentro de un sobre junto a las secciones pedidas.
periodstringopcionalMes a consultar, YYYY-MM. Obligatorio en cuanto se expande algo que vive en un mes; sin él esas expansiones responden 400.

Expansiones · include

customerEl cliente al que pertenece.
pointsLos puestos que cuelgan.
workerspide periodLas personas asignadas y las programadas, cada una con assigned: true | false. Alguien puede cubrir un puesto sin estar asignado, y alguien asignado puede no tener ni un turno.
assignmentspide periodLas asignaciones del período.
shiftspide periodLos turnos del período.
incidentspide periodLas novedades del período. Cada una lleva además fields: sus detalles, las respuestas al formulario de novedades de la organización, como [{ fieldId, label, value }] en el orden del formulario, sólo con lo respondido y visible, y con value ya legible (la etiqueta de una lista, fechas DD/MM/AAAA, importes en pesos). Sin formulario, fields es [].
elsewherepide periodLos turnos y novedades de esas personas fuera de aquí, en el mismo mes: lo que responde si alguien está libre. Sólo llega lo que la clave alcanza. Hay que pedir también workers.
positionsLos cargos referidos por los registros, sin repetir.
categoriesLas categorías de novedad referidas, sin repetir.

Petición

curl "https://harmony.report/api/v1/areas/j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "id": "m9231bc4de5f6g7h8i9j0k1l2m3n4o5p",
  "name": "Torre Norte",
  "description": "Acceso principal y parqueaderos",
  "active": true,
  "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1"
}

Campos de Area

idstringIdentificador de Convex.
namestringNombre de la sede.
descriptionstringDescripción libre.
activebooleanSi está activa.
customerIdstringCliente al que pertenece.
GET/points/{id}

Un puesto por su identificador. Es la ruta que resuelve el caso completo: su sede, su cliente, quién está asignado, quién está programado, los turnos y las novedades del mes, y dónde más está esa gente — todo en una petición.

Parámetros

idstring · rutaobligatorioIdentificador del puesto.
includestringopcionalSecciones que añadir a la respuesta, separadas por comas. Sin este parámetro la respuesta no cambia; con él, el recurso pasa a venir dentro de un sobre junto a las secciones pedidas.
periodstringopcionalMes a consultar, YYYY-MM. Obligatorio en cuanto se expande algo que vive en un mes; sin él esas expansiones responden 400.

Expansiones · include

areaLa sede del puesto. Es null cuando el puesto cuelga del cliente sin sede.
customerEl cliente al que pertenece.
workerspide periodLas personas asignadas y las programadas, cada una con assigned: true | false. Alguien puede cubrir un puesto sin estar asignado, y alguien asignado puede no tener ni un turno.
assignmentspide periodLas asignaciones del período.
shiftspide periodLos turnos del período.
incidentspide periodLas novedades del período. Cada una lleva además fields: sus detalles, las respuestas al formulario de novedades de la organización, como [{ fieldId, label, value }] en el orden del formulario, sólo con lo respondido y visible, y con value ya legible (la etiqueta de una lista, fechas DD/MM/AAAA, importes en pesos). Sin formulario, fields es [].
elsewherepide periodLos turnos y novedades de esas personas fuera de aquí, en el mismo mes: lo que responde si alguien está libre. Sólo llega lo que la clave alcanza. Hay que pedir también workers.
positionsLos cargos referidos por los registros, sin repetir.
categoriesLas categorías de novedad referidas, sin repetir.

Petición

curl "https://harmony.report/api/v1/points/j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "id": "n8321cd5ef6g7h8i9j0k1l2m3n4o5p6q",
  "name": "Portería Norte",
  "description": "24 horas",
  "areaId": "m9231bc4de5f6g7h8i9j0k1l2m3n4o5p",
  "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
  "idle": false,
  "active": true
}

Campos de Point

idstringIdentificador de Convex.
namestringNombre del puesto.
descriptionstringDescripción libre.
areaIdstring | nullSede en la que está, si tiene.
customerIdstringCliente al que pertenece.
idlebooleanPuesto inactivo.
activebooleanSi está activo.
GET/areas

Las sedes cuelgan del cliente y ése es su único índice, así que customerId es obligatorio.

Parámetros

customerIdstringobligatorioCliente del que listar las sedes.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/areas?customerId=j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "m9231bc4de5f6g7h8i9j0k1l2m3n4o5p",
      "name": "Torre Norte",
      "description": "Acceso principal y parqueaderos",
      "active": true,
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1"
    }
  ],
  "nextCursor": null
}

Campos de Area

idstringIdentificador de Convex.
namestringNombre de la sede.
descriptionstringDescripción libre.
activebooleanSi está activa.
customerIdstringCliente al que pertenece.
GET/points

Se piden por cliente o por sede — uno de los dos, no los dos a la vez.

Parámetros

customerIdstringopcionalCliente del que listar los puestos.
areaIdstringopcionalSede de la que listar los puestos.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/points" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "n8321cd5ef6g7h8i9j0k1l2m3n4o5p6q",
      "name": "Portería Norte",
      "description": "24 horas",
      "areaId": "m9231bc4de5f6g7h8i9j0k1l2m3n4o5p",
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "idle": false,
      "active": true
    }
  ],
  "nextCursor": null
}

Campos de Point

idstringIdentificador de Convex.
namestringNombre del puesto.
descriptionstringDescripción libre.
areaIdstring | nullSede en la que está, si tiene.
customerIdstringCliente al que pertenece.
idlebooleanPuesto inactivo.
activebooleanSi está activo.
GET/workers

workspaceId es obligatorio: el personal no tiene índice por organización, sólo por espacio y por cliente.

Parámetros

workspaceIdstringobligatorioEspacio del que listar el personal.
customerIdstringopcionalAcota al personal de un cliente de ese espacio.
searchstringopcionalBúsqueda difusa por nombre. Devuelve los mejores resultados de una vez, con nextCursor siempre en null.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/workers?workspaceId=k17fgbsj1hyw66bq5gw5sz2g8s82fs5j" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "w4412ef6gh7i8j9k0l1m2n3o4p5q6r7s",
      "name": "Ana María Pérez",
      "identifier": "1023456789",
      "group": "Grupo A",
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "workspaceId": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j",
      "idle": false,
      "active": true,
      "hasForm": true,
      "createdAt": "2026-02-10T16:40:00.000Z"
    }
  ],
  "nextCursor": null
}

Campos de Worker

idstringIdentificador de Convex.
namestringNombre de la persona.
identifierstringDocumento de identidad.
groupstring | nullGrupo o cuadrilla.
customerIdstringCliente al que está adscrita.
workspaceIdstringEspacio al que pertenece.
idlebooleanInactiva temporalmente.
activebooleanSi está activa.
hasFormbooleanTiene ficha de formulario.
createdAtstringCreación, ISO 8601.
GET/workers/{id}

Una persona por su identificador, si la clave la alcanza. Con include responde a la pregunta girada: no quién cubre un puesto, sino dónde está esta persona este mes.

Parámetros

idstring · rutaobligatorioIdentificador de la persona.
includestringopcionalSecciones que añadir a la respuesta, separadas por comas. Sin este parámetro la respuesta no cambia; con él, el recurso pasa a venir dentro de un sobre junto a las secciones pedidas.
periodstringopcionalMes a consultar, YYYY-MM. Obligatorio en cuanto se expande algo que vive en un mes; sin él esas expansiones responden 400.

Expansiones · include

workspaceEl espacio de trabajo al que pertenece.
customerEl cliente al que pertenece.
assignmentspide periodLas asignaciones del período.
shiftspide periodLos turnos del período.
incidentspide periodLas novedades del período. Cada una lleva además fields: sus detalles, las respuestas al formulario de novedades de la organización, como [{ fieldId, label, value }] en el orden del formulario, sólo con lo respondido y visible, y con value ya legible (la etiqueta de una lista, fechas DD/MM/AAAA, importes en pesos). Sin formulario, fields es [].
positionsLos cargos referidos por los registros, sin repetir.
categoriesLas categorías de novedad referidas, sin repetir.

Petición

curl "https://harmony.report/api/v1/workers/j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "id": "w4412ef6gh7i8j9k0l1m2n3o4p5q6r7s",
  "name": "Ana María Pérez",
  "identifier": "1023456789",
  "group": "Grupo A",
  "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
  "workspaceId": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j",
  "idle": false,
  "active": true,
  "hasForm": true,
  "createdAt": "2026-02-10T16:40:00.000Z"
}

Campos de Worker

idstringIdentificador de Convex.
namestringNombre de la persona.
identifierstringDocumento de identidad.
groupstring | nullGrupo o cuadrilla.
customerIdstringCliente al que está adscrita.
workspaceIdstringEspacio al que pertenece.
idlebooleanInactiva temporalmente.
activebooleanSi está activa.
hasFormbooleanTiene ficha de formulario.
createdAtstringCreación, ISO 8601.
GET/assignments

Qué persona cubre qué puesto en un mes. Las asignaciones cuelgan del cliente —no del espacio—, así que se piden con customerId.

Parámetros

periodstringobligatorioMes a consultar, YYYY-MM. Obligatorio: la operación se guarda por período mensual y no hay rango de fechas.
customerIdstringobligatorioCliente cuyas asignaciones se listan.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/assignments?period=2026-08&customerId=j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "a1122gh8ij9k0l1m2n3o4p5q6r7s8t9u",
      "period": "2026-08",
      "pointId": "n8321cd5ef6g7h8i9j0k1l2m3n4o5p6q",
      "pointName": "Portería Norte",
      "workerId": "w4412ef6gh7i8j9k0l1m2n3o4p5q6r7s",
      "workerName": "Ana María Pérez",
      "workerIdentifier": "1023456789",
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "skipExtraDays": false
    }
  ],
  "nextCursor": null
}

Campos de Assignment

idstringIdentificador de Convex.
periodstring | nullMes, YYYY-MM.
pointIdstringPuesto cubierto.
pointNamestringNombre del puesto al asignar.
workerIdstringPersona asignada.
workerNamestringNombre al asignar.
workerIdentifierstringDocumento al asignar.
customerIdstringCliente del puesto.
skipExtraDaysbooleanExcluye los días adicionales del mes.
GET/shifts

Los turnos programados de un espacio en un mes, descansos incluidos (color: "gray").

Parámetros

periodstringobligatorioMes a consultar, YYYY-MM. Obligatorio: la operación se guarda por período mensual y no hay rango de fechas.
workspaceIdstringobligatorioEspacio cuyos turnos se listan.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/shifts?period=2026-08&workspaceId=k17fgbsj1hyw66bq5gw5sz2g8s82fs5j" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "s7712ij0kl1m2n3o4p5q6r7s8t9u0v1w",
      "date": "2026-08-12",
      "period": "2026-08",
      "day": 12,
      "description": "06:00 a 18:00",
      "color": "green",
      "startsAt": "2026-08-12T06:00:00-05:00",
      "endsAt": "2026-08-12T18:00:00-05:00",
      "workerId": "w4412ef6gh7i8j9k0l1m2n3o4p5q6r7s",
      "workerName": "Ana María Pérez",
      "workerIdentifier": "1023456789",
      "pointId": "n8321cd5ef6g7h8i9j0k1l2m3n4o5p6q",
      "positionId": "p1122kl2m3n4o5p6q7r8s9t0u1v2w3x",
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "workspaceId": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j",
      "sequenceId": null,
      "sequenceName": "Rotativa 2x2"
    }
  ],
  "nextCursor": null
}

Campos de Shift

idstringIdentificador de Convex.
datestring | nullFecha completa del turno, YYYY-MM-DD.
periodstring | nullMes, YYYY-MM.
daynumberDía del mes.
descriptionstring«06:00 a 18:00» o «Descanso».
colorstringgreen turno · gray descanso.
startsAtstring | nullInicio con huso, ISO 8601. Nulo en un descanso.
endsAtstring | nullFin con huso, ISO 8601.
workerIdstringPersona que cubre el turno.
workerNamestringNombre al programar.
workerIdentifierstringDocumento al programar.
pointIdstring | nullPuesto cubierto.
positionIdstring | nullCargo aplicado.
customerIdstringCliente del turno.
workspaceIdstringEspacio del turno.
sequenceIdstring | nullSecuencia que lo generó.
sequenceNamestringNombre de la secuencia.
GET/incidents

Faltas, adicionales y seguimientos de un espacio en un mes, con su categoría.

Parámetros

periodstringobligatorioMes a consultar, YYYY-MM. Obligatorio: la operación se guarda por período mensual y no hay rango de fechas.
workspaceIdstringobligatorioEspacio cuyas novedades se listan.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/incidents?period=2026-08&workspaceId=k17fgbsj1hyw66bq5gw5sz2g8s82fs5j" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "i9912kl1m2n3o4p5q6r7s8t9u0v1w2x3",
      "date": "2026-08-14",
      "period": "2026-08",
      "day": 14,
      "abbreviation": "FI",
      "description": "Falta injustificada",
      "color": "red",
      "keep": false,
      "categoryId": "c2231lm2n3o4p5q6r7s8t9u0v1w2x3y4",
      "categoryName": "Falta",
      "startsAt": null,
      "endsAt": null,
      "workerId": "w4412ef6gh7i8j9k0l1m2n3o4p5q6r7s",
      "workerName": "Ana María Pérez",
      "workerIdentifier": "1023456789",
      "pointId": "n8321cd5ef6g7h8i9j0k1l2m3n4o5p6q",
      "positionId": null,
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "workspaceId": "k17fgbsj1hyw66bq5gw5sz2g8s82fs5j"
    }
  ],
  "nextCursor": null
}

Campos de Incident

idstringIdentificador de Convex.
datestring | nullFecha completa, YYYY-MM-DD.
periodstring | nullMes, YYYY-MM.
daynumberDía del mes.
abbreviationstringSigla con la que se pinta.
descriptionstringDescripción de la novedad.
colorstringsky · red · yellow.
keepbooleanSi cuenta como día trabajado.
categoryIdstring | nullCategoría aplicada.
categoryNamestring | nullNombre al registrar.
startsAtstring | nullInicio con huso, ISO 8601.
endsAtstring | nullFin con huso, ISO 8601.
workerIdstringPersona implicada.
workerNamestringNombre al registrar.
workerIdentifierstringDocumento al registrar.
pointIdstring | nullPuesto donde ocurrió.
positionIdstring | nullCargo aplicado.
customerIdstringCliente de la novedad.
workspaceIdstringEspacio de la novedad.
GET/financial-records

Con una clave de organización se leen todos los del mes; con una acotada, customerId es obligatorio.

Parámetros

periodstringobligatorioMes a consultar, YYYY-MM. Obligatorio: la operación se guarda por período mensual y no hay rango de fechas.
customerIdstringsegún alcanceCliente cuyos registros se listan.
limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/financial-records?period=2026-08" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "f3312mn3o4p5q6r7s8t9u0v1w2x3y4z5",
      "period": "2026-08",
      "type": "income",
      "concept": "Servicio de vigilancia agosto",
      "amount": 18500000,
      "customerId": "j5712xk9qb3v8w1n0m4pz6r2t8s5c7d1",
      "costCenterId": "k9912ab3c4d5e6f7g8h9i0j1k2l3m4n5",
      "costCenterCode": "00201",
      "costCenterName": "CAJAMAG"
    }
  ],
  "nextCursor": null
}

Campos de FinancialRecord

idstringIdentificador de Convex.
periodstring | nullMes, YYYY-MM.
typestringincome ingreso · expense egreso.
conceptstringConcepto del registro.
amountnumberMonto, en pesos.
customerIdstring | nullCliente al que se imputa. Nulo en un centro indirecto, cuyo devengo no se factura a ningún cliente.
costCenterIdstring | nullCentro de costo del registro. Nulo cuando la facturación llega agregada sobre varios centros.
costCenterCodestring | nullCódigo externo del centro.
costCenterNamestring | nullNombre del centro.
GET/positions

Catálogo de cargos de la organización. Es una entidad de organización, así que una clave acotada a espacios lo ve igual.

Parámetros

limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/positions" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "p1122kl2m3n4o5p6q7r8s9t0u1v2w3x",
      "name": "Guarda de seguridad",
      "value": 1423500,
      "year": 2026,
      "active": true
    }
  ],
  "nextCursor": null
}

Campos de Position

idstringIdentificador de Convex.
namestringNombre del cargo.
valuenumberValor asociado al cargo.
yearnumberAño de vigencia.
activebooleanSi está activo.
GET/categories

Catálogo de categorías de la organización, con su sigla y si cuentan como día trabajado.

Parámetros

limitintegeropcionalTamaño de página, de 1 a 5.000. Por defecto 50. Para volumen —todas las novedades de un mes— conviene subirlo: son menos peticiones contra el mismo límite por minuto.
cursorstringopcionalEl nextCursor de la página anterior.

Petición

curl "https://harmony.report/api/v1/categories" \
  -H "Authorization: Bearer hk_live_tu_clave"

Respuesta · 200

{
  "data": [
    {
      "id": "c2231lm2n3o4p5q6r7s8t9u0v1w2x3y4",
      "name": "Falta",
      "abbreviation": "FI",
      "color": "red",
      "keep": false,
      "shouldCount": true
    }
  ],
  "nextCursor": null
}

Campos de Category

idstringIdentificador de Convex.
namestringNombre de la categoría.
abbreviationstringSigla con la que se pinta.
colorstringsky · red.
keepbooleanSi cuenta como día trabajado.
shouldCountbooleanSi entra en los conteos.

Errores

{
  "error": {
    "code": "missing_parameter",
    "message": "Falta un parámetro obligatorio: period"
  }
}
codeHTTPCuándo
missing_authorization401No llegó la cabecera `Authorization`.
invalid_api_key401La clave no existe o está mal escrita.
revoked_api_key401La clave fue revocada.
expired_api_key401La clave caducó.
missing_parameter400Falta un parámetro obligatorio; el mensaje lo nombra.
invalid_period400El período no tiene la forma `YYYY-MM`.
invalid_limit400`limit` fuera de 1–5.000.
response_too_large413La respuesta no cabe. Baja el `limit` o pide menos expansiones a la vez.
not_found404El recurso no existe o está fuera del alcance de la clave.
rate_limited429Más de 60 peticiones en un minuto. Trae `Retry-After`.
method_not_allowed405La API es de sólo lectura: sólo admite `GET`.
internal_error500Error inesperado al atender la petición.

Un recurso fuera del alcance de la clave responde 404, no 403: distinguirlos confirmaría la existencia de datos ajenos.

Límite de peticiones

60 peticiones por minuto y por clave. Al superarlo, la respuesta es 429 con Retry-After en segundos. Si necesitas más volumen, pide menos páginas más grandes: limit=100.