Aller au contenu

WordPress et WooCommerce

Un plugin, neuf intégrations et les hooks nécessaires pour créer la vôtre.

Le plugin Wajub transforme un site WordPress en surface de paiement. Il détecte les plugins d'e-commerce, de dons, de LMS, d'adhésion et de formulaires déjà installés. Il s'enregistre comme moyen de paiement dans chacun d'eux et utilise des shortcodes lorsqu'aucune passerelle native n'existe. Un jeu de clés et un webhook suffisent pour toutes les intégrations.

Fonctionnement du plugin

Neuf intégrations fournissent une véritable passerelle. Le plugin ne charge chacune d'elles que s'il détecte le plugin correspondant. Une installation avec seulement WooCommerce ne charge donc jamais le code de GiveWP ou des LMS.

IntégrationDétectée parCheckoutRemboursements depuis WordPress
WooCommerceClasse WooCommerceRedirection, en ligne, superposition, BlocksOui
Easy Digital DownloadsEDD_VERSIONRedirectionOui, au changement de statut
GiveWP 3.xgivewp_register_payment_gatewayRedirectionOui
GiveWP avant 2.18GIVE_VERSIONRedirectionOui, au changement de statut
CharitableCHARITABLE_VERSIONRedirectionOui
Tutor LMSTUTOR_VERSIONCheckout Ecommerce natifOui
LifterLMSLLMS_PLUGIN_FILERedirectionOui
LearnDashLEARNDASH_VERSIONBouton shortcodeAucun modèle de commande à rembourser
MemberPressMEPR_VERSIONRedirectionOui
Gravity FormsClasse GFFormsRedirectionOui

Cinq autres apparaissent dans l'administration avec un badge shortcode. Ils ne proposent aucune API de passerelle à laquelle le plugin peut se connecter. Ajoutez plutôt [wajub_pay] sur la page : WPForms, Bookly, The Events Calendar, WP Simple Pay et Amelia. WP Crowdfunding passe par WooCommerce. L'activation de l'intégration WooCommerce le prend donc en charge.

Prérequis

ComposantMinimumRemarque
WordPress6.2Testé jusqu'à la version 7.0
PHP8.1En dessous, le plugin affiche une notification et s'arrête
WooCommerce8.0Seulement si vous l'utilisez. Testé jusqu'à la version 11.0
HTTPSObligatoireLe webhook et l'URL de retour en ont besoin
Un compte WajubObligatoireLes clés de sandbox suffisent pour commencer

Le plugin se déclare compatible avec les deux fonctionnalités WooCommerce qui rendent les anciennes passerelles incompatibles : High Performance Order Storage ainsi que le panier et le checkout Blocks. Vous n'avez donc pas besoin de conserver les anciennes tables de commandes.

Installer le plugin

Le plugin est distribué sous forme d'archive zip, pas dans le répertoire WordPress.org. Il n'est donc pas disponible dans la recherche et ne se met pas à jour automatiquement. Demandez la version actuelle à votre contact Wajub.

  1. 1

    Téléverser l'archive zip

    Dans l'administration WordPress, accédez à Plugins, Add New Plugin, Upload Plugin, choisissez l'archive zip et installez-la. Activez le plugin à la fin du téléversement.

  2. 2

    Ou l'installer depuis la ligne de commande

    WP-CLI accepte directement le chemin ou l'URL de l'archive zip.

  3. 3

    Ou déposer le dossier par SFTP

    Décompressez l'archive localement et téléversez le dossier dans wp-content/plugins/, puis activez-le depuis l'écran des plugins.

WP-CLI effectue la même installation en une ligne. La seconde commande confirme que le plugin est actif sous le bon nom de dossier.

WP-CLI
wp plugin install ./wajub.zip --activate

wp plugin list --name=wajub --fields=name,status,version

L'activation effectue trois opérations. Elle crée les pages Payment Successful, Payment Failed et Payment Processing, chacune avec un shortcode [wajub_pay_message]. Elle crée la table wp_wajub_transactions. Enfin, elle programme l'actualisation des règles de réécriture pour que les routes REST répondent immédiatement.

