Pagos Recurrentes en Efectivo

Pagos Recurrentes en efectivo

Hemos creado este tutorial para que puedas recibir pagos recurrentes en efectivo a través de Conekta. Así, tus clientes podrán pagar las veces que quieran tus productos o servicios. En el caso de Oxxo Pay, cada cliente tendrá una referencia única para realizar los pagos.

📘

Primeros pasos

-Te recomendamos tener conocimiento de APIs.

  • Es preferible ser desarrollador fullstack, es decir desarrollador frontend y backend
  • Instalar e incluir una de las librerías disponibles de Conekta.
  • Contar con tus API Keys (llave personal) de pruebas.

Paso 1 - Agrega tu llave privada y versión del API

Copia tus llaves privadas de pruebas. Si aún no las tienes, puedes obtenerlas en el siguiente enlace: panel Conekta](https://admin.conekta.com/settings/keys).

# N/A
require_once("/path/to/lib/Conekta.php");
\Conekta\Conekta::setApiKey("key_eYvWV7gSDkNYXsmr");
\Conekta\Conekta::setApiVersion("2.0.0");
require "conekta"
Conekta.api_key = "key_eYvWV7gSDkNYXsmr"
Conekta.api_version = "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");
com.conekta.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 tu orden de pago recurrente

CUSTOM_REFERENCE_RETURNED​ se refiere a su ​referencia personalizada ​y barcode_url es la imagen del código de barras generada.

begin
  customer = Conekta::Customer.create({
        name: "Fulanito",
        email: "[email protected]",
        phone: "52134659439",
        payment_method: {
            type: "cash_recurrent"
        }
  })
rescue Conekta::Error => error
  for error_detail in error.details do
    puts error_detail.message
  end
end
curl --request POST \
  --url https://api.conekta.io/customers \
  --header 'accept: application/vnd.conekta-v2.0.0+json' \
  -u key_eYvWV7gSDkNYXsmr: \
  --header 'content-type: application/json' \
  --data '{
      "name": "Fulanito",
      "email": "[email protected]",
      "phone": "+5218181818181",
      "payment_sources": [{
        "type": "oxxo_recurrent"
        }]
  }'

#Respuesta json de API
{
"livemode":​false​, 
"name":​"Oxxo recc"​, 
"email":​"[email protected]"​, 
"phone":​"52134659439"​, 
"id":​"cus_2jP5P8huCTWqcTtrn"​, 
"object":​"customer"​,
"created_at":​1538686075​, 
"corporate":​false​, 
"custom_id":​""​, 
"payment_sources":{
    "object":​"list"​, 
    "has_more":​false​, 
    "total":​1​,
"data":[{
"id":​"off_ref_2jP5P8huCTWqcTtro"​, 
"object":​"payment_source"​, 
"type":​"oxxo_recurrent"​,
"provider":​"Oxxo"​, 
"reference":​"CUSTOM_REFERENCE_RETURNED"​, 
"barcode":​"CUSTOM_REFERENCE_RETURNED"​, 
"barcode_url":​"https://sandbox_reference.png"​,
"expires_at":​0​, 
"created_at":​1538686075​, 
"parent_id":​"cus_2jP5P8huCTWqcTtrn" }]
}}try{
    $customer = \Conekta\Customer::create(
      array(
          'name'  => "fulanito",
          'email' => "[email protected]",
          'phone' => "+5218181818181",
          'payment_sources' => array(
                array(
                'type' => "oxxo_recurrent"
                )
            )
      )
    );
    var_dump(json_encode($customer));
  } catch (\Conekta\ProcessingError $error){
    echo $error->getMessage();
  } catch (\Conekta\ParameterValidationError $error){
    echo $error->getMessage();
  } catch (\Conekta\Handler $error){
    echo $error->getMessage();
  }

