> ## Documentation Index
> Fetch the complete documentation index at: https://docs.venezuelateayuda.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Personas

> Reglas importantes para crear y actualizar personas.

# Personas

Las personas son el recurso principal del registro.

## Visibilidad publica

El registro distingue entre personas del directorio publico y personas privadas.
Las consultas de personas exponen las publicas: una persona privada no aparece
en `GET /persons`, y `GET /persons/{person_id}` responde `404`, igual que sus
endpoints de foto, informacion de comunidad y reportes. El detalle de una
revision de duplicados que contiene una persona privada tambien responde `404`.
Una actualizacion que vuelve privada a una persona devuelve el resultado una vez;
las consultas posteriores ya no permiten acceder a ella.

Las personas privadas son, en la practica, destinatarias de ayuda registradas
por el equipo de coordinacion. No son casos de busqueda y no se publican.

El estado `not_missing` identifica a una persona que nunca fue reportada como
desaparecida. Toda persona con ese estado es privada. El filtro `status` de
`GET /persons` admite `missing`, `found` o `all`; `not_missing` responde `422`.
Un `PATCH` que establece `not_missing` puede devolver ese estado en su respuesta
antes de que el registro deje de ser accesible.

## Lectura y datos sensibles

Usa `persons:read` para consultar y `persons:write` para crear, actualizar,
eliminar o gestionar fotos. `GET /persons` lista personas publicas de todas las
fuentes. El detalle y las operaciones por `person_id` exigen que la persona
pertenezca a la fuente de la llave; en caso contrario responden `404`.

Las respuestas de lectura (`GET /persons` y `GET /persons/{person_id}`) estan
minimizadas por defecto. La API no devuelve documentos completos: cuando existe
una cedula, `document_id` se devuelve enmascarado con solo los
ultimos 4 digitos. Para menores de
edad, la API tampoco devuelve foto, edad exacta, ubicacion precisa, datos de
contacto, autores/contactos de informacion de comunidad, fuentes crudas ni
detalles clinicos. La informacion de comunidad puede devolverse con mensaje y
fecha, pero sin telefono y con autor generico.

Los detalles sensibles quedan reservados para gestion interna o acceso
verificado separado. La lectura sensible no se concede automaticamente con
`persons:read`.

Si la llave tiene `persons:sensitive:read`, las respuestas de personas incluyen
el documento completo, edad, foto, ubicacion, descripcion, datos del reportante,
telefono de quien localizo, hospital, fuentes y telefonos de informacion de
comunidad. Esta lectura sensible tambien aplica a respuestas que contienen
personas dentro de duplicados, upserts y fotos.

## Crear una persona

Usa:

```http theme={null}
POST /v1/persons
```

Envía un objeto JSON sin envoltura. El campo `source` no se envía: la API lo
infiere desde la llave. Los campos desconocidos se rechazan con `422`.
Una creación correcta responde `201` con `{ "data": { ...persona } }`.

Son obligatorios `first_name` y `last_name`, con al menos dos caracteres. También
debes proporcionar `contact_person_first_name`, `contact_person_phone` y
`contact_person_email`. `contact_person_last_name` es opcional.
Usa `location` para la ubicación y `document_type` + `document_id` para documentos.
Los campos anteriores `reporter_*`, `national_id` y `last_seen_location` se
rechazan con `422` y ya no aparecen en respuestas de personas.

Fecha de nacimiento y edad:

* Usa `birth_date` cuando exista una fecha exacta, en formato `YYYY-MM-DD`.
* Usa `age` cuando solo exista una edad aproximada.

Para menores de edad (`age < 18`) son obligatorios:

* `contact_person_relationship`
* `is_guardian_verified: true`

Esta validación de creación se activa por el campo `age`.

Valores de `contact_person_relationship`:

```txt theme={null}
mother
father
sibling
grandparent
aunt_uncle
cousin
friend
legal_guardian
```

## Actualizar una persona

Usa:

```http theme={null}
PATCH /v1/persons/{person_id}
```

El cuerpo es un objeto JSON parcial y rechaza campos desconocidos. Responde
`200` con la persona actualizada. El cuerpo vacío `{}` también se acepta y puede
cambiar `updated_at` aunque no incluya campos de la persona.

Los teléfonos aceptan formatos nacionales o internacionales comunes y se
guardan como texto E.164, por ejemplo `+584263105662`. Cada campo admite un solo
número; valores vacíos o placeholders como `N/A` no reemplazan un número válido.

Las actualizaciones respetan estados terminales: una persona `found` no vuelve
a `missing` ni a `not_missing`. `deceased` es un valor de `hospital_status`, no
de `status`, y se conserva una vez establecido. Hospital y refugio son
mutuamente excluyentes y cualquiera de los dos implica `found`.

Si la persona es menor de edad o tiene condiciones/notas de salud, actualizarla,
eliminarla o cambiar su foto requiere `persons:sensitive:read` ademas de
`persons:write`.

No envíes campos internos de la web como `photo_key`, `verified_at`,
`verified_by` o `deleted_at`. La foto se gestiona con el endpoint de fotos.
`is_public` sí se puede actualizar: al establecerlo en `false`, la respuesta
devuelve el registro modificado, pero las siguientes consultas y modificaciones
por ID responden `404`. Establecer `status: "not_missing"` también lo vuelve privado.

Para marcar como localizada:

```json theme={null}
{
  "status": "found",
  "found_notes": "Localizada con familiares.",
  "found_state": "distrito_capital",
  "found_city": "libertador",
  "finder_name": "Nombre Apellido",
  "finder_phone": "+584121234567"
}
```

