a) Generando una liga de pago

Construye una cadena XML , cífrala con el SDK adecuado a tu tecnología, sométela al servicio de Generación de Ligas, descrifra la respuesta con el mismo SDK y obtén una liga.

Paso 1: Cadena XML


Aquí tienes la descripción de la cadena que debes construir. Puedes copiar y editar el ejemplo.

<P>

Elemento PADRE dentro del esquema XML de la cadena.

Contiene los parámetros para identificar al comercio en Centro de Pagos, que realiza la petición.

Identificador del Comercio al que se le asociará el pago.
Para sandbox usa SNBX

Identificador de la Sucursal del Comercio a la que se le asociará el pago.
Para sandbox usa 01SNBXBRNCH

Usuario que genera la petición. Con este usuario se procesará la transacción de cobro.
Para sandbox usa SNBXUSR01

Contraseña de acceso para autenticación del usuario.
Para sandbox usa SECRETO

Contiene los parámetros con las instrucciones del comercio para registrar una intención de cobro y vincularlos a una liga de pago.

Referencia única/irrepetible del comercio para conciliar un pago con su lógica de negocio. Se sugiere número de factura o pedido.
Se cuenta con el valor de 50 caracteres para agregar información.

Importe a pagar con 2 decimales separado por un punto.

Específica la moneda para la intención de cobro, si se tienen configuradas afiliaciones en pesos y dólares en la sucursal.
Valores posibles: MXN ó USD .

Valor fijo, debe ser W.

Si este elemento se recibe con el valor 0 , se enviará la notificación de cobro realizada al tarjetahabiente vía correo electrónico, con formato e imagen de Centro de Pagos.
Valores posibles: 0 ó 1 .

Si este elemento se recibe, indica las promociones a meses con las que se puede realizar el pago, cuando se tienen varias afiliaciones con promociones configuradas en la sucursal.
Para forzar el pago a sólo contado, deberá indicarse sólo C .

Si este elemento se recibe, se debe informar el token de la campaña que se generó, para que se pueda aplicar la promoción creada.

Si este elemento se recibe con el valor 1 , se solicitará la captura del correo electrónico en el formulario de pago.
Valores posibles: 0 ó 1 .

Si este elemento está presente y se recibe con una fecha en el futuro, la intención de cobro estará vigente hasta la fecha indicada.
El valor por omisión es de 3 meses a partir de la intención de cobro.

Si el elemento está presente se precargará este valor en el campo “Correo Electrónico” del formulario de pago. El tarjetahabiente podrá cambiarlo si así lo desea. Nota: el campo st_correo deberá indicar 1 .

Si el elemento está presente con el valor A, al desplegar el formulario se considerarán las reglas del enrolamiento automático.
Si el elemento está presente con el valor M, Se mostrará el checkbox para permitir el enrolamiento.

Contiene los parámetros para identificar el canal que solicita la generación del enlace WPP.

Especifica el canal que manda a solicitar una liga. Es obligatorio colocar el valor IntegraWPP.

Si la afiliación lo requiere y éste elemento está presente, contiene la información necesaria para solicitar una autenticación al servicio de 3D Secure.

Especifica el correo electrónico del tarjetahabiente de hasta cien caracteres.

Especifica el número telefónico del tarjetahabiente de hasta veinte posiciones.

Especifica el domicilio del tarjetahabiente de hasta sesenta caracteres.

Especifica la ciudad del domicilio del tarjetahabiente de hasta treinta caracteres.

Especifica la clave ISO 3166-2 del estado del domicilio del tarjetahabiente de dos caracteres.

Especifica el código postal del domicilio del tarjetahabiente de hasta diez caracteres.

Especifica la clave numérica ISO 3166-1 del país del domicilio del tarjetahabiente de 3 caracteres.

Si este elemento está presente, se incluirán los elementos hijos data en el formulario de pago y serán devueltos en la respuesta del resultado de un cobro. Si se especifica el atributo “display” con el booleano true , estos se mostrarán en el formulario de pago.

<data id="1" display="true">
  <label>Talla</label>
  <value>Grande</value>
</data>

Agrupa un par de elementos de tipo label y value, se deberá especificar el atributo “id” para diferenciarlos. Máximo 6 datos del tipo etiqueta-valor.

Ejemplos


Para familiarizarte con la cadena adecuada a tus necesidades, elige uno de nuestros ejemplos.

								<?xml version="1.0" encoding="UTF-8"?>