Ces trois pages sont des pages ordinaires. Modifiez-les, personnalisez leur style et adaptez-les à votre thème. Le plugin a seulement besoin de leurs identifiants, stockés dans wajub_success_page_id, wajub_failure_page_id et wajub_callback_page_id.

Connecter votre compte Wajub

Accédez à Wajub, Settings. Le plugin conserve deux jeux d'identifiants, sandbox et live. Une option détermine celui que chaque requête utilise.

OptionContenuUtilisée lorsque
wajub_test_modeOption de sandbox, activée par défautToujours, elle choisit la paire ci-dessous
wajub_secret_key_testClé sk_test.Le mode test est activé
wajub_webhook_secret_testSecret whsec_test_Le mode test est activé
wajub_secret_keyClé sk.Le mode test est désactivé
wajub_webhook_secretSecret whsec_Le mode test est désactivé
wajub_debug_logOption des logs de débogageÉcrit dans les logs WooCommerce ou dans error_log

Une clé secrète Wajub contient un préfixe, un point, puis 96 caractères. Les clés live commencent par sk., et celles de la sandbox par sk_test.. Copiez-les depuis le Dashboard. Le plugin ne demande jamais de clé publique : le navigateur reçoit un jeton de session créé par votre serveur, jamais une clé.

Aucun élément ne lit automatiquement une variable d'environnement, mais WordPress fournit le hook nécessaire. Le filtre natif pre_option_ court-circuite toute lecture d'option. Vous pouvez ainsi conserver entièrement les secrets hors de la base de données.

Clés issues de l'environnement dans un plugin must-use
<?php
// wp-content/mu-plugins/wajub-keys.php

foreach ([
    'wajub_secret_key' => 'WAJUB_SECRET_KEY',
    'wajub_secret_key_test' => 'WAJUB_SECRET_KEY_TEST',
    'wajub_webhook_secret' => 'WAJUB_WEBHOOK_SECRET',
    'wajub_webhook_secret_test' => 'WAJUB_WEBHOOK_SECRET_TEST',
] as $option => $env) {
    add_filter("pre_option_{$option}", static function () use ($env) {
        $value = getenv($env);

        return $value === false || $value === '' ? false : $value;
    });
}

Renvoyer false permet à WordPress de lire normalement l'option enregistrée. Les champs de l'administration fonctionnent donc toujours sur une machine où les variables ne sont pas définies.

Le tableau de bord sous Wajub appelle GET /payments à chaque chargement de page pour vérifier les clés. Connected indique une clé valide, Error un refus de l'API et Not configured un champ vide.

Enregistrer le webhook

Le webhook est obligatoire. Lui seul confirme un paiement lorsque le client ferme l'onglet, perd le réseau après avoir approuvé sur son téléphone ou utilise un canal dont le règlement prend plusieurs minutes. Toutes les intégrations de ce plugin en dépendent.

Copiez l'URL depuis Wajub, Settings, ou construisez-la vous-même.

ÉlémentValeur
URLhttps://your-site.com/wp-json/wajub/v1/webhook
MethodPOST
En-tête de signatureX-Wajub-Signature: v1=<hmac>
En-tête d'horodatageX-Wajub-Timestamp
Payload signéL'horodatage, un point, puis le corps brut
AlgorithmeHMAC SHA-256 avec votre secret de webhook
Tolérance300 secondes

Collez-la dans les endpoints de webhook du Dashboard Wajub. Copiez ensuite le secret de signature fourni dans le champ correspondant sous Wajub, Settings, puis enregistrez.

Vous pouvez vérifier le fonctionnement de l'endpoint depuis votre terminal. Signez un payload comme Wajub, puis envoyez-le.

Envoyer un événement de test signé
SECRET='whsec_test_your_secret_here'
BODY='{"id":"evt_local_test","event":"payment.succeeded","data":{"reference":"wc_42_1757000000","status":"succeeded","amount":25000,"currency":"XAF","metadata":{"source":"woocommerce","source_id":"42"}}}'
TS=$(date +%s)

SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d" " -f1)

curl -i -X POST https://your-site.com/wp-json/wajub/v1/webhook \
  -H "Content-Type: application/json" \
  -H "X-Wajub-Timestamp: $TS" \
  -H "X-Wajub-Signature: v1=$SIG" \
  -d "$BODY"

