Aller au contenu principal
Sur cette page

Commencez avec Nequi#

Cette page fournit un guide complet pour intégrer avec succès Nequi à DEUNA dans votre commande.

Nequi est un portefeuille numérique géré par Bancolobia et est largement utilisé en Colombie.

Comment ça marche#

L'intégration de DEUNA avec Nequi permet aux utilisateurs de payer par un flux de notification de poussée, entièrement géré dans le Widget de paiement DEUNA — aucune redirection externe nécessaire.

Processus de paiement

La liste suivante décrit un processus de paiement valide avec Nequi :

  1. L'utilisateur sélectionne Nequi dans le Widget de paiement.
  2. L'utilisateur entre son vrai numéro de téléphone Nequi.
  3. Une notification de poussée est envoyée à leur application mobile Nequi.
  4. L'utilisateur approuve le paiement directement dans l'application.
  5. DEUNA reçoit le statut de paiement .
  6. DEUNA déclenche l'événement de rappel approprié dans le widget :
    • onSuccess pour les paiements approuvés
    • onError pour les produits refusés ou périmés

surGestion des événements

Le widget DEUNA déclenche la onError callback dans les scénarios suivants:

  1. Le numéro de téléphone fourni dans le formulaire de paiement est valide mais n'est pas associé à un compte Nequi.
  2. L'utilisateur rejette la notification de poussée de l'application Nequi.

Dans les deux cas, DEUNA retourne une réponse comprenant un code d'erreur et un message d'erreur décrivant l'échec. Vous pouvez gérer la réponse en fonction de votre logique d'affaires et de l'expérience utilisateur souhaitée.

Exigences#

Le contenu suivant énumère toutes les exigences pour une intégration réussie avec Nequi.

Vos identifiants Nequi sandbox et production doivent être demandés directement à votre gestionnaire de compte Bancoloombia ou Nequi.

Environnements:

Terminer le processus de certification avec Nequi et obtenir les titres de compétence suivants fournis par Nequi :

  • Merchant ID

  • Mot de passe marchand

  • Clé publique.

  • Code d'identification

  • Durée de validité (max. 45min)

Configurer les webhooks dans Nequi#

Configurez des webhooks dans votre session Nequi pour chaque magasin.

Si vous ne configurez pas les webhooks de Nequi, les mises à jour de l'état dans Nequi vont prendre entre deux et cinq minutes.

Assurez-vous que votre point d'arrivée webhook est très disponible et évolutif. En option, vous pouvez configurer l'inversion de transaction si la confirmation de paiement échoue en raison de l'indisponibilité du service.

Charge utile Webhook

Nequi enverra la charge utile JSON suivante:

JSON
{
  "commerceCode": "29603",
  "value": "1",
  "phoneNumber": "3195414070",
  "messageId": "60396545535",
  "transactionId": "350-12345-34000201-60396545535",
  "region": "C001",
  "receivedAt": "2023-02-27T15:50:13.527Z",
  "paymentStatus": "SUCCESS"
}

Champs de charge utile

ChampDescriptif
commerceCodeVotre code Nequi
valueMontant du paiement
phoneNumberNuméro de téléphone mobile du payeur
messageIdidentificateur unique de la transaction
transactionIdIdentifiant de paiement
regionRégion de paiement P001 (Panama) ou C001 (Colombie)
receivedAtéchéancier de paiement au format JSON
paymentStatusÉtat du paiement SUCCESS, CANCELED, ou DENIED

Vérification de la demande de sécurité

Toutes les requêtes webhook de Nequi incluent des en-têtes de sécurité que vous devez vérifier:

Demander en-têtes

JSON
{
  "Content-Type": "application/json",
  "Digest": "SHA-256=43GpOk5L54gfpAMBE0xNX1bj2hJA9JJ1RR0dErHfZhI=",
  "Signature": "keyId=\"YourClientId\",algorithm=\"hmac-sha384\",headers=\"content-type digest\",signature=\"...\""
}

Processus de vérification

Vous devez vérifier deux choses pour chaque demande :

1. Vérifier le digestage corporel

Le Digest l'en-tête contient un hachage SHA-256 du corps de la demande:

JavaScript
// Convert body to string
const parsedBody = JSON.stringify(request.body);

// Calculate SHA-256 hash
const calculatedDigest = `SHA-256=${createHash('sha256')
  .update(parsedBody)
  .digest('base64')}`;

// Verify it matches the header
if (calculatedDigest !== request.headers.Digest) {
  return 401; // Invalid Digest
}
2. Vérifier la signature de la demande

Le Signature header s'assure que la demande est venue de Nequi:

  1. Pars l'en-tête Signature.
JavaScript
const parts = request.headers.Signature.split(',');
const signature = {};

for (const part of parts) {
  const [key, value] = part.split('=');
  signature[key] = value.slice(1, -1); // Remove quotes
}

// Result:
// {
//   keyId: "YourClientId",
//   algorithm: "hmac-sha384",
//   headers: "content-type digest",
//   signature: "..."
// }
  1. Construisez le texte de signature.