Si la persona es menor de edad, `found_state` y `found_city` son obligatorios.
Si se envía `hospital_status`, también debe enviarse `hospital`. Si se envía
`shelter_status`, también debe enviarse `shelter`. No combines esos datos con
`status: "missing"`.

Valores de `hospital_status`:

```txt theme={null}
admitted
discharged
deceased
```

Para registrar una persona en un refugio, envía `shelter` con un handle oficial
y `shelter_status`. Hospital y refugio no deben coexistir.

Valores de `shelter_status`:

```txt theme={null}
present
departed
```

Los campos `verified_at` y `verified_by` son de solo lectura. Los escribe el
equipo interno cuando verifica un registro.

## Eliminar una persona

```http theme={null}
DELETE /v1/persons/{person_id}
```

La eliminación es lógica y responde `204` sin cuerpo. Eliminar una persona
canónica con registros fusionados dependientes responde `409`. Se aplican las
mismas restricciones de fuente, visibilidad y acceso sensible que en `PATCH`.

## Upsert por fuente externa

Usa:

```http theme={null}
PUT /v1/persons/source/{source_id}
```

Este endpoint busca una persona existente por la fuente asociada a la llave y el
`source_id` de la ruta. Si existe, actualiza la persona. Si no existe, crea una
nueva persona. Responde `200` al actualizar o `201` al crear, con
`{ "data": { ...persona } }`.

Ambos casos exigen el cuerpo completo de creación, incluidos los contactos y
las reglas de menores. No es un `PATCH`: no admite `status`, `hospital`,
`found_*` ni `photo_key`. Los campos permitidos son los definidos en
`CreatePersonRequest`. El cuerpo se valida antes de
buscar el registro; un cuerpo inválido responde `422` aunque el registro no sea
accesible. Si el registro existente es privado, un cuerpo válido responde `404`.

El `source_id` del cuerpo se ignora para decidir el upsert. El identificador
externo correcto es siempre el de la ruta. `source_notes` se utiliza al crear;
no reemplaza las notas de fuente de un registro existente.

Este endpoint requiere `persons:write`. A diferencia de `PATCH`, no exige
`persons:sensitive:read` para actualizar un registro sensible existente. Ese
permiso sigue controlando qué datos sensibles aparecen en la respuesta.

## Información de comunidad y reportes

Las rutas `/v1/persons/{person_id}/tips` y
`/v1/persons/{person_id}/reports` aceptan `GET` y `POST`. Para un registro
individual, agrega `/{tip_id}` o `/{report_id}`; esas rutas aceptan `GET`,
`PATCH` y `DELETE`.

La llave necesita `tips:read` o `reports:read` para consultar y `tips:write`
o `reports:write` para crear, actualizar o eliminar. La persona debe ser pública
y pertenecer a la fuente de la llave; de lo contrario, se responde `404`.

Para crear información de comunidad, envía `sender_name` y `message`.
`sender_phone` es opcional y acepta un único teléfono válido. Se normaliza a
E.164. El teléfono solo aparece con `persons:sensitive:read`; sin ese permiso,
los menores muestran un autor genérico y ningún teléfono. Estas reglas también
se aplican a las respuestas de creación y actualización.

Para crear un reporte, envía `reason`, `reporter_name` y `reporter_email`.
`details` es opcional. Los motivos permitidos son `duplicate`, `inappropriate`,
`incorrect_info`, `already_found` y `other`.

Los reportes nuevos quedan en `pending`. `PATCH` permite cambiar el estado a
`completed`. La lista y las operaciones individuales solo encuentran reportes
activos pendientes: después de completarlo, su consulta, actualización o
eliminación por esta API responde `404`. `DELETE` realiza una eliminación
lógica y responde `204` sin cuerpo.

Envía cuerpos JSON sin envoltura `tip` o `report`. `POST` rechaza campos
desconocidos; `PATCH` los descarta y requiere al menos un campo reconocido.

## Fotos

Para subir o reemplazar una foto:

```http theme={null}
POST /v1/persons/{person_id}/photo
Content-Type: multipart/form-data
```

Envía el campo `file` como archivo WebP con tipo `image/webp` y tamaño máximo
de 5 MiB (5 242 880 bytes). La API no convierte otros formatos. Un archivo
ausente, un tipo diferente o un tamaño mayor responde `422`.

Una carga correcta responde `201` con
`{ "data": { "person": { ...persona }, "photo": { "key": "...", "url": "..." } } }`.

Para quitar la foto:

```http theme={null}
DELETE /v1/persons/{person_id}/photo
```

La eliminación responde `200` con `{ "data": { ...persona } }`, también si la
persona ya no tiene foto. Las dos operaciones requieren `persons:write` y, para
un registro sensible, `persons:sensitive:read`.

Una respuesta `500` de escritura puede ocurrir después de guardar un cambio.
Consulta el registro antes de reintentar una creación, modificación o carga.

El `photo_url` de las respuestas apunta a `/media/photos/...`. Esa ruta tiene
límite de peticiones por IP y responde con una caché corta más `ETag`: guarda
el `ETag` y revalida con `If-None-Match` en vez de descargar la imagen cada vez.

La caché usa `public, max-age=60, must-revalidate`. Una revalidación vigente
responde `304` sin cuerpo. Una foto eliminada responde `404`, incluso al enviar
su `ETag` anterior. El límite de lectura es de 600 peticiones por minuto por IP;
una respuesta `429` incluye `Retry-After: 60`.

El listado de reportes admite únicamente `limit` (50 por defecto, máximo 100) y
`cursor`. Devuelve reportes pendientes activos por `created_at desc`; el cursor
queda vinculado a la persona. Los filtros, el orden y los cursores inválidos
responden `422`.