#Respuesta json de API
{
"livemode":​false​, 
"name":​"Oxxo recc"​, 
"email":​"[email protected]"​, 
"phone":​"52134659439"​, 
"id":​"cus_2jP5P8huCTWqcTtrn"​, 
"object":​"customer"​,
"created_at":​1538686075​, 
"corporate":​false​, 
"custom_id":​""​, 
"payment_sources":{
    "object":​"list"​, 
    "has_more":​false​, 
    "total":​1​,
"data":[{
"id":​"off_ref_2jP5P8huCTWqcTtro"​, 
"object":​"payment_source"​, 
"type":​"oxxo_recurrent"​,
"provider":​"Oxxo"​, 
"reference":​"CUSTOM_REFERENCE_RETURNED"​, 
"barcode":​"CUSTOM_REFERENCE_RETURNED"​, 
"barcode_url":​"https://sandbox_reference.png"​,
"expires_at":​0​, 
"created_at":​1538686075​, 
"parent_id":​"cus_2jP5P8huCTWqcTtrn" }]
}}
try{
    $customer = \Conekta\Customer::create(
      array(
          'name'  => "fulanito",
          'email' => "[email protected]",
          'phone' => "+5218181818181",
          'payment_sources' => array(
                array(
                'type' => "oxxo_recurrent"
                )
            )
      )
    );
    var_dump(json_encode($customer));
  } catch (\Conekta\ProcessingError $error){
    echo $error->getMessage();
  } catch (\Conekta\ParameterValidationError $error){
    echo $error->getMessage();
  } catch (\Conekta\Handler $error){
    echo $error->getMessage();
  }

#Respuesta json de API
{
"livemode":false, 
"name":"Oxxo recc", 
"email":"[email protected]",
"phone":"52134659439",
"id":"cus_2jP5P8huCTWqcTtrn", 
"object":"customer",
"created_at":1538686075,
"corporate":false, 
"custom_id":"", 
"payment_sources":{
  "object":"list", 
  "has_more":false, 
  "total":1,
  "data":[{
    "id":"off_ref_2jP5P8huCTWqcTtro", 
    "object":"payment_source",
    "type":"oxxo_recurrent",
    "provider":"Oxxo",
    "reference":"CUSTOM_REFERENCE_RETURNED",
    "barcode":"CUSTOM_REFERENCE_RETURNED",
    "barcode_url":"https://sandbox_reference.png",
    "expires_at":0,
    "created_at":1538686075,
    "parent_id":"cus_2jP5P8huCTWqcTtrn"}]
}}
try:
  customer = conekta.Customer.create({
      "name": "Fulanito",
      "email": "[email protected]",
      "phone": "+5218181818181",
      "payment_method": {
        "type": "oxxo_recurrent"
      }
  })
except conekta.ConektaError as e:
  print e.message

#Respuesta json de API
{
"livemode":false, 
"name":"Oxxo recc", 
"email":"[email protected]",
"phone":"52134659439",
"id":"cus_2jP5P8huCTWqcTtrn", 
"object":"customer",
"created_at":1538686075,
"corporate":false, 
"custom_id":"", 
"payment_sources":{
  "object":"list", 
  "has_more":false, 
  "total":1,
  "data":[{
    "id":"off_ref_2jP5P8huCTWqcTtro", 
    "object":"payment_source",
    "type":"oxxo_recurrent",
    "provider":"Oxxo",
    "reference":"CUSTOM_REFERENCE_RETURNED",
    "barcode":"CUSTOM_REFERENCE_RETURNED",
    "barcode_url":"https://sandbox_reference.png",
    "expires_at":0,
    "created_at":1538686075,
    "parent_id":"cus_2jP5P8huCTWqcTtrn"}]
}}
customer = conekta.Customer.create({
    "name": "Fulanito",
    "email": "[email protected]",
    "phone": "+5218181818181",
    "payment_method": {
      "type": "oxxo_recurrent"
    }
}, function(err, res) {
    console.log(res.toObject());
});

//Respuesta json de API
{
"livemode":false, 
"name":"Oxxo recc", 
"email":"[email protected]",
"phone":"52134659439",
"id":"cus_2jP5P8huCTWqcTtrn", 
"object":"customer",
"created_at":1538686075,
"corporate":false, 
"custom_id":"", 
"payment_sources":{
  "object":"list", 
  "has_more":false, 
  "total":1,
  "data":[{
    "id":"off_ref_2jP5P8huCTWqcTtro", 
    "object":"payment_source",
    "type":"oxxo_recurrent",
    "provider":"Oxxo",
    "reference":"CUSTOM_REFERENCE_RETURNED",
    "barcode":"CUSTOM_REFERENCE_RETURNED",
    "barcode_url":"https://sandbox_reference.png",
    "expires_at":0,
    "created_at":1538686075,
    "parent_id":"cus_2jP5P8huCTWqcTtrn"}]
}}
try{
  Customer customer = Customer.create(
    new JSONObject("{"
        + "'name': 'Fulanito',"
        + "'email': '[email protected]',"
        + "'phone': '+5218181818181',"
        + "'payment_method': {"
          + "'type': 'oxxo_recurrent',"
        + "}"
    + "}"
    )
  );
}catch (Conekta::Error e) {
   System.out.println(e.details.get(0).message);
}

//Respuesta json de API
{
"livemode":false, 
"name":"Oxxo recc", 
"email":"[email protected]",
"phone":"52134659439",
"id":"cus_2jP5P8huCTWqcTtrn", 
"object":"customer",
"created_at":1538686075,
"corporate":false, 
"custom_id":"", 
"payment_sources":{
  "object":"list", 
  "has_more":false, 
  "total":1,
  "data":[{
    "id":"off_ref_2jP5P8huCTWqcTtro", 
    "object":"payment_source",
    "type":"oxxo_recurrent",
    "provider":"Oxxo",
    "reference":"CUSTOM_REFERENCE_RETURNED",
    "barcode":"CUSTOM_REFERENCE_RETURNED",
    "barcode_url":"https://sandbox_reference.png",
    "expires_at":0,
    "created_at":1538686075,
    "parent_id":"cus_2jP5P8huCTWqcTtrn"}]
}}
try{
  conekta.Customer customer = new conekta.Customer ().create(@"{
      ""name"": ""Fulanito"",
      ""email"": ""[email protected]"",
      ""phone"": ""+5218181818181"",
      ""payment_method"": {
        ""type"": ""oxxo_recurrent"",
      }
  }");
} 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"));
  }
}

//Respuesta json de API
{
"livemode":false, 
"name":"Oxxo recc", 
"email":"[email protected]",
"phone":"52134659439",
"id":"cus_2jP5P8huCTWqcTtrn", 
"object":"customer",
"created_at":1538686075,
"corporate":false, 
"custom_id":"", 
"payment_sources":{
  "object":"list", 
  "has_more":false, 
  "total":1,
  "data":[{
    "id":"off_ref_2jP5P8huCTWqcTtro", 
    "object":"payment_source",
    "type":"oxxo_recurrent",
    "provider":"Oxxo",
    "reference":"CUSTOM_REFERENCE_RETURNED",
    "barcode":"CUSTOM_REFERENCE_RETURNED",
    "barcode_url":"https://sandbox_reference.png",
    "expires_at":0,
    "created_at":1538686075,
    "parent_id":"cus_2jP5P8huCTWqcTtrn"}]
}}
payment := &conekta.PaymentSourceCreateParams{
    PaymentType: "oxxo_recurrent",
}

cus := &conekta.CustomerParams{}
cus.Name = "fulanito"
cus.Email = "[email protected]"
cus.Phone = "+5215555555555"
cus.PaymentSources = append(cus.PaymentSources, payment)

res, err := customer.Create(cus)

//Respuesta de API
{
"livemode":false, 
"name":"Oxxo recc", 
"email":"[email protected]",
"phone":"52134659439",
"id":"cus_2jP5P8huCTWqcTtrn", 
"object":"customer",
"created_at":1538686075,
"corporate":false, 
"custom_id":"", 
"payment_sources":{
  "object":"list", 
  "has_more":false, 
  "total":1,
  "data":[{
    "id":"off_ref_2jP5P8huCTWqcTtro", 
    "object":"payment_source",
    "type":"oxxo_recurrent",
    "provider":"Oxxo",
    "reference":"CUSTOM_REFERENCE_RETURNED",
    "barcode":"CUSTOM_REFERENCE_RETURNED",
    "barcode_url":"https://sandbox_reference.png",
    "expires_at":0,
    "created_at":1538686075,
    "parent_id":"cus_2jP5P8huCTWqcTtrn"}]
}}

Paso 3 - Presenta la ficha de pago

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

399399

Ficha de pago en efectivo con Conekta

Tienes que incluirla en tu Checkout o enviarla por correo para ofrecer una mejor experiencia.
Puedes obtenerla en Ejemplo de pago en efectivo con Conekta

Paso 4 - Crea un Webhook

Recuerda que Conekta debe estar en constante comunicación con tu sitio a través de Webhooks para:

1)​ Validar que la referencia del usuario sea correcta y pueda hacer pagos
2)​ Aprobar la cantidad que el usuario quiere pagar
3)​ Notificar un pago
Un “Webhook” es un sistema de notificaciones, donde tu sitio debe definir una dirección o URL, para que nuestra API mande peticiones HTTP y pueda notificarte de los eventos que se van a realizar en tu sitio. Por ello, deberás crear un “Webhook” desde tu perfil de administrador con los siguientes pasos:

Abre el menú principal de tu cuenta, ubicado en la esquina superior derecha, y selecciona la sección “​Webhooks”.

Paso 4.1 - Crear un Webhook Sincrónico para Aprobar Pagos

En el caso de pagos recurrentes, vas a recibir eventos especiales para poder aprobar o declinar los pagos de forma dinámica. Estas peticiones te van a llegar en tiempo real y tienes un máximo de dos segundos para contestarlas o se va declinar el pago. En el Perfil de Administrador abre el menú principal de tu cuenta, ubicado en la esquina superior derecha, y selecciona Webhooks​

201201

Selecciona la opción “​Crear Webhook” al presionarlo se abrirá una ventana con un formulario en donde deberás colocar la dirección o URL del “Webhook” donde deseas recibir las notificaciones de los pagos recurrentes en efectivo con Conekta, selecciona la casilla de "Usar para Oxxo Pay Recurrente" y da clic en “Crear”.

451451

Ya estás listo para recibir pagos recurrentes desde tu sitio.

Paso 4.2 - Crea un Webhook asincrónico para recibir notificaciones de pagos

Adicional al primer Webhook, tendrías que armar endpoint para escuchar notificaciones asincrónicas de pago. A diferencia de las notificaciones anteriores, Conekta va reintentar las notificaciones en caso de que fallen y vas a recibir mayor carga de otras notificaciones por eso que es importante ocupar otro endpoint.

Cuando creas este Webhook, no tendrías que indicar que es para pagos recurrentes.

Paso 5 - Responder a Webhooks

A diferencia de métodos de pago en línea, como tarjetas, los usuarios tienen que realizar acciones offline para hacer pagos en efectivo así que flujo es asincrónico y el procesamiento y seguridad de notificaciones es fundamental para tu flujo.

Paso 5.1 - Responder a Consultas

El primero notificación a responder, es una notificación sincrónica de consulta y con el tipo de inbound_payment.lookup.

{
  "data":{
    "object": {
      "payment_method": {
        "service_name": "OxxoPay",
        "barcode_url": "https://barcode/url.png",
        "object": "cash_payment",
        "type": "oxxo",
        "expires_at": 1541289600,
        "reference": "8400003726321"
      },
      "charge_id": "5bb675388a268e0ef4a56a42",
      "livemode": true,
      "created_at": 0,
      "object": "inbound_payment",
      "amount": 0,
      "currency": "MXN",
      "customer_id": "cus_2jP5P8huCTWqcTtrn"
    },
    "previous_attributes": {}
  },
  "livemode": true,
  "webhook_status": "not_applicable",
  "webhook_logs": [],
  "id": "5b438f82583eb80d50b4652c",
  "object": "event",
  "type": "inbound_payment.lookup",
  "created_at": 1531154306
}

Para aprobar el pago tendrías que contestar en JSON, indica que payable es true, y el rango de cantidades en centavos.

{
    "payable": true,
    "min_amount": 5000,
    "max_amount": 1000000
}

En caso que quieras declinar un pago, puedes indicar payable: false y un código de rechazo. Puedes consultar la lista completa de códigos de rechazo al final del tutorial.

{
    "payable": false,
    "failure_code": "15"
}

Paso 5.2 - Responder a confirmaciones de Pago

La primer notificación a responder, es una notificación sincrónica de consulta y con el tipo de inbound_payment.payment_attempt.

{
  "data": {
  "object": {
    "payment_method": {
        "service_name":"OxxoPay",
        "barcode_url": "https://s3.amazonaws.com/cash_payment_barcodes/84000045432316.png",
        "object": "cash_payment",
        "type": "oxxo",
        "expires_at": 1541289600,
        "reference": "84000045432316"
      },
      "charge_id": "5bb6755d8a268e0ed9a56acb", "livemode": true,
      "created_at": 1538684253,
      "object": "inbound_payment",
      "amount": 110700,
      "currency": "MXN",
      "customer_id": "cus_2jHUgfTB4pYmjmHpB"
    },
    "previous_attributes": {}
  },
  "livemode": true,
  "webhook_status": "not_applicable",
  "webhook_logs": [],
  "id": "5b439072583eb80d50b46534",
  "object": "event",
  "type": "inbound_payment.payment_attempt",
  "created_at": 1531154546
}

Para aprobar el pago tendrías que contestar en JSON, indicando que payable es true

{
    "payable": true
}