JavaScript
const headerNames = signature.headers.split(' '); // ["content-type", "digest"]
const linesForSignature = [];

for (const headerName of headerNames) {
  const value = request.headers[headerName.toLowerCase()];
  linesForSignature.push(`${headerName}: ${value}`);
}

const textForSignature = linesForSignature.join('\n');
// Result:
// "content-type: application/json
// digest: SHA-256=43GpOk5L54gfpAMBE0xNX1bj2hJA9JJ1RR0dErHfZhI="
  1. Calculer et vérifier l'AMAC.
JavaScript
const APP_SECRET = 'YourSharedSecret'; // Store securely, never hardcode

// Calculate HMAC-SHA384
const base64hmac = createHmac('sha384', APP_SECRET)
  .update(textForSignature)
  .digest('base64');

// Convert to base64url format
const calculatedSignature = base64hmac
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=+$/, '');

// Verify signature
if (calculatedSignature !== signature.signature) {
  return 401; // Invalid Signature
}

Exemple complet de mise en œuvre (Node.js)

JavaScript
const { createHash, createHmac } = require('node:crypto');

// Store securely - use environment variables
const APP_SECRET = process.env.NEQUI_WEBHOOK_SECRET;

async function handleNequiWebhook(request, response) {
  try {
    // 1. Verify Body Digest
    const parsedBody = JSON.stringify(request.body);
    const calculatedDigest = `SHA-256=${createHash('sha256')
      .update(parsedBody)
      .digest('base64')}`;
    
    if (calculatedDigest !== request.headers.digest) {
      return response.status(401).send('Invalid Digest');
    }

    // 2. Parse Signature Header
    const parts = request.headers.signature.split(',');
    const signatureData = {};
    
    for (const part of parts) {
      const [key, value] = part.split('=');
      signatureData[key] = value.slice(1, -1);
    }

    // 3. Build Signing Text
    const headerNames = signatureData.headers.split(' ');
    const linesForSignature = headerNames.map(name => 
      `${name}: ${request.headers[name.toLowerCase()]}`
    );
    const textForSignature = linesForSignature.join('\n');

    // 4. Verify Signature
    const base64hmac = createHmac('sha384', APP_SECRET)
      .update(textForSignature)
      .digest('base64');
    
    const calculatedSignature = base64hmac
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');

    if (calculatedSignature !== signatureData.signature) {
      return response.status(401).send('Invalid Signature');
    }

    // 5. Process the payment notification asynchronously
    processPaymentAsync(request.body);

    // 6. Respond immediately (within 10 seconds)
    return response.status(200).send('OK');

  } catch (error) {
    console.error('Webhook processing error:', error);
    return response.status(500).send('Internal Server Error');
  }
}

async function processPaymentAsync(paymentData) {
  // Process payment in background
  // Update your database, trigger notifications, etc.
  
  const { transactionId, paymentStatus, value, phoneNumber } = paymentData;
  
  if (paymentStatus === 'SUCCESS') {
    // Handle successful payment
  } else if (paymentStatus === 'CANCELED' || paymentStatus === 'REFUSED') {
    // Handle failed payment
  }
}

Intégrer Nequi#

Maintenant que les exigences techniques sont définies, vous pouvez commencer l'intégration étape par étape.

1. Créez un order_token

Pour effectuer un achat, vous devez créer une commande DEUNA.

Faites une demande au Créer une commande endpoint.

L'API renvoie un order_token, qui est utilisé tout au long du flux.

2. Obtenez le order_token

Faites une demande au Obtenir la commande endpoint.

Utilisez ce jeton pour les prochaines étapes.

3. Afficher le widget de paiement

Après avoir reçu le jeton de commande, vous pouvez restituer le Widget DEUNA.

JavaScript
await DeunaSDK.initPaymentWidget({
    orderToken: "<DEUNA order token>",
    callbacks: ...,
    paymentMethods: [
        {
            paymentMethod: "voucher",
            processors: ["nequi_push_voucher"],
        },
    ],
});

4. Effectuer un paiement par carte

Faites une demande de paiement par carte à la Acheter la V2 point final et traiter le paiement.

Renvoie la commande traitée avec son

