NEQUI
  • Colombia

  • Panamá

  • Cómo usar el SDK
  • Creación de un cliente
  • Servicio para generar código de pago mediante QR
  • Servicio de Pago sin Registro
  • Servicio para validar pago

Consumo del API de Pagos en Java o Android

Cómo usar el SDK

Para poder consumir el API de Nequi en su proyecto Java debe agregar el SDK como una dependencia de maven, el id del artefacto cambia según si el ambiente es QA o producción.

Por favor incluya en la parte de dependencias de su pom.xml lo siguiente:

  • Ambiente de pruebas o QA:

      
      <dependency>
          <groupid>com.nequi</groupid>
          <artifactid>nequi-api-client-qa</artifactid>
          <version>1.0.1</version>
      </dependency>
      

 

  • Ambiente de producción:
      
      <dependency>
          <groupid>com.nequi</groupid>
          <artifactid>nequi-api-client</artifactid>
          <version>1.0.1</version>
      </dependency>
      

 

Si no va a usar el artefacto de maven sino que el equipo de NEQUI le entregó los jars requeridos, agregue estos al classpath de su proyecto; o en caso que tenga las fuentes del SDK de Java en un .zip, descomprímalo y en la raíz donde se encuentra el archivo pom.xml ejecute el comando mvn install para instalar el paquete en su repositorio local de maven.

Creación de un cliente

Ya teniendo el SDK integrado en nuestro proyecto, lo siguiente para consumir el API de NEQUI es instanciar un nuevo cliente mediante el objeto ApiClientFactory y la interfaz NequiGatewayClient que representa el contrato de servicio con las operaciones que se pueden hacer sobre el API de Nequi.

Para este proceso va a necesitar el apiKey, accessKey y secretKey que le ha suministrado el equipo de Nequi como sus credenciales de acceso al API para poder configurar la autorización mediante alguno de los múltiples proveedores que ofrece AWS (mediante Variables de entorno, archivos de propiedades, AWS Security Token Service, etc.) o alguna estrategia que usted desee crear. Para este ejemplo vamos a utilizar un proveedor que nos expone el SDK de Nequi llamado BasicAWSCredentialsProvider.

En el siguiente código en java podemos ver un ejemplo de cómo instanciar un cliente del API:


//Se inicializa la fábrica de clientes
ApiClientFactory factory = new ApiClientFactory();
//Se instancia el proveedor de credenciales
AWSCredentialsProvider credenetialsProvider = new
BasicAWSCredentialsProvider(ACCESS_KEY,SECRET_KEY);
//Se setea el api key
factory.apiKey(API_KEY);
//Se asigna el proveedor de credenciales a la fábrica de clientes factory.credentialsProvider(credenetialsProvider);
//Se instancia un nuevo cliente del api a partir del contrato establecido por NequiGatewayClient
NequiGatewayClient apiClient = factory.build(NequiGatewayClient.class);

 

Ya con el contrato o interfaz NequiGatewayClient instanciada podemos ejecutar de manera sincrónica cualquiera de los siguientes métodos:


public interface NequiGatewayClient {
    JsonObject servicesPaymentserviceGeneratecodeqrPost(JsonObject body);
    JsonObject servicesPaymentserviceGeneratecodeqrOptions();
    JsonObject servicesPaymentserviceGetstatuspaymentPost(JsonObject body);
    JsonObject servicesPaymentserviceGetstatuspaymentOptions();
    JsonObject servicesPaymentserviceUnregisteredpaymentPost(JsonObject body);
    JsonObject servicesPaymentserviceUnregisteredpaymentOptions();
}

 

De los anteriores métodos solo nos van a interesar las que no terminan con la palabra Options, porque estos servicios o recursos solo son útiles para permitir CORS.

Como se puede ver en la anterior imagen, cada método o servicio del API recibe un JsonObject que representa el cuerpo de la petición que requiere el servicio y retorna un JsonObject que representa la respuesta del servicio.

Servicio para generar código de pago mediante QR