Une signature valide renvoie {"received":true}. Une signature incorrecte renvoie 403. Rejouer le même id renvoie {"received":true} sans répéter le traitement, car le handler conserve pendant une semaine chaque identifiant d'événement reçu.

Deux détails sont importants. Le handler accepte type et event comme clé du nom d'événement, ce qui compte car le format Wajub utilise event. Il route aussi le traitement avec metadata.source et metadata.source_id, les deux champs écrits par chaque intégration lors de la création du paiement. Cette paire indique au webhook la commande, le don ou l'entrée à finaliser.

WooCommerce

WooCommerce bénéficie de l'intégration la plus complète : trois modes de checkout, la prise en charge de Blocks, les remboursements dans les deux sens, les notifications de litige sur la commande et un parcours de nouvelle tentative qui reconstruit le panier.

Activer la passerelle

Accédez à WooCommerce, Settings, Payments et activez Wajub. La passerelle reste masquée dans le checkout tant qu'aucune clé secrète n'est enregistrée. Si elle n'apparaît pas, les clés sont absentes.

Choisir un mode de checkout

ModeAppel du SDKLieu du paiement
redirectauthorization_urlSur le checkout hébergé Wajub, puis retour vers votre page de remerciement
inlinewajub.mount()Sur votre page de checkout, dans un cadre intégré
overlaywajub.open()Sur votre page de checkout, dans une fenêtre modale

La redirection est le mode par défaut et le meilleur point de départ. Elle comporte le moins d'éléments et reste le seul mode fonctionnel lorsque JavaScript est désactivé.

Les modes en ligne et en superposition chargent Wajub.js depuis https://js.wajub.com et gardent le client sur la page de checkout. Deux réglages supplémentaires s'appliquent : une locale et un thème system, light ou dark.

Les libellés des modes dans les réglages sont obsolètes

La liste indique encore que les modes en ligne et en superposition s'intègrent à la page de paiement de la commande. Depuis la version 1.2.0, ils s'intègrent directement à la page de checkout, sans navigation. Le texte d'aide sous le champ est exact.

Maintien des modes en ligne et en superposition sur la page

Le checkout classique et le checkout Blocks suivent des parcours différents pour obtenir le même résultat. Tous deux utilisent une page fonctionnelle en repli si JavaScript ne s'exécute pas.

Dans le checkout classique, WooCommerce déclenche checkout_place_order_success sur le formulaire avec le résultat AJAX, juste avant de lire result.redirect et de naviguer. Le plugin l'écoute, remplace cette redirection par un fragment du même document et monte le widget de paiement sur place.

Dans le checkout Blocks, WooCommerce attend les observateurs onCheckoutSuccess avant de choisir la destination. Le plugin renvoie donc une promesse qui reste en attente pendant le paiement et se résout avec la destination réelle.

Si l'un des scripts ne se charge pas, WooCommerce suit la redirection originale vers la page de paiement de la commande, où le même widget est rendu côté serveur. Le client peut toujours payer, avec une navigation supplémentaire.

Tant que le widget est ouvert, la page interroge wajub/v1/embed-status toutes les trois secondes pendant dix minutes au maximum. Cet endpoint demande le statut réel du paiement à l'API, finalise la commande en cas de réussite et renvoie une URL de nouvelle tentative en cas d'échec.

Remboursements

Les remboursements fonctionnent dans les deux sens.

Un remboursement lancé dans WooCommerce appelle POST /refunds et inscrit l'identifiant du remboursement Wajub sur la commande pour éviter un double enregistrement par le webhook. Un remboursement lancé dans le Dashboard Wajub arrive par le webhook refund.succeeded et crée le remboursement WooCommerce correspondant avec refund_payment défini sur false, car l'argent a déjà été déplacé.

La métadonnée de commande _wajub_refund_<id> sécurise les remboursements partiels. Un webhook dont l'identifiant de remboursement est déjà marqué est ignoré. Un montant supérieur au solde remboursable est rejeté au lieu d'être plafonné.

Métadonnées de commande écrites par le plugin