Card payment exampleJavaScript
{
  "order": {
    "cash_change": 0,
    "currency": "USD",
    "discounts": [],
    "display_items_total_amount": "",
    "display_shipping_amount": "",
    "display_sub_total": "",
    "display_tax_amount": "",
    "display_total_amount": "",
    "display_total_discount": "",
    "gift_card": [],
    "items": [
      {
        "brand": "",
        "category": "",
        "color": "",
        "description": "Papa Fritas",
        "details_url": "",
        "discounts": [],
        "id": "001",
        "image_url": "https://images-staging.getduna.com/95463fb5-6279-4ec3-8ff9-fe07aacd2142/cd928351d12c6b96_domicilio_316_744x744.png?d=600x600",
        "isbn": "",
        "manufacturer": "",
        "name": "Papa Fritas",
        "options": "",
        "quantity": 1,
        "size": "",
        "sku": "",
        "tax_amount": {
          "amount": 44,
          "currency": "USD",
          "currency_symbol": "$",
          "display_amount": ""
        },
        "taxable": false,
        "total_amount": {
          "amount": 594,
          "currency": "USD",
          "currency_symbol": "$",
          "display_amount": "",
          "display_original_amount": "",
          "display_total_discount": "",
          "original_amount": 0,
          "total_discount": 0
        },
        "type": "",
        "unit_price": {
          "amount": 550,
          "currency": "USD",
          "currency_symbol": "$",
          "display_amount": ""
        },
        "uom": "",
        "upc": "",
        "weight": {
          "unit": "",
          "weight": 0
        }
      },
      {
        "brand": "",
        "category": "",
        "color": "",
        "description": "Hamburguesa ",
        "details_url": "",
        "discounts": [],
        "id": "002",
        "image_url": "https://images-staging.getduna.com/95463fb5-6279-4ec3-8ff9-fe07aacd2142/cd928351d12c6b96_domicilio_51330_744x744_1646338877.png?d=600x600",
        "isbn": "",
        "manufacturer": "",
        "name": "Hamburguesa",
        "options": "",
        "quantity": 2,
        "size": "",
        "sku": "",
        "tax_amount": {
          "amount": 88,
          "currency": "USD",
          "currency_symbol": "$",
          "display_amount": ""
        },
        "taxable": false,
        "total_amount": {
          "amount": 3088,
          "currency": "USD",
          "currency_symbol": "$",
          "display_amount": "",
          "display_original_amount": "",
          "display_total_discount": "",
          "original_amount": 0,
          "total_discount": 0
        },
        "type": "",
        "unit_price": {
          "amount": 1500,
          "currency": "USD",
          "currency_symbol": "$",
          "display_amount": ""
        },
        "uom": "",
        "upc": "",
        "weight": {
          "unit": "",
          "weight": 0
        }
      }
    ],
    "items_total_amount": 3682,
    "metadata": {
      "key1": "NO REQUERIDO",
      "key2": "NO REQUERIDO"
    },
    "order_id": "order116",
    "payment": {
      "data": {
        "amount": {
          "amount": 3770,
          "currency": "USD"
        },
        "authorization_3ds": {
          "html_content": "<div></div>",
          "url_challenge": "",
          "version": "1.1.1"
        },
        "authorization_code": "TEST00",
        "created_at": "2022-07-22 20:22:48.408419489 +0000 UTC",
        "customer": {
          "email": "jhondoe@deuna.com",
          "id": "xxxxxx-0eb3-450f-8b26-4ff23208470f"
        },
        "from_card": {
          "card_brand": "Visa",
          "first_six": "411111",
          "last_four": "1111"
        },
        "id": "order116",
        "installments": {
          "installment_amount": 5999,
          "installment_rate": 0.12,
          "installment_type": "MCI",
          "installments": 3,
          "plan_id": "7471ed27-094d-44c4-a62d-225644b782f7",
          "plan_option_id": "87309ea8-3942-4fdf-95ec-ce29a792aff2"
        },
        "merchant": {
          "id": "9a85e296-cc3d-454b-b591-208d6e538126",
          "store_code": "all"
        },
        "metadata": {
          "authorization_code": "TEST00"
        },
        "method_type": "credit_card",
        "processor": "paymentez",
        "reason": "",
        "status": "processed",
        "updated_at": "2022-07-22 20:22:48.408809765 +0000 UTC"
      }
    },
    "redirect_url": "",
    "scheduled_at": "",
    "shipping": null,
    "shipping_address": {
      "additional_description": "Piso 9",
      "address_type": "home",
      "address1": "Av. de los Incas 15-33, Ambato 180202, Ecuador",
      "address2": "Av. de los Incas 15-33, Ambato 180202, Ecuador",
      "city": "Ambato",
      "country_code": "EC",
      "created_at": "0001-01-01T00:00:00Z",
      "first_name": "Jhon",
      "id": 0,
      "identity_document": "146565656",
      "is_default": true,
      "last_name": "Doe",
      "lat": -1.2480678792202227,
      "lng": -78.62532788804577,
      "phone": " 946565665",
      "state_name": "Tungurahua",
      "updated_at": "0001-01-01T00:00:00Z",
      "user_id": "xxxxx4e2-xxxx-xxxx-xxxx-xxxxx5b7b2e",
      "zipcode": "180202"
    },
    "shipping_amount": 0,
    "shipping_method": null,
    "shipping_methods": [],
    "shipping_options": {},
    "status": "succeeded",
    "store_code": "",
    "sub_total": 3550,
    "tax_amount": 132,
    "timezone": "",
    "total_amount": 3770,
    "total_discount": 0,
    "user_instructions": "Piso 9",
    "webhook_urls": null
  },
  "order_token": "0b98dbe8-d265-49bc-b80d-536cea46509c"
}

Essai Nequi#

Pour tester Nequi, vous devez exiger les données de test pour Nequi. Si nécessaire, le paiement peut être remboursé par l'intermédiaire du panneau administratif DEUNA ou par l'intermédiaire du API de remboursement.