NEQUI
  • Colombia

  • Panamá

  • Cómo usar el SDK
  • Creación de un cliente
  • Autenticación en Nequi Conecta
  • Servicio para crear una nueva suscripción
  • Servicio para consulta de suscripción
  • Servicio para realizar un pago automático
  • Servicio para Validar pago

Consumo del API de Suscripciones en Java o Android

Cómo usar el SDK

Para poder consumir el API de Suscripciones 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-subscriptions-api-sdk-qa</artifactId>
            <version>2.0.0</version>
        </dependency>
    
  • Ambiente de producción:
    
        <dependency>
            <groupId>com.nequi</groupId>
            <artifactId>nequi-subscriptions-api-sdk</artifactId>
            <version>2.0.0</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 NequiSubscriptionsGatewayClient 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 NequiSubscriptionsGatewayClient
NequiSubscriptionsGatewayClient apiClient = factory.build(NequiSubscriptionsGatewayClient.class);

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


public interface NequiSubscriptionsGatewayClient {    
    JsonObject servicesSubscriptionpaymentserviceAutomaticpaymentPost(JsonObject body, String authorization);
    JsonObject servicesSubscriptionpaymentserviceGetsubscriptionPost(JsonObject body, String authorization);
    JsonObject servicesSubscriptionpaymentserviceNewsubscriptionPost(JsonObject body, String authorization);
    JsonObject servicesSubscriptionpaymentserviceGetstatuspaymentPost(JsonObject body, String authorization);
    JsonObject servicesReverseservicesReversetransactionPost(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.

Autenticación en Nequi Conecta

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:

  • NEQUI_CLIENT_ID: Proveida por Conecta Nequi en la sección de credenciales.
  • NEQUI_CLIENT_SECRET: Proveida por Conecta Nequi en la sección de credenciales.
  • NEQUI_AUTH_URI: Es la URI del endpoint que debe consumir para autenticarse, para producción es "https://oauth.nequi.com/oauth2/token"(sin las comillas).
  • NEQUI_AUTH_GRANT_TYPE: Tipo de acceso a los recursos del API, el valor recomendado es "client_credentials"(sin las comillas).

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:

  • NequiAuth.getInstance().with: Este método recibe los siguientes valores:
    • String clientId: Proveida por Conecta Nequi en la sección de credenciales.
    • String clientSecret: Proveida por Conecta Nequi en la sección de credenciales.
    • String authUri: Es la URI del endpoint que debe consumir para autenticarse, para producción es "https://oauth.nequi.com/oauth2/token"(sin las comillas).
    • String authGranType: Tipo de acceso a los recursos del API, el valor recomendado es "client_credentials"(sin las comillas).

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");
  • Usando los métodos .withXYZ: La clase NequiAuth cuenta con 4 métodos concatenables que permiten asignar los valores manualmente:
    • .withClientId(String clientId)
    • .withClientSecret(String clientSecret)
    • .withAuthUri(String authUri)
    • .withAuthGranType(String authGranType)

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();

 

Servicio para crear una nueva suscripción

El servicio para crear una nueva suscripción envía una solicitud a un cliente Nequi mediante una notificación PUSH para suscribirse a un comercio con el objetivo de permitirle a éste realizar pagos o débitos automáticos de esa cuenta Nequi. El usuario cuenta con la posibilidad de aprobarla o rechazarla.

De los métodos que ofrece el NequiNotificationGateWayClient vamos a utilizar servicesSubscriptionpaymentserviceNewsubscriptionPost para consumir el servicio para crear una nueva suscripción.

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 
NequiSubscriptionsGatewayClient apiClient = factory.build(NequiSubscriptionsGatewayClient.class); 
//Se instancia la clase para autenticarse 
NequiAuth auth = NequiAuth.getInstance().fromEnvVars();

String phone_number = "3996581361";
String code = "123456789";
String name = "Prueba"; 
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient.servicesSubscriptionpaymentserviceNewsubscriptionPost(BodyUtils.getNewSubscription(phone_number, code, name), 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.getNewSubscription, 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 o canal 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 //Identificador de la terminal, nodo o servidor
          "Destination": {
        "ServiceName": "SubscriptionPaymentService", //Servicio que se quiere consumir
        "ServiceOperation": "newSubscription", //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": {
        "newSubscriptionRQ": {
          "phoneNumber": STRING, //Número de celular del cliente Nequi 
          "code": STRING, //Combinación del tipo y número de identificación del comercio
          "name": STRING //Nombre del comercio con el cual se desea aparezca en el PUSH
        }
      }
    }
  }
}

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 suscripciones
public static final String CHANNEL = "PDA05-C001";
//Construye a partir del celular, tipo y número de identificación del comercio y nombre el mensaje de entrada del servicio de nueva
//suscripción
public static JsonObject getNewSubscription(String phoneNumber, String code, String name) {
  //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)+"\","
        //identificador de la terminal o servidor
        + "\"ClientID\":\"123\""
        + ", \"Destination\": {"                    
          +"\"ServiceName\":\"SubscriptionPaymentService\""
          +  ", \"ServiceOperation\": \"newSubscription\""
          +  ", \"ServiceRegion\": \"C001\""
          +  ", \"ServiceVersion\": \"1.0.0\""
        + "}"
      + "},"
      + "\"RequestBody\":{"
        + "\"any\":{"
          + "\"newSubscriptionRQ\":{"
            + "\"phoneNumber\":\""+ phoneNumber + "\","
            + "\"code\":\"" + code + "\","
            + "\"name\":\"" + name + "\""
          + "}"
        + "}"
      + "}"
    + "}}";
  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 token requerido para poder usar por primera vez el servicio de pago automático, el token debería ser almacenado porque no hay ningún otro servicio que lo retorne nuevamente por temas de seguridad, si lo pierde tendría que consumir de nuevo este servicio y esperar que el usuario apruebe la suscripción. La estructura de la respuesta del servicio 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, //Identificador de la terminal o servidor
      //Datos técnicos que no deberían ser procesados o almacenados
      "Destination": {
        "ServiceName": "SubscriptionPaymentService", //Nombre del Servicio
        "ServiceOperation": "newSubscription" //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
        "newSubscriptionRS": {
          "token": STRING //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  newSubscriptionRS sino que any  será un elemento o cadena vacía.

Servicio para consulta de suscripción

El servicio para consulta de suscripción permite a partir de un celular de un usuario Nequi, el tipo y número de identificación de un comercio y el último token que se tenga de esa suscripción, consultar los datos de dicha suscripción principalmente el estado que define si ya fue aprobada, rechazada, expirada o si sigue pendiente.

De los métodos que ofrece el NequiSubscriptionsGatewayClient vamos a utilizar servicesSubscriptionpaymentserviceGetsubscriptionPost para consultar una suscrpción.

En código Java seria de la siguiente forma:

//Inicialización del cliente API
ApiClientFactory factory = new ApiClientFactory();
factory.apiKey(_API_KEY);
//Se instancia un nuevo cliente
NequiSubscriptionsGatewayClient apiClient = factory.build(NequiSubscriptionsGatewayClient.class);
//Se instancia la clase para autenticarse
NequiAuth auth = NequiAuth.getInstance().fromEnvVars();

String phone_number = "3993457689";
String token = "AWSDERRGTTGFD";
String code = "12345"; 
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient.servicesSubscriptionpaymentserviceGetsubscriptionPost(BodyUtils.getBodyGetSubscription(phone_number, code, token), 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.getBodyGetSubscription, 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 //Identificador de la terminal o servidor
          "Destination": {
        "ServiceName": " SubscriptionPaymentService", //Servicio que se quiere consumir
        "ServiceOperation": "getSubscription", //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": {
        "getSubscriptionRQ": {
          "phoneNumber": STRING, //Número de celular del cliente
          "code": STRING, //Combinación del tipo y número de identificación del comercio
          "token": STRING //Último token retornado por el servicio de nueva suscripción 
        }
      }
    }
  }
}

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 suscripciones
public static final String CHANNEL = "PDA05-C001";
public static JsonObject getBodyGetSubscription(String phone, String code, String token) {
  //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)+"\","
        //Identificador de la terminal
        + "\"ClientID\":\"12345\""
        + ", \"Destination\": {"                    
          +     "\"ServiceName\": \"SubscriptionPaymentService\""
          +", \"ServiceOperation\": \"getSubscription\""
          +    ", \"ServiceRegion\": \"C001\""
          +    ", \"ServiceVersion\": \"1.0.0\""
        + "}"
      + "},"
      + "\"RequestBody\":{"
        + "\"any\":{"
          + "\"getSubscriptionRQ\":{"
            + "\"phoneNumber\":\""+ phone + "\","
            + "\"code\":\""+ code + "\","    
            + "\"token\":\"" + token + "\""
          + "}"
        + "}"
      + "}"
    + "}}";
  return gson.fromJson(input, JsonObject.class);
}

Llegado el caso que el consumo del servicio sea exitoso, el JsonObject que retorna el método trae los datos de la suscripción, 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, //Identificador de la terminal o servidor
      //Datos técnicos que no deberían ser procesados o almacenados
      "Destination": {
        "ServiceName": "SubscriptionPaymentService", //Nombre del Servicio
        "ServiceOperation": "getSubscription" //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
        "getSubscriptionRS": {
          "dateCreated": STRING, //Fecha de generación de la suscripción,
          "name": STRING, //Nombre del comercio asociado a la suscripción
          "status": STRING //Estado de la suscripción
        }
      }
    }
  }
}

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  getSubscriptionRS sino que any  será un elemento o cadena vacía.

