Negativo
In questa pagina
Inizia con Nequi#
Questa pagina fornisce una guida completa per integrare con successo Nequi con DEUNA nel tuo checkout.
Nequi è un portafoglio digitale gestito da Bancolombia ed è ampiamente utilizzato in Colombia.
Come funziona#
L'integrazione di DEUNA con Nequi consente agli utenti di pagare attraverso un flusso di notifica push, completamente gestito all'interno del DEUNA Payment Widget, senza reindirizzamenti esterni richiesti.
Processo di pagamento
L'elenco seguente descrive un processo di pagamento valido con Nequi:
- L'utente seleziona Nequi all'interno del Payment Widget.
- L'utente entra nel proprio numero di telefono Nequi reale.
- Una notifica push viene inviata alla loro app mobile Nequi.
- L'utente approva il pagamento direttamente nell'app.
- DEUNA riceve lo stato di pagamento .
- DEUNA attiva l'evento di callback appropriato nel widget:
onSuccessper pagamenti approvationErrorper quelli rifiutati o scaduti
sulla gestione degli eventi di Error
Il widget DEUNA attiva il onError callback nei seguenti scenari:
- Il numero di telefono fornito nel modulo di checkout è valido ma non associato a un account Nequi.
- L'utente rifiuta la notifica push dall'app Nequi.
In entrambi i casi, DEUNA restituisce una risposta, tra cui un codice di errore e un messaggio di errore che descrive il fallimento. Puoi gestire la risposta in base alla logica aziendale e all'esperienza utente desiderata.
Requisiti#
I seguenti contenuti elencano tutti i requisiti per una corretta integrazione con Nequi.
Le credenziali di produzione e sandbox Nequi devono essere richieste direttamente dal gestore del tuo account Bancolombia o Nequi.
Ambienti:
- Sandbox: https://api.sandbox.deuna.io
- Produzione: https://api.deuna.io
Completa il processo di certificazione con Nequi e ottieni le seguenti credenziali fornite da Nequi:
-
Merchant ID
-
Password di Merchant
-
Public Key.
-
Codice di identificazione
-
Tempo di scadenza (max. 45min)
Configura i webhook in Nequi#
Configura i webhooks nella tua sessione Nequi per ogni negozio.
Se non si configurano i webhook Nequi, allora gli aggiornamenti di stato in Nequi si lagranno tra due a cinque minuti.
Assicurarsi che il vostro endpoint webhook è altamente disponibile e scalabile. Opzionalmente, è possibile configurare l'inversione di transazione se la conferma di pagamento non viene eseguita a causa di un servizio indisponibile.
Webhook Payload
Nequi invierà il seguente carico di pagamento 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"
}Campi di carico
| Campo | Descrizione |
|---|---|
commerceCode | Il tuo codice commerciale interno Nequi |
value | Importo di pagamento |
phoneNumber | Numero di telefono cellulare del Payer |
messageId | Identificatore di transazione unico |
transactionId | Identificativo di pagamento |
region | Regione di pagamento: P001 (Panama) o C001 (Colombia) |
receivedAt | timestamp di pagamento in formato JSON |
paymentStatus | Stato di pagamento: SUCCESS, CANCELEDo DENIED |
Verifica della richiesta di sicurezza
Tutte le richieste di webhook da Nequi includono intestazioni di sicurezza che è necessario verificare:
Richiesta intestazioni
{
"Content-Type": "application/json",
"Digest": "SHA-256=43GpOk5L54gfpAMBE0xNX1bj2hJA9JJ1RR0dErHfZhI=",
"Signature": "keyId=\"YourClientId\",algorithm=\"hmac-sha384\",headers=\"content-type digest\",signature=\"...\""
}Processo di verifica
È necessario verificare due cose per ogni richiesta:
1. Verificare il digerimento del corpo
Il Digest intestazione contiene un hash SHA-256 del corpo di richiesta:
// 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. Verificare la firma della richiesta
Il Signature l'intestazione assicura che la richiesta provenga da Nequi:
- Parsare l'intestazione della firma.
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: "..."
// }- Costruisci il testo della firma.
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="- Calcola e verifica HMAC.
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
}Esempio di applicazione completo (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
}
}Integrare Nequi#
Ora che i requisiti tecnici sono impostati, è possibile avviare l'integrazione passo-passo.
1. Creare un order_token
Per effettuare un acquisto, è necessario creare un ordine DEUNA.
Fai una richiesta al Creare un Ordine endpoint.
L'API restituisce un order_token, che viene utilizzato durante tutto il flusso.
2. Prendi il order_token
Fai una richiesta al Ordinare endpoint.
Utilizzare questo token per i prossimi passi.
3. Render il widget di pagamento
Dopo aver ricevuto il gettone dell'ordine, è possibile rendere il widget DEUNA.
await DeunaSDK.initPaymentWidget({
orderToken: "<DEUNA order token>",
callbacks: ...,
paymentMethods: [
{
paymentMethod: "voucher",
processors: ["nequi_push_voucher"],
},
],
});4. Fare un pagamento della carta
Fai una richiesta di pagamento della carta al Acquisto V2 endpoint e processare il pagamento.
Restituisce l’ordine elaborato con
{
"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"
}Test Nequi#
Per testare Nequi, è necessario richiedere i dati di prova per Nequi. Se necessario, il pagamento può essere rimborsato tramite il Pannello di amministrazione DEUNA o tramite il Rimborsi API.