Clé de métadonnéeContenu
_wajub_referenceVotre référence, wc_<order id>_<timestamp>
_wajub_payment_idL'identifiant du paiement Wajub, trx_…
_wajub_session_idLe jeton d'autorisation utilisé par les modes en ligne et en superposition
_wajub_modeLe mode utilisé pour créer la commande
_wajub_dispute_statusLe dernier événement de litige reçu pour cette commande
_wajub_refund_<id>Indique qu'un remboursement Wajub a déjà été enregistré

Lisez-les avec $order->get_meta() dans votre code. Consignez la référence dans les logs, car elle apparaît dans le Dashboard Wajub et dans chaque webhook.

Litiges

Un événement dispute.created, dispute.won ou dispute.lost retrouve la commande par référence ou identifiant de paiement, écrit _wajub_dispute_status, ajoute une note avec le motif et le montant, puis envoie au responsable du site un e-mail avec l'échéance de réponse. Les événements intermédiaires sont enregistrés sur la commande sans e-mail.

Nouvelle tentative après un échec

Lorsqu'un paiement échoue ou que la confirmation expire, le client reçoit un lien de nouvelle tentative. Ce lien annule la commande pending, remet les mêmes produits et variations dans le panier, puis renvoie le client au checkout avec une notification. Il contient un nonce et ne peut donc être ni partagé ni rejoué.

Dons avec GiveWP

Les deux générations de GiveWP sont prises en charge. Le plugin choisit la bonne au chargement.

GiveWP 3 et les versions ultérieures s'enregistrent avec givewp_register_payment_gateway sous l'identifiant wajub-givewp. Activez-le dans Donations, Settings, Payment Gateways. Les donateurs sont redirigés vers le checkout hébergé, puis reviennent par une route sécurisée qui vérifie le don, définit son statut et les envoie vers votre page de réussite.

GiveWP avant la version 2.18 utilise l'ancien filtre give_payment_gateways et un callback give-listener. La configuration reste identique.

Wajub statuses map onto Give statuses rather than collapsing into a single failure:

Statut WajubStatut du don GiveWP
succeededComplete
canceled, cancelled, expiredCancelled
abandonedAbandoned
failed, rejectedFailed
refunded, partially-refundedRefunded

Rembourser un don depuis l'administration GiveWP appelle l'API Wajub. Les dons récurrents ne sont pas pris en charge.

GiveWP utilise uniquement la redirection

Le formulaire de don redirige vers le checkout hébergé. Pour une expérience en ligne ou en superposition, construisez plutôt la page avec le shortcode [wajub_pay type="donation"], qui prend en charge les trois modes.

Dons avec Charitable

La passerelle étend Charitable_Gateway et s'enregistre automatiquement. Elle lit les clés dans Wajub, Settings. L'écran des réglages de la passerelle Charitable ne contient donc rien à remplir.

Les donateurs sont redirigés vers le checkout hébergé. À leur retour, le plugin vérifie le paiement auprès de l'API, puis confirme que la référence enregistrée et source_id correspondent au don. Il marque ensuite le don comme terminé et affiche le reçu. Un remboursement depuis l'administration Charitable appelle POST /refunds une seule fois et marque le don pour ignorer un second appel.

Easy Digital Downloads

Wajub apparaît dans le checkout EDD sous Wajub (Mobile Money, Card). Aucun formulaire de carte n'est à afficher, la passerelle le masque donc.

Le flux crée d'abord un paiement EDD pending, puis le paiement Wajub, avant de rediriger. Au retour, le plugin vérifie le paiement auprès de l'API. Il le publie avec une note contenant la référence, ou le marque comme échoué avec son motif.

EDD pilote lui-même les remboursements. Passer un paiement à refunded ou partially_refunded appelle l'API Wajub une seule fois. La métadonnée _wajub_refund_api_done bloque un second appel.

Cours avec Tutor LMS, LifterLMS et LearnDash

Les trois plugins LMS proposent trois niveaux d'intégration différents, car leurs surfaces d'extension ne sont pas les mêmes.

Tutor LMS bénéficie d'une passerelle native. Elle s'intègre à Tutor Ecommerce avec tutor_payment_gateways. Wajub apparaît dans le checkout Tutor normal et l'inscription suit le flux de commande de Tutor. Les remboursements lancés dans Tutor appellent l'API. Si Tutor Ecommerce est désactivé, un bouton [wajub_pay] apparaît sur la page du cours.

