Recetas por plataforma

WooCommerce

Dos hooks en el functions.php de tu tema hijo bastan para un control de edad al pasar por caja: uno redirige a la página alojada cuando el carrito lo requiere, el otro confirma el resultado a la vuelta.

add_action('template_redirect', function () {
  if (!is_checkout() || !carrito_afectado()) { return; }
  if (WC()->session->get('todis_verificado')) { return; }
  $r = wp_remote_post('https://verify.todis.eu/hosted/sessions', [
    'headers' => ['Authorization' => 'Bearer ' . TODIS_TOKEN,
                  'Content-Type' => 'application/json'],
    'body' => wp_json_encode([
      'check' => 'age_over_18', 'country_code' => 'FR',
      'locale' => 'es',
      'success_url' => wc_get_checkout_url() . '?todis_retorno=1',
    ]),
  ]);
  $recorrido = json_decode(wp_remote_retrieve_body($r), true);
  WC()->session->set('todis_session_id', $recorrido['session_id']);
  wp_redirect($recorrido['hosted_url']);
  exit;
});

// Prioridad 9: confirmar ANTES del hook de redirección de arriba.
add_action('template_redirect', function () {
  if (!isset($_GET['todis_retorno'])) { return; }
  $r = wp_remote_get('https://verify.todis.eu/verify/sessions/'
      . WC()->session->get('todis_session_id'),
    ['headers' => ['Authorization' => 'Bearer ' . TODIS_TOKEN]]);
  $cuerpo = json_decode(wp_remote_retrieve_body($r), true);
  // «verified» significa verificación superada, no mayor de edad: leer el valor.
  if (($cuerpo['status'] ?? '') === 'verified'
      && ($cuerpo['claims']['age_over_18'] ?? false) === true) {
    WC()->session->set('todis_verificado', true);
  }
}, 9);

El token se queda en el servidor (una constante o una variable de entorno), nunca en una página. success_url significa verificación superada, nunca que el usuario sea mayor de edad: una prueba de edad que vale false también llega allí, como cualquier resultado verificado. Lee el resultado en el servidor (claims.age_over_18 con el atajo age_over_18) y aplícale tu propia regla.

PrestaShop

La misma lógica, dentro de un pequeño módulo propio: el hook actionFrontControllerSetMedia (o un controlador front dedicado) crea el recorrido y redirige cuando el carrito contiene un producto sujeto al control, y tu controlador de retorno confirma el status y el valor de claims.age_over_18 vía API antes de dejar que el pedido continúe. Guarda el session_id en la cookie de sesión de PrestaShop, y el token en la configuración del módulo, nunca en una plantilla.

Shopify

Shopify no permite código arbitrario en el checkout: el patrón pasa por una pequeña app custom (la que tu agencia Shopify probablemente ya te hizo) que expone dos rutas a través de un App Proxy: una crea el recorrido y redirige, la otra recibe el retorno y confirma. El disparo se coloca antes del checkout (página del carrito) o después de la compra (página de estado del pedido), según tu obligación regulatoria. Todavía no hay una app de Todis en la App Store: dínoslo si la echas de menos.

Las tres reglas que nunca cambian. El token de licencia se queda en el servidor. El resultado se confirma con un GET /verify/sessions/{id} autenticado, nunca sobre la base de un parámetro de URL o un evento del navegador. Y no hay nada que almacenar: ni copia del documento, ni foto, solo la respuesta verificada que pediste, como se explica en la FAQ.