Saltar a contenido

Referencia de endpoints — API del BackOffice GDI

Generado desde el OpenAPI del BackOffice con scripts/build_backoffice_endpoints.py. No editar a mano: regenerar.

Todos los endpoints llevan los 3 headers de autenticación (X-API-Key, X-Tenant-Schema, X-User-ID) y exigen que el usuario tenga rol Administrador. Las rutas son relativas a $GDI_BO_URL. Los marcados con ⚠️ borran datos o cortan accesos: se confirman con el administrador antes de ejecutarlos.

105 endpoints.

Índice

  • Usuarios (20)
  • Reparticiones (departments) (8)
  • Sectores (5)
  • Rangos jerárquicos (4)
  • Sellos del municipio (4)
  • Tipos de documento (12)
  • Tipos de expediente (case templates) (8)
  • Familias de legajos (12)
  • Configuración del municipio (3)
  • Ciudadanos (Base TAD) (3)
  • API Keys (8)
  • Certificados de firma (7)
  • Estadísticas (7)
  • Auditoría (1)
  • Organigrama (1)
  • Propuestas al catálogo global (2)

Usuarios

GET /admin/users

Listar todos los usuarios con roles

Lista todos los usuarios del sistema con informacion completa incluyendo roles asignados.

Requiere: - Token JWT valido - Rol de Administrador (role_id = 'a0000000-0000-0000-0000-000000000003')

Respuesta incluye: - Datos personales (email, nombre, CUIT) - Informacion de sector y departamento - Estado del usuario (activo/inactivo) - Fechas de creacion y ultimo acceso - Lista de roles asignados con nombre y descripcion

Parámetro Dónde Tipo Oblig. Descripción
search query string filtra por email/nombre; incluye usuarios archivados
estado query integer filtro exacto por estado (0=Inactivo, 1=Activo, 2=Pendiente, 5=Archivado). Si se pasa, desactiva la exclusion default de archivados.
department_id query string filtro por UUID de departamento (via sector).
role_id query string Solo usuarios que tienen este rol (UUID). Ej: Administrador.
exclude_role_id query string Solo usuarios que NO tienen este rol (UUID).
limit query integer Cantidad maxima de usuarios a devolver (1-500). Default: 100.
offset query integer Desplazamiento para paginacion. Default: 0.

POST /admin/users

Crear nuevo usuario

Crea un nuevo usuario en el sistema.

Campos requeridos: - email: Email unico del usuario - full_name: Nombre completo - sector_id: UUID del sector principal

Campos opcionales: - country_id: CUIT/DNI - role_ids: Lista de UUIDs de roles a asignar

Notas: - El email se guarda en minusculas - El usuario se crea con estado=1 (activo) - auth_id se llenara automaticamente cuando el usuario haga login en Auth0

Body JSON:

Campo Tipo Oblig. Descripción
email string (email) Email del usuario (unico)
full_name string Nombre completo
sector_id string (uuid) UUID del sector principal
country_id string CUIT/DNI (opcional)
role_ids lista de string (uuid) UUIDs de roles a asignar Default: [].
city_seal_id integer ID del sello obligatorio
can_global_search_documents boolean Puede buscar documentos de cualquier sector Default: false.
can_global_search_cases boolean Puede buscar expedientes de cualquier sector Default: false.
auth_method social | database Metodo de autenticacion: 'social' (Google/Microsoft) o 'database' (email+password) Default: "social".
as_backoffice_admin boolean si es True, usa el flujo de alta de Administrador del BackOffice (rol Administrador auto-asignado, auth_method forzado a 'database', ticket de activacion y mail con el client_id del BackOffice). Default: false.

GET /admin/users/emails

Emails de usuarios activos (para dedupe en creacion masiva)

**** endpoint liviano que devuelve solo los emails (en minuscula) de los usuarios NO archivados del tenant. El modal de creacion masiva del BO lo usa para avisar duplicados sin tener que rehidratar el listado paginado completo. Excluye archivados (estado=5), el AI worker y el rol Sistema TEST, igual que el modo default de GET /admin/users.

IMPORTANTE: esta ruta va ANTES de /users/{user_id} para que FastAPI no matchee 'emails' como un user_id.

GET /admin/users/{user_id}

Obtener detalle de un usuario

Obtiene informacion completa de un usuario especifico incluyendo roles.

Respuesta incluye: - Datos personales completos - Sector y departamento - Lista de roles asignados - Fechas de creacion y ultimo acceso

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

PATCH /admin/users/{user_id}

Actualizar usuario

Actualiza un usuario existente (actualizacion parcial - PATCH).

Campos actualizables: - full_name: Nombre completo - sector_id: UUID del sector principal - country_id: CUIT/DNI

Solo se actualizan los campos enviados en el request.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

Body JSON:

Campo Tipo Oblig. Descripción
full_name string Nombre completo
sector_id string (uuid) UUID del sector principal
country_id string CUIT/DNI
can_global_search_documents boolean Puede buscar documentos de cualquier sector
can_global_search_cases boolean Puede buscar expedientes de cualquier sector

DELETE /admin/users/{user_id} ⚠️ requiere confirmación

Borrar usuario definitivamente

Hard delete de un usuario. - Sin actividad -> se borra (BD + Auth0 database si corresponde). - Con actividad -> 409 con detalle; el admin debe desactivar o archivar.

Auth0: solo se elimina la identidad si auth_method='database' Y su email no queda en ningun otro tenant. Cuentas social NO se tocan. Fallo de Auth0 = warning no fatal (el usuario ya salio de la BD).

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario a borrar

PATCH /admin/users/{user_id}/email ⚠️ requiere confirmación

Cambiar email de login

Cambia el email de login de un usuario. Resetea auth_id (re-link en el proximo login). Si el usuario es database, primero actualiza el email en Auth0; si es social, solo se cambia en BD (el email lo posee el IdP).

Bloqueos: - Email ya en uso en el mismo municipio (409). - Email ya en uso en OTRO municipio de la plataforma (409, C1).

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

Body JSON:

Campo Tipo Oblig. Descripción
new_email string (email) Nuevo email de login (unico en el schema)

PATCH /admin/users/{user_id}/auth-method ⚠️ requiere confirmación

Cambiar metodo de acceso (social/database)