LifterLMS bénéficie aussi d'une véritable passerelle. Elle étend LLMS_Payment_Gateway et s'enregistre avec lifterlms_payment_gateways. Une commande payante redirige vers le checkout hébergé. Le webhook de confirmation enregistre la transaction sur la commande LifterLMS et inscrit l'étudiant.

LearnDash ne propose aucun modèle de commande exploitable par ce plugin. Un bouton de paiement est donc ajouté aux boutons du cours, et l'accès est accordé avec le hook wajub_payment_complete. Aucun remboursement n'est possible depuis WordPress. Utilisez plutôt le Dashboard Wajub.

Adhésions avec MemberPress

La passerelle s'enregistre avec mepr-gateway-paths et gère les paiements uniques d'adhésion. Un achat redirige vers le checkout hébergé. Le callback de retour vérifie ensuite le paiement, finalise la transaction MemberPress et envoie le reçu.

La facturation récurrente n'est pas implémentée. Une adhésion avec un tarif d'abonnement ne sera pas débitée automatiquement une nouvelle fois.

Gravity Forms

L'extension repose sur le framework d'extensions de paiement de Gravity Forms. Elle se comporte donc comme vos autres feeds de paiement : créez un feed sur le formulaire, associez le montant et l'e-mail, puis Wajub s'occupe du reste.

Les soumissions redirigent vers le checkout hébergé. Le callback de retour vérifie le paiement auprès de l'API, compare la référence enregistrée et source_id à l'entrée, marque celle-ci comme Paid, puis déclenche gform_post_payment_status pour exécuter vos feeds et notifications.

Un remboursement depuis l'entrée Gravity Forms appelle l'API Wajub une seule fois, grâce à la métadonnée d'entrée wajub_refund_api_done.

Tout autre plugin avec des shortcodes

Trois shortcodes couvrent tous les plugins sans passerelle et toutes vos pages personnalisées. Ils utilisent une route REST publique qui crée le paiement côté serveur. Aucune clé n'atteint donc le navigateur.

Un bouton de paiement

[wajub_pay] affiche un petit formulaire qui demande un e-mail et, facultativement, un nom. Il lance ensuite le paiement dans le mode choisi.

amountnumberfacultatif
Montant dans l'unité principale. 25 000 XAF représente vingt-cinq mille francs.
currencystringfacultatifdéfaut : XAF
Code de trois lettres. Toute autre valeur utilise XAF en repli.
moderedirect | inline | overlayfacultatifdéfaut : redirect
Toute autre valeur utilise redirect en repli.
typepayment | donationfacultatifdéfaut : payment
Un don affiche un champ de montant rempli par le donateur.
descriptionstringfacultatif
Affichée dans le checkout et enregistrée sur le paiement. Limitée à 500 caractères.
product_idnumberfacultatif
Identifiant de produit WooCommerce. Son prix et son nom remplacent le montant et la description.
content_idstringfacultatif
Indique que le paiement déverrouille un contenu.
button_textstringfacultatifdéfaut : Pay with Wajub
Libellé du bouton d'envoi.
classstringfacultatif
Classe CSS supplémentaire sur le wrapper.
Trois façons de placer le bouton
[wajub_pay amount="25000" currency="XAF" description="Consultation" mode="redirect"]

[wajub_pay product_id="482" mode="overlay" button_text="Buy now"]

[wajub_pay type="donation" currency="XAF" mode="inline" button_text="Support us"]

Contenu verrouillé

[wajub_pay_content] enveloppe un contenu qui apparaît seulement après le paiement du lecteur. En attendant, il affiche le même formulaire et utilise par défaut le mode en superposition afin que la page ne change pas sous ses yeux.

Une section payante
[wajub_pay_content content_id="masterclass-2026" amount="15000" currency="XAF"]
The full recording, the slides, and the worksheet live here.
[/wajub_pay_content]

L'accès est mémorisé de deux façons : sur le compte lorsque l'acheteur est connecté, ou pendant trente jours dans une donnée temporaire indexée par l'identifiant du contenu et son e-mail lorsqu'il ne l'est pas. Un acheteur déconnecté qui change de navigateur devra payer de nouveau. Cet outil convient donc à un téléchargement numérique ou à un article unique, pas à une adhésion. MemberPress ou LifterLMS gèrent correctement ce dernier cas.

