Docs

Registrar y consultar el consentimiento

POST /v1/consent, lote, idempotencia y lectura de estado e historial.

Este es el endpoint que llama tu banner o tu backend en el momento en que alguien toma una decisión: regístrala una vez y Croombit guarda en bóveda la versión exacta de la cláusula que vio, además de devolverte un justificante firmado al que puedes señalar como prueba.

Registrar

POST /v1/consent
Authorization: Bearer sk_live_…
Idempotency-Key: 4b0f…

{
  "subject": "email:user@example.com",
  "purpose": "marketing_email",
  "state": "GRANTED",
  "channel": "banner",
  "locale": "es",
  "pageUrl": "https://acme.com/signup"
}

El subject puede ser un id interno, <tipo>:<valor> o un objeto { "identifiers": [{ "type", "value" }] } para crear el sujeto si no existe. state solo puede ser GRANTED, DENIED o WITHDRAWN.

Respuesta 201: { id, subjectId, subjectCreated, purpose, state, purposeVersion, source, collectedAt, expiresAt, receiptId }. Campos opcionales del cuerpo: channel, locale, country, pageUrl, collectedAt, expiresAt, metadata (cualquier objeto JSON tuyo) y source (más abajo).

Lote

POST /v1/consent/batch con { "records": [ … ] } (máx. 100). Emite un justificante por sujeto que cubre todos sus registros del lote.

Quién actuó: source

Cada registro lleva un source. Es la diferencia entre «la persona aceptó» y «lo afirmamos nosotros», y quien lea la bóveda puede verla:

`source`SignificadoQuién puede escribirlo
API (por defecto)Actuó el sujeto: el banner, el centro de preferencias o tu aplicación en su nombre.Cualquier clave
IMPORTLo afirmas tú, como responsable: una importación de contactos, una anotación del personal. El sujeto no hizo nada.Solo sk_
MIGRATIONTraído desde un sistema anterior.Solo sk_
CONSOLEEscrito por el propio sistema, por ejemplo una política de caducidad que pasa una concesión a EXPIRED. Tú nunca lo envías.La plataforma

Una clave pk_ que envíe IMPORT o MIGRATION recibe 403 secret_key_required: una clave pública solo puede escribir lo que hizo un sujeto. El origen vuelve en la respuesta de escritura, en cada fila del historial, como recordedVia al leer el estado y en los webhooks consent.* (data.source). También queda firmado en el justificante: collection.method es api, import o migration. En un lote, el justificante de un sujeto dice import / migration solo si ninguno de sus registros del lote es del propio sujeto.

La `legalBasis` de un propósito (CONSENT, LEGITIMATE_INTEREST, CONTRACT, LEGAL_OBLIGATION, VITAL_INTEREST, PUBLIC_TASK) dice por qué puedes tratar los datos. El `state` de un registro dice qué se registró. Son campos distintos, y el defaultState de un propósito (NOT_GIVEN, GRANTED o DENIED: lo que lee alguien sin registro) es un tercer ajuste propio: no se deriva de la base legal. Un GRANTED escrito con source: "API" significa que actuó el sujeto; un GRANTED escrito con source: "IMPORT" significa que lo afirmas tú.

Para cargar contactos que ya tienes bajo una base distinta del consentimiento —por ejemplo, clientes existentes bajo un contrato—:

  1. Crea un propósito cuya legalBasis sea esa base (CONTRACT), por ejemplo order_updates, y publícalo.
  2. Escribe cada contacto con source: "IMPORT" y tu propio metadata (el lote de importación, la referencia del contrato) para poder acreditar la base más adelante.
  3. Léelos con recordedVia (estado) o source (historial) para distinguirlos de quienes dieron su consentimiento por sí mismos.
POST /v1/consent/batch
Authorization: Bearer sk_live_…

{ "records": [
  { "subject": "email:ana@example.com", "purpose": "order_updates", "state": "GRANTED",
    "source": "IMPORT", "channel": "crm_import",
    "metadata": { "importBatch": "2026-09-crm", "contractRef": "C-10482" } }
] }
Cada contacto sigue necesitando un identificador (email:, external_id:…): consulta Sujetos e identificadores. El defaultState no sustituye a los registros: cambia lo que lee una persona sin registro, pero no deja prueba individual.

Leer el estado

GET /v1/subjects/email:user@example.com/consent?purpose=marketing_email
→ { "subjectId": "…", "purposes": {
     "marketing_email": { "state": "GRANTED", "purposeVersion": 3,
       "needsReconsent": false, "latestPurposeVersion": 3,
       "legalBasis": "CONSENT", "recordedVia": "API" } } }

Los propósitos publicados sin registro para el sujeto aparecen con su defaultState y source: "default". Todos los propósitos llevan su legalBasis; recordedVia (API, IMPORT, MIGRATION o CONSOLE) indica cómo entró el último registro. needsReconsent es true si la versión guardada va por detrás de una versión posterior publicada como RECONSENT_REQUIRED, o si el registro ha caducado.

Historial

GET /v1/subjects/{ref}/consent/history?purpose= (solo sk_) devuelve hasta 500 filas de solo anexión, de la más reciente a la más antigua. Cada fila trae purposeKey, purposeVersion, state, source, channel, locale, pageUrl, collectedAt, expiresAt, tu metadata, su proof (el hash de la cláusula exacta con la que se registró) y la cadena supersedesId. Un mapa legalBasis de nivel superior da la base de cada propósito. No se devuelven direcciones IP ni user agents. El historial puede incluir filas EXPIRED escritas por el sistema (source: "CONSOLE"). Para mostrarlo a la persona a quien pertenece, consulta Guía: mostrar a un usuario su propio historial.