Webhook de verificación de identidad: recuperar un estado pendiente sin consultar al proveedor
Tu servicio de alta creó una sesión de verificación alojada, la guardó como pendiente y el webhook nunca llegó. Debes decidir en qué estado queda la sesión y qué ocurre después. Este artículo usa el ejemplo local verificado: persistencia en SQLite, un plazo y un paso recover que vence la sesión localmente. Nunca consulta a un proveedor, y una notificación ausente nunca se convierte en aprobación.
curl https://gridzen.ai/console/api/quickstart/trial \
-H 'Content-Type: application/json' \
-d '{"task": "identity_onboarding", "scenario": "success"}'El problema: una sesión pendiente sin notificación
Un vendedor inicia la verificación de identidad alojada. Tu servicio escribe una sesión pendiente con un plazo y espera. La notificación puede perderse, retrasarse o bloquearse por un endpoint mal configurado. Si nada actúa al vencer el plazo, la sesión queda pendiente para siempre. El usuario queda atascado y tu equipo de soporte no tiene un estado claro que leer. Los atajos tentadores son aprobar tras un tiempo o rechazar en silencio. Ambos convierten la falta de evidencia en una decisión. Tu decisión real es más acotada: cuando pasa el plazo, mover la sesión a un estado terminal que signifique que no llegó respuesta, y dirigir la siguiente acción a revisión o a una actualización de estado autorizada que controla tu propia integración.
Lo que el ejemplo local implementa de verdad
El ejemplo descargable es un fixture en Python 3.10+ sin dependencias, credenciales ni red. La clase Identity guarda sesiones en SQLite con los campos status, deadline, granted y grants, además de policy_version y allow_action. create solo acepta identificadores que empiezan por fixture- y un timeout entre 1 y 3600 segundos, y escribe status pending con deadline igual a now más timeout. recover recibe una sesión y la hora actual. Si deadline es menor o igual que now y status es pending, review o unknown, pone status en expired. Luego devuelve el resultado de lectura más next con review_or_authorized_provider_refresh y provider_polled en false. Esa marca es literal: recover no llama a ningún proveedor. Los eventos solo aceptan mode synthetic_fixture y source fixture_callback; lo demás lanza PRODUCTION_SIGNATURE_VERIFIER_NOT_IMPLEMENTED. No hay verificación real de firmas. Esto es distinto de la prueba HTTP anónima de tres escenarios y del ejemplo telefónico de cuatro ramas.
Escenario hipotético y salidas esperadas del fixture
Hipotético: se crea la sesión sintética fixture-session en el tiempo 0 con el timeout por defecto de 60 segundos, así que deadline vale 60. No llega notificación. Tu planificador, que construirías tú, llama a recover en el tiempo 61. La salida probada es: mode synthetic_fixture, session fixture-session, status expired, deadline 60, permission_granted false, grant_count 0, live_permission_changed false, policy_version 1, allow_action true, next review_or_authorized_provider_refresh, provider_polled false. Como el estado vive en SQLite, reiniciar el proceso con el mismo archivo de base de datos y llamar a recover da el mismo resultado. Si llega un evento sintético Approved tardío después del plazo, el manejador lo registra y mantiene la sesión expirada; no concede nada. allow_action true solo indica que la política local permitiría una acción; no es una concesión.
Manejo de fallos que corresponde a tu aplicación
Diseño propuesto, no comportamiento implementado: ejecuta recover desde un planificador duradero, no desde la petición que creó la sesión. Trata expired como ausencia de respuesta, no como rechazo, y ofrece al usuario una vía para reintentar. Si tienes una ruta de proveedor autorizada, puede seguir una actualización de estado acotada, con validación de firma y conciliación propias de ese proveedor; el ejemplo no establece ninguna de las dos. Los errores del fixture son explícitos: leer una sesión desconocida lanza SESSION_NOT_FOUND, y un evento para una sesión desconocida o con tenant o subject incorrectos lanza BINDING_MISMATCH. Los eventos duplicados se registran por id y devuelven el estado actual sin una segunda concesión. Registra estos códigos en lugar de reintentar a ciegas.
Límites que conviene tener presentes
El fixture solo prueba transiciones de estado locales. No demuestra que una persona real completó un recorrido alojado, que una notificación del proveedor estaba firmada ni que cambió algún permiso real. permission_granted sintético es un registro local, nunca un permiso de negocio real. hosted_link apunta a un dominio de ejemplo inválido y link_executable es false. Las pruebas de ingeniería cubren transiciones, vinculaciones, duplicados, reinicio y vencimientos; no son evidencia de éxito en producción ni de adopción. La disponibilidad de la ruta real requiere confirmación aparte.
Lista de aceptación
Ejecuta las pruebas de reinicio y de recuperación por vencimiento y confirma que pasan. Crea una sesión, reinicia y confirma que status sigue en pending con el mismo deadline. Llama a recover tras el plazo y confirma status expired, permission_granted false y provider_polled false. Envía un Approved sintético tardío y confirma que no hay concesión. Confirma que las sesiones desconocidas lanzan SESSION_NOT_FOUND o BINDING_MISMATCH. Confirma que tu diseño nunca convierte expired en aprobación. Anota qué componente futuro será responsable de la validación de firmas y de la actualización autorizada antes de solicitar una integración sandbox.
Ejecutar el ejemplo sintético comprobado
Descargue y extraiga https://gridzen.ai/downloads/verification-delivery.zip, entre en verification_delivery y ejecute con Python 3.10+. El ejemplo local no hace llamadas de red. Use una base nueva para otra prueba de identidad.
python3 delivery.py identity --db /tmp/gridzen-article-fixture.sqliteFuentes y alcance
https://gridzen.ai/guides/missing-verification-webhook/ https://gridzen.ai/guides/current-capabilities/ Basado en las fuentes comprobadas y el ejemplo local; las reglas propuestas son recomendaciones de diseño, no comportamiento de producción demostrado. Redacción asistida por IA con revisión independiente.
Probar por separado tres resultados del sandbox Crear una cuenta para continuar la integración
Una descarga no demuestra una ejecución correcta. Los ejemplos locales y el sandbox en línea se prueban por separado.