Cambia el metodo de autenticacion del usuario. Resetea auth_id (re-link en el proximo login con el nuevo metodo).

  • social -> database: crea (o reusa) la identidad Auth0 Database Connection, genera un link de activacion y encola el mail de invitacion.
  • database -> social: actualiza primero la BD (camino seguro); el usuario entra con Google/Microsoft usando su email actual. La identidad Auth0 Database vieja se borra despues (best-effort, no fatal) SOLO si el email no queda en uso como database en ningun otro tenant de la plataforma (mismo guard que el hard delete de .

Si el usuario ya tiene el metodo pedido, es un no-op (200).

****: si el email de este usuario es shared_identity=true (ver GET /admin/users/{id}), este endpoint devuelve 409 code=SHARED_IDENTITY en las DOS direcciones (social->database Y database->social) -- el metodo de acceso es una propiedad de la identidad Auth0 compartida, no de la ficha de este municipio, y no se puede tocar desde aca.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

Body JSON:

Campo Tipo Oblig. Descripción
auth_method social | database Nuevo metodo de autenticacion: 'social' o 'database'

GET /admin/users/{user_id}/sector-permissions

Obtener permisos de sectores adicionales de un usuario

Retorna los sectores adicionales asignados a un usuario con sus permisos de lectura y escritura.

Respuesta incluye: - Lista de sectores con acronimo, departamento y permisos (can_view, can_edit)

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

PUT /admin/users/{user_id}/sector-permissions

Reemplazar permisos de sectores adicionales de un usuario

Reemplaza todos los permisos de sectores adicionales del usuario. Los permisos existentes se eliminan y se insertan los nuevos.

Request body: - permissions: Lista de objetos con sector_id, can_view, can_edit

Notas: - Enviar lista vacia para remover todos los permisos adicionales - El sector principal del usuario (users.sector_id) NO se modifica

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

Body JSON:

Campo Tipo Oblig. Descripción
permissions lista de SectorPermissionItem Lista de permisos a asignar (reemplaza los existentes) Default: [].

GET /admin/users/{user_id}/seal

Obtener sello de firma de un usuario

Retorna el sello de firma asignado al usuario. Cada usuario puede tener maximo un sello asignado.

Respuesta: - seal: Objeto con datos del sello o null si no tiene

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

PUT /admin/users/{user_id}/seal

Asignar o remover sello de firma de un usuario

Asigna un sello de firma al usuario o lo remueve.

Request body: - city_seal_id: ID del sello a asignar, o null para remover

Notas: - Cada usuario puede tener maximo un sello - Si ya tiene uno asignado, se reemplaza - Enviar city_seal_id: null para remover el sello

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

Body JSON:

Campo Tipo Oblig. Descripción
city_seal_id integer ID del sello a asignar (null para remover)

POST /admin/users/{user_id}/admin-role ⚠️ requiere confirmación

Asignar rol Administrador a un usuario

Asigna el rol de Administrador a un usuario activo.

No se puede: - Asignar a un usuario inactivo

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

DELETE /admin/users/{user_id}/admin-role ⚠️ requiere confirmación

Quitar rol Administrador a un usuario

Quita el rol de Administrador a un usuario.

No se puede: - Quitarse el rol a si mismo - Quitar el rol a un usuario que no lo tiene

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

POST /admin/users/{user_id}/deactivate ⚠️ requiere confirmación

Desactivar usuario

Desactiva un usuario y rechaza automaticamente todos sus documentos pendientes de firma con motivo "Sistema BackOffice".

No se puede: - Desactivar al admin que ejecuta la accion - Desactivar un usuario ya inactivo

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario a desactivar

POST /admin/users/{user_id}/reactivate

Reactivar usuario

Reactiva un usuario previamente desactivado.

No se puede: - Reactivar al admin que ejecuta la accion - Reactivar un usuario ya activo

Nota importante: Reactivar un usuario NO restaura los documentos que fueron rechazados automaticamente al desactivarlo. Si el usuario tenia documentos pendientes de firma cuando se lo desactivo, esos documentos quedaron en estado 'rechazado' con motivo "Sistema BackOffice" y permanecen asi. El admin debe crear nuevos documentos si es necesario.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario a reactivar

POST /admin/users/{user_id}/archive ⚠️ requiere confirmación

Archivar usuario

Archiva un usuario (estado=5). El archivado desaparece del listado default; se ve solo en busqueda por texto con badge 'Archivado' y no puede loguear. Uso tipico: ex-empleados con actividad que no se pueden borrar.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario a archivar

POST /admin/users/{user_id}/unarchive

Desarchivar usuario

Desarchiva un usuario (estado=5 -> estado=1). Vuelve a listado y login.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario a desarchivar

POST /admin/users/{user_id}/reinvite

Reenviar invitacion o email de bienvenida

Reenvia la comunicacion al usuario segun su auth_method:

  • Database: Genera un nuevo link de activacion y reenvia email de invitacion.
  • Social: Reenvia el email de bienvenida con el link de acceso a la app.

Util cuando el usuario no recibio el email o necesita las instrucciones de acceso.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

POST /admin/users/{user_id}/activation-link

Generar link de activacion para entrega manual

Genera un link de activacion (password change ticket de Auth0) y lo devuelve SIN enviar ningun email, para que el admin lo entregue por otro canal (WhatsApp, telefono, en persona) cuando el mail no llega o no existe.

Funciona siempre, tenga o no correo configurado el ambiente (SaaS u on-premise).

Solo aplica a usuarios con auth_method = database: los usuarios con login social (Google/Microsoft) no tienen contraseña en GDI, entran directo con su cuenta desde la URL de la app.

El link sirve una sola vez y vence a los 5 dias. Tratarlo como una contraseña.

Parámetro Dónde Tipo Oblig. Descripción
user_id path string UUID del usuario

Reparticiones (departments)

GET /admin/departments

Arbol de departamentos

Lista todos los departamentos como arbol jerarquico.

Respuesta incluye: - Arbol con departamentos raiz y sus hijos - Rank asociado a cada departamento - Titular (head_user) de cada departamento - Estadisticas: empleados, sectores, sub-departamentos

POST /admin/departments

Crear reparticion

Crea una nueva reparticion (departamento) como hija de otra existente.

Requiere: - Nombre (2-100 caracteres) - Acronimo unico (2-20 caracteres, se convierte a mayusculas) - ID de la reparticion padre

Auto-crea un sector PRIV para la nueva reparticion.

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre de la reparticion
acronym string Acronimo unico. 2-20 caracteres, letras y numeros (se guarda en mayusculas)
parent_id string UUID de la reparticion padre
rank_id string UUID del rank (Intendente/Secretario/Director)

GET /admin/departments/{department_id}/available-users

Usuarios disponibles para asignar como titular

Lista usuarios activos que pueden ser asignados como titular de un departamento.

Respuesta incluye: - Usuarios activos con nombre, email, sector y departamento actual

Parámetro Dónde Tipo Oblig. Descripción
department_id path string UUID del departamento
limit query integer Cantidad maxima de usuarios a devolver (1-500). Default: 100.
offset query integer Desplazamiento para paginacion. Default: 0.

PATCH /admin/departments/{department_id}/head

Asignar o remover titular de departamento

Asigna o remueve el titular (head_user) de un departamento.

Para asignar: enviar head_user_id con el UUID del usuario. Para remover: enviar head_user_id como null.

Al asignar: - El usuario se mueve al sector PRIV del departamento - Se le asigna el sello correspondiente al rank del departamento - Si el departamento ya tenia otro titular, se remueve primero

Al remover: - Se quita el sello del usuario anterior - Se limpia el head_user_id del departamento

Parámetro Dónde Tipo Oblig. Descripción
department_id path string UUID del departamento

Body JSON:

Campo Tipo Oblig. Descripción
head_user_id string UUID del responsable (null para remover)

PATCH /admin/departments/{department_id}/color

Actualizar colores de departamento y sectores

Actualiza el color primario de un departamento y los colores de sus sectores atomicamente.

Recibe: - primary_color: Color hex del departamento (#RRGGBB) - sector_colors: Diccionario sector_id -> color hex (opcional, para override manual)

Parámetro Dónde Tipo Oblig. Descripción
department_id path string UUID del departamento

Body JSON:

Campo Tipo Oblig. Descripción
primary_color string Color hex (#RRGGBB)
sector_colors object Map sector_id -> color hex

PATCH /admin/departments/{department_id}

Actualizar nombre/acronimo/rank de reparticion

Actualiza el nombre, acronimo y/o rank de una reparticion existente.

Parámetro Dónde Tipo Oblig. Descripción
department_id path string UUID del departamento

Body JSON:

Campo Tipo Oblig. Descripción
name string Nuevo nombre
acronym string Nuevo acronimo. 2-20 caracteres, letras y numeros (se guarda en mayusculas)
rank_id string UUID del rango (null para quitar)
parent_id string UUID del departamento padre (string vacio para mover a raiz)

DELETE /admin/departments/{department_id} ⚠️ requiere confirmación

Eliminar reparticion

Elimina una reparticion si cumple todas las condiciones.

Parámetro Dónde Tipo Oblig. Descripción
department_id path string UUID del departamento

GET /admin/departments/{department_id}

Detalle de departamento

Obtiene detalle de un departamento con sus sectores, usuarios y sub-departamentos.

Respuesta incluye: - Datos del departamento (nombre, acronimo, rank, titular) - Sectores con sus usuarios - Usuarios con rank, sello, estado e indicador de titular - Sub-departamentos con estadisticas

Parámetro Dónde Tipo Oblig. Descripción
department_id path string UUID del departamento

Sectores

POST /admin/sectors

Crear sector

Crea un nuevo sector dentro de un departamento.

Request body: - department_id: UUID del departamento (requerido) - acronym: Acronimo unico del sector (1-10 caracteres, se convierte a mayusculas)

Validaciones: - El acronimo 'PRIV' esta reservado y no puede usarse - El departamento debe existir - El acronimo debe ser unico dentro del municipio

Ejemplo:

{"department_id": "uuid-del-depto", "acronym": "MESA"}

Body JSON:

Campo Tipo Oblig. Descripción
department_id string ID del departamento al que pertenece
acronym string Acronimo del sector (ej: MESA, ADMIN). 2-10 caracteres, letras y numeros (se guarda en mayusculas)

PATCH /admin/sectors/{sector_id}

Actualizar sector

Actualiza un sector (actualizacion parcial - PATCH).

Campos editables: - acronym: Nuevo acronimo (1-10 caracteres) - is_active: Estado activo/inactivo

Restricciones: - El sector PRIV no puede ser modificado - El nuevo acronimo no puede ser 'PRIV' - El acronimo debe ser unico

Parámetro Dónde Tipo Oblig. Descripción
sector_id path string UUID del sector

Body JSON:

Campo Tipo Oblig. Descripción
acronym string Nuevo acronimo. 2-10 caracteres, letras y numeros (se guarda en mayusculas)
is_active boolean Estado activo/inactivo
primary_color string Color primario hex

DELETE /admin/sectors/{sector_id} ⚠️ requiere confirmación

Desactivar sector (soft-delete)

Desactiva un sector (soft-delete). No elimina fisicamente, sino que marca is_active = false y end_date = NOW().

Validaciones: - El sector PRIV no puede ser desactivado - El sector no debe estar ya inactivo - El sector no debe tener usuarios activos asignados (reasignarlos primero)

Nota: Los datos historicos (expedientes, movimientos, notas) se mantienen intactos.

Parámetro Dónde Tipo Oblig. Descripción
sector_id path string UUID del sector

GET /admin/sectors/{sector_id}/deactivation-status

Estado de desactivacion de un sector

Evalua (solo lectura) si un sector se puede desactivar y, si no, por que. Corre las mismas validaciones que el DELETE pero sin ejecutar nada.

Devuelve: - can_deactivate: si el sector se puede desactivar - blockers: lista de motivos que lo impiden (codigo + cantidad + mensaje) - counts: conteos de usuarios, expedientes, movimientos y permisos

Parámetro Dónde Tipo Oblig. Descripción
sector_id path string UUID del sector

POST /admin/sectors/{sector_id}/assign-user

Asignar usuario a sector

Asigna un usuario existente a un sector.

Request body: - user_id: UUID del usuario a asignar (requerido)

Validaciones: - El sector debe existir y estar activo - El usuario debe existir y estar activo (estado = 1) - El usuario no debe estar ya asignado a ese sector

Ejemplo:

{"user_id": "uuid-del-usuario"}

Parámetro Dónde Tipo Oblig. Descripción
sector_id path string UUID del sector

Body JSON:

Campo Tipo Oblig. Descripción
user_id string ID del usuario a asignar

Rangos jerárquicos

GET /admin/ranks

Listar ranks jerarquicos

Lista todos los ranks (rangos jerarquicos) configurados en el municipio.

Respuesta incluye: - ID del rank - Nombre del rank (ej: Intendente, Secretario, Director) - Nivel jerarquico (1 = mas alto, ej: Intendente = 1, Secretario = 2) - Nombre del sello vinculado para titulares (head_signature) - ID del city_seal vinculado (si tiene)

Jerarquia y uso: - Los ranks definen niveles jerarquicos en la organizacion - Cada departamento tiene un rank asociado - El titular de un departamento hereda el rank y sello del departamento - Los ranks pueden restringir quien puede firmar ciertos tipos de documento

Sello automatico: - Cuando un rank tiene city_seal_id asignado - Al designar titular de departamento con ese rank - El usuario recibe automaticamente ese sello

POST /admin/ranks

Crear rank jerarquico

Crea un nuevo rank (rango jerarquico) y vincula un sello obligatorio para titulares.

Request body: - name: Nombre del rango (requerido, 2-50 caracteres, ej: "Director General") - level: Nivel jerarquico (requerido, >= 1). Nivel 1 = mas alto (ej: Intendente) - city_seal_id: ID del sello a vincular (obligatorio). Titulares con este rank reciben el sello automaticamente

Validaciones: - El nombre debe ser unico dentro del municipio (case-insensitive) - El sello debe existir y no estar vinculado a otro rank - El nivel debe ser >= 1

Uso posterior: - Asignar a departamentos al crearlos o editarlos - Configurar como rank permitido para firmar tipos de documento especificos - Cuando se asigne titular a departamento con este rank, recibira el sello vinculado

Ejemplo:

{
  "name": "Subsecretario",
  "level": 3,
  "city_seal_id": 2
}

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre del rango
level integer Nivel jerarquico (1=mas alto)
city_seal_id integer ID del sello a vincular (obligatorio)

DELETE /admin/ranks/{rank_id} ⚠️ requiere confirmación

Eliminar rank jerarquico

Elimina un rank (rango jerarquico) del municipio de forma permanente.

Parametros: - rank_id: UUID del rank a eliminar

Validaciones: - El rank NO debe tener departamentos asociados - Si tiene departamentos, reasignarlos o eliminarlos primero

Advertencia: - La eliminacion es permanente - El sello vinculado al rank se desvincula automaticamente (no se elimina)

Flujo seguro: 1. Verificar via GET /admin/ranks que el rank no tenga departamentos dependientes 2. Reasignar departamentos si es necesario 3. Eliminar rank

Parámetro Dónde Tipo Oblig. Descripción
rank_id path string UUID del rango

PATCH /admin/ranks/{rank_id}

Actualizar rank jerarquico

Actualiza un rank (rango jerarquico) del municipio (actualizacion parcial - PATCH).

Parametros: - rank_id: UUID del rank a actualizar

Campos editables: - name: Nombre del rango (2-50 caracteres) - level: Nivel jerarquico (>= 1) - city_seal_id: ID del sello a vincular (no se permite null, un rango siempre debe tener sello)

Validaciones: - El nuevo nombre debe ser unico dentro del municipio (case-insensitive) - El sello (si se envia) debe existir y no estar vinculado a otro rank - No se permite enviar city_seal_id: null (sello obligatorio) - Debe enviarse al menos un campo para actualizar

Impacto: - Cambiar nombre: Se actualiza en toda la UI - Cambiar level: Puede afectar jerarquia de permisos - Cambiar sello: Futuros titulares recibiran el nuevo sello

Ejemplo - Cambiar sello:

{
  "city_seal_id": 5
}

Parámetro Dónde Tipo Oblig. Descripción
rank_id path string UUID del rango

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre del rango
level integer Nivel jerarquico (1=mas alto)
city_seal_id integer ID del sello a vincular

Sellos del municipio

GET /admin/city-seals

Listar sellos del municipio

Lista todos los sellos configurados en el municipio.

Respuesta incluye: - ID del sello - Nombre del sello - Descripcion opcional - ID del rank vinculado (si tiene) - Fecha de creacion

Uso de sellos: - Vinculacion a ranks: Cuando un rank tiene sello vinculado, el titular del departamento con ese rank recibe automaticamente ese sello - Asignacion manual: Los sellos tambien pueden asignarse manualmente a usuarios especificos via /admin/users/{user_id}/seal

Nota: Un sello vinculado a un rank no puede eliminarse hasta desvincular el rank.

POST /admin/city-seals

Crear sello del municipio

Crea un nuevo sello municipal que puede vincularse a rangos o asignarse a usuarios.

Request body: - name: Nombre del sello (requerido, 2-100 caracteres) - description: Descripcion opcional del sello (max 500 caracteres)

Validaciones: - El nombre debe ser unico dentro del municipio (case-insensitive)

Usos posteriores: 1. Vincular a rank: PATCH /admin/ranks/{rank_id} con city_seal_id - Cuando se asigna titular a departamento, recibe este sello automaticamente 2. Asignar a usuario: PUT /admin/users/{user_id}/seal con city_seal_id - Asignacion manual directa a un usuario especifico

Ejemplo de uso: - Crear sello "Intendente Municipal" → vincular al rank "Intendente" - Cuando se asigne titular a Intendencia, recibira el sello automaticamente

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre del sello
description string Descripcion opcional

DELETE /admin/city-seals/{seal_id} ⚠️ requiere confirmación

Eliminar sello del municipio

Elimina un sello del municipio de forma permanente.

Parametros: - seal_id: ID del sello a eliminar

Validaciones: - El sello NO debe estar vinculado a un rank - Si esta vinculado, desvincular primero via PATCH /admin/ranks/{rank_id} con city_seal_id: null

Advertencia: - La eliminacion es permanente - Si usuarios tienen este sello asignado, se desvincularan automaticamente - Verificar que no este en uso antes de eliminar

Flujo seguro: 1. Verificar via GET /admin/city-seals si el sello tiene rank_id asignado 2. Si tiene rank, desvincular primero via PATCH rank 3. Eliminar sello

Parámetro Dónde Tipo Oblig. Descripción
seal_id path integer

PATCH /admin/city-seals/{seal_id}

Actualizar sello del municipio

Actualiza un sello del municipio (actualizacion parcial - PATCH).

Parametros: - seal_id: ID del sello a actualizar

Campos editables: - name: Nombre del sello (2-100 caracteres) - description: Descripcion del sello (max 500 caracteres)

Validaciones: - El nuevo nombre debe ser unico dentro del municipio (case-insensitive) - Debe enviarse al menos un campo para actualizar

Nota: - La vinculacion a ranks se gestiona via /admin/ranks/{rank_id}, no aqui - Si el sello esta asignado a usuarios, mantendran la asignacion con el nuevo nombre

Parámetro Dónde Tipo Oblig. Descripción
seal_id path integer

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre del sello
description string Descripcion

Tipos de documento

GET /admin/document-types

Listar tipos de documento

Lista todos los tipos de documento configurados localmente en el municipio.

Respuesta incluye: - ID local y ID del tipo global de origen - Nombre y acronimo del tipo - Tipo de documento (HTML, Importado, NOTA) - Tipo de firma requerida (electronic, digital_all, digital_num) - Estado activo/inactivo - Confiabilidad (gobierno/externo) - Fecha de creacion local

Uso: - Ver catalogo local de tipos disponibles para crear documentos - Identificar tipos activos e inactivos - Obtener IDs para operaciones de actualizacion

POST /admin/document-types

Crear tipo de documento propio del tenant

Crea un Tipo de Documento PROPIO del municipio, sin origen en el Catalogo Global.

Validaciones: - acronym: 2-6 letras A-Z (mayusculas). Se normaliza automaticamente (strip + upper). - El acronimo NO puede coincidir con ninguno del Catalogo Global (activos ni inactivos). - El acronimo NO puede repetirse en el municipio. - type: HTML | Importado | NOTA | MEMO. - signature_policy: electronic | digital_all | digital_num. - Si se provee field_definitions: el tipo nace inactivo (is_active=false) hasta que se validen los campos.

El acronimo es inmutable post-creacion (decision de diseno: la numeracion depende de el).

**visibility ** clasificacion elegida al crear. interno (default) | reservado | publico. Inmutable despues de la creacion. El BackOffice-Front lo pide como seleccion obligatoria y explicita en el modal de alta, no como checkbox opcional.

Errores posibles: - 400: Formato de acronimo invalido, o dato de Pydantic invalido. - 409: Acronimo ya existe en el Catalogo Global o en el municipio. - 403: Sin permisos de Administrador.

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre del tipo de documento
acronym string Acronimo unico (2-6 letras A-Z, mayusculas). Inmutable post-creacion.
description string Descripcion opcional
type HTML | Importado | NOTA | MEMO Tipo base del documento. SIN FFCC: 'Formulario Controlado' es una capacidad que se activa via field_definitions, no un valor de este campo.
signature_policy electronic | digital_all | digital_num Politica de firma del tenant: electronic=FirmadorGDI (.p12), digital_all=firma digital todos, digital_num=firma digital solo numerador
trust boolean True = documento de gobierno (confiable). False = externo (requiere validacion). Default: true.
special_numbering boolean Si usa numeracion especial independiente (no la numeracion general). Default: false.
external_signable boolean (TAD Ciudadano): si true, habilita a un ciudadano a crear y firmar documentos de este tipo desde /api/v1/tad/*. Solo valido si signature_policy='electronic' (422 si no). Default: false.
visibility interno | reservado | publico Clasificacion de visibilidad , obligatoria y mutuamente excluyente: 'interno' (default) | 'reservado' | 'publico'. Se elige UNA vez al crear el tipo (selector obligatorio en el BackOffice) e inmutable despues (no se puede cambiar por PATCH una vez creado en 'reservado' o 'publico'). Default: "interno".
field_definitions lista de FieldDefinition Definicion de campos de formulario controlado (capacidad FFCC). Si se provee, el tipo nace inactivo (is_active=false) hasta validar los campos.

GET /admin/document-types/options/sectors

Listar sectores disponibles

Lista sectores activos disponibles para configurar como habilitados en tipos de documento.

Respuesta incluye: - ID del sector - Acronimo del sector - Nombre del departamento al que pertenece - Acronimo del departamento

Uso: - Obtener opciones para campo enabled_sector_ids al actualizar tipos de documento - Si un tipo tiene sectores habilitados, solo usuarios de esos sectores pueden usarlo - Si la lista esta vacia, todos los sectores pueden usar el tipo

GET /admin/document-types/options/ranks

Listar rangos disponibles

Lista rangos jerarquicos disponibles para configurar como permitidos para firmar tipos de documento.

Respuesta incluye: - ID del rank - Nombre del rank (ej: Intendente, Secretario, Director) - Nivel jerarquico (1 = mas alto)

Uso: - Obtener opciones para campo allowed_rank_ids al actualizar tipos de documento - Si un tipo tiene ranks permitidos, solo usuarios con esos ranks pueden firmarlo - Si la lista esta vacia, no hay restriccion de rank para firmar

GET /admin/document-types/global

Listar tipos de documento globales

Lista los tipos de documento del catalogo global maestro disponibles para importar al municipio.

Parametros de query: - include_copied: Si es true, incluye tipos ya copiados al municipio. Por defecto false (solo muestra no copiados).

Respuesta incluye: - ID del tipo global - Nombre, acronimo y descripcion - Tipo de firma sugerido - Tipo de documento (HTML, Importado, NOTA) - is_copied: Indica si ya fue copiado al municipio - local_id: ID local si ya fue copiado (null si no)

Flujo de uso: 1. Listar tipos globales disponibles (include_copied=false) 2. Identificar tipo deseado por su id 3. Crear copia local via POST /from-global

Catalogo maestro: - Los tipos globales son gestionados por el equipo GDI - Incluyen tipos comunes a todos los municipios (Informe, Dictamen, Resolucion, etc.) - Se agregan nuevos tipos periodicamente

Parámetro Dónde Tipo Oblig. Descripción
include_copied query boolean

POST /admin/document-types/from-global

Crear tipo de documento desde catalogo global

Crea una copia local de un tipo de documento desde el catalogo global maestro.

Request body: - global_document_type_id: ID del tipo en el catalogo global a copiar - type (opcional): tipo base con el que se crea la copia local (HTML | Importado | NOTA | MEMO). Si se omite se hereda el del catalogo. El catalogo trae un type fijo por item (DECRE viene como HTML) y no todos los municipios lo usan igual: el que importa los decretos escaneados necesita Importado.

Validaciones: - El tipo global debe existir y estar activo - No debe existir una copia local previa (evita duplicados) - type, si viene, debe ser uno de los 4 tipos base

Operacion: - Copia nombre, acronimo, descripcion y tipo de firma del catalogo - El tipo de documento es el elegido en type, o el del catalogo si no se eligio - El nuevo tipo se crea activo por defecto (is_active=true) - Mantiene referencia al tipo global (global_document_type_id)

Posterior configuracion: - Usar PATCH /admin/document-types/{id} para: - Habilitar sectores especificos (enabled_sector_ids) - Configurar rangos permitidos para firmar (allowed_rank_ids) - Ajustar nombre o descripcion local - Corregir el type base, mientras el tipo siga sin documentos - Desactivar si es necesario

Importante: - No se puede copiar dos veces el mismo tipo global - El acronimo queda fijo (heredado del tipo global)

Body JSON:

Campo Tipo Oblig. Descripción
global_document_type_id string ID del tipo global a copiar
type HTML | Importado | NOTA | MEMO Tipo base a usar en la copia local. Si se omite se hereda el type del catalogo global (comportamiento historico). El catalogo trae un type fijo por item (ej. DECRE es 'HTML') y no todos los municipios lo usan asi: el que importa los decretos escaneados necesita 'Importado'. Como el acronimo es inmutable y ademas colisiona con el global, adoptar con el type errado dejaba la sigla inutilizable.

GET /admin/document-types/{document_type_id}

Detalle de tipo de documento

Obtiene el detalle completo de un tipo de documento local, incluyendo configuracion de sectores habilitados y rangos permitidos para firmar.

Parametros: - document_type_id: ID local del tipo de documento

Respuesta incluye: - Datos basicos: nombre, acronimo, tipo de documento, tipo de firma, estado - Info del tipo global: datos del tipo global de origen desde catalogo maestro - Sectores habilitados: lista de sectores que pueden usar este tipo (vacio = todos) - Rangos permitidos: lista de rangos que pueden firmar documentos de este tipo (vacio = sin restriccion)

Uso: - Ver configuracion completa antes de actualizar - Validar sectores y rangos configurados

Parámetro Dónde Tipo Oblig. Descripción
document_type_id path integer

PATCH /admin/document-types/{document_type_id}

Actualizar tipo de documento

Actualiza un tipo de documento local del municipio (actualizacion parcial - PATCH).

Parametros: - document_type_id: ID local del tipo de documento a actualizar

Campos editables: - name: Nombre del tipo de documento (2-100 caracteres) - description: Descripcion del tipo (max 250 caracteres) - type: Tipo de documento (HTML, Importado, NOTA) - signature_policy: Tipo de firma (electronic, digital_all, digital_num) - is_active: Estado activo/inactivo (boolean) - trust: Confiabilidad - true = gobierno, false = externo - enabled_sector_ids: Lista de IDs de sectores habilitados (vacia = todos los sectores pueden usar) - allowed_rank_ids: Lista de IDs de ranks permitidos para firmar (vacia = sin restriccion de rank) - visibility: Cambia la clasificacion interno/reservado/publico Restricciones: - El acronimo NO se puede cambiar (definido desde tipo global) - Debe enviarse al menos un campo para actualizar - type solo se puede cambiar mientras el tipo este VIRGEN (sin documentos draft ni oficiales); con documentos existentes se rechaza con 400. Ademas no se puede pasar a Importado con formulario controlado (FFCC) vigente: hay que desactivarlo antes. - visibility es inmutable salvo interno -> reservado o interno -> publico, y solo si el tipo NO tiene documentos creados (400 si tiene). Desde reservado o publico nunca se sale (400 con mensaje explicito).

Validaciones: - type debe ser uno de: HTML, Importado, NOTA - signature_policy debe ser uno de: electronic, digital_all, digital_num - Los IDs de sectores y ranks deben existir - Si enabled_sector_ids esta vacia, se permite uso desde cualquier sector - Si allowed_rank_ids esta vacia, cualquier usuario puede firmar (segun permisos)

Ejemplo de request:

{
  "type": "Importado",
  "signature_policy": "electronic",
  "description": "Informe grafico importado desde archivo"
}

Parámetro Dónde Tipo Oblig. Descripción
document_type_id path integer

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre del tipo
description string Descripcion
type HTML | Importado | NOTA | MEMO Tipo base del documento (HTML, NOTA, MEMO, Importado). La capacidad de formulario controlado se configura via field_definitions, no via este campo.
required_signature electronic | digital_all | digital_num Tipo de firma: electronic (Notary .p12), digital_all (AutoFirma todos), digital_num (AutoFirma solo numerador)
is_active boolean Si esta activo
trust boolean true = gobierno (confiable), false = externo (requiere validacion)
special_numbering boolean Si usa numeracion especial independiente
accepts_embedded_files boolean Si permite adjuntar archivos embebidos al PDF
external_signable boolean (TAD Ciudadano): habilita/deshabilita la firma ciudadana externa para este tipo. Solo se puede activar (true) si signature_policy (actual o enviado en el mismo PATCH) es 'electronic'; si no, 422.
visibility interno | reservado | publico Cambia la clasificacion de visibilidad . INMUTABLE en general: se rechaza con 400 si el tipo actual ya es 'reservado' o 'publico' (una vez fijado, no se sale). Unica transicion permitida via PATCH: interno -> reservado o interno -> publico, y solo si el tipo no tiene documentos creados (guard FOR UPDATE + EXISTS, molde .
enabled_sector_ids lista de string IDs de sectores habilitados (lista vacia = todos)
allowed_rank_ids lista de string IDs de ranks permitidos (lista vacia = sin restriccion)
field_definitions lista de FieldDefinition Agrega capacidad de formulario controlado al tipo. NO aplica a type='Importado'.

GET /admin/document-types/{document_type_id}/fields

Obtener campos de formulario FFCC

Retorna la definicion de campos del tipo de documento FFCC.

  • El tipo de documento debe ser FFCC (de lo contrario retorna 404)

Tipos de campo soportados (ADR-7, alineados con RLM): text, textarea, number, date, select, boolean, file

Parámetro Dónde Tipo Oblig. Descripción
document_type_id path integer

PUT /admin/document-types/{document_type_id}/fields

Reemplazar campos de formulario FFCC

Reemplaza completamente la definicion de campos de un tipo FFCC (ADR-4: sin versionado, UNIQUE por document_type_id).

  • El tipo de documento debe ser FFCC (de lo contrario retorna 404)

Comportamiento: - Si el tipo no tiene campos aun: INSERT. - Si ya tiene campos: reemplaza completamente (no merge). - Los documentos ya firmados NO se ven afectados (tienen su propio snapshot, ADR-3).

Validaciones de estructura: - name debe ser unico dentro del formulario. - options es requerido cuando type='select'. - Los 7 tipos de campo son los mismos que RLM (ADR-7).

Parámetro Dónde Tipo Oblig. Descripción
document_type_id path integer

Body JSON:

Campo Tipo Oblig. Descripción
field_definitions lista de FieldDefinition Nueva definicion completa de campos

DELETE /admin/document-types/{document_type_id}/fields ⚠️ requiere confirmación

Desactivar formulario FFCC (eliminar campos)

Elimina la definicion de campos de un tipo FFCC, devolviendolo a tipo normal (NOTA/MEMO/HTML sin formulario controlado).

Comportamiento: - Guard de inmutabilidad: NO se puede desactivar si existen documentos del tipo (retorna 409). - Idempotente: si el tipo no tenia campos, responde 200 con deleted=false. - Los documentos ya firmados NO se ven afectados (snapshot propio, ADR-3).

Parámetro Dónde Tipo Oblig. Descripción
document_type_id path integer

GET /admin/document-types/{document_type_id}/api-schema

Descargar esquema de integracion API TAD Ciudadano

Arma el JSON con todo lo que el software del municipio necesita para crear y firmar documentos de este tipo via API TAD Ciudadano endpoint, headers requeridos y un ejemplo de body (varia segun el tipo: Importado manda pdf_base64, FFCC manda form_data, HTML "libre" manda content_html; se agrega embedded_files si el tipo acepta adjuntos embebidos).

  • El tipo de documento debe tener external_signable=true (de lo contrario 422: hay que habilitarlo primero)

La URL del gateway del ambiente NO la conoce el BackOffice: el body trae un placeholder {GATEWAY_URL} que el municipio reemplaza por la URL publica de su gateway.

Parámetro Dónde Tipo Oblig. Descripción
document_type_id path integer

Tipos de expediente (case templates)

GET /admin/case-templates

Listar templates de expediente

Lista todos los templates de expediente configurados en el municipio.

Respuesta incluye: - ID local y global - Nombre y acronimo - Canal de creacion (web, api, both) - Departamento de radicacion - Estado (activo/inactivo)

POST /admin/case-templates

Crear tipo de expediente propio del tenant

Crea un Tipo de Expediente PROPIO del municipio, sin origen en el Catalogo Global.

Validaciones: - acronym: 2-6 letras A-Z (mayusculas). Se normaliza automaticamente (strip + upper). - El acronimo NO puede coincidir con ninguno del Catalogo Global (activos ni inactivos). - El acronimo NO puede repetirse en el municipio. - creation_channel: web | api | both. - filing_department_id: debe existir y estar activo en el municipio.

El acronimo es inmutable post-creacion (decision de diseno: la numeracion depende de el).

**visibility ** clasificacion elegida al crear. interno (default) | reservado. NUNCA publico (400: los expedientes no pueden ser publicos, D8). Inmutable post-creacion. El BackOffice-Front lo pide como seleccion obligatoria y explicita en el modal de alta.

Errores posibles: - 400: Formato de acronimo invalido, o dato de Pydantic invalido. - 403: Sin permisos de Administrador. - 404: Departamento de radicacion no encontrado o inactivo. - 409: Acronimo ya existe en el Catalogo Global o en el municipio.

Body JSON:

Campo Tipo Oblig. Descripción
type_name string Nombre del tipo de expediente
acronym string Acronimo unico (2-6 letras A-Z, mayusculas). Inmutable post-creacion.
description string Descripcion opcional
creation_channel web | api | both Canal de creacion: web (formulario), api (integracion), both (ambos) Default: "web".
filing_department_id string UUID del departamento de radicacion. Debe existir, estar activo, y NO ser de sistema TAD).
filing_sector_id string (TAD): UUID del sector de radicacion. La radicacion es DPTO#SECTOR: debe existir, estar activo y pertenecer a filing_department_id.
visibility interno | reservado | publico Clasificacion de visibilidad 'interno' (default) | 'reservado' | 'publico'. 'publico' se declara aca (Literal completo) para que el service lo rechace con un 400 explicito ('expedientes no pueden ser publicos', D8) en vez de un 422 generico de Pydantic. Se elige UNA vez al crear el tipo (selector obligatorio en el BackOffice) e inmutable despues. Default: "interno".

GET /admin/case-templates/global

Listar templates de expediente globales

Lista los templates de expediente globales disponibles para agregar al municipio.

Respuesta incluye: - Templates globales activos - Indicador de si ya fueron copiados al municipio

Parámetro Dónde Tipo Oblig. Descripción
include_copied query boolean

POST /admin/case-templates/from-global

Crear template de expediente desde global

Crea una copia local de un template de expediente global.

Requisitos: - El template global debe existir y estar activo - No debe existir una copia local previa - Se debe especificar el departamento de radicacion

Se copia: - Nombre, acronimo, descripcion - El nuevo template se crea activo por defecto

Body JSON:

Campo Tipo Oblig. Descripción
global_case_template_id string UUID del template global a copiar
filing_department_id string UUID del departamento de radicacion
filing_sector_id string (TAD): UUID del sector de radicacion. Debe pertenecer a filing_department_id.
creation_channel string Canal: web, api, both Default: "web".

GET /admin/case-templates/options/departments

Listar departamentos disponibles

Lista departamentos activos para seleccionar como permitidos en un template.

GET /admin/case-templates/options/sectors

Listar sectores disponibles (picker de radicacion,

Lista sectores activos con su departamento, para el picker DEPENDIENTE de "Depto. radicacion" la radicacion de un Tipo de Expediente es DPTO#SECTOR).

Contrato para el Front: - GET /admin/case-templates/options/sectors (sin query param): TODOS los sectores activos del municipio (excluye sectores de departamentos de sistema, ej. TAD) — igual forma que /admin/document-types/options/sectors. - GET /admin/case-templates/options/sectors?department_id={id}: SOLO los sectores de ese departamento. Uso tipico: el Front primero elige el departamento (picker /options/departments) y con ese id pide acá el picker de sector dependiente. - Respuesta: {"sectors": [{"id", "acronym", "primary_color", "department_name", "department_acronym"}, ...]} (mismo shape que el picker de document-types).

Parámetro Dónde Tipo Oblig. Descripción
department_id query string Si viene, filtra solo los sectores de ese departamento (picker dependiente)

GET /admin/case-templates/{case_template_id}

Detalle de template de expediente

Obtiene detalle completo de un template de expediente.

Respuesta incluye: - Datos basicos del template - Info del template global de origen - Departamentos permitidos para crear expedientes de este tipo

Parámetro Dónde Tipo Oblig. Descripción
case_template_id path string UUID del template de expediente

PATCH /admin/case-templates/{case_template_id}

Actualizar template de expediente

Actualiza un template de expediente local del municipio.

Campos editables: - type_name: Nombre del tipo de expediente - description: Descripcion - creation_channel: Canal de creacion (web, api, both) - filing_department_id: UUID del departamento de radicacion (puede ser null) - is_active: Estado activo/inactivo - visibility: Cambia la clasificacion interno/reservado . 'publico' SIEMPRE 400. - allowed_department_ids: Lista de UUIDs de departamentos permitidos

NOTA: El acronimo NO se puede cambiar.

**visibility ** inmutable salvo interno -> reservado, y solo activable en tipos virgenes. - interno -> reservado: solo si el tipo NO tiene expedientes creados. Si tiene, 400. - Desde reservado: siempre rechazado con 400 (inmutable). - publico: siempre rechazado con 400 (expedientes no pueden ser publicos, D8).

Parámetro Dónde Tipo Oblig. Descripción
case_template_id path string UUID del template de expediente

Body JSON:

Campo Tipo Oblig. Descripción
type_name string Nombre del tipo
description string Descripcion
creation_channel string Canal: web, api, both
filing_department_id string UUID del departamento de radicacion
filing_sector_id string (TAD): UUID del sector de radicacion. Si se cambia filing_department_id sin enviar filing_sector_id (o viceversa), se valida el par EFECTIVO resultante (el sector debe pertenecer al departamento vigente tras el PATCH).
is_active boolean Si esta activo
visibility interno | reservado | publico Cambia la clasificacion de visibilidad . 'publico' SIEMPRE rechazado con 400 (expedientes no pueden ser publicos, D8). INMUTABLE en general: se rechaza con 400 si el tipo actual ya es 'reservado'. Unica transicion permitida: interno -> reservado, y solo si el tipo no tiene expedientes creados (guard FOR UPDATE + EXISTS, molde .
allowed_department_ids lista de string UUIDs de departamentos permitidos

Familias de legajos

GET /admin/global-registry-families

Listar plantillas globales de familias de legajos

Lista todas las plantillas globales de familias de legajos disponibles.

Respuesta incluye: - Datos de cada plantilla (code, name, description, default_data_schema, default_states) - Indicador de si ya fue copiada al tenant (is_copied) - UUID local si ya fue copiada (local_id)

GET /admin/registry-families

Listar familias de legajos del tenant

Lista todas las familias de legajos configuradas en el municipio.

Respuesta incluye: - ID, code, name, is_active - Cantidad de campos en data_schema (field_count) - Cantidad de estados (state_count)

POST /admin/registry-families

Crear familia de legajos

Crea una familia de legajos. Dos modalidades:

Desde plantilla global:

{ "from_global_id": "uuid-de-plantilla-global" }

Custom:

{
  "code": "VEHICULOS",
  "name": "Legajo de Vehiculos",
  "data_schema": { ... },
  "states": ["activo", "baja"]
}

Validaciones: - El codigo debe ser unico por tenant - Si es desde global, la plantilla debe existir y no haber sido copiada

Body JSON:

Campo Tipo Oblig. Descripción
from_global_id string UUID de la plantilla global (si se crea desde global)
code string Codigo unico (solo para custom, max 10 chars)
name string Nombre (solo para custom)
description string Descripcion (solo para custom)
data_schema object Schema de campos (solo para custom)
states lista de string Estados posibles (solo para custom)

GET /admin/registry-families/{family_id}

Obtener detalle de familia de legajos

Obtiene el detalle completo de una familia de legajos por su ID.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos

PATCH /admin/registry-families/{family_id}

Actualizar familia de legajos

Actualiza una familia de legajos.

Campos editables: - name: Nombre descriptivo - states: Lista de estados posibles - is_active: Activar/desactivar - is_public: Publica o despublica la familia . Reversible, sin restricciones (D4). - public_config: fields / visible_states / show_documents / show_cases / show_related_records. fields debe ser subconjunto de data_schema, visible_states subconjunto de states (400 si no).

NOTA: El code NO se puede cambiar (inmutable).

Validacion: No se puede desactivar si hay legajos activos.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre descriptivo
description string Descripcion de la familia
states lista de string Estados posibles
is_active boolean Activar/desactivar
is_public boolean Publica o despublica la familia . Reversible sin restricciones (D4): a diferencia de document_types, no hay guard de 'virgen' ni irreversibilidad.
public_config PublicConfig Configuracion de exposicion publica . 'fields' debe ser subconjunto de data_schema; 'visible_states' debe ser subconjunto de states (400 si no cumple).

DELETE /admin/registry-families/{family_id} ⚠️ requiere confirmación

Desactivar familia de legajos (soft delete)

Desactiva una familia de legajos (soft delete, is_active = false).

Validacion: No se puede desactivar si hay legajos activos en esta familia. Si hay legajos activos, responde con error incluyendo la cantidad.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos

PATCH /admin/registry-families/{family_id}/schema

Agregar/editar campo en data_schema

Agrega o actualiza un campo en el data_schema de la familia.

Si el campo (field_key) ya existe: lo actualiza. Si no existe: lo agrega.

Tipos soportados: text, number, date, select, boolean, file, textarea. Para campos tipo select, incluir lista de options.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos

Body JSON:

Campo Tipo Oblig. Descripción
field_key string Clave del campo (minusculas, numeros, underscore)
type text | number | date | select | boolean | file | textarea Tipo de dato
label string Etiqueta visible
required boolean Si es obligatorio Default: false.
has_expiration boolean Si tiene fecha de vencimiento Default: false.
has_verification boolean Si requiere verificacion Default: false.
options lista de string Opciones para campos tipo select

DELETE /admin/registry-families/{family_id}/schema/{field_key} ⚠️ requiere confirmación

Eliminar campo del data_schema

Elimina un campo del data_schema de la familia.

Validacion: No se puede eliminar si hay legajos con datos en ese campo. Si hay datos, responde con error incluyendo la cantidad de legajos afectados.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos
field_key path string

GET /admin/registry-families/{family_id}/permissions

Listar permisos por sector

Lista todos los sectores con sus permisos para la familia de legajos.

Respuesta incluye: - Sector ID y nombre - Flags: can_create, can_edit, can_view, can_verify

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos

POST /admin/registry-families/{family_id}/permissions

Agregar sector con permisos

Agrega un sector con permisos a la familia de legajos.

Permisos disponibles: - can_create: Puede crear legajos - can_edit: Puede editar legajos - can_view: Puede ver legajos - can_verify: Puede verificar legajos

Validacion: UNIQUE(family_id, sector_id). No se puede duplicar.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos

Body JSON:

Campo Tipo Oblig. Descripción
sector_id string UUID del sector
can_create boolean Puede crear legajos Default: false.
can_edit boolean Puede editar legajos Default: false.
can_view boolean Puede ver legajos Default: true.
can_verify boolean Puede verificar legajos Default: false.

PATCH /admin/registry-families/{family_id}/permissions/{sector_id}

Editar permisos de sector

Actualiza los permisos de un sector para la familia de legajos.

Campos editables: - can_create, can_edit, can_view, can_verify (todos opcionales)

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos
sector_id path string UUID del sector

Body JSON:

Campo Tipo Oblig. Descripción
can_create boolean Puede crear legajos
can_edit boolean Puede editar legajos
can_view boolean Puede ver legajos
can_verify boolean Puede verificar legajos

DELETE /admin/registry-families/{family_id}/permissions/{sector_id} ⚠️ requiere confirmación

Quitar sector de permisos

Elimina el permiso del sector para la familia de legajos.

Parámetro Dónde Tipo Oblig. Descripción
family_id path string UUID de la familia de legajos
sector_id path string UUID del sector

Configuración del municipio

GET /admin/settings

Obtener configuracion del municipio

Retorna la configuracion completa del municipio desde la tabla {schema}.settings.

Respuesta incluye: - city: Ciudad para usar en documentos oficiales - address: Domicilio fiscal del municipio - annual_slogan: Lema o frase institucional del año - logo_url: URL del logo institucional completo - isologo_url: URL del isologo (version simplificada del logo) - cover_url: URL de la imagen de portada para onboarding - timezone: Zona horaria del municipio (ej: America/Argentina/Buenos_Aires) - updated_at: Fecha de ultima actualizacion de configuracion

Nota: Las URLs de imagenes se gestionan por separado via endpoints de upload.

PUT /admin/settings

Actualizar configuracion del municipio

Actualiza la configuracion textual del municipio. Los campos de imagenes se gestionan por separado via endpoints de upload de archivos.

Campos editables: - city: Ciudad para documentos oficiales (max 100 caracteres) - address: Domicilio fiscal del municipio (max 150 caracteres) - annual_slogan: Lema o frase institucional (max 255 caracteres)

Validaciones: - Debe enviarse al menos un campo para actualizar - Los campos enviados reemplazan los valores actuales

Nota: Las URLs de imagenes (logo_url, isologo_url, cover_url) NO se actualizan mediante este endpoint. Usar endpoints especificos de upload de archivos.

Auditoria: La actualizacion registra el user_id del administrador que realizo el cambio.

Body JSON:

Campo Tipo Oblig. Descripción
city string
address string
annual_slogan string
primary_color string

POST /admin/settings/upload-image

Subir logo o isologo

Sube imagen a R2 y guarda URL en settings.

Body multipart/form-data (subida de archivo):

Campo Tipo Oblig. Descripción
file string
field string

Ciudadanos (Base TAD)

GET /admin/citizens

Listar/buscar ciudadanos (Base TAD)

Lista la Base de Ciudadanos del municipio , TAD Ciudadano), con busqueda opcional por nombre o CUIL/DNI.

Requiere: Rol de Administrador.

Parámetro Dónde Tipo Oblig. Descripción
search query string Filtra por nombre o CUIL/DNI (case-insensitive)
page query integer Numero de pagina (1-based)
page_size query integer Tamano de pagina (1-500)

POST /admin/citizens

Alta manual de ciudadano (mostrador)

Da de alta un ciudadano manualmente (ej. validacion presencial en el mostrador). country_id (CUIL/DNI) debe ser unico dentro del municipio.

Si estado='validado', el admin que crea queda registrado como validador.

Body JSON:

Campo Tipo Oblig. Descripción
full_name string Nombre y apellido
country_id string CUIL/DNI
estado pendiente | validado | bloqueado Estado inicial. Default 'pendiente'. Si se envia 'validado', el admin que crea queda registrado como validador (validated_by/validated_at). Default: "pendiente".

PATCH /admin/citizens/{citizen_id}/estado

Cambiar estado de ciudadano

Cambia el estado de un ciudadano: pendiente | validado | bloqueado. Nombre e ID (CUIL/DNI) NO se editan por este endpoint (inmutables por ahora).

Uso tipico: validar identidad presencial (-> validado) o bloquear un ciudadano por un problema puntual (-> bloqueado).

Parámetro Dónde Tipo Oblig. Descripción
citizen_id path string UUID del ciudadano

Body JSON:

Campo Tipo Oblig. Descripción
estado pendiente | validado | bloqueado Nuevo estado: pendiente | validado | bloqueado

API Keys

GET /admin/api-keys

Listar API Keys del municipio

Lista todas las API Keys creadas por el municipio con conteo de usuarios autorizados.

Parámetro Dónde Tipo Oblig. Descripción
limit query integer Cantidad maxima de API Keys a devolver (1-500). Default: 100.
offset query integer Desplazamiento para paginacion. Default: 0.

POST /admin/api-keys

Crear API Key

Crea una nueva API Key. La key completa se muestra SOLO en esta respuesta.

Body JSON:

Campo Tipo Oblig. Descripción
name string Nombre descriptivo de la API Key
description string Descripcion opcional
expires_at string Fecha de expiracion ISO 8601 (null = no expira)
rate_limit_per_minute integer Limite de requests por minuto Default: 60.
key_type api | tad 'api' (default, Gateway REST comun) | 'tad' habilita SOLO la superficie /api/v1/tad/* para el software del municipio). Inmutable post-creacion. Default: "api".
webhook_url string URL de callback , evento documents.notified)
webhook_secret string Secreto para firmar el webhook (HMAC X-GDI-Signature). Se guarda CIFRADO y nunca se devuelve en claro por la API.
allowed_origins lista de string Origenes permitidos (CORS). Opcional (tambien para key_type='tad').

GET /admin/api-keys/{key_id}/users

Listar usuarios autorizados de una API Key

Parámetro Dónde Tipo Oblig. Descripción
key_id path string UUID de la API Key
limit query integer Cantidad maxima de usuarios a devolver (1-500). Default: 100.
offset query integer Desplazamiento para paginacion. Default: 0.

POST /admin/api-keys/{key_id}/users

Agregar usuario autorizado a una API Key

Parámetro Dónde Tipo Oblig. Descripción
key_id path string UUID de la API Key

Body JSON:

Campo Tipo Oblig. Descripción
user_id string UUID del usuario a autorizar

DELETE /admin/api-keys/{key_id}/users/{user_id} ⚠️ requiere confirmación

Remover usuario autorizado de una API Key

Parámetro Dónde Tipo Oblig. Descripción
key_id path string UUID de la API Key
user_id path string UUID del usuario autorizado

GET /admin/api-keys/{key_id}

Detalle de una API Key

Parámetro Dónde Tipo Oblig. Descripción
key_id path string UUID de la API Key

PATCH /admin/api-keys/{key_id}

Actualizar API Key

Actualiza campos parciales de una API Key (nombre, descripcion, estado, expiracion, rate limit).

Parámetro Dónde Tipo Oblig. Descripción
key_id path string UUID de la API Key

Body JSON:

Campo Tipo Oblig. Descripción
name string
description string
is_active boolean
expires_at string
rate_limit_per_minute integer
webhook_url string URL de callback
webhook_secret string Nuevo secreto del webhook (se re-cifra). Enviar null no lo borra: usar '' para eso.
allowed_origins lista de string Origenes permitidos (CORS)

DELETE /admin/api-keys/{key_id} ⚠️ requiere confirmación

Eliminar API Key

Elimina una API Key y todos sus usuarios autorizados.

Parámetro Dónde Tipo Oblig. Descripción
key_id path string UUID de la API Key

Certificados de firma

GET /admin/certificates

Listar certificados

Lista todos los certificados de tenants registrados.

POST /admin/certificates

Subir certificado digital

Sube un archivo .p12 y su password para un tenant. El archivo se almacena en R2 y el password se encripta con Fernet.

Body multipart/form-data (subida de archivo):

Campo Tipo Oblig. Descripción
cert_file string Archivo .p12 (max 5MB)
cert_password string Password del archivo .p12
tenant_id string Tenant ID (default: tenant del admin)

POST /admin/certificates/generate-csr

Generar KEY + CSR para solicitud ONTI

Genera una clave privada RSA 2048 y un CSR con los campos requeridos por AC ONTI.

El municipio debe: 1. Guardar la key_pem en un lugar seguro (nunca compartirla) 2. Enviar el csr_pem a ONTI via JIRA 3. Cuando reciba el .cer de ONTI, llamar a /finalize

GDI no almacena la clave privada.

POST /admin/certificates/finalize

Finalizar certificado con .cer de ONTI

Combina el .cer emitido por ONTI con la clave privada del municipio, genera el .p12 y lo activa en GDI automaticamente.

El municipio debe aportar: - El archivo .cer recibido de ONTI - El archivo .key que guardo en el paso de generacion del CSR - Una contrasena para proteger el certificado (min 8 caracteres)

La clave privada NO se almacena. Solo se usa para armar el .p12.

Body multipart/form-data (subida de archivo):

Campo Tipo Oblig. Descripción
cer_file string Archivo .cer/.crt/.pem/.p7b emitido por ONTI
key_file string Archivo .key generado en el paso anterior
cert_password string Contrasena para proteger el certificado (min 8 chars)
tenant_id string Tenant ID (default: tenant del admin)

GET /admin/certificates/{tenant_id}

Info de certificado

Obtiene informacion de un certificado por tenant_id.

Parámetro Dónde Tipo Oblig. Descripción
tenant_id path string

DELETE /admin/certificates/{tenant_id} ⚠️ requiere confirmación

Eliminar certificado

Elimina un certificado de R2 y BD.

Parámetro Dónde Tipo Oblig. Descripción
tenant_id path string

POST /admin/certificates/send-instructions

Enviar instrucciones de certificado por email

Envía al admin logueado las instrucciones del proceso ONTI con la nota modelo.

Body JSON:

Campo Tipo Oblig. Descripción
cn string
org string
sha256 string
nota_texto string
fd_code string Default: "".

Estadísticas

GET /admin/stats/summary

Metricas generales del tenant

Retorna metricas generales del tenant: expedientes (total/activos/cerrados/last_14_days), documentos firmados, usuarios, notas enviadas, departamentos activos y sectores activos.

GET /admin/stats/documents-by-type

Documentos por tipo en el periodo

Documentos oficiales agrupados por tipo de documento en el periodo indicado. Default: ultimos 14 dias.

Parámetro Dónde Tipo Oblig. Descripción
date_from query string Fecha inicio YYYY-MM-DD
date_to query string Fecha fin YYYY-MM-DD

GET /admin/stats/cases-activity

Expedientes creados por dia

Expedientes creados por dia en el periodo indicado. Default: ultimos 14 dias.

Parámetro Dónde Tipo Oblig. Descripción
date_from query string Fecha inicio YYYY-MM-DD
date_to query string Fecha fin YYYY-MM-DD

GET /admin/stats/signatures

Estadisticas de firmas digitales

Firmas de public.firma_audit_log filtrado por schema del tenant y periodo. Default: ultimos 14 dias.

Parámetro Dónde Tipo Oblig. Descripción
date_from query string Fecha inicio YYYY-MM-DD
date_to query string Fecha fin YYYY-MM-DD

GET /admin/stats/last-access

Ultimos accesos de usuarios

Retorna los N usuarios que accedieron mas recientemente al sistema.

Parámetro Dónde Tipo Oblig. Descripción
limit query integer Numero de usuarios a retornar

GET /admin/stats/recent-signed-documents

Ultimos documentos firmados

Retorna los N documentos firmados mas recientes. Default: ultimos 14 dias.

Parámetro Dónde Tipo Oblig. Descripción
limit query integer Numero de documentos a retornar
date_from query string Fecha inicio YYYY-MM-DD
date_to query string Fecha fin YYYY-MM-DD

GET /admin/stats/cases-list

Lista paginada de todos los expedientes

Lista paginada de TODOS los expedientes del tenant con filtros opcionales de status, busqueda de texto y rango de fechas.

Parámetro Dónde Tipo Oblig. Descripción
page query integer Pagina actual
page_size query integer Expedientes por pagina
status query string Filtrar por status
search query string Buscar en numero o asunto
date_from query string Fecha inicio YYYY-MM-DD
date_to query string Fecha fin YYYY-MM-DD

Auditoría

GET /admin/audit

Historial de auditoria del organigrama

Devuelve el historial de cambios registrado automaticamente via triggers SQL sobre las tablas del organigrama.

Tablas disponibles: departments, ranks, sectors, user_roles, user_seals, user_sector_permissions, users

Por defecto devuelve departments + sectors (el organigrama completo).

Cada entrada incluye: - Quien hizo el cambio (nombre + email del usuario, o 'Sistema') - Cuando (timestamp con timezone) - Que tabla y que operacion (INSERT / UPDATE / DELETE) - La entidad afectada (id + nombre/acronimo) - Para UPDATE: los campos modificados con valor viejo y nuevo - Para INSERT/DELETE: snapshot de los campos relevantes

Paginacion: limit (max 500) + offset. Ordenado por event_time DESC.

Parámetro Dónde Tipo Oblig. Descripción
tables query lista de string Tablas a incluir. Permitidas: departments, ranks, sectors, user_roles, user_seals, user_sector_permissions, users. Se puede enviar multiples veces (?tables=departments&tables=sectors). Si se omite, devuelve departments + sectors.
from query string (date) Fecha de inicio del filtro (ISO date, ej: 2026-01-01). Inclusivo.
to query string (date) Fecha de fin del filtro (ISO date, ej: 2026-05-31). Inclusivo (hasta 23:59:59).
limit query integer Cantidad maxima de resultados (1-500). Default: 100.
offset query integer Desplazamiento para paginacion. Default: 0.

Organigrama

GET /admin/organigrama/export

Exportar organigrama a XLSX

Genera y descarga el organigrama completo del municipio en formato Excel (.xlsx).

Incluye tres hojas: - Reparticiones: árbol plano de departamentos activos con titular, rango y estadísticas - Sectores: listado de sectores con conteo de empleados - Usuarios: padrón completo (activos e inactivos) con roles, permisos y sellos

No tiene LIMIT: exporta todos los registros del tenant.

Propuestas al catálogo global

POST /admin/catalog/propose

Proponer nuevo item al catalogo global

Un admin municipal propone un nuevo item para el catalogo global.

Flujo: 1. Valida acronimo/codigo contra conflictos existentes 2. Llama a AgenteLANG para analisis IA (fuera de transaccion) 3. Si IA aprueba automaticamente: UPSERT en tabla global + guarda propuesta como 'approved' 4. Si IA deriva a revision: guarda propuesta como 'pending' + envia email a el equipo de GDI

Rate limit: 60 req/min (global por IP, aplicado por middleware)

Body JSON:

Campo Tipo Oblig. Descripción
catalog_table global_document_types | global_case_templates | global_registry_families
data DocumentTypeProposalData | CaseTemplateProposalData | RegistryFamilyProposalData

GET /admin/catalog/proposals

Listar propuestas de catalogo

Lista las propuestas de catalogo, filtrable por status.

Status posibles: pending | approved | rejected

Parámetro Dónde Tipo Oblig. Descripción
status query string
catalog_table query string