<P>
  <business>
    <id_company>SNBX</id_company>
    <id_branch>01SNBXBRNCH</id_branch>
    <user>SNBXUSR01</user>
    <pwd>SECRETO</pwd>
  </business>
  <url>
    <reference>FACTURA999</reference>
    <amount>1.00</amount>
    <moneda>MXN</moneda>
    <canal>W</canal>
    <omitir_notif_default>1</omitir_notif_default>
    <promociones>C</promociones>
    <st_correo>1</st_correo>
    <fh_vigencia>24/11/2021</fh_vigencia>
    <mail_cliente>mail@dominio.com</mail_cliente>
    <datos_adicionales>
      <data id="1" display="true">
        <label>Talla</label>
        <value>Grande</value>
      </data>
      <data id="2" display="false">
        <label>Color</label>
        <value>Azul</value>
      </data>
    </datos_adicionales>
    <version>IntegraWPP</version>
  </url>
</P>


Encontrarás el XSD y ejemplos de código para validarla con tu servidor en GitHub


				

Paso 2: Cifrando la cadena


Una vez que has construido la cadena en claro, cífrala en AES-128, con el SDK adecuado a tu servidor, el cual puedes obtener en GitHUB.

Cadena usada como llave para cifrar la petición.

Para sandbox usa 5DCC67393750523CD165F17E1EFADD21

El desarrollador recibirá las credenciales productivas del administrador del comercio.

Ejemplo


								String key = "5DCC67393750523CD165F17E1EFADD21";
String originalString = "[USAR LA CADENA DEL EJEMPLO UNO]";
String encrypted = encrypt(key, originalString);
System.out.println(encrypted);

							
								function aesFunction() {
    var originalString = '[USAR LA CADENA DEL EJEMPLO UNO]';
    var key  = '5DCC67393750523CD165F17E1EFADD21';
    var ciphertext = CryptoJS.AES.encrypt(originalString, key ).toString();
    console.log("ciphertext: " + ciphertext);
}	
                                
							
								<?php
$originalString = '[USAR LA CADENA DEL EJEMPLO UNO]';
$key = '5dcc67393750523cd165f17e1efadd21'; 
$encrypted = AesCipher::encrypt($key,$originalString);
var_dump($encrypted);
?>
							
								<?php
$originalString = '[USAR LA CADENA DEL EJEMPLO UNO]';
$key = '5dcc67393750523cd165f17e1efadd21';
$encrypted = AesCipher::encrypt($key,$originalString);
var_dump($encrypted);
?>
							
								Imports AESCrypto.vb
Dim originalString As String = "[USAR LA CADENA DEL EJEMPLO UNO]"
Dim key As String = "5DCC67393750523CD165F17E1EFADD21"
Dim encryptedString As String = AESCrypto.Encrypt(originalString, key)
Dim finalString As String = encryptedString.Replace("%", "%25").Replace(" ", "%20").Replace("+", "%2B").Replace("=", "%3D").Replace("/", "%2F")
							
								using AESCrypto.cs
string originalString ="[USAR LA CADENA DEL EJEMPLO UNO]";
string key = "5DCC67393750523CD165F17E1EFADD21";
string encryptedString =
  AESCrypto.encrypt(originalString, key);
string finalString = encryptedString.Replace("%", "%25").Replace(" ", "%20").Replace("+", "%2B").Replace("=", "%3D").Replace("/", "%2F");
							
								originalString = "[USAR LA CADENA DEL EJEMPLO UNO]"
key = "5dcc67393750523cd165f17e1efadd21"
ciphertext = AESCipher(key).encrypt(originalString)
print(ciphertext)
							
								originalString = "[USAR LA CADENA DEL EJEMPLO UNO]"
key = "5dcc67393750523cd165f17e1efadd21"
ciphertext = AESCipher(key).encrypt(originalString)
print(ciphertext)
							


				

Paso 3: Servicio de Generación


Para garantizar la seguridad en la transmisión de información, Centro de Pagos cuenta con servidores HTTPS los cuales utilizan el protocolo Transport Layer Security TLS v1.2 como protocolo de transporte seguro para realizar transacciones. Por su parte, el comercio debe de contar también con servidores TLS v1.2, para garantizar el intercambio seguro de información al realizar sus transacciones.

https://wppsandbox.mit.com.mx/gen

Este endpoint de Sandbox recibe la petición con las instrucciones del comercio para registrar una intención de cobro. Como respuesta de la petición al Servicio de Generación de Ligas, obtendrás una cadena de respuesta cifrada.

La implementación se basa en el envío al servicio por POST de una cadena en el parámetro xml con la siguiente estructura:

xml=
<pgs>
  <data0>Cadena fija asignada al comercio</data0>
  <data>CadenaCifrada en AES-128</data>
</pgs>

Cadena fija, asignada al comercio.

Para sandbox usa SNDBX123

El desarrollador recibirá las credenciales productivas del administrador del comercio.

