Safe Creative Platform

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-Remaining y RateLimit-Reset (segundos); un 429 rate_limited añade Retry-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_unavailable con Retry-After: reintenta, con el mismo client_ref si registras eventos.
  • Idioma: el message de los errores va en inglés por defecto y en español con Accept-Language: es.
  • Escenarios de prueba forzados: con una clave test, X-SC-Test-Scenario: unpaid | unpaid_limit | rate_limited reproduce 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 Z y exactamente seis decimales (microsegundos, la precisión con que se guardan), p. ej. 2026-09-28T07:00:16.526317Z. El acuse de POST /events devuelve received_at exactamente 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 (Z o ±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

Webhooks

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

Respuestas

201Evento registrado (nuevo).Event
200Reintento idempotente: mismo client_ref y mismo contenido; se devuelve el evento original.Event
400Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error).Error
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
402Límite de impagados alcanzado (unpaid_limit_exceeded).Error
403Canal 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
409client_ref ya usado en este canal con otro contenido (client_ref_conflict).Error
413Cuerpo por encima del límite de la modalidad (payload_too_large).Error
422Bloqueado por un límite de consumo del usuario con la acción «bloquear» (limit_blocked).Error
429Lí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
503No 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

fromqueryLí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).
toqueryLí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_fromquery
seq_toquery
statusquery
limitquery
cursorqueryCursor opaco de paginación.

Respuestas

200Lista paginada de eventos, por orden de secuencia.application/json
400Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error).Error
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
429Lí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_idpath · obligatorio

Respuestas

200El evento.Event
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
404No existe en este canal (not_found).Error
429Lí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_idpath · obligatorio

Respuestas

200El contenido: application/json si es JSON, application/octet-stream si es un fichero.application/json | application/octet-stream
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
404No existe en este canal (not_found).Error
429Lí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

200El canal con su configuración vigente y el historial de versiones.Channel
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
429Lí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

200Estado del saldo.AccountBalance
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
429Lí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

Respuestas

202Aceptada; la emisión se hace de forma asíncrona.Certification
400Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error).Error
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
402account_not_operational (hay impagados o saldo negativo) o insufficient_balance (precio de emisión, si lo hay).Error
403Canal 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
429Lí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
503No 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

statusquery
limitquery
cursorquery

Respuestas

200Lista paginada, las más recientes primero.application/json
400Cuerpo o parámetros no válidos, o modalidad que no corresponde al canal (validation_error).Error
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
429Lí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_idpath · obligatorio

Respuestas

200La 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
401Clave ausente, no válida o revocada (invalid_key / revoked_key).Error
403Canal 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
404No existe en este canal (not_found).Error
429Lí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.

data: WebhookBalanceExhaustedData

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.

data: WebhookConsumptionLimitData

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.

CampoTipo
client_ref *stringIdentificador único del evento en el sistema emisor (clave de idempotencia por canal).
payload *objectEl contenido declarado (JSON). Cuerpo de 256 KB como máximo.
occurred_atstring (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.

CampoTipo
client_ref *string
hash *stringHuella en hexadecimal del contenido que custodia el cliente.
hash_alg *string: sha-256 · sha-512
occurred_atstring (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.

CampoTipo
client_ref *string
file *string (binary)
occurred_atstring (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

CampoTipo
event_id *string
channel_id *string
client_ref *string
sequence *integerEstrictamente 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_atstring | null (date-time)Declarada por el emisor; Safe Creative no la acredita. Se devuelve en UTC, microsegundos (ver Formatos).
hash *stringHuella del contenido (o la huella declarada por el cliente en la modalidad solo-huella).
hash_algstring
modality *string: content · hash_onlycontent = 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 *stringHuella encadenada que une este evento con el anterior del canal.
status *string: registered · unpaid · testunpaid = registrado y sellado, pendiente de pago; bloquea las certificaciones de toda la cuenta.
timestampEventTimestampCobertura de este evento por un sello de tiempo cualificado.
config_version *integerVersió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).

CampoTipo
type *string: individual · batch · pending · simulatedbatch = 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.
referencestring | nullReferencia del sello o del tramo sellado una vez consolidado (seg_… para un tramo sellado).
sealed_atstring | null (date-time)Cuándo se obtuvo el sello que lo cubre. UTC, microsegundos (ver Formatos).

Channel

CampoTipo
channel_id *string
name *string
mode_note *stringRecordatorio 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.

CampoTipo
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
namestring
descriptionstring
declarant *stringPersona 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_infostring | nullTexto opcional del cliente que explica qué significan los datos declarados.

NewCertification

Rango por fechas o por números de secuencia (exactamente un par).

CampoTipo
fromstring (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).
tostring (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_fromintegerPrimer número de secuencia, incluido.
seq_tointegerÚltimo número de secuencia, incluido.

Certification

CampoTipo
certification_id *string
channel_id *string
status *string: processing · completed · failed
progressnumber | nullProgreso aproximado (0–1) mientras se procesa.
requested_at *string (date-time)Cuándo se aceptó la solicitud. UTC, microsegundos (ver Formatos).
completed_atstring | 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 *CertificationRangeEl rango tal como se solicitó. Al aceptarlo se resuelve y se congela en números de secuencia de la cadena.
event_countinteger | null
config_versions_in_rangeinteger[]
report_urlstring | nullDescarga 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.
reportsCertificationReport[]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_urlstring | nullDescarga del ZIP de evidencias (URL con caducidad).
verification_codestring | nullCódigo para la página de verificación pública.
mode *string: live · test
content_partsContentPart[]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).

CampoTipo
languages *string[]Idioma del informe, [es] o [en]; los dos en el informe bilingüe de certificaciones anteriores.
url *stringURL de descarga (con caducidad, como report_url).
sha256 *stringSHA-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.

CampoTipo
fromstring | null (date-time)Inicio del rango de recepción, incluido. UTC, microsegundos (ver Formatos).
tostring | null (date-time)Fin del rango de recepción, excluido; un to futuro se recorta al momento de la solicitud. UTC, microsegundos.
seq_frominteger | nullPrimer número de secuencia, incluido.
seq_tointeger | nullÚltimo número de secuencia, incluido.

ContentPart

Una parte ZIP del contenido declarado de una certificación (Certification.content_parts).

CampoTipo
name *stringNombre del fichero, content-part-NNN.zip.
url *stringURL de descarga (con caducidad, como report_url).
sha256 *stringSHA-256 de la parte, en hexadecimal en minúsculas; figura también en el manifiesto de evidencias y en los informes.
bytes *integerTamañ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.

CampoTipo
balance *integerCréditos disponibles. Solo es negativo si una compra se anula después de gastar sus créditos.
operational *booleanfalse mientras la cuenta tenga eventos impagados o saldo negativo («cuenta sin saldo operativo»).
unpaid_events *integerEventos 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}}
CampoTipo
id *stringIdentificador 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 · testModo 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 | WebhookTestDataDatos del aviso. Su modelo depende de type (ver la tabla de arriba).

