Consentimientos
El motor de consentimiento gira en torno a dos recursos: la campaña (consent_campaign), que define a quién se le pide qué y por qué canal, y la solicitud (consent_request), el pedido individual a un titular o su apoderado, con sus entregas, su decisión y su evidencia sellada. Por API puedes crear y operar campañas, seguir cada solicitud y recuperar la evidencia; el registro manual de decisiones con documentos queda en la consola.
El recorrido completo —desde el diseño de la campaña hasta la decisión del apoderado— está narrado en la guía del flujo de consentimiento; el trabajo entre organizaciones que comparten padrón, en campañas compartidas y su página de producto.
El ciclo de vida de una campaña
- Nombre
status- Tipo
- string
- Descripción
draft→published→closed. Publicar exige que la audiencia esté materializada (409 CONSENT_CAMPAIGN_AUDIENCE_NOT_READYsi no lo está); cerrar invalida las solicitudes pendientes y cancela los contactos no resueltos.
- Nombre
channels- Tipo
- string[]
- Descripción
emaily/owhatsapp. No hay canal impreso: los formularios en papel son un respaldo manual (manualFallback) con su propio PDF enGET /consent-campaigns/:id/print-forms.
- Nombre
endsAt- Tipo
- timestamp | null
- Descripción
Expiración de la campaña; debe estar en el futuro al crearla. Al vencer, las solicitudes sin decisión pasan a
expired.
- Nombre
campaignMode- Tipo
- string
- Descripción
targeted(audiencia definida por el colegio) opublic(registro abierto con revisión posterior del personal).
- Nombre
dispatchMode- Tipo
- string
- Descripción
bulk(despacho masivo al publicar) oper_subject(sobres despachados uno a uno).
- Nombre
redirectMode- Tipo
- string
- Descripción
autoobridge; junto condefaultSuccessRedirectUrlydefaultDeclineRedirectUrlcontrola a dónde vuelve el apoderado. Los destinos deben pertenecer a un origen de redirección autorizado.
Listar campañas
Requiere consents.read. Cada campaña llega con sus estadísticas (stats) calculadas: el embudo completo desde pending hasta granted/denied, tasa de completitud y desglose por canal. Pagina con limit y cursor.
Solicitud
curl -G "https://app.edugoverna.com/api/consent-campaigns" \
-H "x-api-key: {tu_api_key}" \
-d limit=25
Respuesta (recortada)
{
"consentCampaigns": [
{
"id": "c81d…",
"name": "Salida pedagógica agosto",
"status": "published",
"campaignMode": "targeted",
"dispatchMode": "bulk",
"channels": ["email", "whatsapp"],
"endsAt": "2026-09-10T03:59:59.000Z",
"publishedAt": "2026-08-20T13:00:00.000Z",
"closedAt": null,
"publicUrl": null,
"processingActivity": {
"processingActivityId": "a2f1…",
"activityCode": "ACT-004",
"activityName": "Comunicaciones académicas",
"versionTitle": "v2 · salidas pedagógicas",
"versionNumber": 2
},
"stats": {
"total": 182,
"pending": 4,
"sent": 170,
"opened": 121,
"completed": 96,
"granted": 88,
"denied": 8,
"revoked": 0,
"expired": 0,
"failed": 2,
"errored": 2,
"completionRate": 0.53,
"channelBreakdown": { "email": 150, "whatsapp": 32 }
}
// …
}
],
"meta": {
"totalMatchedCount": 12,
"limit": 25,
"returnedCount": 12,
"nextCursor": null,
"hasMore": false
}
}
Crear una campaña
Requiere consents.write. Si defines la audiencia por Generaciones, Cursos o estudiantes individuales, la llamada exige además students.read; si usas padrones compartidos (sharedAudience), shared_campaigns.write. La campaña nace en draft; publicarla es un paso aparte.
Atributos requeridos
- Nombre
processingActivityVersionId- Tipo
- string
- Descripción
La versión de la actividad de tratamiento cuyo consentimiento se pide. Si esa versión es de modelo granular, las opciones de consentimiento vienen de ella — la campaña no las define.
- Nombre
name- Tipo
- string
- Descripción
Nombre de la campaña (2 a 160 caracteres).
Atributos opcionales frecuentes
- Nombre
channels- Tipo
- string[]
- Descripción
["email"]por defecto; hasta 2 (email,whatsapp).
- Nombre
endsAt- Tipo
- timestamp
- Descripción
Expiración, en el futuro.
- Nombre
audience- Tipo
- object
- Descripción
{ cohortIds, segmentIds, studentSubjectIds }— Generaciones, Cursos o estudiantes puntuales (hasta 1000).
- Nombre
reminderDayOffsets- Tipo
- integer[]
- Descripción
Hasta 3 recordatorios, en días crecientes (1 a 30).
[]los apaga.
- Nombre
dispatchMode- Tipo
- string
- Descripción
bulkoper_subject.
- Nombre
sharedAudience- Tipo
- object
- Descripción
{ shareIds }para campañas sobre padrones compartidos.
- Nombre
id- Tipo
- string
- Descripción
UUID generado por el cliente: hace idempotente el envío repetido.
Solicitud
curl -X POST "https://app.edugoverna.com/api/consent-campaigns" \
-H "x-api-key: {tu_api_key}" \
-H "Content-Type: application/json" \
-d '{
"processingActivityVersionId": "9d4e…",
"name": "Salida pedagógica agosto",
"channels": ["email", "whatsapp"],
"endsAt": "2026-09-10T03:59:59.000Z",
"audience": { "segmentIds": ["5b2c…"] }
}'
Respuesta · 201 (recortada)
{
"consentCampaign": {
"id": "c81d…",
"name": "Salida pedagógica agosto",
"status": "draft",
"channels": ["email", "whatsapp"],
"endsAt": "2026-09-10T03:59:59.000Z",
"stats": { "total": 0, "pending": 0, "completed": 0 }
// …
}
}
Detalle y operación de la campaña
GET /consent-campaigns/:campaignId (con consents.read) devuelve consentCampaign, processingActivity, los contacts paginados (cada uno con su solicitud, entregas y última decisión), outcomes (decisiones agrupadas), coverage (cuántos estudiantes son alcanzables y por qué no los demás) y pendingVerificationCount para el modo público. El resto de la operación:
| Método y ruta | Permiso | Qué hace |
|---|---|---|
POST /consent-campaigns/:id/publish | consents.write | Publica: draft → published y despacha según dispatchMode. |
PATCH /consent-campaigns/:id | consents.write | Edita la campaña en borrador. |
GET /consent-campaigns/:id/coverage | consents.read | Cobertura de audiencia sin abrir el detalle. |
POST /consent-campaigns/audience-coverage | consents.read | Simula la cobertura de una audiencia antes de crear. |
POST /consent-campaigns/:id/resend-pending | consents.write | Reenvía a todos los pendientes. |
POST /consent-campaigns/:id/contacts/:contactId/resend | consents.write | Reenvía a un contacto puntual. |
POST /consent-campaigns/:id/process-error-contacts | consents.write | Reprocesa contactos con datos de contacto erróneos. |
POST /consent-campaigns/:id/contacts/:contactId/verify | consents.write | Aprueba un registro público pendiente de revisión. |
POST /consent-campaigns/:id/contacts/:contactId/reject | consents.write | Rechaza un registro público (cascada sobre lo acuñado). |
POST /consent-campaigns/:id/envelopes | consents.write | Despacha sobres (modo per_subject / compartidas). |
POST /consent-campaigns/:id/sync-audience | consents.write | Resincroniza la audiencia con el padrón compartido. |
POST /consent-campaigns/:id/redirects | consents.write | Carga redirects explícitos por RUT. |
POST /consent-campaigns/redirect-pairs/parse | consents.write | Parsea un archivo de pares RUT → URL antes de cargarlo. |
GET /consent-campaigns/:id/print-forms | consents.read | PDF con los formularios impresos del respaldo manual. |
POST /consent-campaigns/:id/close | consents.write | Cierra: responde los contadores invalidatedRequestCount y cancelledContactCount. |
Listar solicitudes de consentimiento
Requiere consents.read. Cada elemento es la solicitud completa: estado, entregas por canal, última decisión con sus opciones y evidencia referenciada, y el resumen del titular bajo la proyección de contacto que tu key permita (subjectContactProjection: none, masked o full).
Parámetros opcionales
- Nombre
scope- Tipo
- string
- Descripción
activas,por-expirar,otorgadas,denegadas,revocadas,expiradasorecaptura.
- Nombre
subjectId- Tipo
- string
- Descripción
Todas las solicitudes de un titular.
- Nombre
q- Tipo
- string
- Descripción
Búsqueda (hasta 120 caracteres).
- Nombre
counts- Tipo
- string
- Descripción
counts=1agregameta.scopeCountscon los contadores por alcance.
- Nombre
sort / dir / limit / cursor- Tipo
- varios
- Descripción
sort:solicitada,estado,vence.limitpor defecto 100, máximo 250.
Solicitud
curl -G "https://app.edugoverna.com/api/consents/requests" \
-H "x-api-key: {tu_api_key}" \
-d scope=otorgadas -d counts=1
Respuesta (recortada)
{
"consentRequests": [
{
"id": "b9d2…",
"status": "granted",
"requestedAt": "2026-08-20T13:05:00.000Z",
"expiresAt": "2026-09-10T03:59:59.000Z",
"consentCampaignId": "c81d…",
"processingActivityTitle": "Comunicaciones académicas",
"subjectContactProjection": "masked",
"targetSubjectSummary": {
"id": "3f6f…",
"subjectType": "student",
"referenceCode": "EST-2026-0412",
"currentAgeBand": "minor_14_17",
"displayName": "Martina Rojas",
"primaryContact": {
"contactType": "email",
"value": null,
"maskedValue": "m***@example.cl"
}
},
"deliveries": [
{ "channel": "email", "status": "opened", "sentAt": "2026-08-20T13:06:00.000Z" }
],
"latestDecision": {
"decision": "granted",
"options": null,
"evidence": [
{ "evidenceType": "sealed_manifest", "checksum": "e4a6acc35331fc53" }
]
}
// …
}
],
"meta": {
"totalMatchedCount": 96,
"limit": 100,
"returnedCount": 96,
"hasMore": false,
"nextCursor": null
}
}
El detalle (GET /consents/requests/:consentRequestId) devuelve el mismo cuerpo aplanado más consentModel (bundled o granular) y versionConsentOptions — las opciones granulares definidas por la versión de la actividad. GET /consents/requests/:id/print-form entrega el formulario individual en PDF.
Evidencia de consentimiento
Requiere consents.read. Una fila por artefacto de evidencia: manifiestos sellados, certificados de recibo y documentos de firma manual, cada uno con su checksum. La búsqueda q cruza checksum, ids y actividad — nunca datos de personas.
Parámetros opcionales
- Nombre
tipo- Tipo
- string
- Descripción
Filtra por
evidenceType(p. ej.sealed_manifest,receipt_certificate,receipt_certificate_pdf,manual_signature_document).
- Nombre
decision- Tipo
- string
- Descripción
grantedodenied.
- Nombre
limit / offset- Tipo
- integer
- Descripción
Por defecto 25, máximo 100.
La descarga de los bytes
(GET /consents/evidence/:artifactId/download) es sólo disponible con
sesión de la consola (permiso consent_evidence.download): la API
entrega el índice y los checksums, no el contenido.
Solicitud
curl -G "https://app.edugoverna.com/api/consents/evidence" \
-H "x-api-key: {tu_api_key}" \
-d tipo=sealed_manifest
Respuesta (recortada)
{
"consentEvidence": [
{
"id": "ev01…",
"evidenceType": "sealed_manifest",
"checksum": "e4a6acc35331fc53",
"capturedAt": "2026-08-21T02:11:09.000Z",
"artifactId": "ar77…",
"decision": "granted",
"consentRequestId": "b9d2…",
"requestStatus": "granted",
"processingActivityTitle": "Comunicaciones académicas",
"targetSubjectSummary": { "referenceCode": "EST-901" },
"sourceOrganization": null
}
],
"meta": {
"totalMatchedCount": 3,
"limit": 25,
"offset": 0,
"returnedCount": 3,
"typeCounts": { "sealed_manifest": 1, "receipt_certificate": 1, "manual_signature_document": 1 },
"totalCount": 3
}
}
Solicitudes sueltas y recaptura
| Método y ruta | Permiso | Qué hace |
|---|---|---|
POST /consents/requests | consents.write | Crea una solicitud individual fuera de campaña. |
POST /consents/recapture | consents.write | Al publicar una versión nueva de la actividad, acuña solicitudes de recaptura: processingActivityVersionId requerido, targetSubjectIds opcional (omitido = todos los titulares con consentimiento de versiones anteriores). Responde { consentRequests }. |
POST /consents/deliveries/:consentDeliveryId/status | consents.write | Actualiza el estado de una entrega (queued, sent, delivered, opened, failed). |
Sólo disponible con sesión de la consola: el registro manual de una
decisión (POST /consents/requests/:id/decisions, permiso
consents.record.manual), la subida de evidencia firmada (POST /consents/requests/:id/evidence-uploads) y la revocación administrativa
(POST /consents/requests/:id/revoke). Registrar a mano lo que un apoderado
decidió exige una persona identificable detrás.