Ejemplo


								try {
	SecureRandom random = new SecureRandom();
	byte[] ivArr = random.generateSeed(16);
	IvParameterSpec ivSpec = new IvParameterSpec(ivArr);
	SecretKeySpec secretKey = new SecretKeySpec(fixKey(key).getBytes(StandardCharsets.UTF_8), "AES");

	Cipher cipher = Cipher.getInstance(CIPHER_NAME);
	cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);

	byte[] encryptedData = cipher.doFinal((data.getBytes()));

	String encryptedDataInBase64 = Base64.getEncoder().encodeToString(encryptedData);
	String ivInBase64 = Base64.getEncoder().encodeToString(ivArr);
	String resultEnc = encryptedDataInBase64 + ":" + ivInBase64;

	return Base64.getEncoder().encodeToString(resultEnc.getBytes());

} catch (Exception ex) {
	throw new RuntimeException(ex);
}
							
								var CTRGladman = CryptoJS.lib.BlockCipherMode.extend();
var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({
     processBlock: function (words, offset) {
         // Shortcuts
         var cipher = this._cipher
         var blockSize = cipher.blockSize;
         var iv = this._iv;
         var counter = this._counter;

         // Generate keystream
         if (iv) {
             counter = this._counter = iv.slice(0);

             // Remove IV for subsequent blocks
             this._iv = undefined;
         }

incCounter(counter);

var keystream = counter.slice(0);
         cipher.encryptBlock(keystream, 0);

         // Encrypt
         for (var i = 0; i < blockSize; i++) {
             words[offset + i] ^= keystream[i];
         }
     }
 });

 CTRGladman.Decryptor = Encryptor;
							
								static function encrypt($key, $data) {
    $ivlen = openssl_cipher_iv_length('AES-128-CBC');
    $iv = openssl_random_pseudo_bytes($ivlen);
    $encodedEncryptedData = base64_encode(openssl_encrypt($data, 'aes-128-cbc', AesCipher::fixKey($key), OPENSSL_RAW_DATA, $iv));
    $encodedIV = base64_encode($iv);
    $encryptedPayload = $encodedEncryptedData.":".$encodedIV;

    return base64_encode($encryptedPayload);
}
							
								static function encrypt($key, $data) {
    $ivlen = openssl_cipher_iv_length('AES-128-CBC');
    $iv = openssl_random_pseudo_bytes($ivlen);
    $encodedEncryptedData = base64_encode(openssl_encrypt($data, 'aes-128-cbc', AesCipher::fixKey($key), OPENSSL_RAW_DATA, $iv));
    $encodedIV = base64_encode($iv);
    $encryptedPayload = $encodedEncryptedData.":".$encodedIV;

    return base64_encode($encryptedPayload);
}
							
								'' Esta implementación utiliza http://restsharp.org v105
    Dim encodedString As String = HttpUtility.UrlEncode("SNDBX123[USAR LA CADENA DEL EJEMPLO UNO]")
    Dim postParam As String = "xml=" & encodedString
    Dim client = New RestClient("https://wppsandbox.mit.com.mx/gen")
    Dim request = New RestRequest(Method.POST)
    request.AddHeader("cache-control", "no-cache")
    request.AddHeader("content-type", "application/x-www-form-urlencoded")
    request.AddQueryParameter(postParam, ParameterType.RequestBody)
    Dim response As IRestResponse = client.Execute(request)
    Dim content = response.Content
							
								// Esta implementación utiliza http://restsharp.org v105
string encodedString = 
  HttpUtility.UrlEncode("<pgs><data0>SNDBX123</data0><data>[USAR LA CADENA DEL EJEMPLO UNO]</data></pgs>");
string postParam = "xml=" + encodedString;
var client = new RestClient("https://wppsandbox.mit.com.mx/gen");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddQueryParameter(postParam, ParameterType.RequestBody);

IRestResponse response = client.Execute(request);
var content = response.Content;
							
								def encrypt(self, raw):
