Integrating Todis into your online shop
The per-platform recipes, built on the hosted flow. Each recipe is a starting point to adapt, not a module to install: in every case, nothing personal is stored, neither on your side nor at Todis. The other guide: mobile apps and native integration.
Recipes per platform
WooCommerce
Two hooks in your child theme's functions.php are
enough for an age check at checkout: one redirects to the
hosted page when the basket is concerned, the other confirms
the result on return.
add_action('template_redirect', function () {
if (!is_checkout() || !basket_concerned()) { return; }
if (WC()->session->get('todis_verified')) { 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' => 'en',
'success_url' => wc_get_checkout_url() . '?todis_return=1',
]),
]);
$journey = json_decode(wp_remote_retrieve_body($r), true);
WC()->session->set('todis_session_id', $journey['session_id']);
wp_redirect($journey['hosted_url']);
exit;
});
// Priority 9: confirm BEFORE the redirect hook above.
add_action('template_redirect', function () {
if (!isset($_GET['todis_return'])) { return; }
$r = wp_remote_get('https://verify.todis.eu/verify/sessions/'
. WC()->session->get('todis_session_id'),
['headers' => ['Authorization' => 'Bearer ' . TODIS_TOKEN]]);
$body = json_decode(wp_remote_retrieve_body($r), true);
// "verified" means the verification succeeded, not of age: read the value.
if (($body['status'] ?? '') === 'verified'
&& ($body['claims']['age_over_18'] ?? false) === true) {
WC()->session->set('todis_verified', true);
}
}, 9);
The token stays server-side (a constant or an environment
variable), never in a page.
success_url means the verification
succeeded, never that the user is of age: a proof of
age that is false lands there too, like any
verified result. Read the result server-side
(claims.age_over_18 with the
age_over_18 shortcut) and apply your own rule to
it.
PrestaShop
Same logic, inside a small in-house module: the
actionFrontControllerSetMedia hook (or a
dedicated front controller) creates the journey and redirects
when the basket contains a product subject to the check, then
your return controller confirms the status and
the value of claims.age_over_18 through the API
before letting the order proceed. Store the
session_id in the PrestaShop session cookie, and
the token in the module configuration, never in a template.
Shopify
Shopify does not allow arbitrary code at checkout: the pattern goes through a small custom app (the one your Shopify agency probably already built for you) exposing two routes through an App Proxy: one creates the journey and redirects, the other receives the return and confirms. The trigger sits before checkout (cart page) or after purchase (order status page), depending on your regulatory constraint. There is no Todis app on the App Store yet: tell us if you miss it.
The three rules that never change. The license
token stays server-side. The result is confirmed through an
authenticated GET /verify/sessions/{id}, never on the
basis of a URL parameter or a browser event. And there is nothing
to store: no ID copy, no photo, only the verified answer you asked
for, as explained in the
FAQ.