Pular para o conteúdo principal
Nesta página

Comece com Nequi#

Esta página fornece um guia completo para integrar com sucesso Nequi com DEUNA em seu checkout.

Nequi é uma carteira digital administrada pelo Bancolombia e amplamente utilizada na Colômbia.

Como funciona#

A integração da DEUNA com o Nequi permite que os usuários paguem por meio de um fluxo de notificação push, totalmente gerenciado dentro do widget de pagamento DEUNA - sem necessidade de redirecionamentos externos.

Processo de pagamento

A lista a seguir descreve um processo de pagamento válido com Nequi:

  1. O usuário seleciona Nequi dentro do widget de pagamento.
  2. O usuário insere seu número de telefone real do Nequi.
  3. Uma notificação push é enviada para o aplicativo móvel Nequi.
  4. O usuário aprova o pagamento diretamente no app.
  5. DEUNA recebe o status do pagamento.
  6. DEUNA aciona o evento de retorno de chamada apropriado no widget:
    • onSuccess para pagamentos aprovados
    • onError para aqueles recusados ou expirados

manipulação de eventos onError

O widget DEUNA aciona o onError retorno de chamada nos seguintes cenários:

  1. O número de telefone fornecido no formulário de checkout é válido, mas não está associado a uma conta Nequi.
  2. O usuário rejeita a notificação push do aplicativo Nequi.

Em ambos os casos, DEUNA retorna uma resposta incluindo um código de erro e uma mensagem de erro descrevendo a falha. Você pode lidar com a resposta com base na lógica de negócios e na experiência do usuário desejada.

Requisitos#

O conteúdo a seguir lista todos os requisitos para uma integração bem-sucedida com o Nequi.

Suas credenciais de sandbox e produção Nequi devem ser solicitadas diretamente ao seu gerente de conta Bancolombia ou Nequi.

Ambientes:

Conclua o processo de certificação com Nequi e obtenha as seguintes credenciais fornecidas por Nequi:

  • Merchant ID

  • Senha do comerciante

  • Chave pública.

  • Código de identificação

  • Tempo para expirar (máx. 45min)

Configurar webhooks no Nequi#

Configure webhooks em sua sessão Nequi para cada loja.

Se você não configurar os webhooks do Nequi, as atualizações de status no Nequi demorarão entre dois a cinco minutos.

Certifique-se de que seu endpoint de webhook esteja altamente disponível e escalonável. Opcionalmente, você pode configurar o estorno da transação caso a confirmação do pagamento falhe por indisponibilidade do serviço.

Carga útil do webhook

Nequi enviará a seguinte carga JSON:

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"
}

Campos de carga útil

CampoDescrição
commerceCodeSeu código interno de comerciante Nequi
valueValor do pagamento
phoneNumberNúmero de celular do pagador
messageIdIdentificador exclusivo de transação
transactionIdIdentificador de pagamento
regionRegião de pagamento: P001 (Panamá) ou C001 (Colômbia)
receivedAtCarimbo de data e hora de pagamento no formato JSON
paymentStatusSituação do pagamento: SUCCESS, CANCELED, ou DENIED

Verificação de solicitação de segurança

Todas as solicitações de webhook do Nequi incluem cabeçalhos de segurança que você deve verificar:

Solicitar cabeçalhos

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

Processo de verificação

Você deve verificar duas coisas para cada solicitação:

1. Verifique a digestão corporal

O Digest header contém um hash SHA-256 do corpo da solicitação:

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. Verifique a assinatura da solicitação

O Signature header garante que a solicitação veio de Nequi:

  1. Analise o cabeçalho da assinatura.
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. Construa o texto de assinatura.
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. Calcule e verifique o HMAC.
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
}

Exemplo completo de implementação (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
  }
}

Integrar Nequi#

Agora que os requisitos técnicos estão definidos, você pode iniciar a integração passo a passo.

1. Crie um order_token

Para efetuar uma compra, você deve criar um pedido DEUNA.

Faça uma solicitação ao Crie um pedido endpoint.

A API retorna um order_token, que é usado em todo o fluxo.

2. Obtenha o order_token

Faça uma solicitação ao Obter pedido endpoint.

Use este token para as próximas etapas.

3. Renderize o widget de pagamento

Depois de receber o token do pedido, você pode renderizar o Widget DEUNA.

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

4. Faça um pagamento com cartão

Faça uma solicitação de pagamento com cartão para o Comprar V2 endpoint e processar o pagamento.

Resposta

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"
}

Teste Nequi#

Para testar o Nequi, você precisa solicitar os dados de teste do Nequi. Se necessário, o pagamento pode ser reembolsado através do Painel de Administração DEUNA ou através do API de reembolsos.