> Webhooks

Notifica al comercio cuando una orden ha sido pagada. (En el payload solamente se envía {order_id:'valor', reference_id:'valor'})

Notifica al comercio cuando una orden ha sido rechazada / anulada. (En el payload solamente se envía {order_id:'valor', reference_id:'valor'})

Importante:

  • order_id: Es el id de la orden entregado por Multicaja.
  • reference_id: Es el id de la orden entregado por el comercio.

Ejemplo de implementación:


  // webhooks.js
  // https://micomercio/webhook_validation
  // https://micomercio/webhook_confirm
  // https://micomercio/webhook_reject
  
  const express = require('express');
  const bodyParser = require("body-parser");
  const app = express();
  const router = express.Router();
  const crypto = require('crypto');

  function validateApikey(headerApikey, order) {
    let ecommerceOrderId = order.reference_id;
    let multicajaOrderId = order.order_id;
    console.log('ecommerceOrderId: ', ecommerceOrderId);
    console.log('multicajaOrderId: ', multicajaOrderId);
  
    //es tu apikey privada otorgada por Multicaja:
    let apikey = "SKSJKFH84JKDFNGDFGNDFGNN284895060"; 
    let key = ecommerceOrderId + multicajaOrderId + apikey;
    
    // este hash es el que debes comparar con el que te llegará en el header "Apikey" 
    // mediante el request a tus webhooks   
    let hashApiKey = crypto.createHash("sha256").update(key).digest("hex");
    return hashApiKey == headerApikey;
  }

  router.post('/webhook_validation', function(req, res) {
    try {
      let order = req.body;
      let ecommerceOrderId = order.reference_id;
      console.log('ecommerceOrderId: ', ecommerceOrderId);
  
      // hacer algo...
  
      res.status(200);
      res.json(order);
    } catch(error) {
      res.status(500);
      res.end('error');
    }
  });

  router.post('/webhook_confirm', function(req, res) {
    try {
      let order = req.body;
      let headerApikey = req.header('Apikey');
  
      if (!validateApikey(headerApikey, order)) {
        throw new Error('Error en autenticación');
      }
  
      // hacer algo...
  
      res.status(200);
      res.json(order);
    } catch(error) {
      res.status(500);
      res.end('error');
    }
  });
  
  router.post('/webhook_reject', function(req, res) {
    try {
      let order = req.body;  
      let headerApikey = req.header('Apikey');
  
      if (!validateApikey(headerApikey, order)) {
        throw new Error('Error en autenticación');
      }
  
      // hacer algo...
  
      res.status(200);
      res.json(order);
    } catch(error) {
      res.status(500);
      res.end('error');
    }
  });
  
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use(bodyParser.json());
  app.use(router);
  app.listen(7000);
  

  /*
  <dependency>
     <groupId>commons-codec</groupId>
     <artifactId>commons-codec</artifactId>
     <version>1.11</version>
  </dependency>
  */
                    
  // WebhooksResource.java
  // https://micomercio/webhook_validation
  // https://micomercio/webhook_confirm
  // https://micomercio/webhook_reject
  
  package resources;
                    
  import org.springframework.http.*;
  import org.springframework.web.bind.annotation.*;
  import java.util.Map;
  import org.apache.commons.codec.digest.DigestUtils;
                    
  @RestController
  @RequestMapping("/")
  public class WebhooksResource {
                    
  private boolean validateApikey(StriheaderApikey, Map<String, Object> order) {
    String ecommerceOrderId = String.valueOf(order.get("reference_id"));
    String multicajaOrderId = String.valueOf(order.get("order_id"));
    System.out.println("ecommerceOrderId: " + ecommerceOrderId);
    System.out.println("multicajaOrderId: " + multicajaOrderId);
                        
    //es tu apikey privada otorgada por Multicaja:
    String apikey = "SKSJKFH84JKDFNGDFGNDFGNN284895060"; 
    String key = ecommerceOrderId + multicajaOrderId + apikey;
                        
    //este hash es el que debes comparar con el que te llegará en el 
    //header "Apikey" mediante el request a tus webhooks:
    String hashApiKey = DigestUtils.sha256Hex(key);
    return hashApiKey.equals(headerApikey);
    }
                    
    @RequestMapping(path  = "/webhook_validation", method = RequestMethod.POST,
    consumes = "application/json", produces = "application/json")
  public ResponseEntity<?> webhookValidation(@RequestBody(required=true) Map<String, Object> order) {
    try {
      String ecommerceOrderId = String.valueOf(order.get("reference_id"));
      System.out.println("ecommerceOrderId: " + ecommerceOrderId);
                    
    // hacer algo...
                    
      return new ResponseEntity<>(order, HttpStatus.CREATED);
    } catch(Exception ex) {
      return new ResponseEntity<>("error", HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
                    
  @RequestMapping(path = "/webhook_confirm", method = RequestMethod.POST,
                        consumes = "application/json", produces = "application/json")
  public ResponseEntity<?> webhookConfirm(@RequestBody(required=true) Map<String, Object> order,
  @RequestHeader(value="Apikey", required = true) String headerApikey) {
    try {     
                    
      if (!validateApikey(headerApikey, order)) {
        throw new Exception("Error en autenticación");
      }
                    
    // hacer algo...
                    
      return new ResponseEntity<>(order, HttpStatus.CREATED);
    } catch(Exception ex) {
      return new ResponseEntity<>("error", HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
                    
  @RequestMapping(path = "/webhook_reject", method = RequestMethod.POST,
    consumes = "application/json", produces = "application/json")
  public ResponseEntity<?> webhookReject(@RequestBody(required=true) Map<String, Object> order,
  @RequestHeader(value="Apikey", required = true) String headerApikey) {
    try {
      if (!validateApikey(headerApikey, order)) {
        throw new Exception("Error en autenticación");
      }
                    
    // hacer algo...
                    
    return new ResponseEntity<>(order, HttpStatus.CREATED);
    } catch(Exception ex) {
    return new ResponseEntity<>("error", HttpStatus.INTERNAL_SERVER_ERROR);
      }
    }
  }
  
  
  <?php 
  // webhooks.php
  // https://micomercio/webhwebhook=validation
  // https://micomercio/webhwebhook=confirm
  // https://micomercio/webhwebhook=reject
                
  function getHeader($headers, $name) {
    foreach ($headers as $hname => $hvalue) {
      if (strtolower($hname) == strtolower($name)){
        return $hvalue;
      }
    }
    return null;
  }
  
  function validateApikey($headerApikey, $decoded) {

    $ecommerceOrderId = $decoded['reference_id'];  
    $multicajaOrderId = $decoded['order_id'];
    error_log(print_r('ecommerceOrderId: ' . $ecommerceOrderId, true));
    error_log(print_r('multicajaOrderId: ' . $multicajaOrderId, true));

    # es tu apikey privada otorgada por Multicaja:
    $apikey = "SKSJKFH84JKDFNGDFGNDFGNN284895060"; 
    $key = $ecommerceOrderId . $multicajaOrderId . $apikey;
    
    // este hash es el que debes comparar con el que te llegará 
    // en el header "Apikey" el request a tus webhooks:
    $hashApiKey = hash('sha256', $key);
    return $hashApiKey == $headerApikey;
  }
  
  try {
  
    if(strcasecmp($_SERVER['REQUEST_METHOD'], 'POST') != 0){
       throw new NotFoundException('Request method must be POST!');
    }
  
    $contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : ';
    if(strcasecmp($contentType, 'application/json') != 0){
      throw new NotFoundException('Content type must be:application/json');
    }
  
    //Recibe los datos post raw
    $json = trim(file_get_contents("php://input"));
  
    //decodifica el json
    $decoded = json_decode($json, true);
  
    //si json_decode falla, el json es inválido
    if(!is_array($decoded)){
      throw new BadRequestException('Received content contained invalid JSON!');
    }
  
    $webhook = $_GET['webhook'];
    error_log(print_r('webhook: ' . $webhook, true));
                    
  
    if(strcasecmp($webhook, 'validation') == 0) {

    // hacer algo...
  
    } else {
        $headerApikey = $this->getHeader(apache_request_headers(), 'Apikey');
        if (!$this->validateApikey($headerApikey, $decoded)) {
          throw new UnauthorizedException('Error en autenticación');
        }
        if(strcasecmp($webhook, 'confirm') == 0) {     
  
            // hacer algo confirm...
  
        } else if(strcasecmp($webhook, 'reject') == 0) {
      
  
            // hacer algo para reject...
        }

    }

    //retorna el json
    http_response_code(200);
    echo $json;

  } catch (Exception $e) {
    error_log(print_r('Excepción capturada: ',  $e->getMessage()));
    http_response_code(500);
    echo "error";
  }
                

  # webhooks.rb
  # https://micomercio/webhook_validation
  # https://micomercio/webhook_confirm
  # https://micomercio/webhook_reject

  require 'sinatra'
  require 'json'
  require 'digest'

  set :port, 7000
  set :bind, '0.0.0.0'

  def validateApikey(headerApikey, order)
    ecommerceOrderId = order['reference_id']
    multicajaOrderId = order['order_id']
    puts "ecommerceOrderId: #{ecommerceOrderId}"
    puts "multicajaOrderId: #{multicajaOrderId}"
    
    #es tu apikey privada otorgada por Multicaja:
    apikey = "SKSJKFH84JKDFNGDFGNDFGNN284895060" 
    key = ecommerceOrderId + multicajaOrderId + apikey
    
    #este hash es el que debes comparar con el que te llegará en el 
    #header "Apikey" mediante el request a tus webhooks:
    hashApiKey = Digest::SHA256.hexdigest(key)
    return hashApiKey ==  headerApikey
  end

  post '/webhook_validation' do
    begin
      request.body.rewind
      order = JSON.parse request.body.read
      ecommerceOrderId = order['reference_id']
      puts "ecommerceOrderId: #{ecommerceOrderId}"

      # hacer algo...

      content_type :json
      halt 200, order.to_json
    rescue StandardError => error
      halt 500, 'error'
    end
  end

  post '/webhook_confirm' do
    begin
      request.body.rewind
      order = JSON.parse request.body.read

      headerApikey = request.env["Apikey"]

      if (!validateApikey(headerApikey, order))
       raise "Error en autenticación"
      end

      # hacer algo...

      content_type :json
      halt 200, order.to_json
    rescue StandardError => error
      halt 500, 'error'
    end
  end

  post '/webhook_reject' do
    begin
      equest.body.rewind
      order = JSON.parse request.body.read
      headerApikey = request.env["Apikey"]

      if (!validateApikey(headerApikey, order))
      raise "Error en autenticación"
      end

      # hacer algo...

      content_type :json
      halt 200, order.to_json
    rescue StandardError => error
      halt 500, 'error'
    end
  end