Message de résultat

[wajub_pay_message] affiche le message de réussite, d'échec ou de traitement. Les trois pages créées à l'activation le contiennent. Il n'affiche rien si l'URL ne contient pas de paramètre reference, et reste donc invisible lors d'une visite directe.

Shortcodes dans un template de thème

En dehors de l'éditeur, exécutez-les avec do_shortcode().

Dans un fichier de template
<?php
$amount = (float) get_post_meta(get_the_ID(), 'ticket_price', true);

if ($amount > 0) {
    echo do_shortcode(sprintf(
        '[wajub_pay amount="%s" currency="XAF" description="%s" mode="overlay"]',
        esc_attr((string) $amount),
        esc_attr(get_the_title())
    ));
}

Créer votre propre intégration

Tout ce qui précède repose sur trois éléments que vous pouvez utiliser directement : un client API, un jeton de callback HMAC et un ensemble de hooks déclenchés par le handler de webhook.

Hooks

HookArgumentsDéclenché lorsque
wajub_payment_complete$reference, $data, $source, $sourceIdUn paiement réussit
wajub_payment_failed$reference, $data, $source, $sourceIdUn paiement échoue, est annulé, abandonné, rejeté ou expiré
wajub_refund_complete$paymentRef, $data, 'woocommerce', $orderIdUn remboursement réussit sur une commande WooCommerce
wajub_dispute_received$eventType, $dataTout événement de litige
wajub_webhook_received$eventType, $dataChaque événement vérifié, après le routage
wajub_webhook_missing_secret$rawPayloadUn événement arrive sans secret configuré
wajub_webhook_invalid_signature$rawPayloadUn événement échoue à la vérification de signature ou d'horodatage
wajub_default_phone_country_code'237'Un numéro à neuf chiffres a besoin d'un indicatif pays

Le dernier est un filtre. Les autres sont des actions. $source et $sourceId proviennent directement des metadata définies à la création du paiement. Votre propre nom de source peut ainsi fonctionner.

Livrer votre propre enregistrement

Définissez votre propre metadata.source lors de la création du paiement, puis traitez-la. Le hook s'exécute dans le webhook, seul endroit où le paiement est confirmé et non supposé réussi.

Marquer votre propre réservation comme payée
<?php

add_action('wajub_payment_complete', static function (
    string $reference,
    array $data,
    string $source,
    $sourceId
): void {
    if ($source !== 'bookings' || empty($sourceId)) {
        return;
    }

    $booking = get_post((int) $sourceId);
    if (! $booking || $booking->post_type !== 'booking') {
        return;
    }

    update_post_meta($booking->ID, 'payment_status', 'paid');
    update_post_meta($booking->ID, 'wajub_reference', $reference);
    update_post_meta($booking->ID, 'paid_amount', (float) ($data['amount'] ?? 0));

    do_action('bookings_confirmed', $booking->ID);
}, 10, 4);

Créer un paiement depuis votre code

Client::getInstance() fournit un client configuré avec le jeu de clés choisi par l'option du mode test. Les montants utilisent l'unité principale. Le client les arrondit automatiquement pour les devises sans décimales.

Lancer un paiement et rediriger
<?php

use WajubPay\API\Client;
use WajubPay\Security\CallbackToken;

function bookings_start_payment(int $bookingId, float $amount, string $email): string
{
    $callback = add_query_arg([
        'bookings' => 'wajub_return',
        'booking_id' => $bookingId,
        '_wajub_token' => CallbackToken::generate($bookingId),
    ], home_url('/'));

    $result = Client::getInstance()->createPayment([
        'amount' => $amount,
        'currency' => 'XAF',
        'description' => sprintf('Booking #%d', $bookingId),
        'reference' => 'booking_' . $bookingId . '_' . time(),
        'callback' => $callback,
        'customer' => ['email' => $email],
        'metadata' => [
            'source' => 'bookings',
            'source_id' => (string) $bookingId,
        ],
    ]);

    $parsed = Client::parsePaymentResponse($result);
    update_post_meta($bookingId, 'wajub_reference', $parsed['reference']);

    return $parsed['authorization_url'];
}

