
-
Colombia
-
Panamá
Colombia
Panamá
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:
com.nequi nequi-payments-sdk-qa 2.0.0
com.nequi nequi-payments-sdk 2.0.0
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.
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 NequiPaymentsGatewayClient 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 la clase NequiAuth.
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 setea el api key
factory.apiKey(API_KEY);
//Se instancia un nuevo cliente del api a partir del contrato establecido por NequiPaymentsGatewayClient
NequiPaymentsGatewayClient apiClient = factory.build(NequiPaymentsGatewayClient.class);
Ya con el contrato o interfaz NequiPaymentsGatewayClient instanciada podemos ejecutar de manera sincrónica cualquiera de los siguientes métodos:
public interface NequiPaymentsGatewayClient { JsonObject
servicesPaymentserviceCancelqrpaymentPost(JsonObject body,
String authorization); JsonObject
servicesPaymentserviceCancelunregisteredpaymentPost(JsonObject body,
String authorization); JsonObject
servicesPaymentserviceGeneratecodeqrPost(JsonObject body,
String authorization); JsonObject
servicesPaymentserviceGetstatuspaymentPost(JsonObject body,
String authorization); JsonObject
servicesPaymentserviceUnregisteredpaymentPost(JsonObject body,
String authorization); JsonObject
servicesReverseservicesReversetransactionPost(JsonObject body,
String authorization); JsonObject
servicesStaticqrservicesCreatependingpaymentPost(JsonObject body,
String authorization); JsonObject
servicesStaticqrservicesGetinfoPost(JsonObject body,
String authorization); JsonObject
servicesStaticqrservicesGetpendingpaymentPost(JsonObject body,
String authorization); JsonObject
servicesStaticqrservicesGetstatuspaymentPost(JsonObject body,
String authorization); JsonObject
servicesStaticqrservicesReversepaymentPost(JsonObject body,
String authorization); }
Como se puede ver en la anterior código, cada método o servicio del API recibe un JsonObject que representa el cuerpo de la petición y un String con el token de autorización que requiere el servicio, y retorna un JsonObject que representa la respuesta de dicho servicio.
Todos los servicios ofrecidos por el API necesitan de un token de autenticación, el cuál podrá obtener mediante la clase NequiAuth. Dicha autenticación se puede hacer mediante 2 medios:
1. Variables de entorno: Esta es la opción recomendada, siempre que pueda suministrar las variables de entorno tal cual se mencionan a continuación:
Una vez listas las variables de entorno, basta con instanciar la clase de la siguiente forma:
Ejemplo
NequiAuth nequiAuth = NequiAuth.getInstance().fromEnvVars();
2. Asignación manual de los datos: Con este mecanismo podrá asignar manualmente los valores que se necesitan para autenticarse usando alguno de los siguientes métodos de la clase NequiAuth:
Ejemplos:
// Opción 1: Se omite el argumento "authGranType" para que tome el valor por defecto NequiAuth nequiAuth = NequiAuth.getInstance().with("myClientId", "myClienteSecret", "https://oauth.sandbox.nequi.com/oauth2/token"); // Opción 2: Se pasan todos los argumentos necesarios NequiAuth nequiAuth = NequiAuth.getInstance().with("myClientId", "myClienteSecret", "https://oauth.sandbox.nequi.com/oauth2/token", "client_credentials");
Ejemplos:
// Opción 1: Se instancia pasando cada dato en particular NequiAuth nequiAuth = NequiAuth.getInstance() .withClientId("myClientId") .withClientSecret("myClientSecret") .withAuthUri("https://oauth.sandbox.nequi.com/oauth2/token") .withAuthGranType("client_credentials"); // Opción 2: Se instancia a partir de las variables de entorno, pero se puede sobre-escribir cualquier valor NequiAuth nequiAuth = NequiAuth.getInstance().fromEnvVars() .withClientId("myClientId") .withClientSecret("myClientSecret");
Una vez instanciada la clase NequiAuth, puede obtener un token de autorización usando el método .getToken();, el cual puede recibir un flag que indica si se desea obtener concatenado el tipo de token y el token(el resultado es la cabecera HTTP "Authorization" ya lista); o si solo se desea el token. Si no se pasa el flag, por defecto será true.
Ejemplo:
// Retorna el tipo de token y el token concatenados, lo que conforma la cabecera HTTP "Authorization" // Se obtiene el mismo resultado que invocar nequiAuth.getToken(true); String token = nequiAuth.getToken();
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 NequiPaymentsGatewayClient 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(); factory.apiKey(_API_KEY); //Se instancia un nuevo cliente NequiPaymentsGatewayClient apiClient = factory.build(NequiPaymentsGatewayClient.class); //Se instancia la clase para autenticarse NequiAuth auth =
NequiAuth.getInstance().fromEnvVars();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),
auth.getToken());
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.
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 NequiPaymentsGatewayClient 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(); factory.apiKey(_API_KEY); //Se instancia un nuevo cliente NequiPaymentsGatewayClient apiClient = factory.build(NequiPaymentsGatewayClient.class); //Se instancia la clase para autenticarse NequiAuth auth =
NequiAuth.getInstance().fromEnvVars();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), auth.getToken());
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óndel 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óndel 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.
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 NequiPaymentsGatewayClient 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(); factory.apiKey(_API_KEY); //Se instancia un nuevo cliente NequiPaymentsGatewayClient apiClient = factory.build(NequiPaymentsGatewayClient.class); //Se instancia la clase para autenticarse NequiAuth auth =
NequiAuth.getInstance().fromEnvVars();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), auth.getToken());
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.