Chargement de vos clés API…

Xano

Encaissez depuis un backend Xano : deux endpoints, zéro dépendance externe.

Validé de bout en bout

À savoir avant de commencer

  • L'offre gratuite de Xano suffit : appels HTTP sortants, endpoints publics et variables d'environnement y sont disponibles.
  • Xano sert souvent de backend à Bubble, FlutterFlow, WeWeb, Glide ou Softr : cette intégration donne l'encaissement Mobupay à toutes ces applications.
  • Modèle « page hébergée » : votre backend crée un lien de paiement, le client paie chez Mobupay, votre backend reçoit un webhook signé. Aucune donnée carte ne transite par Xano.
  • Chaque endpoint Xano est éditable en XanoScript (vue code de l'endpoint) : les scripts complets, validés de bout en bout, sont fournis ci-dessous.

1. Variables d'environnement

  1. 1Récupérez votre clé API (sk_test_… pour commencer, sk_live_… en production) dans l'espace marchand, rubrique Développeurs.
  2. 2Récupérez votre secret webhook de compte (whsec_…) via l'API (voir ci-dessous). Attention : c'est ce secret qui signe les livraisons vers votre notificationUrl, pas le secret d'un endpoint webhook créé dans l'espace marchand.
  3. 3Dans Xano, menu Keys & Variables : créez MOBUPAY_API_KEY et MOBUPAY_WEBHOOK_SECRET.
curl -s https://api.mobupay.nc/api/v1/webhooks/signing-secret \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
# -> { "webhookSecret": "whsec_..." }

2. Endpoint de réception du webhook (à créer en premier)

Menu APIs : créez un groupe (par exemple mobupay), puis un endpoint POST /mobupay-webhook, et collez ce XanoScript. Il vérifie la signature avant tout traitement (403 sinon), rejette les livraisons de plus de 5 minutes (anti-rejeu), puis route l'événement. Copiez ensuite son URL publique (forme https://…xano.io/api:XXXX/mobupay-webhook) : elle sert à l'étape 3.

query "mobupay-webhook" verb=POST {
  api_group = "mobupay"

  input {
  }

  stack {
    // encoding "none" obligatoire : la signature porte sur le corps brut exact
    util.get_raw_input {
      encoding = "none"
      exclude_middleware = false
    } as $raw_body

    var $ts { value = $env.$http_headers|get:"X-Mobupay-Timestamp" }
    var $sig { value = $env.$http_headers|get:"X-Mobupay-Signature-V2" }
    var $signed { value = $ts ~ "." ~ $raw_body }
    var $expected { value = $signed|hmac_sha256:$env.MOBUPAY_WEBHOOK_SECRET }

    precondition ($expected == $sig) {
      error_type = "accessdenied"
      error = "Signature Mobupay V2 invalide"
    }

    var $age_s { value = (("now"|to_timestamp) / 1000) - ($ts|to_int) }

    precondition ($age_s < 300 && $age_s > -300) {
      error_type = "accessdenied"
      error = "Webhook Mobupay expire (anti-rejeu 5 min)"
    }

    var $event { value = $raw_body|json_decode }

    // payment.authorized OU payment.captured = paye ; rapprochez via externalId.
    // C'est ici que vous ecrivez en base (traitement idempotent) :
    // payment.failed / .cancelled / .expired -> echec ;
    // payment.refunded / .partially_refunded -> remboursee.
    var $paid {
      value = ($event.type == "payment.authorized") || ($event.type == "payment.captured")
    }
  }

  response = {received: true, type: $event.type, externalId: $event.data.externalId, paid: $paid}
}

3. Endpoint de création du lien de paiement

Même groupe : créez un endpoint POST /pay et collez ce script. Remplacez redirectUrl (votre page de remerciement) et notificationUrl (l'URL copiée à l'étape 2). Le montant est en unité mineure (centimes EUR, ou unité XPF).

query pay verb=POST {
  api_group = "mobupay"

  input {
    text reference? filters=trim
    int amount?
    text currency? filters=trim
  }

  stack {
    api.request {
      url = "https://api.mobupay.nc/api/v1/payments/links"
      method = "POST"
      params = {order: {reference: $input.reference, amount: $input.amount, currency: $input.currency}, redirectUrl: "https://VOTRE-SITE/merci", notificationUrl: "https://VOTRE-INSTANCE.xano.io/api:XXXX/mobupay-webhook", externalId: $input.reference}
      headers = []|push:"Content-Type: application/json"|push:"Authorization: Bearer " ~ $env.MOBUPAY_API_KEY|push:"Idempotency-Key: " ~ $input.reference
    } as $mobupay_api
  }

  response = $mobupay_api.response.result
}

La réponse contient linkUrl : votre application l'ouvre ou l'affiche, le client paie sur la page hébergée Mobupay. Rejouer la création avec la même référence renvoie le même lien (idempotence via l'en-tête Idempotency-Key) : pas de doublon sur un nouvel essai réseau.

Pièges connus (si vous montez la pile à la main)

  • Les champs headers et params de l'étape External API Request doivent être saisis en mode expression. En mode texte, les variables ne sont pas évaluées et la requête part en x-www-form-urlencoded (erreur 415 côté Mobupay).
  • Get All Raw Input : gardez encoding = "none". Avec "json", le corps est parsé puis re-sérialisé et la signature ne correspondra jamais. Ne re-sérialisez jamais le JSON avant vérification.
  • $env.$http_headers est un objet dont les clés contiennent des tirets : lisez les en-têtes avec le filtre get, pas en notation pointée.
  • Le filtre hmac_sha256 renvoie l'empreinte en hexadécimal, directement comparable à X-Mobupay-Signature-V2.
  • Le flux carte réel émet payment.authorized ; le bac à sable émet payment.captured. Routez les deux comme « payé ».

Tester

Avec une clé sk_test_…, le parcours complet se rejoue sans argent réel : créez un lien via votre endpoint /pay, payez avec une carte de test, et observez la livraison signée dans le Request History de votre endpoint webhook. Voir aussi les guides Webhooks et No-code & automatisation (pattern général, Make, Zapier, n8n).