parsePaymentResponse() aplatit l'enveloppe de l'API en id, reference, session_id, authorization_url et status. Envoyez le client vers authorization_url pour un checkout avec redirection, ou passez session_id à wajub.mount() pour une intégration en ligne.

L'URL de callback est la destination du client à son retour. Il s'agit d'une redirection du navigateur. Utilisez-la seulement pour choisir la page à afficher, jamais comme preuve de paiement. Vérifiez le jeton, puis le paiement.

Gérer le retour en toute sécurité
<?php

use WajubPay\API\Client;
use WajubPay\Security\CallbackToken;

add_action('init', static function (): void {
    $action = isset($_GET['bookings']) ? sanitize_text_field(wp_unslash($_GET['bookings'])) : '';
    if ($action !== 'wajub_return') {
        return;
    }

    $bookingId = absint($_GET['booking_id'] ?? 0);
    $token = sanitize_text_field(wp_unslash($_GET['_wajub_token'] ?? ''));

    if (! $bookingId || ! CallbackToken::verify($bookingId, $token)) {
        wp_safe_redirect(home_url('/'));
        exit;
    }

    $reference = (string) get_post_meta($bookingId, 'wajub_reference', true);
    $status = 'pending';

    try {
        $payment = Client::getInstance()->retrievePayment($reference);
        $status = (string) (Client::extractTransaction($payment)['status'] ?? 'pending');
    } catch (\Throwable) {
        // The webhook is still the source of truth. Show a waiting page.
    }

    wp_safe_redirect(Client::isSucceededStatus($status)
        ? home_url('/booking-confirmed/')
        : home_url('/booking-pending/'));
    exit;
});

CallbackToken::generate() produit un HMAC de l'identifiant, éventuellement salé avec une seconde valeur comme une clé de commande, puis signé avec votre secret de webhook. Il empêche un visiteur de confirmer la réservation d'une autre personne en modifiant l'identifiant dans l'URL. Passez toujours à verify() le même second argument qu'à generate().

Modifier l'indicatif pays par défaut

Un numéro de téléphone à neuf chiffres sans indicatif est considéré comme camerounais. Modifiez ce réglage une fois pour tout le site.

Le Sénégal par défaut
<?php

add_filter('wajub_default_phone_country_code', static fn (): string => '221');

Fonctionnalités du client API

MéthodeRôle
createPayment(array $params)POST /payments, renvoie l'enveloppe brute
retrievePayment(string $reference)GET /payments/{reference}
cancelPayment(string $reference)DELETE /payments/{reference}
createRefund(string $paymentId, ?float $amount, ?string $reason, string $currency)POST /refunds
refundByStoredIds(string $paymentId, string $reference, …)Résout d'abord l'identifiant trx_, puis rembourse
testConnection()Un simple appel GET /payments, renvoie un booléen
isConfigured(), isTestMode()Lit les réglages enregistrés

Chaque requête transmet la clé secrète brute dans Authorization, sans préfixe bearer, avec un délai d'expiration de 30 secondes et une Idempotency-Key pour les écritures. Elle est retentée deux fois après une erreur réseau, une erreur 429 ou une erreur 5xx. Les échecs déclenchent une exception typée : AuthenticationException, PermissionException, NotFoundException, RateLimitException, InvalidRequestException ou ApiConnectionException. Toutes étendent ApiException avec les propriétés en lecture seule errorCode, httpStatus et body.

Routes REST

Quatre routes se trouvent sous wajub/v1. Elles sont toutes publiques par conception et chacune porte sa propre preuve.

RouteMéthodeProtégée par
/webhookPOSTUne signature HMAC et une fenêtre d'horodatage de 300 secondes
/callbackGETRien, elle redirige seulement. Le statut est relu depuis l'API
/embed-statusGETUn nonce lié à l'identifiant de commande, avec la clé de commande
/create-paymentPOSTUn nonce WordPress, avec 20 requêtes par minute et par IP

Un ancien chemin de webhook, POST /?wajub=webhook, est conservé pour les sites configurés avant la création de la route REST. Il vérifie la même signature. Utilisez la route REST pour toute nouvelle intégration.

Table des transactions