WebhookCertificationData

data de certification.completed y certification.failed.

CampoTipo
certification_id *stringIdentificador 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 *integerEventos del rango certificado.
verification_codestringCódigo de verificación pública (SC-2026-XXXX-XXXX; SC-TEST-… en test). Solo en certification.completed.
incident_idstringReferencia de la incidencia para soporte. Solo en certification.failed.

WebhookBalanceLowData

data de balance.low.

CampoTipo
threshold_id *stringIdentificador del umbral de aviso cruzado (thr_…).
threshold *integerEl umbral, en créditos.
balance *integerSaldo en créditos justo después del cruce.

WebhookBalanceExhaustedData

data de balance.exhausted.

CampoTipo
channel_id *stringCanal del primer evento registrado como unpaid.

WebhookUnpaidLimitData

data de events.unpaid_limit_reached.

CampoTipo
unpaid_limit *integerEl límite de impagados de la cuenta.
unpaid_events *integerImpagados en este momento (igual al límite).
unpaid_credits *integerCréditos que se deben por ellos (uno por evento).

WebhookConsumptionLimitData

data de consumption.limit_reached.

CampoTipo
limit_id *stringIdentificador del límite de consumo (lim_…).
scope *string: channel · keySi el límite se aplica a todo un canal o a una clave de API.
channel_id *stringCanal del evento que alcanzó el límite.
key_id *string | nullIdentificador de la clave de API (key_…) cuando scope es key; null en los límites de canal.
period *string: day · month
period_key *stringEl periodo que alcanzó el límite: día natural YYYY-MM-DD o mes YYYY-MM, en UTC.
max_events *integerEventos permitidos por periodo.
action *string: warn · blockwarn: los registros siguen entrando. block: 422 limit_blocked hasta el periodo siguiente.

WebhookAutoRechargeData

data de recharge.auto_completed y recharge.auto_failed.

CampoTipo
recharge_id *string | nullLa compra (su código de venta en Safe Creative). null si falló antes de crear ninguna compra.
pack_id *stringEl pack configurado para la recarga automática.
credits *integer | nullCréditos del pack comprado. null si falló antes de crear ninguna compra.
amount *string | nullPrecio neto del pack, antes de impuestos, como cadena decimal. null si falló antes de crear ninguna compra.
currency *string | null: EUR · GBP · USD · nullMoneda de amount, la de la región de precios del titular.
threshold *integerEl umbral de la recarga automática, en créditos.
balanceintegerSolo recharge.auto_completed: saldo en créditos después de sumar el pack.
reasonstring: payment_failed · sale_creation_failed · payment_method_missing · pack_unavailable · pricing_country_required · daily_limit · account_suspended · custom_pack_inactiveSolo 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_urlstring | nullSolo recharge.auto_failed: página para pagar la compra a mano cuando se creó pero no se cobró.
auto_recharge_disabledbooleanSolo recharge.auto_failed: siempre true; la recarga automática se ha desactivado y conserva su configuración.

WebhookTestData

data de webhook.test.

CampoTipo
endpoint_id *stringEl endpoint (whk_…) para el que se pidió la prueba.
message *string

Error

CampoTipo
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 *stringLegible por personas; en inglés por defecto y en español con Accept-Language.
doc_urlstring | null
incident_idstring | nullPresente en las respuestas 5xx.