El servicio para generar código de pago mediante QR expuesto en el api permite a partir del celular de un cliente merchant y un valor a cobrar, crear una solicitud o código de pago, que al concatenar con el string “bancadigital-” conforman la cadena con la cual se puede crear un código QR que puede ser leído desde la aplicación móvil NEQUI para concretar el pago.

De los métodos que ofrece el NequiGatewayClient vamos a utilizar servicesPaymentserviceGeneratecodeqrPost para consumir el servicio que genera claves para la creación de QR.

En código Java sería de la siguiente forma:


//Inicialización del cliente API
ApiClientFactory factory = new ApiClientFactory();
AWSCredentialsProvider credenetialsProvider = new BasicAWSCredentialsProvider(ACCESS_KEY, SECRET_KEY);
factory.apiKey(_API_KEY); factory.credentialsProvider(credenetialsProvider);
NequiGatewayClient apiClient = factory.build(NequiGatewayClient.class);
Long phone_number = 123;
Integer value = 100;
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient. servicesPaymentserviceGeneratecodeqrPost(BodyUtils. getBodyGenerateQR(phone_number,value));



 

Si analizamos el anterior código primero se inicializa el cliente y luego se invoca el servicio. Además, en este ejemplo también se usa un método estático, BodyUtils.getBodyGenerateQR, para generar el cuerpo de la petición, este método debería retornar un JsonObject con la siguiente estructura:


{
    "RequestMessage": {
        "RequestHeader": {
            "Channel": CONSUMER_ID, //ID del consumidor para trazabilidad 
            "RequestDate": DATE,
            //Timestamp completo, con milisegundos precisión 3
            "MessageID": ID, //Identificador único de la transacción, timestamp o alguno único
            "ClientID": NUMBER //Número de celular del merchant ó identificador de la terminal
            "Destination": {
                "ServiceName": "PaymentsService", //Servicio que se quiere consumir 
                "ServiceOperation": "generateCodeQR", //Operación del servicio a consumir
                "ServiceRegion": "C001", //Región a la que pertenece el servicio, para panamá P001
                "ServiceVersion": "1.0.0" //Versión del servicio
            }
        }, "RequestBody": {
            "any": {
                "generateCodeQRRQ": {                   
                    "code": "CC_CEDULA", //Cédula
                    "value": VALUE //Valor del pago a cobrar,
                    "reference1": "reference1",
                    "reference2": "reference2",
                    "reference3": "reference3",
                    "tipValue": TIP, //Valor de la propina (solo para Panamá) 
                    "taxValue": TAX  //Valor del impuesto (solo para Panamá) 

                }
            }
        }
    }
}

 

Para construir las cabeceras del cuerpo de la petición o RequestHeader va a necesitar el Channel que le ha sido suministrado por Nequi, generar un datestamp a partir de la fecha en que se realiza la petición para la propiedad RequestDate y definir una forma única de identificar la transacción mediante un alfanumérico de 10 para asignar al campo MessageID. Un ejemplo de la codificación del método sería:


// Canal para pagos con QR
public static final String CHANNEL = "PQR03-C001";
// Construye a partir del celular y valor para generar un codigo de pago el
// mensaje de entrada del servicio de generacion de QR
public static JsonObject getBodyGenerateQR(String code, Integer value,String reference1,String reference2,String reference3) {
    //Fecha de la petición
    Date d = new Date();
    String date = new SimpleDateFormat("yyyy-MM-dd:HH-mm-ss").format(d);
    String miliseconds = Long.toString(System.currentTimeMillis());
    String input =
        "{\"RequestMessage\":{"
            + "\"RequestHeader\":{"
            //Canal
            + "\"Channel\":\""+CHANNEL+"\","
            //Fecha de la petición
            + "\"RequestDate\":\""+date+"\","
            //Identificador único de la transacción
             + "\"MessageID\":\""+miliseconds.substring(miliseconds.length()-9)+"\","
            //Número de celular del merchant ó identificador de la terminal
            + "\"ClientID\":\""+ phone+ "\""
            + ", \"Destination\": {"
                +    "\"ServiceName\": \"PaymentsService\""
                +    ", \"ServiceOperation\": \"generateCodeQR\""
                +    ", \"ServiceRegion\": \"C001\""
                +    ", \"ServiceVersion\": \"1.0.0\""
            + "}"
        + "},"
        + "\"RequestBody\":{"
            + "\"any\":{"
                + "\"generateCodeQRRQ\":{"
                    + "\"code\":\""+ code+ "\","
                    + "\"value\":\"" + value + "\""+ "\","
                    + "\"reference1\":\"" + reference1+ "\""+ "\","
                    + "\"reference2\":\"" + reference2+ "\""+ "\","
                    + "\"reference3\":\"" + reference3+ "\""+ "\","
                + "}"
            + "}"
        + "}"
    + "}}";
    return gson.fromJson(input, JsonObject.class);
}

 