Chaque webhook écrit une ligne dans wp_wajub_transactions, quelle que soit son intégration. C'est le seul endroit où une commande WooCommerce, un don GiveWP et un paiement par shortcode apparaissent ensemble. Wajub, Transactions affiche cette table.

ColonneContenu
referenceVotre référence unique
trxrefLa référence du côté de Wajub
amount, currencyValeurs envoyées par l'API
statusLe dernier statut reçu
source, source_idLa paire de métadonnées qui a routé l'événement
customer_emailProvient du paiement
environmenttest ou live, selon l'option au moment de l'écriture
metadata, payloadJSON
created_at, updated_atHorodatages

Le tableau de bord totalise le volume réussi par devise au lieu de tout additionner. Un site qui accepte le XAF et le GHS affiche donc deux chiffres plutôt qu'un total sans signification.

Désinstaller le plugin supprime cette table et toutes les options wajub_. Le désactiver ne les supprime pas. Exportez les données nécessaires avant de supprimer le plugin.

Passer en live

  1. 1

    Tester tout le parcours dans la sandbox

    Passez une vraie commande avec un numéro Mobile Money de la sandbox et vérifiez que la commande atteint un état payé sans intervention dans l'administration. Testez aussi une annulation et un remboursement.

  2. 2

    Confirmer le déclenchement du webhook

    La commande doit se terminer même si vous fermez l'onglet juste après l'approbation. Si elle se termine seulement à votre retour sur le site, le webhook n'est pas configuré et vous dépendez du callback.

  3. 3

    Ajouter les identifiants live

    Collez la clé secrète live et le secret de webhook live, puis enregistrez la même URL comme endpoint de webhook live dans le Dashboard. Les endpoints live et sandbox sont distincts.

  4. 4

    Désactiver le mode test

    Décochez le mode test dans Wajub, Settings. Vérifiez que le tableau de bord affiche Live et Connected.

  5. 5

    Encaisser un paiement réel

    Encaissez un petit montant sur un vrai téléphone, puis remboursez-le. C'est le seul test qui vérifie ensemble les clés live, le webhook live et votre processus de livraison.

L'activation du compte et le KYC qui déverrouille les clés live sont présentés dans Passer en live.

Dépannage

SymptômeCauseSolution
Wajub est absent du checkout WooCommerceAucune clé secrète enregistrée pour l'environnement actuelLa passerelle reste masquée sans clé. Remplissez le champ de l'environnement choisi par l'option
Les commandes restent sur pending après un paiement réussiLe champ du secret de webhook est vide ou l'endpoint n'est pas enregistréChaque livraison est refusée avec 403 tant que le secret ne correspond pas. Envoyez la requête de test signée ci-dessus
De l'argent réel a été déplacé en mode testLe champ de clé sandbox était vide et le client a utilisé la clé liveRemplissez les deux champs ou effacez la clé live jusqu'au passage en live
Le formulaire du shortcode renvoie une erreur de requête invalideUn nonce expiré servi par un cache de page complèteExcluez la page du cache ou réduisez sa durée à moins de 24 heures
Le feed Gravity Forms n'apparaît pasLe dossier du plugin ne s'appelle pas wajubRenommez-le en wajub et réactivez le plugin
Le checkout en ligne redirige vers une page de paiement séparéeLe script d'intégration ne s'est pas chargéRecherchez dans la console une requête bloquée vers js.wajub.com. La redirection est le repli prévu
Un montant est cent fois trop élevéUtilisation habituelle des unités mineuresWajub utilise l'unité principale. Envoyez 25 000 pour vingt-cinq mille francs, pas 2 500 000
Le tableau de bord d'administration est lentIl appelle l'API à chaque chargement pour afficher l'état de la connexionComportement attendu. Il s'agit d'une seule requête, uniquement sur les écrans d'administration Wajub
Rien n'apparaît dans les logsLes logs de débogage sont désactivésActivez-les dans les réglages ou définissez WP_DEBUG. Lorsque WooCommerce est actif, la sortie va dans ses logs sous la source wajub. Sinon, elle va dans error_log

Pour tout autre problème, activez les logs de débogage, reproduisez-le, puis envoyez les logs au support avec la référence de transaction. N'envoyez jamais de clé.

Que pensez-vous de ce contenu ?