Le WordPress d'aujourd'hui, décodé pour les développeurs

Astuces

Un message d’attente pendant la vérification d’une signature Docusign

Le webhook Docusign met parfois plusieurs secondes à confirmer une signature. Voici comment éviter l'écran blanc côté visiteur pendant ce délai.

Par WordPress Développement • 30 septembre 2026 • 7 min de lecture • Aucun commentaire
Un message d'attente pendant la vérification d'une signature Docusign

envelope-completed : c’est le nom de l’événement que Docusign envoie par webhook une fois une signature validée, et c’est aussi la source d’un problème d’expérience assez classique. Entre le moment où le signataire clique sur « Terminer » dans l’interface Docusign et le moment où le serveur WordPress reçoit réellement ce webhook, il peut s’écouler plusieurs secondes, parfois une douzaine. Pendant ce laps de temps, si rien n’est prévu côté site, le visiteur atterrit sur une page qui ne dit rien, ou pire, sur une ancienne version du statut du contrat.

Ce cas s’est présenté sur un site proposant la signature électronique de mandats. La redirection Docusign ramenait l’utilisateur sur une page de retour immédiatement après la signature dans l’iframe, bien avant que le webhook n’ait eu le temps d’arriver et de mettre à jour le statut de la commande en base. Le correctif consiste à afficher un état d’attente explicite plutôt que de supposer que tout est déjà synchronisé.

Le problème : deux sources de vérité qui ne sont pas synchrones

Docusign propose deux mécanismes de retour : la redirection du navigateur vers une returnUrl définie à la création de l’enveloppe, et l’envoi asynchrone d’un webhook (Connect) vers une URL de callback serveur. Le premier arrive quasiment tout de suite ; le second dépend de la charge des files d’attente Docusign et peut prendre bien plus longtemps.

Traiter la redirection comme une confirmation de signature est l’erreur la plus fréquente : Docusign redirige même si l’utilisateur a annulé, refusé, ou si la session a expiré. Le paramètre event de la returnUrl donne une indication, mais seul le webhook fait foi côté serveur pour le statut final.

La solution : une page d’attente qui interroge le statut réel

La page de retour affiche un état neutre — « Signature en cours de vérification » — puis interroge en arrière-plan un point de terminaison REST qui reflète le statut réellement enregistré en base, mis à jour par le webhook.

L'essentiel à retenir : Rediriger vers un état « en cours » avant confirmation ; Interroger l'API en tâche de fond côté navigateur ; Basculer automatiquement dès réception du webhook

Concrètement, la returnUrl envoyée à Docusign pointe vers une page de WordPress qui ne conclut rien. Elle reçoit la référence de la commande et une clé aléatoire, générée à la création de l’enveloppe et stockée en base. Cette clé évite qu’un tiers ne devine le statut d’une commande d’autrui en incrémentant un numéro.

Côté serveur : un point d’état et la réception du webhook

Deux routes REST suffisent. La première répond au navigateur ; la seconde reçoit le webhook et met à jour le statut. Voici la première, protégée par la clé de retour :

add_action( 'rest_api_init', 'mandats_routes' );

function mandats_routes() {
    register_rest_route( 'mandats/v1', '/statut', array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'mandats_lire_statut',
        'permission_callback' => '__return_true', // Accès protégé par la clé de retour.
        'args'                => array(
            'commande' => array( 'required' => true, 'sanitize_callback' => 'absint' ),
            'cle'      => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
        ),
    ) );
}

function mandats_lire_statut( WP_REST_Request $requete ) {
    $id  = $requete['commande'];
    $cle = (string) get_post_meta( $id, '_cle_retour', true );

    if ( '' === $cle || ! hash_equals( $cle, $requete['cle'] ) ) {
        return new WP_Error( 'mandats_cle', 'Clé de retour invalide.', array( 'status' => 403 ) );
    }

    $statut = get_post_meta( $id, '_statut_signature', true );

    return rest_ensure_response( array(
        'statut' => $statut ? $statut : 'en_cours',
    ) );
}

Le permission_callback est ici volontairement ouvert, car le visiteur n’est pas forcément connecté ; toute la protection repose sur la comparaison hash_equals(), qui évite en outre les attaques par mesure du temps de réponse. La route ne renvoie qu’un mot, jamais le contenu du mandat.

La seconde route reçoit le webhook. Docusign Connect peut signer ses envois avec une clé HMAC : l’en-tête X-DocuSign-Signature-1 contient l’empreinte HMAC-SHA256 du corps de la requête, encodée en base64. Il faut la recalculer et la comparer avant de croire le contenu :