Llegado el caso que el consumo del servicio sea exitoso, el JsonObject que retorna el método trae internamente el código requerido para generar el QR, es un atributo con nombre codeQR, la estructura de la respuesta es similar a la siguiente:


{
    "ResponseMessage": {
        "ResponseHeader": {
            "Channel": CONSUMER_ID, //ID del consumidor para trazabilidad
            "ResponseDate": DATE, //Fecha de respuesta
            "Status": {
                "StatusCode": "0",
                "StatusDesc": "SUCCESS"
            },
            "MessageID": ID, //Identificador único de la transacción, timestamp o alguno único
            "ClientID": NUMBER, //Número de celular del merchant ó identificador de la terminal
            //Datos técnicos que no deberían ser procesados o almacenados
            "Destination": {
                "ServiceName": "PaymentsService", // Nombre del Servicio
                "ServiceOperation": "generateCodeQR" //Nombre de la operación
                "ServiceRegion": "C001", //Región a la que pertenece el servicio, para panamá P001
                "ServiceVersion": "1.0.0" //Versión del servicio
            }
        },
        "ResponseBody": {
            "any": {
                //Presente solo cuando StatusCode es igual a cero
                "generateCodeQRRS": {
                    "codeQR": CODIGO_QR //Esta es la variable que nos interesa
                }
            }
        }
    }
}

 

Cuando la operación del servicio falla, no el consumo HTTP del servicio REST, sino la operación de negocio, el campo StatusCode será diferente de cero y por consiguiente en ResponseBody.any no vendrá el objeto generateCodeQRRS sino que any  será un elemento o cadena vacía.

Servicio de Pago sin Registro

El servicio de pago sin registro  expuesto en el api permite a partir del celular de un cliente NEQUI, un valor a cobrar y el tipo y número de identificación de un comercio al que se le va a pagar, crear una solicitud de pago sin registro que envía una notificación push al celular para que el cliente confirme el pago desde la aplicación móvil de NEQUI.

De los métodos que ofrece el NequiGatewayClient vamos a utilizar servicesPaymentserviceUnregisteredpaymentPost para enviar una solicitud de pago a un cliente NEQUI.

En código Java sería de la siguiente forma:

 


//Inicialización del cliente API
ApiClientFactory factory = new ApiClientFactory();
AWSCredentialsProvider credenetialsProvider = new BasicAWSCredentialsProvider(ACCESS_KEY, SECRET_KEY);
factory.apiKey(_API_KEY);
factory.credentialsProvider(credenetialsProvider);
NequiGatewayClient apiClient = factory.build(NequiGatewayClient.class);

Long phone_number = 123;
Integer value = 100;
String code = “12345”;
 
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient. servicesPaymentserviceUnregisteredpaymentPost(BodyUtils.
getBodyUnregisteredPayment(phone_number,value, code));

 

 

Si analizamos el anterior código primero se inicializa el cliente y luego se invoca el servicio. Además, en este ejemplo también se usa un método estático, BodyUtils.getBodyUnregisteredPayment, para generar el cuerpo de la petición, este método debería retornar un JsonObject con la siguiente estructura:


{
    "RequestMessage": {
        "RequestHeader": {
            "Channel": CONSUMER_ID, //ID del consumidor para trazabilidad
            "RequestDate": DATE, //Timestamp completo, con milisegundos precisión 3
            "MessageID": ID, //Identificador único de la transacción, timestamp o alguno único
            "ClientID": NUMBER //Número de celular del merchant ó identificador de la terminal
            "Destination": {
                "ServiceName": "PaymentsService", //Servicio que se quiere consumir
                "ServiceOperation": "unregisteredPayment", //Operación del servicio a consumir
                "ServiceRegion": "C001", //Región a la que pertenece el servicio, para panamá P001
                "ServiceVersion": "1.0.0" //Versión del servicio
            }
        },
        "RequestBody": {
            "any": {
                "unregisteredPaymentRQ": {
                    //Número de celular del cliente
                    "phoneNumber": NUMBER,
                    "code": CODE, //Combinación del tipo y número de identificación del comercio
                    "value": VALUE //Valor del pago a cobrar,
                    "reference1": "reference1",  
                    "reference2": "reference2",   
                    "reference3": "reference3"
                }
            }
        }
    }
}

 

Para construir las cabeceras del cuerpo de la petición o RequestHeader va a necesitar el Channel que le ha sido suministrado por Nequi, generar un datestamp a partir de la fecha en que se realiza la petición para la propiedad RequestDate y definir una forma única de identificar la transacción mediante un alfanumérico de 10 para asignar al campo MessageID. Un ejemplo de la codificación del método sería:


// Canal para pagos con PUSH o sin registro
public static final String CHANNEL = "PNP04-C001";
// Construye a partir del celular y valor el cuerpo para consumir el servicio de pago sin
// registro. Tener en la cuenta el atributo code, este representa el tipo y número de identificación del comercio
public static JsonObject getBodyUnregisteredPayment(Long phone, Integer value, String code,String reference1,String reference2,String reference3) {
    //Fecha de la petición
    Date d = new Date();
    String date = new SimpleDateFormat("yyyy-MM-dd:HH-mm-ss").format(d);
    String miliseconds = Long.toString(System.currentTimeMillis());
    String input =
        "{\"RequestMessage\":{"
            + "\"RequestHeader\":{"
                //Canal
                + "\"Channel\":\""+CHANNEL+"\","
                //Fecha de la petición
                + "\"RequestDate\":\""+date+"\","
                //Identificador único de la transacción
                 + "\"MessageID\":\""+miliseconds.substring(miliseconds.length()-9)+"\","
                //Número de celular del merchant ó identificador de la terminal
                + "\"ClientID\":\""+ phone+ "\""
                + ", \"Destination\": {"
                    +    "\"ServiceName\": \"PaymentsService\""
                    +", \"ServiceOperation\": \" unregisteredPayment\""
                    +    ", \"ServiceRegion\": \"C001\""
                    +    ", \"ServiceVersion\": \"1.0.0\""
                + "}"
            + "},"
            + "\"RequestBody\":{"
                + "\"any\":{"
                    + "\"generateCodeQRRQ\":{"
                        + "\"phoneNumber\":\""+ phone + "\","
                        + "\"code\":\""+ code + "\","
                        + "\"value\":\"" + value + "\""+ "\","
                        + "\"reference1\":\"" + reference1+ "\""+ "\"," 
                        + "\"reference2\":\"" + reference2+ "\""+ "\"," 
                        + "\"reference3\":\"" + reference3+ "\""
                    + "}"
                + "}"
            + "}"
        + "}}";
    return gson.fromJson(input, JsonObject.class);
}

 

Llegado el caso que el consumo del servicio sea exitoso, el JsonObject que retorna el método trae internamente el identificador de la transacción, es un atributo con nombre transactionId, la estructura de la respuesta es similar a la siguiente:


{
    "ResponseMessage": {
        "ResponseHeader": {
            "Channel": CONSUMER_ID, //ID del consumidor para trazabilidad
            "ResponseDate": DATE, //Fecha de respuesta
            "Status": {
                "StatusCode": "0",
                "StatusDesc": "SUCCESS"
            },
            "MessageID": ID, //Identificador único de la transacción, timestamp o alguno único
            "ClientID": NUMBER, //Número de celular del merchant ó identificador de la terminal
            //Datos técnicos que no deberían ser procesados o almacenados
            "Destination": {
                "ServiceName": "PaymentsService", // Nombre del Servicio
                "ServiceOperation": "unregisteredPayment" //Nombre de la operación
                "ServiceRegion": "C001", //Región a la que pertenece el servicio, para panamá P001
                "ServiceVersion": "1.0.0" //Versión del servicio
            }
        },
        "ResponseBody": {
            "any": {
                //Presente solo cuando StatusCode es igual a cero
                "unregisteredPaymentRS": {
                    "transactionId": TRANSACTION_ID //Esta es la variable que nos interesa
                }
            }
        }
    }
}

 

 

Cuando la operación del servicio falla, no el consumo HTTP del servicio REST, sino la operación de negocio, el campo StatusCode será diferente de cero y por consiguiente en ResponseBody.any no vendrá el objeto  unregisteredPaymentRS sino que any será un elemento o cadena vacía.

Servicio para validar pago

El servicio para validar pagos, expuesto en el api permite a partir del código QR, no una imagen sino el código que responde el servicio de QR, o a partir del transactionId que retorna el servicio de pago sin registro validar si el pago ya fue realizado desde alguna cuenta NEQUI.

De las funciones que ofrece el NequiGatewayClient vamos a utilizar servicesPaymentserviceGetstatuspaymentPost para consumir el servicio que valida el estado de un pago.

En código Java sería de la siguiente forma:


//Inicialización del cliente API
ApiClientFactory factory = new ApiClientFactory();
AWSCredentialsProvider credenetialsProvider = new BasicAWSCredentialsProvider(ACCESS_KEY, SECRET_KEY);
factory.apiKey(_API_KEY);
factory.credentialsProvider(credenetialsProvider);
NequiGatewayClient apiClient = factory.build(NequiGatewayClient.class);

String code = “1234”;
Long phone_number = 123;
 
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient. servicesPaymentserviceGetstatuspaymentPost(BodyUtils. getBodyGetStatusPayment(phone_number, code));



 

En el anterior ejemplo primero se inicializa el cliente y luego se invoca el servicio, si la respuesta es exitosa y el estado del pago es igual a 35, significa que el pago ya está realizado.

Además, en este ejemplo también se usa un método que no está implementado en el ejemplo, BodyUtils.getBodyGetStatusPayment, para generar el cuerpo de la petición, esta función debería retornar un JsonObject  con la siguiente estructura:


{
    "RequestMessage": {
        "RequestHeader": {
            "Channel": CONSUMER_ID, //ID del consumidor para trazabilidad
            "RequestDate": DATE, //Timestamp completo, con milisegundos precisión 3
            "MessageID": ID, //Identificador único de la transacción, timestamp o alguno único
            "ClientID": NUMBER, //Número de celular del merchant ó identificador de la terminal (QR) o celular del cliente al que se le va a requerir el pago (Pago sin registro)
            "Destination": {
                "ServiceName": "PaymentsService", //Servicio que se quiere consumir
                "ServiceOperation": "getStatusPayment", //Operación del servicio a consumir
                "ServiceRegion": "C001", //Región a la que pertenece el servicio, para panamá P001
                "ServiceVersion": "1.0.0" //Versión del servicio
            }
        },
        "RequestBody": {
            "any": {
                "getStatusPaymentRQ": {
                    " codeQR ": NUMBER //Código del pago sea QR o transactionId
                }
            }
        }
    }
}

 

Al igual que en los servicios anteriores para construir las cabeceras del cuerpo de la petición o  RequestHeader va a necesitar el Channel que le ha sido suministrado por Nequi, generar un datestamp a partir de la fecha en que se realiza la petición para la propiedad RequestDate y definir una forma única de identificar la mediante un alfanumérico de 10 para asignar al campo MessageID. Un ejemplo de la codificación del método sería:


// Canal para pagos con QR
public static final String CHANNEL = "PQR03-C001"; // Si es con  PUSH PNP04-C001
//Construye a partir de un código de pago qr o transactionId el mensaje de entrada del
//servicio de validación de pago
public static JsonObject getBodyValidatePayment(Long phone_number, String code) {
    Date d = new Date();
    String date = new SimpleDateFormat("yyyy-MM-dd:HH-mm-ss").format(d);
    tring miliseconds = Long.toString(System.currentTimeMillis());
    String input =
        "{\"RequestMessage\":{"
            + "\"RequestHeader\":{"
                //Canal
                + "\"Channel\":\""+CHANNEL+"\","
                //Feha de la petición
                + "\"RequestDate\":\""+date+"\","
                //Identificador único de la transacción
                + "\"MessageID\":\""+miliseconds.substring(miliseconds.length()-9)+"\","
                + "\"ClientID\":\""+phone_number+ "\""
                + ", \"Destination\": {"
                    + "\"ServiceName\": \"PaymentsService\""
                    + ", \"ServiceOperation\": \"getStatusPayment\""
                    + ", \"ServiceRegion\": \"C001\""
                    + ", \"ServiceVersion\": \"1.0.0\""
                + "}"
            + "},"
            + "\"RequestBody\":{"
                + "\"any\":{"
                    + "\"getStatusPaymentRQ\":{"
                        + "\"codeQR\":\"" + code + "\""
                    + "}"
                + "}"
            + "}"
        + "}}";
    return gson.fromJson(input, JsonObject.class);
}

 

Llegado el caso que el consumo del servicio sea exitoso, el response de la petición o el retorno del método trae internamente el estado del pago, el cual es igual a 35 cuando ya se realizó el pago por parte de algún cliente NEQUI. El estado es un atributo con nombre status y  la estructura de la respuesta es similar a la siguiente:


{
    "ResponseMessage": {
        "ResponseHeader": {
            "Channel": CONSUMER_ID, //ID del consumidor para trazabilidad
            "ResponseDate": DATE, //Fecha de respuesta
            "Status": {
                "StatusCode": "0",
                "StatusDesc": "SUCCESS"
            },
            "MessageID": ID, //Identificador único de la transacción, timestamp o alguno único
            "ClientID": NUMBER, //Número de celular del merchant ó identificador de la terminal
            //Datos técnicos que no deberían ser procesados o almacenados
            "Destination": {
                "ServiceName": "PaymentsService",
                "ServiceOperation": "getStatusPayment",
                "ServiceRegion": "C001", //Región a la que pertenece el servicio, para panamá P001
                "ServiceVersion": "1.0.0"
            }
        },
        "ResponseBody": {
            "any": {
                //Presente solo cuando StatusCode es igual a cero
                "getStatusPaymentRS": {
                    "status": STATUS, //Estado del pago, si es igual a 35 es porque esta completo
                    "phoneNumber": CELL, //Numero del cliente que pago
                    "date": DATE, //Fecha del pago
                    "name": NAME, //Nombre del cliente merchant
                    "trnId": ID, //Id de la transacción
                    "value": VALUE, //Valor pagado
                    "tipValue": TIP, //Valor de la propina (solo en Panamá) 
                    "taxValue": TAX, //Valor del impuesto (solo en Panamá) 
                    "originMoney": [{
                        "name": NAME, //Nombre del origen o bolsillo de dónde provino el dinero
                        "value": VALUE, //Valor debitado
                        "pocketType": POCKET, //Tipo de bolsillo
                    }]
                }
            }
        }
    }
}

 

Cuando la operación del servicio falla, no el consumo HTTP del servicio REST, sino la operación de negocio, el campo StatusCode será diferente de cero y por consiguiente en ResponseBody.any no vendrá el objeto  getStatusPaymentRS sino que any  será un elemento o cadena vacía.

Si tiene dudas técnicas sobre la implementación y uso del API de NEQUI revise el código de la aplicación de ejemplo que se le entregó con esta guía o póngase en contacto con el equipo de NEQUI.