Nequi
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 :
- L'utilisateur sélectionne Nequi dans le Widget de paiement.
- L'utilisateur entre son vrai numéro de téléphone Nequi.
- Une notification de poussée est envoyée à leur application mobile Nequi.
- L'utilisateur approuve le paiement directement dans l'application.
- DEUNA reçoit le statut de paiement .
- DEUNA déclenche l'événement de rappel approprié dans le widget :
onSuccesspour les paiements approuvésonErrorpour 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:
- Le numéro de téléphone fourni dans le formulaire de paiement est valide mais n'est pas associé à un compte Nequi.
- 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:
- Bac à sable : https://api.sandbox.deuna.io
- Fabrication : https://api.deuna.io
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:
{
"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
| Champ | Descriptif |
|---|---|
commerceCode | Votre code Nequi |
value | Montant du paiement |
phoneNumber | Numéro de téléphone mobile du payeur |
messageId | identificateur unique de la transaction |
transactionId | Identifiant de paiement |
region | Ré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
{
"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:
// 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:
- Pars l'en-tête Signature.
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: "..."
// }- Construisez le texte de signature.
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="- Calculer et vérifier l'AMAC.
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)
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.
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
{
"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.