padded_plain_text = self._padPKCS5(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
ivEncoded = b64encode(iv)
dataEncoded = b64encode(cipher.encrypt(padded_plain_text))
return b64encode(dataEncoded+':'+ivEncoded)
							
								def encrypt(self, raw):
padded_plain_text = self._padPKCS5(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key.encode("utf8"), AES.MODE_CBC, iv)
ivEncoded = b64encode(iv)
dataEncoded = b64encode(cipher.encrypt(padded_plain_text.encode("utf8")))
return b64encode(dataEncoded+':'.encode("utf8")+ivEncoded)
							


				

Paso 4: Descifrando la respuesta del Servicio de Generación


Una vez obtenida la respuesta del servicio, la puedes descifrar con el SDK adecuado a tu servidor, y dentro de <nb_url> encontrarás la Liga de Cobro o URL, que debes compartir con tu cliente para recibir su pago.

Ejemplo


								try {
	String cadena = new String(Base64.getDecoder().decode(data));
	data = cadena;
	String[] parts = data.split(":");

	byte[] decodedEncryptedData = Base64.getDecoder().decode(parts[0]);

	byte[] ivBytes = Arrays.copyOfRange(decodedEncryptedData, 0, 16);
	Cipher cipher = Cipher.getInstance(CIPHER_NAME);
	// IvParameterSpec(ivBytes);//Base64.getDecoder().decode(parts[1]));
	IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(parts[1]));
	SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");

	cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);

	byte[] original = cipher.doFinal(decodedEncryptedData);

	return new String(original);
} catch (Exception ex) {
	throw new RuntimeException(ex);
}
							
								decrypt: function (cipher, ciphertext, key, cfg) {
    // Apply config defaults
    cfg = this.cfg.extend(cfg);

    // Convert string to CipherParams
    ciphertext = this._parse(ciphertext, cfg.format);

    // Decrypt
    var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);

    return plaintext;
}
							
								static function decrypt($key, $data) {
     $data = base64_decode($data);
     $parts = explode(':', $data); //Separate Encrypted data from iv.
     $encrypted = $parts[0];
     $iv = $parts[1];
     //$ivlen = openssl_cipher_iv_length('AES-128-CBC');
     //$iv = openssl_random_pseudo_bytes($ivlen);
     $decryptedData = openssl_decrypt(base64_decode($encrypted), 'aes-128-cbc', AesCipher::fixKey($key), OPENSSL_RAW_DATA, base64_decode($iv));
     return $decryptedData;
}
							
								static function decrypt($key, $data) {
   $data = base64_decode($data);
   $parts = explode(':', $data); //Separate Encrypted data from iv.
   $encrypted = $parts[0];
   $iv = $parts[1];
   //$ivlen = openssl_cipher_iv_length('AES-128-CBC');
   //$iv = openssl_random_pseudo_bytes($ivlen);
   $decryptedData = openssl_decrypt(base64_decode($encrypted), 'aes-128-cbc', AesCipher::fixKey($key), OPENSSL_RAW_DATA, base64_decode($iv));
   return $decryptedData;
}
							
								Imports AESCrypto.vb
Dim originalString As String = "Este es el texto a procesar"
originalString = originalString.Replace("%25", "%").Replace("%20", " ").Replace("%2B", "+").Replace("%3D", "=").Replace("%2F", "/")
Dim key As String = "5DCC67393750523CD165F17E1EFADD21"
Dim decryptedString As String = AESCrypto.Decrypt(key, originalString)
							
								using AESCrypto.cs
string originalString ="Este es el texto a procesar";
string key = "5DCC67393750523CD165F17E1EFADD21";
string decryptedString = 
  AESCrypto.decrypt(key, originalString);
							
								def decrypt(self, enc):
enc = b64decode(enc)
dataArr = enc.split(":")
iv = b64decode(dataArr[1])
enc = b64decode(dataArr[0])
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpadPKCS5(cipher.decrypt(enc)).decode('utf-8')
							
								def decrypt(self, enc):
enc = b64decode(enc)
dataArr = enc.split(b":")
iv = b64decode(dataArr[1])
enc = b64decode(dataArr[0])
cipher = AES.new(self.key.encode("utf8"), AES.MODE_CBC, iv)
return self._unpadPKCS5(cipher.decrypt(enc).decode('utf-8'))
							



					
Catálogo de valores, elemento nb_response
nb_response Descripción Solución
Vacía La petición fue procesada correctamente
La petición es invalida La estructura de cadena es inválida, contiene caracteres inválidos o no está correctamente cifrada Utiliza la validación XSD
Los datos de empresa, sucursal o usuario son inválidos Falló la autenticación o estatus de usuario/sucursal/empresa no es activo. Contactar a Centro de Atención MIT
La empresa no tiene autorizado este servicio, por favor contacte a su administrador Falló la configuración o estatus de usuario/sucursal/empresa no es correcta. Contactar a Centro de Atención MIT
No fue posible generar la referencia, por favor intente más tarde Ocurrió un error al procesar la petición (exception). Contactar a Centro de Atención MIT

Paso 5: Liga de Cobro


De la respuesta descifrada, obtienes la liga de pago en el elemento nb_url . Con la liga se puede invocar el formulario de pago por GET en un navegador web, Webview de un App, o incrustándose dentro del portal del comercio en un iframe. Así, tienes la libertad de seleccionar lo mejor que se adapte a tu tecnología. Para saber más visita ¿Cómo publicar una liga?

Ejemplo


¡Wow!
Para obtener una liga de pago, descifra la respuesta obtenida en el paso anterior.


Continúa aquí:

¿Cómo generar una liga?