Referencia del API
API de Safe Creative Platform · versión 1.0-draft · Probar el API en el playground
Generada automáticamente del contrato OpenAPI del API. openapi.yaml
Registro de eventos con evidencias de confianza cualificada, operado por Safe Creative como tercero de confianza independiente.
Qué certifica el servicio: que se recibió una declaración, cuándo exactamente y que no se ha alterado desde entonces; nunca la veracidad del hecho declarado.
URL base: https://platform.safecreative.org/v1.
Modos: toda clave de API es live (sc_live_…) o test (sc_test_…). Las claves test usan
los mismos endpoints con el mismo contrato, no consumen saldo, no tienen valor probatorio y
escriben en una cadena separada por canal. El modo test tiene límites diarios por cuenta (UTC):
10.000 eventos, 100 MB de contenido declarado y 20 certificaciones, de 10.000 eventos como máximo cada
una; superado un límite diario, el API responde 429 test_quota_exceeded con Retry-After hasta el día siguiente.
Convenciones
- Límite de peticiones por clave de API: 50 peticiones/s sostenidas con claves live (ráfagas ×4;
una cuenta puede tener su propio límite) y 10 peticiones/s con claves test. Toda respuesta lleva
RateLimit-Limit,RateLimit-RemainingyRateLimit-Reset(segundos); un429 rate_limitedañadeRetry-After. - Indisponibilidad temporal: un evento solo se acusa cuando está guardado de forma durable y replicada. Ante un
fallo pasajero del almacenamiento cualquier operación puede responder
503 temporarily_unavailableconRetry-After: reintenta, con el mismoclient_refsi registras eventos. - Idioma: el
messagede los errores va en inglés por defecto y en español conAccept-Language: es. - Escenarios de prueba forzados: con una clave test,
X-SC-Test-Scenario: unpaid | unpaid_limit | rate_limitedreproduce las respuestas 402/429 documentadas sin tocar el estado real. - Firma de los webhooks: ver
WebhookEnvelope.
Formatos
- Fechas en respuestas y webhooks: UTC, RFC 3339 con el sufijo
Zy exactamente seis decimales (microsegundos, la precisión con que se guardan), p. ej.2026-09-28T07:00:16.526317Z. El acuse dePOST /eventsdevuelvereceived_atexactamente como queda registrado y como se certificará. - Fechas en peticiones (
occurred_at, rangos de certificación, filtros de consulta): cualquier fecha RFC 3339 con desfase (Zo±hh:mm) y hasta nueve decimales; se normalizan a UTC y se truncan a microsegundos. - Huellas: hexadecimal en minúsculas. Créditos y números de secuencia: enteros.
Operaciones
- POST /events — Declarar (registrar) un evento
- GET /events — Listar los eventos del canal
- GET /events/{event_id} — Obtener un evento con todos sus elementos de prueba
- GET /events/{event_id}/content — Descargar el contenido custodiado de un evento
- GET /channel — Obtener el canal y las versiones de su configuración sellada
- GET /account/balance — Saldo y estado operativo de la cuenta titular del canal
- POST /certifications — Solicitar la certificación de un rango (asíncrona)
- GET /certifications — Listar las certificaciones del canal
- GET /certifications/{certification_id} — Obtener el estado de una certificación y sus enlaces de descarga
Webhooks
- certification.completed — Una certificación solicitada ha terminado correctamente.
- certification.failed — Una certificación solicitada ha fallado (incluye un identificador de incidencia).
- balance.low — El saldo ha bajado de un umbral definido por el usuario.
- balance.exhausted — Primer evento impagado registrado (el saldo ha llegado a cero).
- events.unpaid_limit_reached — Límite de impagados alcanzado; ahora se rechazan los registros.
- consumption.limit_reached — Se ha alcanzado un límite de consumo definido por el usuario.
- recharge.auto_completed — Se ha cobrado una recarga automática y sus créditos ya están en el saldo.
- recharge.auto_failed — Una recarga automática ha fallado y la recarga automática se ha desactivado.
- webhook.test — Entrega de prueba pedida desde la consola.
POST /events Declarar (registrar) un evento Probar
Registra un evento declarado en el canal que identifica la clave de API. El acuse síncrono es el justificante del cliente: fija la posición del evento en la secuencia del canal.
Idempotencia: client_ref debe ser único por canal. Reintentar con el mismo
client_ref y el mismo contenido devuelve 200 con el evento original; el mismo
client_ref con contenido distinto devuelve 409 y nunca sobrescribe.
Saldo agotado: los eventos se siguen registrando, sellando y encadenando con
status: unpaid, hasta el límite de impagados de la cuenta; superado, 402 unpaid_limit_exceeded.
Cuerpo
- application/json: NewEventContent | NewEventHashOnly (uno de estos esquemas)
- multipart/form-data: NewEventFile
Respuestas
| 201 | Evento registrado (nuevo). | Event |
| 200 | Reintento idempotente: mismo client_ref y mismo contenido; se devuelve el evento original. | Event |
| 400 | Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error). | Error |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 402 | Límite de impagados alcanzado (unpaid_limit_exceeded). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 409 | client_ref ya usado en este canal con otro contenido (client_ref_conflict). | Error |
| 413 | Cuerpo por encima del límite de la modalidad (payload_too_large). | Error |
| 422 | Bloqueado por un límite de consumo del usuario con la acción «bloquear» (limit_blocked). | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
| 503 | No disponible temporalmente (temporarily_unavailable): un fallo pasajero del almacenamiento, p. ej. durante un failover de la
base de datos. No se ha acusado nada: reintenta pasado Retry-After con el mismo client_ref, que la idempotencia resuelve. | Error |
GET /events Listar los eventos del canal Probar
Parámetros
| from | query | Límite inferior de la recepción (incluido). Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
| to | query | Límite superior de la recepción (excluido). Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
| seq_from | query | |
| seq_to | query | |
| status | query | |
| limit | query | |
| cursor | query | Cursor opaco de paginación. |
Respuestas
| 200 | Lista paginada de eventos, por orden de secuencia. | application/json |
| 400 | Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error). | Error |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
GET /events/{event_id} Obtener un evento con todos sus elementos de prueba Probar
Parámetros
| event_id | path · obligatorio |
Respuestas
| 200 | El evento. | Event |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 404 | No existe en este canal (not_found). | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
GET /events/{event_id}/content Descargar el contenido custodiado de un evento Probar
Solo en la modalidad contenido (modality: content): devuelve el contenido declarado tal
como lo custodia Safe Creative: el JSON en su forma canónica, la que se usó para la huella, o
el fichero, con su nombre original en Content-Disposition. Su huella es el hash del evento.
Un evento de solo huella no tiene contenido: 404 not_found.
Parámetros
| event_id | path · obligatorio |
Respuestas
| 200 | El contenido: application/json si es JSON, application/octet-stream si es un fichero. | application/json | application/octet-stream |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 404 | No existe en este canal (not_found). | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
GET /channel Obtener el canal y las versiones de su configuración sellada Probar
Respuestas
| 200 | El canal con su configuración vigente y el historial de versiones. | Channel |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
GET /account/balance Saldo y estado operativo de la cuenta titular del canal Probar
Permite a los sistemas del cliente vigilarse solos (saldo bajo, impagados, estado operativo).
Respuestas
| 200 | Estado del saldo. | AccountBalance |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
POST /certifications Solicitar la certificación de un rango (asíncrona) Probar
Inicia la emisión de los informes de certificación firmados (uno en español y otro en inglés) y de su archivo de evidencias para un rango de este canal, por fechas o por números de secuencia.
Se rechaza con 402 account_not_operational mientras la cuenta titular tenga algún evento
impagado («cuenta sin saldo operativo»).
Cuerpo
- application/json: NewCertification
Respuestas
| 202 | Aceptada; la emisión se hace de forma asíncrona. | Certification |
| 400 | Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error). | Error |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 402 | account_not_operational (hay impagados o saldo negativo) o insufficient_balance (precio de emisión, si lo hay). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
| 503 | No disponible temporalmente (temporarily_unavailable): un fallo pasajero del almacenamiento, p. ej. durante un failover de la
base de datos. No se ha acusado nada: reintenta pasado Retry-After con el mismo client_ref, que la idempotencia resuelve. | Error |
GET /certifications Listar las certificaciones del canal Probar
Parámetros
| status | query | |
| limit | query | |
| cursor | query |
Respuestas
| 200 | Lista paginada, las más recientes primero. | application/json |
| 400 | Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error). | Error |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
GET /certifications/{certification_id} Obtener el estado de una certificación y sus enlaces de descarga Probar
Parámetros
| certification_id | path · obligatorio |
Respuestas
| 200 | La certificación. Cuando está completed, incluye las URL de descarga (informes PDF y
ZIP de evidencias; caducan a los 7 días y se renuevan volviendo a consultarla) y el
código de verificación pública. | Certification |
| 401 | Clave ausente, no válida o revocada (invalid_key / revoked_key). | Error |
| 403 | Canal o cuenta titular suspendidos por Safe Creative (suspended: se rechazan el registro de eventos y las certificaciones), o cuenta titular desactivada (account_disabled: se rechazan todas las llamadas; las cuentas se desactivan tras un año sin registrar eventos, pedir certificaciones ni comprar créditos, y el soporte las reactiva). Los datos y las cadenas no se tocan. | Error |
| 404 | No existe en este canal (not_found). | Error |
| 429 | Límite de peticiones superado (rate_limited) o, con una clave test, límite diario del modo test alcanzado (test_quota_exceeded); incluye Retry-After. | Error |
Webhooks
Avisos que la plataforma envía por POST a los endpoints que configures en la consola. Todos comparten el sobre WebhookEnvelope.
POST certification.completed Una certificación solicitada ha terminado correctamente.
La certificación está completed: los informes, el ZIP de evidencias y el código de verificación están listos. Trae
data.verification_code; consulta GET /certifications/{certification_id} para obtener URL de descarga vigentes. mode es el de la certificación.
data: WebhookCertificationData
POST certification.failed Una certificación solicitada ha fallado (incluye un identificador de incidencia).
No se ha podido emitir la certificación (status: failed): se devuelve el precio de emisión, si lo hubo, y data.incident_id
identifica la incidencia para soporte. Se puede volver a solicitar el mismo rango. mode es el de la certificación.
data: WebhookCertificationData
POST balance.low El saldo ha bajado de un umbral definido por el usuario.
Se envía una vez por cada cruce a la baja de cada umbral de aviso definido en la consola; el umbral se rearma cuando una
compra o un ajuste devuelven el saldo por encima. Siempre live.
data: WebhookBalanceLowData
POST balance.exhausted Primer evento impagado registrado (el saldo ha llegado a cero).
El saldo se ha agotado y un evento ha quedado registrado como unpaid (sigue sellado y encadenado). Desde ahora las
certificaciones se rechazan con 402 account_not_operational hasta que una compra liquide los impagados. Se envía una vez por agotamiento. Siempre live.
POST events.unpaid_limit_reached Límite de impagados alcanzado; ahora se rechazan los registros.
La cuenta ha alcanzado su límite de impagados: desde ahora POST /events responde 402 unpaid_limit_exceeded hasta que
una compra liquide la deuda. Siempre live.
data: WebhookUnpaidLimitData
POST consumption.limit_reached Se ha alcanzado un límite de consumo definido por el usuario.
Un límite de consumo definido en la consola (por canal o por clave, diario o mensual en UTC) ha llegado a su máximo. Con la
acción block, los registros siguientes responden 422 limit_blocked hasta el periodo siguiente; con warn, siguen entrando. Se
envía una vez por límite y periodo. Los eventos test no cuentan. Siempre live.
POST recharge.auto_completed Se ha cobrado una recarga automática y sus créditos ya están en el saldo.
El saldo ha bajado del umbral de recarga automática configurado en la consola y se ha comprado el pack elegido con el
medio de pago por defecto en Safe Creative; sus créditos ya están en el saldo (después de liquidar los impagados, si los
había). Safe Creative envía la factura. Siempre live.
data: WebhookAutoRechargeData
POST recharge.auto_failed Una recarga automática ha fallado y la recarga automática se ha desactivado.
No se ha podido hacer la recarga automática (data.reason) y se ha desactivado conservando su configuración: se puede
volver a activar en la consola. Si la compra se creó pero no se cobró, data.payment_url permite pagarla a mano.
Siempre live.
data: WebhookAutoRechargeData
POST webhook.test Entrega de prueba pedida desde la consola.
Solo se envía cuando el titular de la cuenta pide desde la consola una entrega de prueba a un endpoint: un único intento,
sin reintentos, y nunca cuenta para desactivar el endpoint. Siempre live.
data: WebhookTestData
Esquemas
NewEventContent
Modalidad contenido: token JSON generado por el proceso del cliente.
| Campo | Tipo | |
|---|---|---|
| client_ref * | string | Identificador único del evento en el sistema emisor (clave de idempotencia por canal). |
| payload * | object | El contenido declarado (JSON). Cuerpo de 256 KB como máximo. |
| occurred_at | string (date-time) | Cuándo declara el emisor que ocurrió el hecho. Forma parte de la declaración: Safe
Creative acredita la hora de recepción, no este valor. Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
NewEventHashOnly
Modalidad solo-huella: el contenido nunca sale del perímetro del cliente.
| Campo | Tipo | |
|---|---|---|
| client_ref * | string | |
| hash * | string | Huella en hexadecimal del contenido que custodia el cliente. |
| hash_alg * | string: sha-256 · sha-512 | |
| occurred_at | string (date-time) | Cuándo declara el emisor que ocurrió el hecho. Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
NewEventFile
Modalidad contenido: fichero adjunto. 10 MB como máximo.
| Campo | Tipo | |
|---|---|---|
| client_ref * | string | |
| file * | string (binary) | |
| occurred_at | string (date-time) | Cuándo declara el emisor que ocurrió el hecho. Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
Event
| Campo | Tipo | |
|---|---|---|
| event_id * | string | |
| channel_id * | string | |
| client_ref * | string | |
| sequence * | integer | Estrictamente creciente y sin huecos, por canal (por cadena en modo test). |
| received_at * | string (date-time) | Hora de recepción en el servicio: la que acreditan las evidencias. UTC, microsegundos (ver Formatos). |
| occurred_at | string | null (date-time) | Declarada por el emisor; Safe Creative no la acredita. Se devuelve en UTC, microsegundos (ver Formatos). |
| hash * | string | Huella del contenido (o la huella declarada por el cliente en la modalidad solo-huella). |
| hash_alg | string | |
| modality * | string: content · hash_only | content = Safe Creative custodia el JSON o el fichero declarado, que se descarga con
GET /events/{event_id}/content; hash_only = solo se declaró la huella. |
| chain_hash * | string | Huella encadenada que une este evento con el anterior del canal. |
| status * | string: registered · unpaid · test | unpaid = registrado y sellado, pendiente de pago; bloquea las certificaciones de toda la cuenta. |
| timestamp | EventTimestamp | Cobertura de este evento por un sello de tiempo cualificado. |
| config_version * | integer | Versión de la configuración del canal vigente en la recepción. |
| mode * | string: live · test |
EventTimestamp
Cobertura de un evento por un sello de tiempo cualificado (Event.timestamp).
| Campo | Tipo | |
|---|---|---|
| type * | string: individual · batch · pending · simulated | batch = probado por su inclusión en un tramo sellado de la cadena del canal (la política de sellado en uso); pending = dentro de la ventana de sellado; simulated = modo test. individual = sello de tiempo cualificado propio: reservado, hoy no se produce (todo evento live se prueba con el tramo sellado de su canal); se mantiene para poder ofrecer el sellado individual sin romper el contrato. Los clientes deben aceptarlo. |
| reference | string | null | Referencia del sello o del tramo sellado una vez consolidado (seg_… para un tramo sellado). |
| sealed_at | string | null (date-time) | Cuándo se obtuvo el sello que lo cubre. UTC, microsegundos (ver Formatos). |
Channel
| Campo | Tipo | |
|---|---|---|
| channel_id * | string | |
| name * | string | |
| mode_note * | string | Recordatorio de que las cadenas live y test son distintas. |
| current_config * | ChannelConfig | |
| config_versions * | ChannelConfig[] |
ChannelConfig
Una versión de la configuración, sellada e inmutable. Los cambios crean versiones nuevas; ninguna se reescribe.
| Campo | Tipo | |
|---|---|---|
| version * | integer | |
| sealed_at * | string (date-time) | Cuándo se selló esta versión de la configuración (compromiso previo a los hechos). UTC, microsegundos (ver Formatos). |
| modality * | string: content · hash_only | |
| name | string | |
| description | string | |
| declarant * | string | Persona o entidad en cuyo nombre se declaran los eventos y se solicitan las certificaciones. Los informes la presentan como declaración del titular del canal; Safe Creative no la verifica. |
| supplementary_info | string | null | Texto opcional del cliente que explica qué significan los datos declarados. |
NewCertification
Rango por fechas o por números de secuencia (exactamente un par).
| Campo | Tipo | |
|---|---|---|
| from | string (date-time) | Inicio del rango de recepción, incluido. Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
| to | string (date-time) | Fin del rango de recepción, excluido; un valor futuro se recorta al momento de la solicitud. Fecha RFC 3339 con desfase (Z o ±hh:mm); se normaliza a UTC y se trunca a microsegundos (ver Formatos). |
| seq_from | integer | Primer número de secuencia, incluido. |
| seq_to | integer | Último número de secuencia, incluido. |
Certification
| Campo | Tipo | |
|---|---|---|
| certification_id * | string | |
| channel_id * | string | |
| status * | string: processing · completed · failed | |
| progress | number | null | Progreso aproximado (0–1) mientras se procesa. |
| requested_at * | string (date-time) | Cuándo se aceptó la solicitud. UTC, microsegundos (ver Formatos). |
| completed_at | string | null (date-time) | Cuándo se emitió la certificación (la fecha de emisión impresa en los informes) o cuándo falló. UTC (ver Formatos). |
| range * | CertificationRange | El rango tal como se solicitó. Al aceptarlo se resuelve y se congela en números de secuencia de la cadena. |
| event_count | integer | null | |
| config_versions_in_range | integer[] | |
| report_url | string | null | Descarga del informe PDF firmado en el idioma de la petición (Accept-Language: español o
inglés, inglés por defecto); URL con caducidad. reports da los dos idiomas. |
| reports | CertificationReport[] | Los informes PDF firmados: uno en español y otro en inglés, firmados por separado, con el mismo
código de verificación y el mismo archivo de evidencias. Los dos son igual de auténticos y cada uno
se verifica por sí solo. Las certificaciones anteriores pueden tener un único informe bilingüe
(languages: [es, en]). Vacío mientras se procesa. |
| evidence_url | string | null | Descarga del ZIP de evidencias (URL con caducidad). |
| verification_code | string | null | Código para la página de verificación pública. |
| mode * | string: live · test | |
| content_parts | ContentPart[] | Modalidad contenido: el contenido declarado, en partes ZIP de hasta 1 GB que figuran
con su SHA-256 en el manifiesto de evidencias y en los informes (URL con caducidad, como
report_url). Vacío en canales solo-huella y mientras se procesa. |
CertificationReport
Un informe PDF firmado de una certificación (Certification.reports).
| Campo | Tipo | |
|---|---|---|
| languages * | string[] | Idioma del informe, [es] o [en]; los dos en el informe bilingüe de certificaciones anteriores. |
| url * | string | URL de descarga (con caducidad, como report_url). |
| sha256 * | string | SHA-256 del PDF firmado, en hexadecimal en minúsculas; la página de verificación pública lo reconoce. |
CertificationRange
Rango de una certificación (Certification.range), tal como se solicitó: tiene exactamente un par, las fechas
de recepción (from, to) o los números de secuencia (seq_from, seq_to); el otro par es nulo.
| Campo | Tipo | |
|---|---|---|
| from | string | null (date-time) | Inicio del rango de recepción, incluido. UTC, microsegundos (ver Formatos). |
| to | string | null (date-time) | Fin del rango de recepción, excluido; un to futuro se recorta al momento de la solicitud. UTC, microsegundos. |
| seq_from | integer | null | Primer número de secuencia, incluido. |
| seq_to | integer | null | Último número de secuencia, incluido. |
ContentPart
Una parte ZIP del contenido declarado de una certificación (Certification.content_parts).
| Campo | Tipo | |
|---|---|---|
| name * | string | Nombre del fichero, content-part-NNN.zip. |
| url * | string | URL de descarga (con caducidad, como report_url). |
| sha256 * | string | SHA-256 de la parte, en hexadecimal en minúsculas; figura también en el manifiesto de evidencias y en los informes. |
| bytes * | integer | Tamaño de la parte en bytes. |
AccountBalance
Saldo en créditos. Cada evento live consume un crédito; los créditos se compran en packs en la consola, con precio por región y moneda. El saldo en sí no tiene moneda.
| Campo | Tipo | |
|---|---|---|
| balance * | integer | Créditos disponibles. Solo es negativo si una compra se anula después de gastar sus créditos. |
| operational * | boolean | false mientras la cuenta tenga eventos impagados o saldo negativo («cuenta sin saldo operativo»). |
| unpaid_events * | integer | Eventos live registrados sin créditos y aún sin liquidar (un crédito cada uno). |
WebhookEnvelope
Cuerpo común de los webhooks, enviado como POST con Content-Type: application/json. Cabeceras:
X-SC-Webhook-Id (el id del sobre, igual en todos los reintentos: úsalo para deduplicar),
X-SC-Timestamp (segundos Unix) y X-SC-Signature: v1=<hex>, donde <hex> es
HMAC-SHA256 con el secreto del endpoint sobre <X-SC-Timestamp>.<raw body> (el cuerpo tal cual). Verifica la
firma y rechaza marcas de tiempo antiguas (p. ej. de más de 5 minutos) antes de procesarlo. Cualquier 2xx
confirma la recepción; si no, se reintenta con retroceso exponencial (1 min, 5 min, 30 min, 2 h, 6 h,
12 h, 24 h). Un endpoint cuyas entregas siguen fallando se desactiva y se avisa a la cuenta por
correo. webhook.test solo se envía cuando el titular de la cuenta pide una entrega de prueba
desde la consola: un único intento, sin reintentos, y nunca cuenta para desactivar el endpoint.
El modelo de data depende de type. Con el tiempo pueden añadirse campos a data: ignora los que no conozcas.
type |
data |
Se envía cuando |
|---|---|---|
certification.completed |
WebhookCertificationData |
Se ha emitido una certificación (trae verification_code). |
certification.failed |
WebhookCertificationData |
No se ha podido emitir una certificación (trae incident_id). |
balance.low |
WebhookBalanceLowData |
El saldo ha bajado de un umbral de aviso. |
balance.exhausted |
WebhookBalanceExhaustedData |
El primer evento ha entrado como impagado. |
events.unpaid_limit_reached |
WebhookUnpaidLimitData |
Se ha alcanzado el límite de impagados: se rechazan los registros. |
consumption.limit_reached |
WebhookConsumptionLimitData |
Un límite de consumo ha llegado a su máximo en el periodo. |
recharge.auto_completed |
WebhookAutoRechargeData |
Se ha cobrado una recarga automática y sus créditos ya están en el saldo. |
recharge.auto_failed |
WebhookAutoRechargeData |
Una recarga automática ha fallado y la recarga automática se ha desactivado. |
webhook.test |
WebhookTestData |
El titular de la cuenta ha pedido una entrega de prueba. |
Ejemplo (balance.low):
{"id": "ntc_…", "type": "balance.low", "created_at": "2026-09-28T07:00:16.526317Z", "mode": "live",
"data": {"threshold_id": "thr_…", "threshold": 1000, "balance": 999}}
| Campo | Tipo | |
|---|---|---|
| id * | string | Identificador del aviso (ntc_…; tst_… en las entregas de prueba), igual en todos los reintentos. También en X-SC-Webhook-Id. |
| type * | string: certification.completed · certification.failed · balance.low · balance.exhausted · events.unpaid_limit_reached · consumption.limit_reached · recharge.auto_completed · recharge.auto_failed · webhook.test | |
| created_at * | string (date-time) | Cuándo se generó el aviso. UTC, microsegundos (ver Formatos). |
| mode * | string: live · test | Modo del hecho notificado. Los avisos de cuenta y saldo son siempre live; los de certificación llevan el modo de la certificación. |
| data * | WebhookCertificationData | WebhookBalanceLowData | WebhookBalanceExhaustedData | WebhookUnpaidLimitData | WebhookConsumptionLimitData | WebhookAutoRechargeData | WebhookTestData | Datos del aviso. Su modelo depende de type (ver la tabla de arriba). |
WebhookCertificationData
data de certification.completed y certification.failed.
| Campo | Tipo | |
|---|---|---|
| certification_id * | string | Identificador de la certificación (CERT-2026-0000001; CERT-TEST-2026-0000001 en test). Úsalo con GET /certifications/{certification_id}. |
| channel_id * | string | |
| status * | string: completed · failed | |
| event_count * | integer | Eventos del rango certificado. |
| verification_code | string | Código de verificación pública (SC-2026-XXXX-XXXX; SC-TEST-… en test). Solo en certification.completed. |
| incident_id | string | Referencia de la incidencia para soporte. Solo en certification.failed. |
WebhookBalanceLowData
data de balance.low.
| Campo | Tipo | |
|---|---|---|
| threshold_id * | string | Identificador del umbral de aviso cruzado (thr_…). |
| threshold * | integer | El umbral, en créditos. |
| balance * | integer | Saldo en créditos justo después del cruce. |
WebhookBalanceExhaustedData
data de balance.exhausted.
| Campo | Tipo | |
|---|---|---|
| channel_id * | string | Canal del primer evento registrado como unpaid. |
WebhookUnpaidLimitData
data de events.unpaid_limit_reached.
| Campo | Tipo | |
|---|---|---|
| unpaid_limit * | integer | El límite de impagados de la cuenta. |
| unpaid_events * | integer | Impagados en este momento (igual al límite). |
| unpaid_credits * | integer | Créditos que se deben por ellos (uno por evento). |
WebhookConsumptionLimitData
data de consumption.limit_reached.
| Campo | Tipo | |
|---|---|---|
| limit_id * | string | Identificador del límite de consumo (lim_…). |
| scope * | string: channel · key | Si el límite se aplica a todo un canal o a una clave de API. |
| channel_id * | string | Canal del evento que alcanzó el límite. |
| key_id * | string | null | Identificador de la clave de API (key_…) cuando scope es key; null en los límites de canal. |
| period * | string: day · month | |
| period_key * | string | El periodo que alcanzó el límite: día natural YYYY-MM-DD o mes YYYY-MM, en UTC. |
| max_events * | integer | Eventos permitidos por periodo. |
| action * | string: warn · block | warn: los registros siguen entrando. block: 422 limit_blocked hasta el periodo siguiente. |
WebhookAutoRechargeData
data de recharge.auto_completed y recharge.auto_failed.
| Campo | Tipo | |
|---|---|---|
| recharge_id * | string | null | La compra (su código de venta en Safe Creative). null si falló antes de crear ninguna compra. |
| pack_id * | string | El pack configurado para la recarga automática. |
| credits * | integer | null | Créditos del pack comprado. null si falló antes de crear ninguna compra. |
| amount * | string | null | Precio neto del pack, antes de impuestos, como cadena decimal. null si falló antes de crear ninguna compra. |
| currency * | string | null: EUR · GBP · USD · null | Moneda de amount, la de la región de precios del titular. |
| threshold * | integer | El umbral de la recarga automática, en créditos. |
| balance | integer | Solo recharge.auto_completed: saldo en créditos después de sumar el pack. |
| reason | string: payment_failed · sale_creation_failed · payment_method_missing · pack_unavailable · pricing_country_required · daily_limit · account_suspended · custom_pack_inactive | Solo recharge.auto_failed: payment_failed (se rechazó el cobro), sale_creation_failed (Safe Creative no pudo
crear la compra, p. ej. por un medio de pago caducado), payment_method_missing (sin medio de pago por defecto válido),
pack_unavailable (el pack ya no está a la venta), pricing_country_required (sin país de facturación), daily_limit
(se alcanzó el máximo diario de recargas automáticas), account_suspended o custom_pack_inactive (se desactivó el
pack personalizado que compraba; se desactiva en ese momento, sin intentar ninguna compra). |
| payment_url | string | null | Solo recharge.auto_failed: página para pagar la compra a mano cuando se creó pero no se cobró. |
| auto_recharge_disabled | boolean | Solo recharge.auto_failed: siempre true; la recarga automática se ha desactivado y conserva su configuración. |
WebhookTestData
data de webhook.test.
| Campo | Tipo | |
|---|---|---|
| endpoint_id * | string | El endpoint (whk_…) para el que se pidió la prueba. |
| message * | string |
Error
| Campo | Tipo | |
|---|---|---|
| code * | string: validation_error · invalid_key · revoked_key · account_not_operational · unpaid_limit_exceeded · insufficient_balance · not_found · client_ref_conflict · payload_too_large · limit_blocked · rate_limited · test_quota_exceeded · internal · temporarily_unavailable · suspended · account_disabled | |
| message * | string | Legible por personas; en inglés por defecto y en español con Accept-Language. |
| doc_url | string | null | |
| incident_id | string | null | Presente en las respuestas 5xx. |