Los posibles estados que puede tener una suscripción son los siguientes:

  • 0 = Pendiente
  • 1 = Aceptada
  • 2 = Rechazada
  • 3 = Expirada

Solo cuando es aceptada el servicio de pago automático podrá funcionar.

Servicio para realizar un pago automático

El servicio para realizar un pago automático permite a partir de un celular de un usuario Nequi, el tipo y número de identificación de un comercio, un valor a pagar y el último token que se tenga de esa suscripción, realizar un pago o débito automático o en línea de la cuenta del usuario Nequi.

El método que vamos a utilizar para los pagos automáticos es servicesSubscriptionpaymentserviceAutomaticpaymentPost.

En código Java seria de la siguiente forma:

//Inicialización del cliente API
ApiClientFactory factory = new ApiClientFactory();
factory.apiKey(_API_KEY);
//Se instancia un nuevo cliente
NequiSubscriptionsGatewayClient apiClient = factory.build(NequiSubscriptionsGatewayClient.class);
//Se instancia la clase para autenticarse
NequiAuth auth = NequiAuth.getInstance().fromEnvVars();

String phone_number = "3993457689";
String token = "AWSDERRGTTGFD";
String code = "12345";
String value = "1"; 
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient.servicesSubscriptionpaymentserviceAutomaticpaymentPost(BodyUtils.getBodyAutomaticPayment(phone_number, code, token, 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.getBodyAutomaticPayment, 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 //Identificador de la terminal o servidor
          "Destination": {
        "ServiceName": " SubscriptionPaymentService", //Servicio que se quiere consumir
        "ServiceOperation": "automaticPayment", //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": {
        "automaticPaymentRQ": {
          "phoneNumber": STRING, //Número de celular del cliente
          "code": STRING, //Combinación del tipo y número de identificación del comercio
          "valor": STRING, //Valor a cobrar
          "token": STRING, //Último token de la suscripción
          "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 suscripciones
public static final String CHANNEL = "PDA05-C001";
public static JsonObject getBodyAutomaticPayment(String phone, String code, String value, String token,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)+"\","
        //Identificador de la terminal
        + "\"ClientID\":\"12345\""
        + ", \"Destination\": {"                    
          +     "\"ServiceName\": \"SubscriptionPaymentService\""
          +", \"ServiceOperation\": \"automaticPayment\""
          +    ", \"ServiceRegion\": \"C001\""
          +    ", \"ServiceVersion\": \"1.0.0\""
        + "}"
      + "},"
      + "\"RequestBody\":{"
        + "\"any\":{"
          + "\"automaticPaymentRQ\":{"
            + "\"phoneNumber\":\""+ phone + "\","
            + "\"code\":\""+ code + "\","    
            + "\"value\":\""+ value + "\","            
            + "\"token\":\"" + token + "\"," 
​            + "\"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 los datos de la suscripción, 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, //Identificador de la terminal o servidor
      //Datos técnicos que no deberían ser procesados o almacenados
      "Destination": {
        "ServiceName": "SubscriptionPaymentService", //Nombre del Servicio
        "ServiceOperation": "automaticPayment" //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
        "automaticPaymentRS": {
          "transactionId ": STRING, //Identificador de la transacción que se usa en el 
          //servicio de validación o consulta de estado de pago,
          "token": STRING, //Nuevo token para usar en los servicios que lo requieren   
        }
      }
    }
  }
}

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  automaticPaymentRS 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 transactionId que retorna el servicio de pago automático validar si el pago ya fue realizado desde la cuenta NEQUI. Este servicio es útil por si se necesita verificar si el pago fue correcto o no, aunque el servicio de pago automático ya retorna si fue exitoso o no, este es una opción adicional para verificar el pago.

De las funciones que ofrece el NequiSubscriptionsGatewayClient usaremos servicesSubscriptionpaymentserviceGetstatuspaymentPost para consumir el servicio que valida el estado de un pago.

En código Java seria de la siguiente forma:


//Inicialización del cliente API
ApiClientFactory factory = new ApiClientFactory();
factory.apiKey(_API_KEY);
//Se instancia un nuevo cliente
NequiSubscriptionsGatewayClient apiClient = factory.build(NequiSubscriptionsGatewayClient.class);
//Se instancia la clase para autenticarse
NequiAuth auth = NequiAuth.getInstance().fromEnvVars();

String code = "1234";
//Consumo del servicio, retorna un JsonObject con la respuesta del servicio
JsonObject response = apiClient. servicesSubscriptionpaymentserviceGetstatuspaymentPost(BodyUtils. getBodyGetStatusPayment(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, si es 34 fue rechazado y si es 33 ya expiró.

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, //Identificador de la terminal
      "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 ": STRING //transactionId retornado por el servicio de pago automático
        }
      }
    }
  }
}

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 suscripciones
public static final String CHANNEL = "PDA05-C001";
//Construye a partir de un transactionId el mensaje de entrada del
//servicio de validación de pago
public static JsonObject getBodyGetStatusPayment(String code) {
  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+"\","
        //Feha de la petición
        + "\"RequestDate\":\""+date+"\","
        //Identificador único de la transacción
        + "\"MessageID\":\""+miliseconds.substring(miliseconds.length()-9)+"\"," 
        + "\"ClientID\":\"12345\""
        + ", \"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, //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": CEL, //Numero del cliente que pago
          "date": DATE, //Fecha del pago
          "name": NAME, //Nombre del cliente merchant o comercio
          "trnId": ID, //Id de la transacción
          "value": VALUE, //Valor pagado
          "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.

Para consumir este servicio recomendamos las siguientes dos estrategias:

  • Por demanda: donde el usuario del aplicativo que se integre con el API lance el consumo para verificar el pago cuando desee.
  • Por sonda: donde el sistema integrado con el API lanza cada 30 segundos durante 15 minutos una petición para verificar el estado del pago y cuando el estado sea diferente de 33, que es pendiente, pare la sonda.

Si tiene dudas técnicas sobre la implementación y uso del API de NEQUI para notificaciones 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.