add_action( 'rest_api_init', function () {
    register_rest_route( 'mandats/v1', '/webhook', array(
        'methods'             => WP_REST_Server::CREATABLE,
        'callback'            => 'mandats_recevoir_webhook',
        'permission_callback' => 'mandats_verifier_signature',
    ) );
} );

function mandats_verifier_signature( WP_REST_Request $requete ) {
    $secret = defined( 'MANDATS_CLE_HMAC' ) ? MANDATS_CLE_HMAC : '';
    if ( '' === $secret ) {
        return false;
    }
    $recu    = (string) $requete->get_header( 'x_docusign_signature_1' );
    $attendu = base64_encode( hash_hmac( 'sha256', $requete->get_body(), $secret, true ) );

    return hash_equals( $attendu, $recu );
}

function mandats_recevoir_webhook( WP_REST_Request $requete ) {
    $corps = $requete->get_json_params();

    if ( isset( $corps['event'], $corps['data']['envelopeId'] )
        && 'envelope-completed' === $corps['event'] ) {
        $commandes = get_posts( array(
            'post_type'      => 'any',
            'meta_key'       => '_envelope_id',
            'meta_value'     => sanitize_text_field( $corps['data']['envelopeId'] ),
            'fields'         => 'ids',
            'posts_per_page' => 1,
        ) );
        if ( $commandes ) {
            update_post_meta( $commandes[0], '_statut_signature', 'signe' );
        }
    }

    return rest_ensure_response( array( 'recu' => true ) );
}

La structure exacte de la charge utile (le nom de l’événement, l’emplacement de envelopeId) dépend du format de notification choisi dans la configuration Connect : vérifiez-la sur un envoi de test avant de vous appuyer sur ce code. Renvoyez dans tous les cas un code 200 rapidement, sans traitement lourd, pour que Docusign ne considère pas l’envoi en échec et ne le rejoue pas inutilement.

Côté navigateur : interroger sans harceler

La page de retour contient une zone annoncée aux lecteurs d’écran, avec l’attribut aria-live="polite", et un petit script qui interroge la route d’état toutes les trois secondes, pendant une minute au plus :

( function () {
    const zone = document.getElementById( 'attente-signature' );
    if ( ! zone ) {
        return;
    }
    const maxEssais = 20;
    let essais = 0;

    async function verifier() {
        essais++;
        try {
            const reponse = await fetch( zone.dataset.url, { credentials: 'same-origin' } );
            const donnees = await reponse.json();

            if ( donnees.statut === 'signe' ) {
                window.location.href = zone.dataset.merci;
                return;
            }
        } catch ( erreur ) {
            // Une erreur réseau ponctuelle ne doit pas interrompre l'attente.
        }

        if ( essais < maxEssais ) {
            setTimeout( verifier, 3000 );
        } else {
            zone.textContent = 'La vérification prend plus de temps que prévu. Vous recevrez un courriel de confirmation dès que la signature sera enregistrée.';
        }
    }

    verifier();
} )();

Dès que le webhook a mis à jour le statut, la prochaine interrogation renvoie signe et le visiteur est redirigé vers la page de confirmation. Si la minute s’écoule sans réponse, un message honnête remplace l’écran d’attente : le visiteur sait que rien n’est perdu et qu’un courriel suivra.

Un écran d’attente n’est pas un aveu de lenteur ; c’est la seule manière honnête de dire au visiteur que quelqu’un, quelque part, est en train de vérifier.

Les pièges à éviter

  • Conclure sur la seule redirection. Le visiteur peut avoir annulé ou refusé : seul le statut enregistré par le webhook fait foi.
  • Interroger trop souvent. Un intervalle d’une seconde multiplié par des dizaines de visiteurs simultanés charge inutilement le serveur ; trois secondes, avec un plafond d’essais, suffisent.
  • Ne pas prévoir l’échec du webhook. Un webhook peut ne jamais arriver. Une tâche planifiée qui interroge l’API Docusign pour les enveloppes restées « en cours » au-delà de quelques minutes sert de filet de sécurité.
  • Négliger l’accessibilité. Sans région aria-live, un lecteur d’écran n’annonce ni l’attente ni le message d’échec.
  • Laisser la clé HMAC dans le dépôt. Définissez-la dans wp-config.php ou une variable d’environnement.

Conclusion

Le délai entre la signature et la réception du webhook n’est pas un défaut à corriger, mais une réalité de l’architecture à accueillir. En séparant la redirection, qui ramène le visiteur, et le webhook, qui établit la vérité, et en comblant l’écart par un état d’attente explicite, on supprime l’écran blanc, on évite les faux statuts et on garde un parcours cohérent même quand le webhook tarde.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi