# Guion del vídeo, para comentar o para lo que necesites.
# Es una PROYECCIÓN del nuestro: lleva el contenido —qué se dice, qué se ve, en
# qué orden y cuánto dura— y no la maquinaria que lo convierte en vídeo.
id: productos-notificaciones
title: 'Manejar notificaciones: verificar, deduplicar, responder'
audience: Desarrollador que va a escribir el endpoint que recibe los avisos de SPIDI
objetivo: >
  Al terminar, el espectador sabe montar el receptor con los tres pasos —verificar firma,
  deduplicar, responder 2xx— y se lleva los dos detalles que hacen fallar la verificación: el
  timestamp entra en el cálculo, y hay que firmar los bytes recibidos, no el JSON re-serializado.
cta: 'Siguiente: ''Usar el simulador'', para probar tu receptor de verdad.'
target_duration_s: 183
storyboard:
  - 'n': 1
    on_screen: Tres pasos, en este orden
    narracion: >-
      Tu endpoint de avisos hace tres cosas, siempre en este orden: verifica la firma, deduplica, y
      responde 2xx. Vamos con cada una, porque en la primera hay dos detalles que hacen fallar la
      verificación a casi todo el mundo la primera vez.
    visual: Un POST llegando al endpoint propio, con sus tres cabeceras desplegadas.
    duracion_s: 16
  - 'n': 2
    on_screen: Qué llega
    narracion: >-
      Llega un POST a tu URL de webhook con un cuerpo JSON y tres cabeceras: el sello de la firma,
      la marca de tiempo, y una clave de idempotencia. El secreto con el que se firma lo obtienes al
      crear tu cuenta.
    visual: 'El aviso con sus tres cabeceras: el sello, la marca de tiempo y la clave de idempotencia.'
    duracion_s: 16
  - 'n': 3
    on_screen: 1 · Verifica la firma
    visual: Lámina de sección, sin voz.
    duracion_s: 3
  - 'n': 4
    on_screen: Qué se firma, exactamente
    narracion: >-
      La firma es un HMAC-SHA256 con tu secreto sobre una cadena concreta: el valor de la marca de
      tiempo, un punto, y el cuerpo crudo. En hexadecimal, y comparada en tiempo constante con la
      cabecera que te llega.
    visual: 'La cadena que se firma, montada pieza a pieza: marca de tiempo, punto, cuerpo crudo.'
    duracion_s: 15
  - 'n': 5
    on_screen: Los dos detalles que la rompen
    narracion: >-
      Y ahí están los dos detalles. El primero: la marca de tiempo entra en el cálculo. Firmar solo
      el cuerpo no reproduce ninguna firma. El segundo, y este es el que más cuesta ver: el cuerpo
      tiene que ser tal como llegó. Si parseas el JSON y lo vuelves a serializar, el orden de las
      claves o los espacios pueden cambiar, y la firma deja de coincidir. Guarda los bytes recibidos
      y firma sobre esos.
    visual: 'Dos formas de fallar: firmar solo el cuerpo, y firmar el JSON re-serializado.'
    duracion_s: 29
  - 'n': 6
    on_screen: Por qué está ahí la marca de tiempo
    narracion: >-
      Y esa marca de tiempo no es decoración: es lo que impide reenviar un aviso capturado. Una
      firma legítima deja de valer en cuanto se cambia la marca, así que quien intercepte un webhook
      no puede reproducirlo más tarde. De ahí una consecuencia práctica: si falta esa cabecera, no
      hay nada que verificar. Rechaza esa petición en vez de intentar validarla sin ella.
    visual: Un aviso capturado que alguien intenta reenviar más tarde, y la firma dejando de valer.
    duracion_s: 24
  - 'n': 7
    on_screen: 2 y 3 · Deduplica y responde
    visual: Lámina de sección, sin voz.
    duracion_s: 3
  - 'n': 8
    on_screen: Guarda las claves ya vistas
    narracion: >-
      Con la firma verificada, el segundo paso: deduplicar. El mismo aviso puede llegar más de una
      vez, porque SPIDI reintenta. Guarda las claves de idempotencia que ya viste e ignora las
      repetidas: responde 200 sin reprocesar.
    visual: El mismo aviso llegando dos veces con la misma clave, procesado una sola vez.
    duracion_s: 14
  - 'n': 9
    on_screen: Responde rápido; encola lo pesado
    narracion: >-
      Y el tercero: responde 2xx, y hazlo rápido. Si devuelves un error o tardas demasiado, SPIDI
      reintenta. Si necesitas hacer trabajo pesado con ese aviso, encólalo y responde de inmediato.
    visual: Un endpoint que responde rápido y encola el trabajo pesado aparte.
    duracion_s: 12
  - 'n': 10
    on_screen: Los eventos que escucharás
    narracion: >-
      En cuanto a qué vas a recibir: el de pagado, que confirma el débito de la fase uno y no que el
      dinero esté ya en manos del receptor. Y el de acreditado, la fase dos. Ese no se refleja en el
      campo status, que se queda en pagado — pero el aviso no es tu única vía: el mismo dato está en
      receiver_credits, dentro de la respuesta del estado.
    visual: >-
      Los dos eventos del ciclo, con la acreditación apuntando también al campo de créditos del
      status.
    duracion_s: 27
  - 'n': 11
    on_screen: Pruébalo con un rechazo, no con un 200
    narracion: >-
      Y una última cosa sobre cómo se prueba: si repartes, llegará un aviso de acreditación por cada
      parte del acuerdo, todos a tu mismo endpoint. El simulador firma igual que producción y
      reintenta igual, así que puedes comprobar tu verificación ahí. Pero compruébala bien: un 200
      no demuestra que verificas la firma. Eso solo lo demuestra un rechazo a un payload alterado.
    visual: Cierre de marca; un payload alterado siendo rechazado por el endpoint propio.
    duracion_s: 24
