Pagos vía SPEI

Transferencias Bancarias vía SPEI

📘

Primeros pasos

  • Es necesario contar con conocimiento de APIs.
  • Es preferible ser desarrollador fullstack (frontend + backend).
  • Instalar e incluir una de las librerías disponibles de Conekta.
  • Contar con tus API Keys (llave personal) de pruebas.

Paso 1 - Añade tu llave privada y versión del API

Necesitarás tu llave privada de pruebas. Si aún no cuentas con ella, puedes obtenerla en tu panel Conekta.

require "conekta"
Conekta.api_key = "key_eYvWV7gSDkNYXsmr"
Conekta.api_version = "2.0.0"
# N/A
require_once("/path/to/lib/Conekta.php");
\Conekta\Conekta::setApiKey("key_eYvWV7gSDkNYXsmr");
\Conekta\Conekta::setApiVersion("2.0.0");
import conekta
conekta.api_key = "key_eYvWV7gSDkNYXsmr"
conekta.api_version = "2.0.0"
var conekta = require('conekta');
conekta.api_key = 'key_eYvWV7gSDkNYXsmr';
conekta.api_version = '2.0.0';
import com.conekta;
Conekta.setApiKey("key_eYvWV7gSDkNYXsmr");
Conekta.apiVersion = "2.0.0";
using conekta;
conekta.Api.apiKey = "key_eYvWV7gSDkNYXsmr";
conekta.Api.version = "2.0.0";
import (
    conekta "github.com/conekta/conekta-go"
)
conekta.APIKey = "key_pMcnDF4zFyWKyLG15LuqwA"

Paso 2 - Crea una orden

Al crear un order se generará el cargo de tu cliente. Si no deseas crear el cargo inmediato, puedes preparar la orden y después generar el cargo mandando la información del arreglo charges.

Los campos mostrados en el ejemplo son los mínimos requeridos, si deseas saber más sobre el objeto order revisa nuestra REST API.

curl --request POST \
  --url https://api.conekta.io/orders \
  --header 'accept: application/vnd.conekta-v2.0.0+json' \
  -u key_eYvWV7gSDkNYXsmr: \
  --header 'content-type: application/json' \
  --data '{
    "line_items": [{
      "name": "Tacos",
      "unit_price": 1000,
      "quantity": 12
    }],
    "shipping_lines": [{
      "amount": 1500,
      "carrier": "FEDEX"
    }],
    "currency": "MXN",
    "customer_info": {
      "name": "Fulanito Pérez",
      "email": "[email protected]",
      "phone": "+5218181818181"
    },
    "shipping_contact":{
      "address": {
        "street1": "Calle 123, int 2",
          "postal_code": "06100",
          "country": "MX"
       }
    },
    "charges":[{
      "payment_method": {
        "type": "spei",
        "expires_at": 1600886061
      }
    }]
  }'
try{
  $thirty_days_from_now = (new DateTime())->add(new DateInterval('P30D'))->getTimestamp(); 

  $order = \Conekta\Order::create(
    [
      "line_items" => [
        [
          "name" => "Tacos",
          "unit_price" => 1000,
          "quantity" => 12
        ]
      ],
      "shipping_lines" => [
        [
          "amount" => 1500,
          "carrier" => "FEDEX"
        ]
      ], //shipping_lines - physical goods only
      "currency" => "MXN",
      "customer_info" => [
        "name" => "Fulanito Pérez",
        "email" => "[email protected]",
        "phone" => "+5218181818181"
      ],
      "shipping_contact" => [
        "address" => [
          "street1" => "Calle 123, int 2",
          "postal_code" => "06100",
          "country" => "MX"
        ]
      ], //shipping_contact - required only for physical goods
      "charges" => [
        [
          "payment_method" => [
            "type" => "spei",
            "expires_at" => $thirty_days_from_now
          ]
        ]
      ]
    ]
  );
} catch (\Conekta\ParameterValidationError $error){
  echo $error->getMessage();
} catch (\Conekta\Handler $error){
  echo $error->getMessage();
}
begin
  thirty_days_from_now = Time.now.advance(days: 30).to_i 

  order = Conekta::Order.create({
    line_items: [{
        name: "Tacos",
        unit_price: 1000,
        quantity: 12
    }],
    shipping_lines: [{
        amount: 1500,
        carrier: "FEDEX"
    }], #shipping_lines - physical goods only
    currency: "MXN",
    customer_info: {
        name: "Fulanito Pérez",
        email: "[email protected]",
        phone: "+5218181818181"
    },
    shipping_contact: {
        address: {
            street1: "Calle 123, int 2",
            postal_code: "06100",
            country: "MX"
        }
    }, #shipping_contact - required for physical goods only
    charges: [{
        payment_method: {
            type: "spei",
            expires_at: thirty_days_from_now
        }
    }]
  })