En caso que quieras declinar un pago, puedes indicar payable: false y un código de rechazo. Puedes consultar la lista completa de códigos de rechazo al fin del tutorial.

{
    "payable": false,
    "failure_code": "15"
}

Paso 6 - Recibir confirmaciones de pago

La última notificación a recibir es una notificación asincrónica de pago con el tipo de charge.paid. Para seguridad es crítico verificar la firma de notificaciones. El siguiente ejemplo pertenece a una notificación de pago:

{
  "data": {
    "object": {
      "id": "5c0968098a268e02ab8aa3f7",
      "livemode": true,
      "created_at": 1544120329,
      "currency": "MXN",
      "description": null,
      "reference_id": null,
      "failure_code": null,
      "failure_message": null,
      "monthly_installments": null,
      "device_fingerprint": null,
      "refunds": [],
      "payment_method": {
        "barcode": "XXXXXXXXX",
        "reference": "XXXXXXXXX",
        "barcode_url": "https://s3.amazonaws.com/cash_payment_barcodes/XXXXXXXXX.png",
        "object": "cash_payment",
        "type": "oxxo",
        "expires_at": 1546732800,
        "store_name": "OXXO"
      },
      "details": {
        "name": "Juan Perez",
        "phone": null,
        "email": "[email protected]",
        "line_items": [],
        "coupons": [],
        "object": "details"
      },
      "object": "charge",
      "status": "paid",
      "amount": 350000,
      "paid_at": 1544120362,
      "fee": 10150,
      "customer_id": "cus_2j35ehQaF1jZEcWH7",
      "subscription_id": "",
      "amount_refunded": null
      },
    "previous_attributes": {}
  },
  "livemode": true,
  "webhook_status": "not_applicable",
  "webhook_logs": [],
  "id": "5b439072583eb80d50b46534",
  "object": "event",
  "type": "charge.paid",
  "created_at": 1531154546
}

Paso 7 - Flujos de prueba

Tienes disponibles endpoints para que para que puedas probar el flujo de pagos end-to-end antes de hacer pruebas. Recuerda que todo se puede probar pegando el endpoints de https://api.conekta.io/payment_test

Paso 7.1 - Pruebas de Consultas

El siguiente payload va lanzar la notificación a tu endpoint de consulta.

{
  "event_type": "inbound_payment.lookup",
  "reference": "99000000001273"
}

Por ejemplo

curl --request POST \
  --url https://api.conekta.io/payment_test \
  --header 'accept: application/vnd.conekta-v2.0.0+json' \
  -u YOUR_PRIVATE_SANDBOX_API_KEY: \
  --header 'content-type: application/json' \
  --data '{ "event_type": "inbound_payment.lookup", "reference": "99000000001273" }'

Paso 7.2 - Pruebas de confirmaciones de pago

El siguiente payload te enviará una notificación de confirmación de pago a tu Webhook.

{
  "event_type": "inbound_payment.payment_attempt",
  "reference": "99000000001273",
  "amount": "10000"
}

Por ejemplo

curl --request POST \
  --url https://api.conekta.io/payment_test \
  --header 'accept: application/vnd.conekta-v2.0.0+json' \
  -u YOUR_PRIVATE_SANDBOX_API_KEY: \
  --header 'content-type: application/json' \
  --data '{ "event_type": "inbound_payment.payment_attempt", "reference": "99000000001273", "amount": "10000" }'

Paso 7.3 - Pruebas de reversos de pago

El siguiente payload va lanzar una notificación de reverso de pago a tu Webhook.

{
  "event_type": "inbound_payment.reverse",
  "reference": "99000000001273"
}

Por ejemplo

curl --request POST \
  --url https://api.conekta.io/payment_test \
  --header 'accept: application/vnd.conekta-v2.0.0+json' \
  -u YOUR_PRIVATE_SANDBOX_API_KEY: \
  --header 'content-type: application/json' \
  --data '{ "event_type": "inbound_payment.reverse", "reference": "99000000001273" }'

Addendum - Códigos de rechazo

Te compartimos los siguientes códigos de rechazo para que puedes comunicar fallas a tus clientes en cajero

failure_code

Descripción

01

Referencia no encontrada

02

Cantidad inválida

03

Referencia expirada

10

Referencia sin deuda

13

Referencia inactiva

14

Referencia cancelada

15

Usuario bloqueado

16

Cantidad no permitida

18

Comercio fuera de horario

19

No autorizado

35

Monto fuera del rango permitido

36

Referencia ya pagada