Paginación y formato de respuesta
Las tres APIs (instance-api, saascore-api, services-api) responden el éxito con un contrato único: un recurso se devuelve bare (sin envoltura) y una colección usa la envoltura fina CollectionResponse. Es el hermano del formato de error RFC 9457, que cubre 4xx/5xx.
Envelope
| Caso | Forma del cuerpo |
|---|---|
| Recurso único | objeto bare — los campos del recurso al top level, sin envoltura |
| Colección | { "data": [ ... ], "pagination": { ... } } |
| Sin cuerpo | ninguno (status 204) |
No existe envoltura
datapara un recurso único. El envelope{ "data": { ... } }para objetos individuales era el formato previo, reemplazado por la forma bare.
Recurso único
GET /v1/senders/42
{
"id": 42,
"name": "Atención al cliente",
"email_address": "contacto@correos.micomercio.cl",
"domain_id": 7,
"created_at": "2026-05-08T14:24:10Z",
"updated_at": "2026-05-08T14:24:10Z"
}
Colección
GET /v1/senders?page=1&page_size=20
{
"data": [
{ "id": 42, "name": "Atención al cliente", "...": "..." },
{ "id": 43, "name": "Facturación", "...": "..." }
],
"pagination": { "page": 1, "page_size": 20, "has_more": true, "total_items": 57, "total_pages": 3 }
}
Status codes
Regla: el código sigue al cuerpo — primero se decide si el endpoint devuelve representación, después el código.
| HTTP | Cuándo | Cuerpo | Header extra |
|---|---|---|---|
200 OK | Lectura, o update/acción que devuelve un resultado | el recurso o resultado | — |
201 Created | POST/PUT que crea un recurso nuevo direccionable | el recurso creado | Location: /v1/<coleccion>/{id} |
204 No Content | Éxito sin representación (DELETE; PUT/PATCH que no ecoan la entidad) | ninguno (sin body ni Content-Length) | — |
204, no200, cuando no hay cuerpo.201solo cuando se crea un recurso direccionable; una acción tipo/sendo/resetque no crea nada es200.
Paginación
Query params en endpoints de colección:
| Param | Default | Rango |
|---|---|---|
page | 1 | ≥ 1 |
page_size | 20 | 1–100 |
Bloque pagination de la respuesta:
| Campo | Significado |
|---|---|
page | Página actual (1-based). |
page_size | Tamaño de página efectivo. |
has_more | Si existe una página siguiente. Presente siempre, en todo listado. |
total_items | Total de items que matchean el filtro (no solo la página). Puede ser null. |
total_pages | ceil(total_items / page_size); 0 cuando no hay items. Puede ser null. |
has_more es la señal para avanzar de página, y está en toda respuesta de colección. Los
dos totales son un enriquecimiento: un listado sobre una tabla lo bastante chica como para
contarla los informa, y uno cuyo conteo exacto costaría un escaneo completo los deja en
null. Un cliente que solo necesita paginar debe leer has_more; un cliente que muestra
"página X de Y" debe tolerar el null.
Headers
| Header | Presencia | Significado |
|---|---|---|
X-Request-Id | Toda respuesta (éxito y error) | UUID de la request; correlación + audit. El cliente puede enviarlo; si no, la API lo genera. No va en el cuerpo. |
X-Trace-Id | Best-effort (cuando hay traza OTel activa) | ID de traza distribuida para correlación en Tempo/Loki. |
Location | Solo 201 | URI del recurso recién creado. |
Base de payload
- Todo response hereda de
web.BaseResponse:from_attributes(mapea desde el modelo ORM) + serialización dedatetimea RFC 3339 en UTC con sufijoZ. - Los responses no llevan validación de campo — se construyen desde datos ya validados; solo tipos y serializers de salida.
- No existen los envoltorios
ObjectResponse/NoContentResponse/<Entidad>ListResponse.
Para el formato de error (4xx/5xx), esquema del envelope problem+json, code y catálogo completo: Respuestas de error.