rescue Conekta::Error => error
  for error_detail in error.details do
    puts error_detail.message
  end
end
try:
  from datetime import datetime
  from datetime import timedelta 

  thirty_days_from_now = int((datetime.now() + timedelta(days=1)).timestamp()) 

  order = conekta.Order.create({
    "line_items": [{
        "name": "Tacos",
        "unit_price": 1000,
        "quantity": 12
    }],
    "shipping_lines": [{
        "amount": 1500,
        "carrier": "FEDEX"
    }], #shipping_lines - physical goods only
    "currency": "MXN",
    "customer_info": {
      "name": "Fulanito Pérez",
      "email": "[email protected]",
      "phone": "+5218181818181"
    },
    "shipping_contact":{
       "address": {
         "street1": "Calle 123, int 2",
         "postal_code": "06100",
         "country": "MX"
       }
    }, #shipping_contact - required only for physical goods
    "charges":[{
      "payment_method": {
        "type": "spei",
        "expires_at": thirty_days_from_now
      }
    }]
  })
except conekta.ConektaError as e:
  print e.message
thirty_days_from_now = (Math.round(Date.now()/1000 + 60 \* 60 \* 24 \* 30)).toString(); 

order = conekta.Order.create({
  "line_items": [{
      "name": "Tacos",
      "unit_price": 1000,
      "quantity": 12
  }],
  "shipping_lines": [{
      "amount": 1500,
      "carrier": "FEDEX"
  }], //shipping_lines - physical goods only
  "currency": "MXN",
  "customer_info": {
    "name": "Fulanito Pérez",
    "email": "[email protected]",
    "phone": "+5218181818181"
  },
  "shipping_contact":{
     "address": {
       "street1": "Calle 123, int 2",
       "postal_code": "06100",
       "country": "MX"
     }
  }, //shipping_contact - required only for physical goods
  "charges":[{
    "payment_method": {
      "type": "spei",
      "expires_at": thirty_days_from_now
    }
  }]
}, function(err, res) {
    console.log(res.toObject());
});
try {
  Long nowUnixTimestamp = System.currentTimeMillis();
  Long thirtyDaysFromNowUnixTimestamp =  (nowUnixTimestamp + 30L * 24 * 60 * 60 * 1000) / 1000L;
  String thirtyDaysFromNow = thirtyDaysFromNowUnixTimestamp.toString();

  Order order = Order.create(
    new JSONObject("{"
                   + "'line_items': [{"
                   + "'name': 'Tacos',"
                   + "'unit_price': 1000,"
                   + "'quantity': 12"
                   + "}],"
                   + "'shipping_lines': [{"
                   + "'amount': 1500,"
                   + "'carrier': 'FEDEX'"
                   + "}]," //shipping_lines - physical goods only
                   + "'currency': 'MXN',"
                   + "'customer_info': {"
                   + "'name': 'Fulanito Pérez',"
                   + "'email': '[email protected]',"
                   + "'phone': '+5218181818181'"
                   + "},"
                   + "'shipping_contact':{"
                   + "'address': {"
                   + "'street1': 'Calle 123, int 2',"
                   + "'postal_code': '06100',"
                   + "'country': 'MX'"
                   + "}"
                   + "}," //shipping_contact - required only for physical goods
                   + "'charges':[{"
                   + "'payment_method': {"
                   + "'type': 'spei',"
                   + "'expires_at': " + thirtyDaysFromNow
                   + "}"
                   + "}]"
                   + "}"
                  )
	);
} catch (io.conekta.Error e) {
	System.out.println(e.message);
} catch (io.conekta.ErrorList e) {
	System.out.println(e.details.get(0).message);
}
//Calculate an expiration time
DateTime thirtyDaysFromNowDateTime = DateTime.Now.AddDays(30);
long thirtyDaysFromNowUnixTimestamp = (Int64)(thirtyDaysFromNowDateTime.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
String thirtyDaysFromNow = thirtyDaysFromNowUnixTimestamp.ToString(); 

try{
  conekta.Order order = new conekta.Order ().create(@"{
    ""line_items"": [{
        ""name"": ""Tacos"",
        ""unit_price"": 1000,
        ""quantity"": 12
    }],
    ""shipping_lines"": [{
        ""amount"": 1500,
        ""carrier"": ""FEDEX""
    }]," + //shipping_lines - physical goods only
    @"""currency"": ""MXN"",
    ""customer_info"": {
      ""name"": ""Fulanito Pérez"",
      ""email"": ""[email protected]"",
      ""phone"": ""+5218181818181""
    },
    ""shipping_contact"":{
       ""address"": {
         ""street1"": ""Calle 123, int 2"",
         ""postal_code"": ""06100"",
         ""country"": ""MX""
       }
     }," +  //shipping_contact - required only for physical goods only
    @"""charges"":[{
      ""payment_method"": {
        ""type"": ""spei"",
        ""expires_at"": " + thirtyDaysFromNow + @"
      }
    }]
  }");
} catch (ConektaException e) {
  foreach (JObject obj in e.details) {
    System.Console.WriteLine("\n [ERROR]:\n");
    System.Console.WriteLine("message:\t" + obj.GetValue("message"));
    System.Console.WriteLine("debug:\t" + obj.GetValue("debug_message"));
    System.Console.WriteLine("code:\t" + obj.GetValue("code"));
  }
}
Address := &conekta.Address{
    Street1: "Street1",
    Street2: "Street2",
    City: "City",
    State: "State",
    Country: "Country",
    PostalCode: "PostalCode",
}

customerParams := &conekta.CustomerParams{
    //ID: "cus_2nD9kZfqRzMuF8czZ",
    Name: "Fulanito Perez",
    Phone: "5512345678",
    Email: "[email protected]",
}

lineItemParams := &conekta.LineItemsParams{
    Name: "Naranjas Robadas",
    UnitPrice: 10000,
    Quantity: 2,
}

shippingParams := &conekta.ShippingLinesParams{
    Amount: 200,
    TrackingNumber: "123",
    Carrier: "Test Carrier",
    Method: "method",
}

shippingContactParams := &conekta.ShippingContactParams{
    Phone: "55-5555-5555",
    Receiver: "Miguel",
    BetweenStreets: "BetweenStreets",
    Address: Address,
}

chargeParams := &conekta.ChargeParams{
    PaymentMethod: &conekta.PaymentMethodParams{
        Type: "spei",
        ExpiresAt: time.Now().AddDate(0, 0, 90).Unix(),
    },
}

orderParams := &conekta.OrderParams{}
orderParams.Currency = "MXN"
orderParams.CustomerInfo = customerParams
orderParams.LineItems = append(orderParams.LineItems, lineItemParams)
orderParams.ShippingLines = append(orderParams.ShippingLines, shippingParams)
orderParams.ShippingContact = shippingContactParams
orderParams.Charges = append(orderParams.Charges, chargeParams)

ord, err := order.Create(orderParams)
if err != nil {
    code := err.(conekta.Error).Details[0].Code
    fmt.Printf(code)
} else {
    fmt.Println(ord)
}

Paso 3 - Procesar respuesta

Una vez creada la orden y el cargo, deberás procesar la respuesta y presentar la ficha de pago.
Recuerda que la respuesta de una orden es formato JSON.

# N/A
echo $order;
echo "ID: ". $order->id;
echo "Bank: ". $order->charges[0]->payment_method->receiving_account_bank;
echo "CLABE: ". $order->charges[0]->payment_method->receiving_account_number;
echo "$". $order->amount/100 . $order->currency;
echo "Order";
echo $order->line_items[0]->quantity .
      "-". $order->line_items[0]->name .
      "- $". $order->line_items[0]->unit_price/100;


// Response
// ID: ord_2fsQdMUmsFNP2WjqS
// Bank: STP
// CLABE: 646180111812345678
// $ 135.0 MXN
// Order
// 12 - Tacos - $10.0
puts "ID: #{order.id}"
puts "Bank: #{order.charges.data[0].payment_method.receiving_account_bank}"
puts "CLABE: #{order.charges.data[0].payment_method.receiving_account_number}"
puts "$ #{(order.amount/100).to_f} #{order.currency}"
puts "Order"
puts "#{order.line_items.data[0].quantity}
      - #{order.line_items.data[0].name}
      - $ #{(order.line_items.data.unit_price/100).to_f}"


# Response
# ID: ord_2fsQdMUmsFNP2WjqS
# Bank: STP
# CLABE: 646180111812345678
# $ 135.0 MXN
# Order
# 12 - Tacos - $10.0
print("ID: " + order.id)
print("Bank: " + order.charges.data[0].payment_method.receiving_account_bank)
print("CLABE: " + order.charges.data[0].payment_method.receiving_account_number)
print("$" + (order.amount/100) + order.currency)
print("Order")
print(order.line_items.data[0].quantity + " - "
            + order.line_items.data[0].name + " - "
            + (order.line_items.data.unit_price/100))


# Response
# ID: ord_2fsQdMUmsFNP2WjqS
# Payment Method: OxxoPay
# Reference: 123456789012
# $ 135.0 MXN
# Order
# 12 - Tacos - $10.0
console.log("ID: " + order.id);
console.log("Bank: " + order.charges.data[0].payment_method.receiving_account_bank);
console.log("CLABE: " + order.charges.data[0].payment_method.receiving_account_number);
console.log("$" + (order.amount/100) + order.currency);
console.log("Order");
console.log(order.line_items.data[0].quantity + " - "
            + order.line_items.data[0].name + " - "
            + (order.line_items.data.unit_price/100));


// Response
// ID: ord_2fsQdMUmsFNP2WjqS
// Bank: STP
// CLABE: 646180111812345678
// $ 135.0 MXN
// Order
// 12 - Tacos - $10.0
System.out.println("ID: " + order.id);
System.out.println("$" + (order.amount/100) + order.currency);
System.out.println("Order");
System.out.println(order.line_items.data[0].quantity + " - "
            + order.line_items.data[0].name + " - "
            + (order.line_items.data.unit_price/100));


// Response
// ID: ord_2fsQdMUmsFNP2WjqS
// $ 135.0 MXN
// Order
// 12 - Tacos - $10.0
Console.WriteLine("ID: " + order.id);
Console.WriteLine("Bank: " + order.charges.data[0].payment_method.receiving_account_bank);
Console.WriteLine("CLABE: " + order.charges.data[0].payment_method.receiving_account_number);
Console.WriteLine("$" + (order.amount/100) + order.currency);
Console.WriteLine("Order");
Console.WriteLine(order.line_items.data[0].quantity + " - "
            + order.line_items.data[0].name + " - "
            + (order.line_items.data.unit_price/100));


// Response
// ID: ord_2fsQdMUmsFNP2WjqS
// Bank: STP
// CLABE: 646180111812345678
// $ 135.0 MXN
// Order
// 12 - Tacos - $10.0
fmt.Println("ID: ", o.ID)
fmt.Println("Payment Method: ", o.Charges.Data[0].PaymentMethod.ServiceName)
fmt.Println("Reference: ", o.Charges.Data[0].PaymentMethod.Reference)
fmt.Println("$",o.Amount/100, o.Currency)
fmt.Println("------Order------")
fmt.Println(" - ", o.LineItems.Data[0].Quantity)
fmt.Println(" - ", o.LineItems.Data[0].Name)
fmt.Println(" - ", o.LineItems.Data[0].UnitPrice/100)

//Response
//ID:  ord_2nCsbdLXvdAgDVcKr
//Payment Method:  OxxoPay
//Reference:  98000004875830
//$ 152 MXN
//------Order------
// -  1
// -  Producto 7
// -  152

Paso 4 - Presentar ficha de pago

Utiliza una ficha como esta para darle a tu cliente la referencia de pago junto con los pasos necesarios para completar la compra.

Ficha SPEI

Puedes incluirla en tu checkout o envíala por correo para ofrecer una mejor experiencia.
Consulta el repo en GitHub.

Paso 5 - Recibir notificación

Para poder confirmar los pagos que se realicen con SPEI deberás añadir un Webhook en tu Admin Conekta para recibir las notificaciones POST (HTTP JSON) correctamente.

Utiliza URLs públicos: Si no tienes un IP público o un domino a tu disposición, puedes utilizar servicios como ultrahook o localtunnel.

Consultar la referencia sobre Webhooks.

Paso 6 - Notifica a tu cliente

Una buena práctica es notificar a tu usuario vía email.

Paso 7 - Prueba tu webhook

Dentro de tu Admin Conekta puedes probar la funcionalidad de tu webhook

¿Qué necesitarás? La URL de tu webhook y acceso al Admin Conekta.

👍

¡Listo!

Recuerda cambiar tus llaves pública y privada de pruebas por tus llaves de producción después de realizar pruebas.