Introducción
La URL base de nuestra API es distinta por ambiente:
Pruebas: https://api.stg.keynua.com
Producción: https://api.keynua.com
Pruebas: https://api.stg.keynua.com
Producción: https://api.keynua.com
Pruebas: https://api.stg.keynua.com
Producción: https://api.keynua.com
Pruebas: https://api.stg.keynua.com
Producción: https://api.keynua.com
Bienvenid@ a la documentación del API de Keynua! Puedes usar nuestro API para poder crear contratos, obtener el detalle del mismo o eliminar contratos.
Algunas características de nuestra API:
- Está basada en REST: los payload para los
request
yresponse
deben estar en formatoJSON
- Solo soporta
HTTPS
En el siguiente gráfico, podrás ver el flujo básico de integración. El proceso es el mismo tanto para los contratos como para la verificación de identidad; lo único que varía es la API que utilizarás y el payload que enviarás según la documentación.
El flujo básico consta de:
- Crear la transacción usando nuestra API de Creación de Contrato o Creación de Verificación de Identidad.
- El usuario recibirá una notificación con un enlace y podrá realizar el proceso de firma del contrato o de identificación desde su dispositivo.
- Si ocurre un error durante el proceso, el usuario recibirá una notificación para corregirlo.
- Si la validación es exitosa, se generará el certificado de firma, se finalizará el contrato y se enviará una notificación tanto a los firmantes como al creador del contrato.
Si configuras tu Webhook, notificaremos a tu API registrada según los eventos a los que te hayas inscrito.
Si vas a integrar Keynua en tu sitio web o aplicación móvil, puedes revisar la documentación y los ejemplos de integración:
Autenticación
curl 'https://api.stg.keynua.com' \
-H 'x-api-key: YOUR-APIKEY-HERE'
-H 'authorization: YOUR-API-TOKEN-HERE' \
Keynua utiliza API Keys y Authorization tokens para acceder al API. Una vez ya tengas una cuenta en el ambiente de pruebas de Keynua, puedes acceder a la sección Developers y generar tu APIKey y APIToken. Estos valores deberán ser enviados en la cabecera de la siguiente manera:
Header | Description |
---|---|
x-api-key | API Key para acceder al servicio. Debes usar el valor Secret, NO el ID |
authorization | Token único de autorización. Debes usar el valor Secret, NO el ID |
Contratos
El API de Contratos permite crear, ver y eliminar un contrato
Propiedades de un Contrato
{
"id":"some:id",
"accountId":"someone",
"templateId":"template-id",
"createdAt":"2021-01-24T02:52:41.426Z",
"startedAt":"2021-01-24T02:52:42.347Z",
"title":"Contract title",
"description":"Description",
"finishedAt":null,
"deletedAt":null,
"language":"es",
"timezone": "America/Panama",
"metadata":{
"something":"any-value"
},
"reference":"reference",
"shortCode":"12345",
"expirationInHours":0,
"users":User[],
"groups":Group[],
"documents":Document[],
"items":Item[],
"status":"pending_input"
}
Atributo | Tipo | Descripción |
---|---|---|
id | string | Identificador único del contrato |
accountId | string | Identificador único de la cuenta con la que se creó el contrato |
templateId | string | Identificador del Template a usar |
createdAt | string | Fecha de creación del contrato |
startedAt | string | Fecha de inicio del contrato |
title | string | Título del contrato |
description | string | Descripción del contrato |
finishedAt | string | Fecha de finalización del proceso de firma del contrato |
deletedAt | string | Fecha de eliminación del contrato |
language | string | Lenguaje del contrato |
timezone | string | Huso horario para formatear las fechas de firma del contrato |
metadata | object | Metadata del contrato |
reference | string | Referencia del contrato. Este campo es usado como clave de búsqueda en la plataforma web de Keynua. |
shortCode | string | Código corto del contrato para facilitar su identificación |
expirationInHours | integer | Expiración del contrato en horas, a partir de la fecha de inicio del contrato. |
expirationDatetime | string | Fecha y hora de expiración del contrato en UTC y formato ISO 8601. Ejemplo: 2021-06-17T19:53:58.551Z . |
users | array | Usuarios del contrato |
groups | array | Grupos del contrato |
documents | array | Documentos del contrato |
items | array | Items del contrato |
status | string | Estado del contrato actual |
alerts | array | Arreglo de Alertas del contrato |
Estados del Contrato
Valor | Descripción |
---|---|
pending_input | Estado inicial del contrato, cuando ha sido creado pero aún nadie ha comenzado el proceso de firma |
working | Cuando los Items del contrato están en proceso de ejecución |
pending_approval | Cuando existe un Item pendiente a ser aprobado manualmente por el dueño del contrato |
contract_approval | Cuando la aprobación del contrato se encuentra en progreso |
error | Cuando existe un error sin resolver en uno de los Items del contrato |
deleted | Cuando el contrato ha sido eliminado |
done | Cuando el contrato ha sido firmado por todos y ha finalizado correctamente |
Propiedades de un Usuario
{
"id":0,
"name":"Manuel Silva",
"email":"msilva@keynua.com",
"phone":null,
"groups":[
"signers"
],
"token":"token-value",
"state": "working",
"idInfo": {
"type": "pe-id",
"idNumber": "12345678",
"verificationDigit": "9",
"names": "Juan",
"lastName": "Perez Alvarez",
"birthDate": "1992-11-20",
"expirationDate": "2026-03-17"
"address": "Some address",
}
}
Usuarios que firman el contrato.
Atributo | Tipo | Descripción |
---|---|---|
id | integer | Identificador único del usuario en el contrato |
name | string | El nombre del usuario |
string | El correo electrónico del usuario | |
phone | string | El teléfono del usuario |
groups | array | Nombre de los grupos a los que pertenece el usuario, normalmente siempre pertenece a un sólo grupo. El identificador del grupo será asignado por el equipo de Keynua |
token | string | El token del usuario que se utilizará para realizar la firma. Por ejemplo para enviar un archivo multimedia |
state | string | El estado del usuario dentro del contrato, basado en el estado de todos los items del usuario. Solo existe para contratos creados luego del 04/04/2022. |
idInfo | string | Información obtenida del OCR del documento enviado por el firmante. Esta información se devolverá solamente cuando el contrato haya finalizado y de momento aplica solamente para las Identificaciones con DNI Peruano. La información de la dirección (address) se devolverá solamente si el usuario también envía la parte trasera del DNI |
Estados del Usuario
Valor | Descripción |
---|---|
pending | Estado inicial del usuario. Aún no ha enviado sus datos para la firma. |
working | El usuario ya envió sus datos y estos están siendo procesados. |
error | Alguno de los ítems del usuario ha presentado un error. |
done | Todos los datos del usuario han sido validados y son correctos. |
Propiedades de un Grupo
{
"id":"signers",
"name":"Firmantes",
"description":"",
"digitalSignature":false,
"bulk":false
}
Grupos que existen en el contrato.
Atributo | Tipo | Descripción |
---|---|---|
id | string | Identificador del grupo |
name | string | El nombre del grupo |
description | string | Descripción del grupo |
digitalSignature | boolean | Flag que indica si el grupo realizará firma digital o no |
bulk | boolean | Flag que indica si el grupo pertenece a Firma Múltiple o no |
Propiedades de un Documento
{
"id":0,
"name":"DocumentPdf.pdf",
"ext":"pdf",
"sha":"pdf-hash",
"size":3708,
"type":"application/pdf",
"url":"signed-url"
}
Los documentos que son firmados en el contrato.
Atributo | Tipo | Descripción |
---|---|---|
id | integer | Identificador único del documento |
name | string | Nombre del documento incluyendo su extensión |
ext | string | Extensión del documento |
sha | string | Código sha256 del documento |
size | integer | Tamaño en bytes del documento |
type | string | Tipo del documento |
url | string | La URL para poder visualizar el documento |
Cavali
{
"banking": 6,
"product": 3,
"uniqueCode": 5478700,
"issuedDate": "2020-09-20",
"issuedPlace": "Lima",
"client": {
"userId": 0,
"civilStatus": 2,
"domicile": "Lima"
},
"representatives": [
{
"userId": 1
}
]
}
Cavali permite crear un Pagaré y asociarlo a la firma de un contrato. Para crear un contrato, el proceso debe tener un Item Cavali y Item de tipo text con el id documentNumber
El Pagaré está compuesto por lo siguiente:
Atributo | Tipo | Descripción |
---|---|---|
banking | integer | Código de banca |
product | integer | Código de producto |
uniqueCode | integer | Código único del cliente |
creditNumber | integer | Número de crédito |
issuedDate | string | Fecha de emisión. Formato: YYYY-MM-dd |
conditionJustSign | integer | Condición del pagaré. Puede tener los siguientes valores: 1 (si) |
special | integer | Indicador de pagaré especial. Puede tener los siguientes valores: 1 (si) |
issuedPlace | string | Lugar de emisión |
expirationDate | string | Fecha de caducidad. Formato: YYYY-MM-dd |
amount | double | Monto del pagaré |
currency | integer | Moneda del pagaré. Puede tener los siguientes valores: 1 (S/) |
compensatoryInterestAmount | double | El interés compensatorio sobre el monto |
periodOne | integer | El período de capitalización 1 |
compensatoryInterestArrears | double | El interés compensatorio por el período de morosidad |
periodTwo | integer | El período de capitalización 2 |
interestArrears | double | Interés moratorio del periodo |
periodTwo | integer | El período de capitalización 3 |
specialClauses | string | Las Cláusulas especiales que pueda contener el Pagaré |
token | string | El token de validación de firmas para proveedores |
additionalField1 | string | Campo adicional 1 |
additionalField2 | string | Campo adicional 2 |
client | object | Cliente del Pagaré |
representatives | array | Arreglo de Representantes del cliente |
guarantees | array | Arreglo de Garantías del cliente |
Cliente Cavali
El cliente del pagaré. El elemento está compuesto por:
Atributo | Tipo | Descripción |
---|---|---|
userId | integer | Id del firmante. Es el índice del elemento al que hace referencia en el atributo users al crear contrato |
civilStatus | integer | Estado civil del cliente. Puede tener los siguientes valores: 1 (SOLTERO) , 2 (CASADO) , 3 (DIVORCIADO) , 4 (VIUDO) |
domicile | string | Domicilio del cliente Máximo 100 de longitud |
Representantes Cavali
Representante del cliente. El elemento está compuesto por:
Atributo | Tipo | Descripción |
---|---|---|
userId | integer | Id del firmante. Es el índice del elemento al que hace referencia en el atributo users al crear contrato |
Garantías Cavali
Garantía del cliente. El elemento está compuesto por:
Atributo | Tipo | Descripción |
---|---|---|
userId | integer | Id del firmante. Es el índice del elemento al que hace referencia en el atributo users al crear contrato |
civilStatus | integer | Estado civil. Puede tener los siguientes valores: 1 (SOLTERO) , 2 (CASADO) , 3 (DIVORCIADO) , 4 (VIUDO) |
domicile | string | Domicilio Máximo 100 de longitud |
representative | array | Arreglo de Representantes |
Crear un Contrato
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/contracts/v1")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Put.new(url)
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["content-type"] = 'application/json'
request.body = "{\n \"title\": \"Contract created by API\",\n \"language\": \"es\",\n \"userEmailNotifications\": true,\n\t\"templateId\": \"keynua-peru-default\",\n \"documents\": [\n {\n \"name\": \"DocumentPdf.pdf\",\n \"base64\": \"YOUR-BASE64-PDF-HERE\"\n }\n ],\n \"users\": [\n {\n \"name\": \"Manuel Silva\",\n \"email\": \"msilva@keynua.com\",\n\t\t\"groups\": [ \"signers\" ]\n }\n ]\n}\n"
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = "{\n \"title\": \"Contract created by API\",\n \"language\": \"es\",\n \"userEmailNotifications\": false,\n\t\"templateId\": \"keynua-peru-default\",\n \"documents\": [\n {\n \"name\": \"DocumentPdf.pdf\",\n \"base64\": \"YOUR-BASE64-PDF-HERE\"\n }\n ],\n \"users\": [\n {\n \"name\": \"Manuel Silva\",\n \"email\": \"msilva@keynua.com\",\n\t\t\"groups\": [ \"signers\" ]\n }\n ]\n}\n"
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
'content-type': "application/json"
}
conn.request("PUT", "/contracts/v1", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request PUT \
--url https://api.stg.keynua.com/contracts/v1 \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'content-type: application/json' \
--data '{
"title": "Contract created by API",
"language": "es",
"userEmailNotifications": true,
"templateId": "keynua-peru-default",
"documents": [
{
"name": "DocumentPdf.pdf",
"base64": "YOUR-BASE64-PDF-HERE"
}
],
"users": [
{
"name": "Manuel Silva",
"email": "msilva@keynua.com",
"groups": [ "signers" ]
}
],
"flags": {
"chosenNotificationOptions": [
"email"
]
}
}'
const https = require("https");
const data = JSON.stringify({
title: 'Contract created by API',
language: 'es',
userEmailNotifications: true,
templateId: 'keynua-peru-default',
documents: [
{
name: 'DocumentPdf.pdf',
base64: 'YOUR-BASE64-PDF-HERE'
},
],
users: [
{name: 'Manuel Silva', email: 'msilva@keynua.com', groups: ['signers']}
],
flags: {
chosenNotificationOptions: [
"email"
]
}
});
const options = {
method: "PUT",
hostname: "api.stg.keynua.com",
path: "/contracts/v1",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE",
"content-type": "application/json",
"content-length": data.length
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
Si el contrato fue creado satisfactoramente, el API retorna un Json estructurado como aparece en la sección de Contratos
HTTP Request
PUT /contracts/v1
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Content-Type | application/json |
Body
Para crear el contrato, se tiene que enviar la data como un solo objeto JSON
Atributo | Tipo | Descripción |
---|---|---|
title | string | Título del contrato |
description | string | optional Descripción del contrato |
reference | string | optional Referencia del contrato. Este campo es usado como clave de búsqueda en la plataforma web de Keynua |
language | string | Default "es" Idioma del contrato. Puede ser en o es |
userEmailNotifications | boolean | Default "false" Indica si los usuarios serán notificados por email cuando hay un error o finaliza un contrato |
expirationInHours | integer | optional Expiración del contrato en horas, a partir de la fecha de inicio del contrato. Mínimo uno (1) |
expirationDatetime | string | optional Fecha y hora de expiración del contrato en UTC y formato ISO 8601. Ejemplo: 2021-06-17T19:53:58.551Z . |
templateId | string | Id del template a usar. Puedes usar uno de los template públicos de Keynua como keynua-peru-default . Si es un proceso customizado, el equipo de Keynua te enviará este valor |
onBehalfOf | string | AccountId de una cuenta hija. Este campo es usado para organizaciones que necesitan crear contratos como si fueran sus cuentas hijas. Solo funciona si la cuenta hija pertenece a la misma organización de la cuenta padre y si cuenta con el permiso para crear contratos. Los accountId de las cuentas asociadas se pueden obtener aquí, ya sea descargando todos los usuarios o copiando los Id que necesites. |
documents | array | Arreglo de los documentos PDFs encodificados en base64 que van a ser firmados. Mínimo 1 y máximo 10. El peso máximo en total no debe ser mayor a 4.5 MB. En lugar de base64 también se puede enviar storageId , como por ejemplo se obtiene de este API. |
users | array | Arreglo de los usuarios que firmarán el contrato. El email es opcional y el valor a enviar en groups depende del templateId a usar. Para el caso de keynua-peru-default , el valor en groups debe ser signers . Si utilizan un template customizado en el que hay más de un grupo, por ejemplo firmas con DNI + Firma múltiple, el valor del grupo representará al grupo que pertenece dicho usuario. Puedes ver el detalle de las configuraciones posibles en la sección Usuarios del contrato |
metadata | object | optional Metadata del contrato. Puedes enviar información en este campo como key-value para poder identificar el contrato creado por Keynua con algún Identificador interno de tu sistema. |
flags | object | optional Se podrá enviar información adicional para crear un contrato. Por ejemplo para configurar un canal de comunicación o enviar la información de Cavali. Para crear un contrato con Pagaré Electrónico, se enviará el key cavaliData . Puedes ver el detalle de las configuraciones posibles en la sección Flags del contrato |
templateOptions | object | optional Configuración dinámica del template del contrato, si mandas este campo se omite el templateId |
Flags del contrato
Atributo | Tipo | Descripción |
---|---|---|
chosenNotificationOptions | stringArray | Se deben enviar los tipos de notificación como string. Los valores pueden ser sms , whatsapp o email . No se puede enviar sms y whatsapp al mismo tiempo |
Usuarios del contrato
Atributo | Tipo | Descripción |
---|---|---|
name | string | El nombre del usuario |
string | El correo electrónico del usuario | |
phone | string | El teléfono del usuario |
groups | array | Nombre de los grupos a los que pertenece el usuario, normalmente siempre pertenece a un sólo grupo. El identificador del grupo será asignado por el equipo de Keynua |
validationsToSkip | array | La lista de validaciones que se deben omitir en el flujo de firma. Los valores permitidos en la lista son: "expiration-date" (Omitir validación de fecha de expiración), "instructions-grade" (Omitir validación de iletrados). |
Grupos e items precargados
{
"users": [
{
"groups": ["firmantes-precargados"],
"prefilledItems": [
{
"target": "documentNumber",
"value": {
"text": "444332323"
}
}
],
"name": "Manuel Silva",
"email": "msilva@keynua.com"
},
{
"groups": ["firmantes-especiales"],
"prefilledItems": [
{
"target": "role",
"value": {
"text": "Cliente"
}
}
],
"name": "Juan Araujo",
"email": "jaraujo@keynua.com",
}
]
}
Para conocer qué datos precargados y grupos de usuarios se pueden usar al crear un contrato, dirígete a la sección Developers.
En la sección Grupos e items precargados
, elige un template para ver esta información en formato JSON
. Un ejemplo de la respuesta puede ser la siguiente:
A la derecha se puede ver cómo corresponde esta respuesta a la información que se debe enviar al crear el contrato.
Algunas observaciones importantes:
id
corresponde al nombre al id del grupo, se incluye dentro del arreglogroups
.target
corresponde al id del valor precargado, se incluye entarget
, dentro del arregloprefilledItems
.values
corresponde a los valores admitidos dentro de un valor precargado. Se debe escoger un solo valor de esta lista. Debe ir dentro detext
.- De no existir
values
, se puede incluir dentro detext
cualquier valor (relacionado al dato que se desee precargar).
Obtener un Contrato
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/contracts/v1/{contractId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE"
}
conn.request("GET", "/contracts/v1/{contractId}", "", headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request GET \
--url 'https://api.stg.keynua.com/contracts/v1/{contractId}' \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
const http = require("https");
const options = {
"method": "GET",
"hostname": "api.stg.keynua.com",
"path": "/contracts/v1/{contractId}",
"headers": {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
}
};
const req = http.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Si el contrato fue obtenido satisfactoriamente, el API retorna un Json estructurado como aparece en la sección de Contratos
Este API obtiene un contrato específico
HTTP Request
GET /contracts/v1/{contractId}
URL Parameters
Parámetro | Descripción |
---|---|
contractId | El ID del Contrato a obtener |
Query Parameters
Parámetro | Tipo | Descripción |
---|---|---|
startAt | integer | Índice desde el cual se desea iniciar la paginación de los items. Este parámetro es opcional. El valor por defecto es 0 |
limit | integer | Cantidad máxima de elementos a devolver en la consulta. Este parámetro es opcional. El valor por defecto es 50 |
values | boolean | Indica si se quiere obtener los valores de los items. Este parámetro es opcional. El valor por defecto es true |
Eliminar un Contrato
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/contracts/v1/{contractId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Delete.new(url)
request["authorization"] =
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE"
}
conn.request("DELETE", "/contracts/v1/{contractId}", "", headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request DELETE \
--url https://api.stg.keynua.com/contracts/v1/{contractId} \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
const https = require("https");
const options = {
method: "DELETE",
hostname: "api.stg.keynua.com",
path: "/contracts/v1/{contractId}",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Si el contrato fue eliminado, el API retornará un JSON como el siguiente:
{
"deletedAt": "2021-01-25T21:38:50.055Z"
}
Este API elimina un Contrato
HTTP Request
DELETE /contracts/v1/{contractId}
URL Parameters
Parámetro | Descripción |
---|---|
contractId | El ID del Contrato a eliminar |
Aprobación de un Contrato
Este API Aprueba un Contrato, solo retornará un resultado exitoso si el contrato se encuentra en el estado: contract_approval
. Este estado se asigna cuando el item de tipo contractapproval
se pone en working
. Para obtener el evento que asigna el estado puede integrar el webhook ItemWorking
y validar que el atributo type
sea igual al mencionado.
Aprobar un Contrato
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/contracts/v1/approve-contract")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["content-type"] = 'application/json'
request.body = "{\n \"contractId\": \"CONTRACT-ID\",\n \"message\": \"Crédito aprobado\"}\n"
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = "{\n \"contractId\": \"CONTRACT-ID\",\n \"message\": \"Crédito aprobado\"}\n"
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE"
'content-type': "application/json"
}
conn.request("POST", "/contracts/v1/approve-contract", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request DELETE \
--url https://api.stg.keynua.com/contracts/v1/approve-contract \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'content-type: application/json' \
--data '{
"contractId": "CONTRACT-ID",
"message": "Crédito aprobado",
}'
const https = require("https");
const data = JSON.stringify({
contractId: 'CONTRACT-ID',
message: 'Crédito aprobado',
});
const options = {
method: "POST",
hostname: "api.stg.keynua.com",
path: "/contracts/v1/approve-contract",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
"content-type": "application/json",
"content-length": data.length
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
Si el contrato fue aprobado, el API retornará un JSON como el siguiente:
{
"success": true,
"item": {
"itemId": 1,
"itemState": "s",
"itemVersion": 1
}
}
HTTP Request
POST /contracts/v1/approve-contract
Body
Parámetro | Descripción |
---|---|
contractId | El ID del Contrato a eliminar |
message | Motivo de aprobación |
Declinar un Contrato
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/contracts/v1/decline-contract")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["content-type"] = 'application/json'
request.body = "{\n \"contractId\": \"CONTRACT-ID\",\n \"message\": \"Crédito declinado\"}\n"
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = "{\n \"contractId\": \"CONTRACT-ID\",\n \"message\": \"Crédito declinado\"}\n"
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE"
'content-type': "application/json"
}
conn.request("POST", "/contracts/v1/decline-contract", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request DELETE \
--url https://api.stg.keynua.com/contracts/v1/decline-contract \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'content-type: application/json' \
--data '{
"contractId": "CONTRACT-ID",
"message": "Crédito declinado",
}'
const https = require("https");
const data = JSON.stringify({
contractId: 'CONTRACT-ID',
message: 'Crédito declinado',
});
const options = {
method: "POST",
hostname: "api.stg.keynua.com",
path: "/contracts/v1/decline-contract",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
"content-type": "application/json",
"content-length": data.length
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
Si el contrato fue aprobado, el API retornará un JSON como el siguiente:
{
"success": true,
"item": {
"itemId": 1,
"itemState": "e",
"itemVersion": 1
}
}
HTTP Request
POST /contracts/v1/decline-contract
Body
Parámetro | Descripción |
---|---|
contractId | El ID del Contrato a eliminar |
message | Motivo de declinación |
Items del Contrato
Para llevar a cabo el flujo de firma de un contrato, cada uno de los usuarios deberá ingresar la información necesaria para firmar. Por ejemplo: la foto de su DNI, el video diciendo el código corto o el número de su DNI. También hace referencia a los procesos internos llevados a cabo por Keynua, por ejemplo la generación del PDF final o validación biométrica. A cada uno de estos elementos los llamamos Item
Propiedades de un Item
{
"id": 4,
"version": 1,
"state": "success",
"userId": null,
"reference": "pdf",
"title": "Certificado y documentos",
"type": "pdf",
"stageIndex": 1,
"value": {
"url": "signed-url"
}
}
Atributo | Tipo | Descripción |
---|---|---|
id | integer | Identificador del item |
version | integer | Versión del item. Siempre se mostrará la última versión disponible |
state | string | El estado del item. Puede tener los siguientes valores: success , pending , working , error |
userId | integer | El identificador del usuario al que está relacionado este item |
reference | string | La referencia del item (está relacionado con la plantilla del contrato) |
title | string | Un título referente al item |
type | string | El ID del tipo del Item al que pertenece |
stageIndex | integer | El índice del nivel al que pertenece el item |
value | object | El valor del item. La estructura varía de acuerdo al tipo del item. Cuando se trata de un Item que contiene un Archivo, habrá un key url el cual contiene la URL firmada para poder descargar el archivo. Las URLs firmadas tienen una duración máxima de 12 horas. Cuando el item tenga estado Error, se obtendrá el siguiente detalle de error por tipo de Item |
Tipos de Item
En la siguiente tabla podrás ver los Tipos de Items que existen en Keynua. Los Items "User Input" se refieren a los Items que deben ser enviados por los usuarios.
Item | Id | User Input | Descripción |
---|---|---|---|
Términos y condiciones | terms | si |
Hace referencia a si el usuario ha aceptado o no los términos y condiciones |
Verificación de documentos | documents | si |
Indica que se le han mostrado los documentos a firmar al usuario |
Campo de Texto | text | si |
Campo de texto ingresado por el usuario o por el creador del contrato, por ejemplo el número de Documento de Identidad |
Imagen | image | si |
Hace referencia a una imagen subida por un usuario, por ejemplo, foto del documento de identidad |
Firma Ológrafa | imagesign | si |
Firma ológrafa realizada por el usuario en el proceso de firma |
Video | video | si |
Video realizado por el usuario, en la mayoría de los casos hace referencia a la videofirma. |
no |
Hace referencia al envío del email a un usuario | ||
Reconocimiento de Documento | detectlabels | no |
Proceso de Reconocimiento del formato de un Documento. Por ejemplo, si se le pide subir a un usuario la foto de su DNI del país y sube la foto de su pasaporte, este proceso detectará que no es el documento solicitado y arrojará un error |
Reconocimiento de textos | checklabels | no |
Este proceso realiza la verificación de textos entre 2 elementos, por ejemplo la búsqueda del documento de identidad ingresado y los textos extraídos de la imagen del documento |
Conversión de Video | convertvideo | no |
Proceso que indica que el video del firmante tiene un formato correcto para ser procesado |
Reniec | reniec | no |
Proceso que indica el resultado de la búsqueda del DNI ingresado en Reniec |
Validación de Biometría Facial | facematch | no |
Proceso que indica la validación Biométrica entre 2 elementos que pueden ser por ejemplo la foto obtenida de RENIEC y la videofirma realizada por el usuario |
Reconocimiento de texto hablado | transcribe | no |
Indica si el usuario dijo como texto hablado el código que corresponde con los documentos que está firmando |
Prueba de vida | livenessdetection | no |
Indica si se detectó vida en el video del usuario |
Aprobación Manual | manualapproval | no |
Indica si hubo una aprobación manual de algún Item como detectlabels , facematch o transcribe |
Generación de imágenes para insertar en el PDF final | generatethumbnails | no |
Proceso que indica si se pudieron obtener los thumbnails necesarios antes de poder crear el PDF de documento de firma final (Certificado) |
Documento de Firma Electrónica/Digital | no |
Indica si el archivo PDF de la firma electrónica se generó satisfactoriamente. En este Item puedes encontrar el PDF final de firma electrónica generado por Keynua | |
Firma Digital | dsignature | no |
Proceso de firma digital aplicado a un archivo de firma electrónica. En este Item puedes encontrar el archivo digital, en caso de que tu proceso incluya firma digital |
Cavali - Perú | cavali | no |
Proceso que indica el registro de un Pagaré electrónico en Cavali para Perú |
Blockchain | blockchain | no |
Proceso que indica si se registró correctamente el hash del documento de firma electrónica final(certificado) en Blockchain |
Normativa NOM151 - México | knom151 | no |
Proceso que indica si se generó correctamente la constancia de conservación según la norma Méxicana NOM151 |
Firma Múltiple | bulksignature | no |
Indica si se solicitó firmar al usuario de firma múltiple o si firmó satsifactoriamente. El estado "error" no está implementado por el momento en este Item. |
Aprobación de contrato | contractapproval | no |
Solicita aprobación por parte del administrador para finalizar el contrato. |
Formulario de plantilla de documento | documenttemplateform | sí |
Solicita completar un formulario que contiene los campos agregados a la plantilla de documento. |
Validación de cuestionario | questionnairecheck | sí |
Valida las respuestas ingresadas por el usuario en el cuestionario. |
Valores por tipo de item
En las siguientes tablas podrás ver los campos que se retornan en value
de cada item.
Formulario de plantilla de documento
{
"fields": [
{
"id": "number-y2ga911c4cdas",
"value": "123123123"
},
{
"id": "names-ubxx8pjp9a3m",
"value": "test"
}
]
}
Type: documenttemplateform
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
fields | array | no | Arreglo de campos |
fields[].id | string | no | Id del campo |
fields[].value | string | no | Valor del campo |
Cuestionario
{
"questions": [
{
"options": [
"De 0 a 6 meses",
"De 6 meses a un año",
"De un año a 3 años",
"Más de 3 años"
],
"id": "tiempo",
"question": "¿Cuánto tiempo vive usted en la vivienda declarada?",
"type": "radio",
"required": true,
"value": "De 0 a 6 meses"
},
{
"id": "referencias",
"question": "Referencias",
"type": "string",
"required": true,
"value": "testing"
}
]
}
Type: questionnairecheck
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
questions | array | no | Arreglo de preguntas |
questions[].id | string | no | Id de la pregunta |
questions[].options | string[] | sí | Si type es checkbox o radio , opciones de respuesta |
questions[].question | string | no | Pregunta hecha al usuario |
questions[].type | checkbox , radio , string , email , number , date |
no | Tipo de pregunta |
questions[].required | boolean | no | Si responder la pregunta es obligatorio |
questions[].placeholder | string | sí | Sugerencia de respuesta |
questions[].minLength | number | sí | Si type es string , mínima cantidad de caracteres aceptados |
questions[].maxLength | number | sí | Si type es string , máxima cantidad de caracteres aceptados |
questions[].max | number | sí | Si type es number , máximo valor aceptado |
questions[].min | number | sí | Si type es number , mínimo valor aceptado |
questions[].value | string | no | Valor de la respuesta |
Documento PDF final
{
"url": "https://cmfiles.keynua.com/contracts/...",
"individualDocsUrls": [
"https://cmfiles.keynua.com/contracts/...",
"https://cmfiles.keynua.com/contracts/..."
],
"individualDocs": [
{
"hash": "92cc7ac31e511ef740fd7804c58b2d5f8602b467779598793210e69fda5ffe07",
"userIds": [
0
]
}
],
"userGroupDocs": [
{
"hash": "92cc7ac31e511ef740fd7804c58b2d5f8602b467779598793210e69fda5ffe07",
"userIds": [
0
],
"url": "https://cmfiles.keynua.com/contracts/..."
}
]
}
Type: pdf
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
url | string | no | Url del documento PDF firmado Expira en 12 horas |
individualDocsUrls | string[] | sí | Urls por cada documento PDF agregado al contrato |
individualDocs[] | array | sí | Documentos por cada grupo de firmantes (si aplica) o por cada documento del contrato |
individualDocsUrls[].hash | string | no | SHA256 del documento firmado |
individualDocsUrls[].userIds | string[] | no | Ids de los firmantes del documento |
userGroupDocs[] | array | sí | Documentos por cada grupo de firmantes |
userGroupDocs[].hash | string | no | SHA256 del documento firmado |
userGroupDocs[].userIds | string[] | no | Ids de los firmantes del documento |
userGroupDocs[].url | string | no | Url del documento firmado solo por los integrantes del grupo Expira en 12 horas |
Imagen
{
"original": {
"url": "https://cmfiles.keynua.com/cont..."
}
}
Type: image
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
original | string | no | Url de la imagen Expira en 12 horas |
location | GeolocationPosition | sí | Contiene información sobre la posición GPS de la imagen |
address | string | sí | Dirección calculada a partir de la posición |
Conversión de video
{
"success": true
}
Type: convertvideo
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
success | boolean | no | Si la conversión del video fue exitosa. |
OCR y Prueba de vida 3D
{
"auditTrail":"https://cmfiles.keynua.com/...",
"idScanFrontImage": "https://cmfiles.keynua.com/...",
"idScanBackImage": "https://cmfiles.keynua.com/...",
"facematchScore": 99.91,
"ocrData": {
"rut": "17840680",
"birthPlace": "SANTIAGO",
"familyNames": "JEREZ",
"names": "ALVARO",
"nationality": "CHL",
"sex": "M",
"digitChecker": "9",
"type": "cl-id",
"idNumber": "490862869",
"issueDate": "2021-11-16",
"birthDate": "1991-10-04",
"expirationDate": "2031-10-04"
}
}
Type: livenessinput
Atributo | Tipo | Descripción |
---|---|---|
auditTrail | string | URL de la imagen del rostro del usuario obtenida en la prueba de vida 3D Expira en 12 horas |
idScanFrontImage | string | URL de la foto de la parte frontal del documento obtenida en la validación del documento 3D Expira en 12 horas |
idScanBackImage | string | URL de la foto de la parte trasera del documento obtenida en la validación del documento 3D. La parte trasera no se pide en algunos casos, como en el caso del DNI Peruano Expira en 12 horas |
facematchScore | number | Porcentaje de validación biométrico entre la prueba de vida 3D y el documento escaneado. Solo tendrá valor si se realizar la prueba de vida 3D y la validación de documento 3D |
ocrData | object | Información OCR obtenida del documento. La información varía por país y se detalla en los recuadros de abajo |
DocumentType: co-id
Atributo | Tipo | Descripción |
---|---|---|
ocrData.type | string | Tipo de documento |
ocrData.idNumber | string | Número de documento |
ocrData.names | string | Nombre completo |
ocrData.familyNames | string | Apellidos |
ocrData.birthDate | string | Fecha de nacimiento, formato: MMMM-MM-DD |
ocrData.barcode | string | Información de el código de barras del documento |
DocumentType: cl-id
Atributo | Tipo | Descripción |
---|---|---|
ocrData.type | string | Tipo de documento |
ocrData.idNumber | string | Número de documento |
ocrData.names | string | Nombre completo |
ocrData.familyNames | string | Apellidos |
ocrData.birthDate | string | Fecha de nacimiento, formato: MMMM-MM-DD |
ocrData.birthPlace | string | Lugar de nacimiento |
ocrData.expirationDate | string | Fecha de expiración, formato: MMMM-MM-DD |
ocrData.issueDate | string | Fecha de expiración, formato: MMMM-MM-DD |
ocrData.nationality | string | Nacionalidad |
ocrData.rut | string | Número rut |
ocrData.digitChecker | string | Dígito verificador |
ocrData.sex | string | Los valores posibles son: F y M |
DocumentType: mx-id
Atributo | Tipo | Descripción |
---|---|---|
ocrData.type | string | Tipo de documento |
ocrData.idNumber | string | Número de documento |
ocrData.names | string | Nombre completo |
ocrData.familyNames | string | Apellidos |
ocrData.birthDate | string | Fecha de nacimiento, formato: MMMM-MM-DD |
ocrData.expirationDate | string | Fecha de expiración, formato: MMMM-MM-DD |
ocrData.issueDate | string | Fecha de expiración, formato: MMMM-MM-DD |
ocrData.address | string | Dirección actual |
ocrData.sex | string | Los valores posibles son: F y M |
ocrData.voterKey | string | Id del documento |
DocumentType: pe-id
Atributo | Tipo | Descripción |
---|---|---|
ocrData.type | string | Tipo de documento |
ocrData.idNumber | string | Número de documento |
ocrData.names | string | Nombre completo |
ocrData.familyNames | string | Apellidos |
ocrData.birthDate | string | Fecha de nacimiento, formato: MMMM-MM-DD |
ocrData.expirationDate | string | Fecha de expiración, formato: MMMM-MM-DD |
ocrData.issueDate | string | Fecha de expiración, formato: MMMM-MM-DD |
DocumentType: pe-ce
Atributo | Tipo | Descripción |
---|---|---|
ocrData.type | string | Tipo de documento |
ocrData.idNumber | string | Número de documento |
ocrData.names | string | Nombre completo |
ocrData.familyNames | string | Apellidos |
ocrData.birthDate | string | Fecha de nacimiento, formato: MMMM-MM-DD |
ocrData.nationality | string | Nacionalidad, formato: ISO 3166-1 alpha-3 |
ocrData.sex | string | Los valores posibles son: F y M |
DocumentType: global
Atributo | Tipo | Descripción |
---|---|---|
ocrData.type | string | Tipo de documento |
ocrData.idNumber | string | Número de documento |
ocrData.names | string | Nombre completo |
ocrData.familyNames | string | Apellidos |
ocrData.expirationDate | string | Fecha de expiración, formato: MMMM-MM-DD |
Errores por tipo de Item
Cuando ocurra un error en un Item, se obtendrán principalmente 2 atributos: code
y message
.
Por ejem:
{
"code": "NotValidIdCard",
"message": "El documento de identificación no es válido."
}
El valor de code
depende del tipo de error y tipo de Item como se detalla a continuación
documents
Code | Descripción |
---|---|
DocumentRejectedBySigner | El usuario rechazó el documento. |
reniec
Code | Descripción |
---|---|
ReniecFailed | Ha fallado la conexión con Reniec y no fue posible obtener la información. |
NotAllowedCancellation | El documento se encuentra cancelado. |
NotAllowedRestriction | El documento presenta restricciones por parte de Reniec. |
NotAllowedObservation | El documento presenta observaciones por parte de Reniec. |
convertvideo
Code | Descripción |
---|---|
ConvertVideoFailed | No ha sido posible procesar el video del firmante. Este error puede ocurrir si el video es inválido. |
detectlabels
Code | Descripción |
---|---|
DidNotPass | La imagen procesada no es un documento válido. |
DetectLabelsFailed | No ha sido posible detectar el formato esperado ni textos en la imagen. |
checklabels
Code | Descripción |
---|---|
unmatchedInputText | El texto ingresado no coincide con la imagen del documento de identificación. |
NotValidIdCard | El documento de identificación no es válido. |
NotValidExpirationDateInIdCard | La fecha de expiración del documento no es válida. |
ExpirationDateNotDetected | No se ha detectado la fecha de expiración en el documento. |
NoDetectedTextsInImage | No se pudo detectar ningún texto dentro de la imagen. |
DuplicatesFoundInId | Se ha detectado más de un documento de identificación. |
transcribe
Code | Descripción |
---|---|
ShortCodeNotFound | Error en el código hablado. |
TranscriptionFailed | No fue posible extraer el audio del video. |
facematch
Code | Descripción |
---|---|
NotAMatch | La cara del video no coincide con el documento oficial. |
SourceFaceNotFound | La cara en la imagen no se pudo encontrar. |
FacemasksDetected | Se ha detectado una mascarilla en la imagen. |
FaceMatchError | No fue posible encontrar una coincidencia facial. |
MarkedAsFraud | Ha sido marcado como un posible fraude por parte de Keynua. |
livenessdetection
Code | Descripción |
---|---|
AdminReject | Error obteniendo la prueba de vida del video. |
ManyFacesDetected | Han sido detectadas múltiples caras en el video. |
ScoreTooLow | El video no ha pasado el score mínimo y debe volver a enviarse. |
NoFacesDetected | No se detectó ningún rostro en el video |
InvalidPayloadStructure | Error obteniendo la prueba de vida del video. |
MarkedAsFraud | Ha sido marcado como un posible fraude por parte de Keynua. |
manualapproval
Code | Descripción |
---|---|
ManualApproveRejected | El item ha sido rechazado por el administrador del contrato. |
Customizar opciones de un item por usuario
Las opciones de los items que se encuentran establecidas en el template del contrato pueden ser customizadas para un usuario en especifico. Estas se indican para cada tipo de item que el usario tenga asignado en su proceso de firma. Las opciones deben ir dentro del atributo items de la metadata del usuario durante la creacion del contrato.
Esta configuración de puede aplicar a los siguientes items:
{
"name": "some:user-name",
"groups": ["signers"],
// Some user attributes...
"metadata": {
"items": {
"terms": {
"table": {
"title": "CONDICIONES DEL CRÉDITO",
"items": [
{
"title": "Monto del crédito",
"value": "S/ 6000.00"
},
{
"title": "Fecha del primer pago",
"value": "28/07/2021"
},
// Some items...
]
}
}
}
}
}
Terms:
Proceso de firma vía API
Por defecto, Keynua ofrece al usuario completar el flujo de firma mediante la web de Keynua, sin necesidad de descargar un App o hacer algún registro previo. Esta web de Keynua puedes integrarla a tu propio dominio o a tu App móvil mediante un WebView, siguiendo las instrucciones que se detallan en esta documentación
Puedes usar las APIs de esta sección si lo que quieres es crear tu front personalizado para el flujo de firma. Luego de recibir los inputs del usuario, los procesaremos y validaremos según el flujo de firma que estés usando.
Antes de comenzar, debes reconocer los Items que necesitas enviar de acuerdo a los Tipos de Item "User Input" que tiene el template que estás usando.
Flujo lógico
Flujo lógico - Error
Obtener Items pendientes
Con este API podrás obtener un resumen de los Items que están pendientes a ser enviados. Es muy importante obtener el tipo de item que está pendiente a ser enviado, el itemId y el item version. El item version cambiará por cada intento de envío que hagas. Por ejemplo; si subes una foto de un documento que no es reconocido como el documento del país, devolveremos un error en el item de validación de formato del documento, pero el itemId y version que enviarás debe corresponder a la imagen del documento.
{
"id": "4d50f870-xxxx-xxxx-xxxx-1b50872e31d5e1",
"templateId": "keynua-peru-default",
"userName": "Usuario Prueba",
"views": [
{
"id": "view_2_0",
"type": "input",
"input": {
"id": 2,
"type": "terms",
"userId": 0,
"version": 0,
"title": "Aceptación de Términos"
}
},
{
"id": "view_3_0",
"type": "input",
"input": {
"id": 3,
"type": "documents",
"userId": 0,
"version": 0,
"title": "Revisión de Documentos"
}
},
{
"id": "dniView",
"type": "input",
"input": {
"id": 4,
"type": "text",
"userId": 0,
"version": 0,
"title": "Nº DNI"
}
},
{
"id": "imageDniView",
"type": "input",
"input": {
"id": 5,
"type": "image",
"userId": 0,
"version": 0,
"title": "Foto del DNI"
}
},
{
"id": "videoView",
"type": "input",
"input": {
"id": 6,
"type": "video",
"userId": 0,
"version": 0,
"title": "Videofirma"
}
}
]
}
HTTP Request
POST /contracts/v1/sign
Headers
Key | Value |
---|---|
Content-Type | application/json |
Body
Atributo | Tipo | Descripción |
---|---|---|
token | string | El token del usuario del cual se obtendrá la información |
Response body
Nombre | Tipo | Descripción |
---|---|---|
id | string | Identificador único del contrato (contractId) |
templateId | string | Identificador de la plantilla utilizada |
userName | string | Nombres del usuario que firma el contrato |
views | array | Lista de vistas del contrato |
views.id | string | Identificador único de la vista |
views.type | string | Tipo de vista, puede ser info o input . Los que nos interesan son sólo los de tipo input |
views.input | object | Si es un view de tipo input , obtendrás este objeto con más detalle |
views.input.type | string | Tipo de Item, puede ser cualquiera de estos ItemValues |
views.input.id | number | Id del item, corresponde al valor de itemId |
views.input.version | number | Versión actual del item |
views.input.userId | number | Identificador del usuario |
views.input.title | string | Título del item |
Enviar un archivo multimedia
Para poder enviar un archivo multimedia, debes conocer previamente los archivos que necesitas subir. El procedimiento se debe repetir por cada archivo que subirás, solo aplica para los items de tipo image
y video
.
Paso 1: solicitar la información antes de subir un archivo
Body payload
{
"token": "some:user:token",
"name": "some_file.jpg"
}
Si la solicitud fue satisfactoria, la respuesta tendrá la información para que puedas subir el contenido del archivo
{
"linkId": "some:id",
"url": "https://some:url:for:upload",
"method": "PUT",
"headers": {
"Content-Type": "image/jpeg",
"x-amz-tagging": "account-id={accountId}",
"{another-key}": "{another-val}"
}
}
Ten en cuenta que {another-key} y {another-val} se refieren a posibles valores que podemos devolver y que deben ser enviados en el paso 2
HTTP Request
POST /contracts/v1/sign/upload
Headers
Key | Value |
---|---|
Content-Type | application/json |
Body
Atributo | Tipo | Descripción |
---|---|---|
token | string | El token del usuario del cual se actualizará el item |
name | string | El nombre del archivo que se va a subir. Debe incluir su extensión |
Paso 2: subir el contenido del archivo
curl --request PUT \
--url 'https://some:url:for:upload' \
--header 'content-type: image/jpeg' \
--header {another-key}: {another-val} \
--data-binary "@some_file.jpg"
const axios = require("axios");
const fs = require("fs");
// Read image file
const image = fs.readFileSync("some_file.jpg");
// Send PUT request
axios
.put(
"https://some:url:for:upload",
image,
{
headers: {
"Content-Type": "image/jpeg",
{another-key}: {another-val}
},
}
)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
Ten en cuenta que {another-key} y {another-val} se refieren a posibles valores que se retornarán en el paso 1 y que deben ser enviados obligatoriamente en este paso. Si no hubo errores al subir el archivo, se retornará el código de estado 200
Con la información obtenida en el paso 1, se subirá el archivo. IMPORTANTE: Ten en cuenta enviar los headers recibidos en el paso 1
HTTP Request
PUT {URL-STEP-1}
Headers
Key | Value |
---|---|
Content-Type | {Content-Type-Step-1} |
{another-key} | {another-value} (Hace referencia a otro header que se puede haber enviado en el paso1) |
Body
El archivo en binario de no más de 1MB y video de no más de 15 segundos de duración
Enviar información de firma
Luego de detectar los Items que debes enviar, puedes usar este API para finalmente enviar la información de firma por cada Item. Los Items que podrás enviar son los Items "User Input" como por ejemplo la aceptación de Términos y Condiciones, la visualización de Documentos, un texto y los archivos multimedia como imagen y video.
curl --request PUT \
--url https://api.stg.keynua.com/contracts/v2/sign/batch \
--header 'Content-Type: application/json' \
--data '{
"token": "USER-TOKEN-HERE",
"items": [
{
"itemId": 0,
"version": 0,
"value": {
"viewedAt": "2023-03-30T20:15:30.001Z"
}
},
{
"itemId": 1,
"version": 0,
"value": {
"opened": true
}
},
{
"itemId": 2,
"version": 0,
"value": {
"text": "46464646"
}
},
{
"itemId": 3,
"version": 0,
"value": {
"linkId": "LINK-ID-HERE"
}
}
]
}'
HTTP Request
PUT /contracts/v2/sign/batch
Headers
Key | Value |
---|---|
Content-Type | application/json |
Body
Atributo | Tipo | Descripción |
---|---|---|
token | string | El token del usuario del cual se actualizará la información |
items | array | Arreglo de Item Values a enviar |
otpToken | string | El token de otp necesario solo para los contratos que utilizan otp. |
Response body
Nombre | Tipo | Descripción |
---|---|---|
ok | boolean | Si se ha recibido la información correctamente, obtendrás true |
Item Values
Atributo | Tipo | Descripción |
---|---|---|
itemId | integer | El identificador del item |
version | integer | La versión actual del item. Ten en cuenta que en caso de un error, esta versión aumentará y deberás usar siempre el último valor. Por ello es importante obtener la último versión mediante el API Obtener Items pendientes |
value | object | El value a enviar por cada tipo de Item. En las siguientes tablas podrás ver el detalle del value a enviar por cada tipo de item |
Item de Términos y Condiciones
Atributo | Tipo | Descripción |
---|---|---|
viewedAt | string | ISO String de la fecha |
Item de Documentos
Atributo | Tipo | Descripción |
---|---|---|
opened | boolean | Si los archivos fueron abiertos |
Item de Texto
Atributo | Tipo | Descripción |
---|---|---|
text | string | Valor del texto |
Archivos multimedia (image/video)
Atributo | Tipo | Descripción |
---|---|---|
linkId | string | linkId obtenido en el paso 1 de Enviar un archivo multimedia |
Configuración dinámica del template
curl --request PUT \
--url https://api.stg.keynua.com/contracts/v1 \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'content-type: application/json' \
--data '{
"title": "Contract created by API",
"language": "es",
"userEmailNotifications": true,
"templateOptions": {
"mock": true,
"classesId": "custom-classes-v2",
"stages": [
{
"groups": [
{
"name": "Firmantes",
"type": "signers",
"views": {
"nothingMore": "nothing-more-custom",
"finished": "finished",
"validating": "validating-custom",
"items": {
"terms": "terms-basic",
"documents": "documents-v1",
"documentNumber": "document-number-dni",
"idFront": "image-front-dni",
"idBack": "image-back-dni",
"videoSignature": "video-signature"
}
},
"documentSides": "both",
"documentType": "pe-dni",
"allowsUpdateItemTypes": [
"detectlabels",
"facematch",
"checklabels"
],
"documentValidations": [
"verify-content-reniec",
"expiration-date"
],
"signatureTypes": [
"video-signature"
],
"allViewsAtOnce": true,
"prefilledActive": true,
"workingMessages": {
"approvalMessageTitle": "Tu solicitud está en proceso. Por favor comunícate con nuestro Call Center." },
"errorMessages": {
"contentReniecUnmatchedTitle": "El número del DNI registrado: {documentNumber}, no coincide con el número del DNI de la foto",
"contentReniecUnmatchedSubtitle": "Contáctanos para mayor información: respondepe@example.com"
},
"dynamicFields": [
{
"name": "Foto recibo agua o Luz",
"type": "image",
"viewId": "imagereciboview",
"options": {
"orientation": "vertical",
"overlay": true,
"camera": "environment",
"invalidExtensions": [
".pdf",
".mp4"
]
}
}
],
"minimumScore": {
"idfront": 30,
"idback": 30,
"liveness-detection": 50,
"idfront-approval": 50,
"idback-approval": 60,
"reniec-video-approval": 80,
"reniec-idfront-approval": 80
},
"matchPercent": {
"reniec-idfront": 30,
"reniec-video": 60
},
"validateMinAge": 18,
"reviewEachDocument": false,
"disableNotification": true,
"disableReminder": true,
"skipSurveyEmail": true,
"maskDocumentNumberValue": true
}
]
}
]
},
"documents": [
{
"name": "DocumentPdf.pdf",
"base64": "YOUR-BASE64-PDF-HERE"
}
],
"users": [
{
"name": "Manuel Silva",
"email": "msilva@keynua.com",
"groups": [ "signers" ]
}
]
}'
const https = require("https");
const data = JSON.stringify({
title: 'Contract created by API',
language: 'es',
userEmailNotifications: true,
templateOptions: {
"mock": true,
"classesId": "custom-classes-v2",
"stages": [
{
"groups": [
{
"name": "Firmantes",
"type": "signers",
"views": {
"nothingMore": "nothing-more-custom",
"finished": "finished",
"validating": "validating-custom",
"items": {
"terms": "terms-basic",
"documents": "documents-v1",
"documentNumber": "document-number-dni",
"idFront": "image-front-dni",
"idBack": "image-back-dni",
"videoSignature": "video-signature"
}
},
"documentSides": "both",
"documentType": "pe-dni",
"allowsUpdateItemTypes": [
"detectlabels",
"facematch",
"checklabels"
],
"documentValidations": [
"verify-content-reniec",
"expiration-date"
],
"signatureTypes": [
"video-signature"
],
"allViewsAtOnce": true,
"prefilledActive": true,
"workingMessages": {
"approvalMessageTitle": "Tu solicitud está en proceso. Por favor comunícate con nuestro Call Center." },
"errorMessages": {
"contentReniecUnmatchedTitle": "El número del DNI registrado: {documentNumber}, no coincide con el número del DNI de la foto",
"contentReniecUnmatchedSubtitle": "Contáctanos para mayor información: respondepe@example.com"
},
"dynamicFields": [
{
"name": "Foto recibo agua o Luz",
"type": "image",
"viewId": "imagereciboview",
"options": {
"orientation": "vertical",
"overlay": true,
"camera": "environment",
"invalidExtensions": [
".pdf",
".mp4"
]
}
}
],
"minimumScore": {
"idfront": 30,
"idback": 30,
"liveness-detection": 50,
"idfront-approval": 50,
"idback-approval": 60,
"reniec-video-approval": 80,
"reniec-idfront-approval": 80
},
"matchPercent": {
"reniec-idfront": 30,
"reniec-video": 60
},
"validateMinAge": 18,
"reviewEachDocument": false,
"disableNotification": true,
"disableReminder": true,
"skipSurveyEmail": true,
"maskDocumentNumberValue": true
}
]
}
]
},
documents: [
{
name: 'DocumentPdf.pdf',
base64: 'YOUR-BASE64-PDF-HERE'
},
],
users: [
{name: 'Manuel Silva', email: 'msilva@keynua.com', groups: ['signers']}
]
});
const options = {
method: "PUT",
hostname: "api.stg.keynua.com",
path: "/contracts/v1",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE",
"content-type": "application/json",
"content-length": data.length
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
Si el contrato fue creado satisfactoramente, el API retorna un Json estructurado como aparece en la sección de Contratos
Describe las opciones que podemos enviar en el atributo templateOptions
al crear el contrato
Atributo | Tipo | Descripción |
---|---|---|
mock | boolean | Default "false" Indica si es un flujo de prueba, se remueven del flujo las validaciones de identidad |
classesId | string | Id del registro de Custom Classes |
global | objeto | Configuraciones globales del template |
stages | array | Contiene las estapas del template |
Configuraciones globales
Atributo | Tipo | Descripción |
---|---|---|
maximumSigningAttempts | integer | optional Indica la cantidad máxima de intentos de firma de un usuario |
autoRefresh | integer | optional Indica el tiempo mínimo en segundos de espera en el que se actualiza el widget automáticamente al finalizar el envío de firma. Si está activado se muestra una nueva vista para indicar el progreso. |
contractApproval | boolean | optional Activa la funcionalidad de aprobación de contratos, ver detalle del api para Aprobar un Contrato |
Stages
Los Stages no solo contienen las configuraciones de los grupos, tambien indica cuando inicia la ejecucion de sus items puesto que se ejecutan si y solo si el stage previo finaliza.
Atributo | Tipo | Descripción |
---|---|---|
groups | array | Configuraciones de los grupos. |
Grupos
Los grupos incluyen los siguientes tipos: viewers
, signers
y bulk
.
Viewers
Atributo | Tipo | Descripción |
---|---|---|
name | string | Nombre del grupo, este mismo nombre tendrías que agregarlo a cada usuario que quieras que pertenezca a este gurpo al crear el contrato |
type | enum | viewers |
dynamicFields | array | Agrega items customizados al flujo. |
removeUserInput | boolean | Indica si el visor no debe completar el input text ingresando su nombre o rol en el flujo. Si se envía true , el usuario no tendrá que realizar ninguna acción y solo se le enviará una notificación avisándole que va en copia y otra notificación cuando finalice el contrato. |
rejectDocuments | boolean | Indica si el visor puede rechazar el documento |
Signers
Atributo | Tipo | Descripción |
---|---|---|
name | string | Nombre del grupo, este mismo nombre tendrías que agregarlo a cada usuario que quieras que pertenezca a este gurpo al crear el contrato |
type | enum | signers |
documentType | string | El tipo de documento que se quiere validar. Ver tabla de los tipos de documentos soportados |
documentSides | string | Lados del documento de identidad. Puede ser both , back o frontal |
signatureTypes | array | Indica los tipos de firma. Puede ser selfie , video-signature , draw y digital-signature |
facematch | array | Indica los items a los cuales se le aplicará el reconocimiento facial. Puede ser selfie , liveness , video-signature , reniec y document-frontal |
liveness3D | boolean | Incluir validación 3D |
documentValidations | array | Indica las opciones de validación que puedes agregar a los documentos. Puede ser verify-content-reniec , para comparar que los datos de la foto del DNI coincidan con Reniec (Sólo Perú) o expiration-date , para comprobar que el documento de identidad no ha expirado aún o verify-id-number , para comprobar que el número de documento ingresado en el flujo de firma se encuentre en el documento. |
countries | array | Indica los países cuyos documentos de identidad son aceptados. Solo disponible para OCR 3D. Los valores permitidos deben cumplir con la convención ISO 3166-1 alpha-3. |
idTypes | array | Indica los tipos de documentos aceptados. Solo disponible para OCR 3D. Los valores permitidos son: ID Card , Driver License , Passport . |
views | object | Vistas customizadas del template |
dynamicFields | array | Agrega items customizados al flujo |
uploadSelfieButton | boolean | Sirve para mostrar el botón nativo para subir la foto de selfie en el flujo de firma. |
uploadVideoButton | boolean | Sirve para mostrar el botón nativo para subir el video en el flujo de firma. |
showReniecNames | boolean | Sirve para mostrar los nombres del usuario que se obtienen de reniec en el pdf final |
placeholders | objeto | Sirve para persolizar textos en las vistas del flujo de firma. Por el momento el único atributo disponible es documentName . Este campo es opcional, si no se ingresa se usaran los valores por defecto según corresponda. |
maxNamesDifference | float | Porcentaje de similitud entre los nombres y apellidos que extrae del documento y reniec, la sensibilidad se encuentra en el intervalo de 0 a 1, mientras más se acerque a 0 la validación es más estricta. Por ejemplo: 0.5 indica una sensibilidad intermedia. |
prefilledActive | boolean | Activa los prefilled items , para que el creador del contrato pueda pre-rellenar el número de documento del firmante. Cuando se activa esta opción, el valor que debes ingresar como targetId dentro de cada user es documentNumber. Más referencia en la sección de crear contrato |
reviewEachDocument | boolean | Indica si se debe debe obligar al firmante a abrir todos los documentos para poder continuar con la firma |
disableNotification | boolean | Indica si se quiere omitir el correo de inicio |
disableReminder | boolean | Indica si se quiere omitir el recordatorio |
skipSurveyEmail | boolean | Indica si se quiere omitir la encuesta de satisfacción |
allViewsAtOnce | boolean | Esta modalidad muestra todos los pasos del flujo de firma en vertical |
maskDocumentNumberValue | boolean | Oculta el número de documento ingresado en caso de error |
validateMinAge | number | Edad minima del firmante permitida. Disponible para validaciones gubernamentales |
denyInstructionsGrade | boolean | Si activas esta opción, se devolverá un error si el DNI evaluado tiene el grado de Instrucción de Iletrado o Educación Especial. Para contratos, esta opción está activa por defecto |
minimumScore | objeto | Customizar la sensibilidad de las validaciones de identidad. Para más detalle consultar la sección Customizar validaciones |
matchPercent | objeto | Customizar la sensibilidad de las validaciones de reconocimiento facial. Para más detalle consultar la sección Customizar validaciones |
workingMessages | objeto | Customizar mensajes del flujo de firma en progreso. Para más detalle consultar la sección Customizar mensajes |
errorMessages | objeto | Customiar mensaje de error del flujo de firma. Para más detalle consultar la sección Customizar mensajes |
Bulk (Firma gerentes)
Atributo | Tipo | Descripción |
---|---|---|
name | string | Nombre del grupo, este mismo nombre tendrías que agregarlo a cada usuario que quieras que pertenezca a este gurpo al crear el contrato |
type | enum | bulk |
requiredItems | array | El arreglo puede contener los siguientes elementos: video , imagesign , visto e image |
Vistas customizadas
Las vistas personalizadas permiten modificar la apariencia del Widget dinámicamente.
El atributo de views
debe completarse con la siguiente estructura:
Nombre | Descripción |
---|---|
expired |
Personalizar vista de expiración del contrato |
finished |
Personalizar vista de finalización del contrato |
deleted |
Personalizar vista de contrato eliminado |
nothingMore |
Personalizar vista de firma enviada |
validating |
Personalizar vista de validación de firma |
maxAttempts |
Personalizar vista de bloqueo por máximo de intentos de firma |
pending |
Personalizar vista de flujo de firma pendiente |
viewers |
Personalizar vista de Vistos buenos |
terms |
Vista asignada al input de términos y condiciones. |
documents |
Vista asignada al input de Documentos. |
documentNumber |
Vista asignada al input de Número de documento. |
idFront |
Vista asignada al input de Foto frotal del documento de identidad. |
idBack |
Vista asignada al input de Foto posterior del documento de identidad. |
drawnSignature |
Vista asignada al input de firma dibujada. |
selfie |
Vista asignada al input de Foto Selfie. |
videoSignature |
Vista asignada al input de Video firma. |
Items customizados
Los items customizado tienen una estructura base en cual cambian los options
acorde a su tipo. Los tipos disponibles: image
, text
y video
.
Atributo | Tipo | Descripción |
---|---|---|
name | string | Nombre del item |
type | string | Puede ser image , text o video |
prefilledId | string | Si tenemos el atributo prefilledActive activado podemos especificar el id de referencia para ingresar el valor del item |
viewId | string | Id de la vista customizada |
options | object | Opciones del item |
Opciones del item:
- Imagen (
image
)
Atributo | Tipo | Descripción |
---|---|---|
btnLabel | string | Texto del botón principal |
invalidExtensions | array | Extensiones inválidas |
placeholderImgName | string | Id de la ilustración del item |
orientation | string | Orientación de la cámara. Puede ser horizontal o vertical |
camera | string | Tipo de cámara. Puede ser environment o user |
- Texto (
text
)
Atributo | Tipo | Descripción |
---|---|---|
regex | string | Validación del formato |
type | string | Tipo del input. Puede ser text , number o tel |
minLength | number | Longitud máxima del input |
maxLength | number | Longitud mínima del input |
- Video (
video
)
Atributo | Tipo | Descripción |
---|---|---|
btnLabel | string | Texto del botón principal |
invalidExtensions | array | Extensiones inválidas |
placeholderImgName | string | Id de la ilustración del item |
orientation | string | Orientación de la cámara. Puede ser horizontal o vertical |
camera | string | Tipo de cámara. Puede ser environment o user |
hideNativeButton | boolean | Oculta botón de la cámara nativa |
Customizar mensajes
Customizar mensajes de un flujo en proceso:
Atributo | Tipo | Descripción |
---|---|---|
approvalMessageTitle | string | Título de la aprobación manual |
approvalMessageSubtitle | string | Subtítulo de la aprobación manual |
Customizar mensajes de error:
Atributo | Tipo | Descripción |
---|---|---|
idNumberUnmatchedTitle | string | Título del mensaje cuando el número de documeto es inválido |
idNumberUnmatchedSubtitle | string | Subtítulo del mensaje cuando el número de documeto es inválido |
contentReniecUnmatchedTitle | string | Título del mensaje cuando el contenido del documento es inválido |
contentReniecUnmatchedSubtitle | string | Subtítulo del mensaje cuando el contenido del documento es inválido |
Customizar validaciones
Customizar validaciones de identidad:
Atributo | Tipo | Descripción |
---|---|---|
idfront | number | Validación del formato frontal del documento |
idback | number | Validación del formato posterior del documento |
idfront-approval | number | Aprobación manual de la parte frontal del documento |
idback-approval | number | Aprobación manual de la parte posterior del documento |
liveness-detection | number | Aprobación manual de la prueba de vida |
video-idfront-approval | number | Aprobación manual entre video y la parte frontal del documento |
reniec-idfront-approval | number | Aprobación manual entre reniec y la parte frontal del documento |
reniec-video-approval | number | Aprobación manual entre reniec y la video firma |
reniec-liveness-approval | number | Aprobación manual entre reniec y prueba de vida |
video-liveness-approval | number | Aprobación manual entre video firma y prueba de vida |
selfie-reniec-approval | number | Aprobación manual entre selfie y reniec |
selfie-idfront-approval | number | Aprobación manual entre selfie y la parte frontal del documento |
Customizar validaciones de reconocimiento facial:
Atributo | Tipo | Descripción |
---|---|---|
video-idfront | number | Facematch entre video firma y la parte frontal del documento |
reniec-idfront | number | Facematch entre reniec y la parte frontal del documento |
reniec-video | number | Facematch entre reniec y video firma |
reniec-liveness | number | Facematch entre reniec y prueba de vida |
video-liveness | number | Facematch entre video firma y prueba de vida |
selfie-reniec | number | Facematch entre selfie y reniec |
selfie-idfront | number | Facematch entre selfie y la parte frontal del documento |
Documentos de identidad soportados
id | Descripción |
---|---|
pe-dni |
Documento de identidad Perú |
pe-ce |
Carné de extrangerīa Perú |
passport |
Pasaporte |
co-cedula |
Cédula Colombiana |
br-denatran |
Denatran Brasil |
cl-cedula |
Cédula Chile |
mx-ife |
Documento de identidad Mexico (IFE) |
sv-dui |
DUI (El Salvador) |
pa-id |
Cédula panameña |
ar-id |
Cédula argentina |
br-id |
Cédula brasilera |
bo-id |
Cédula boliviana |
cr-id |
Cédula costarricense |
cu-id |
Cédula cubana |
ec-id |
Cédula ecuatoriana |
gt-id |
Cédula guatemalteca |
hn-id |
Cédula hondureña |
ni-id |
Cédula nicaraguense |
py-id |
Cédula paraguaya |
pr-id |
Cédula puertorriqueña |
do-id |
Cédula dominicana |
uy-id |
Cédula uruguaya |
us-id |
Licencia de conducir |
ve-id |
Cédula venezolana |
ch-cedula |
Cédula chilena |
global |
Global |
Deceval
Permite asociar un Pagaré emitido en el sistema de Deceval a un contrato.
Restricciones
- El objeto
decevalData
se debe agregar a los flags en la creación del contrato. - Todos los usuarios del contrato que se agregan mediante el atributo
users
deben pertenecer al grupo de firmantes del proceso si y solo si participan en el Pagaré.
Flujo de firma
- Registrar giradores.
- Creación del Pagaré en Deceval.
- Usuario realiza la firma del contrato mediante el Widget de keynua.
- Se ejecuta el item de firma Deceval: Este item usa la accion "FirmarPagares" del servicio de Deceval para registrar la firma del participante.
- Se ejecuta el item de validación del Pagaré: consulta el estado del Pagaré en el sistema de Deceval mediante la acción "ConsultarPagares" para guardar el documento generado en el contrato y adjuntarlo al pdf final.
Crear girador natural
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/deceval/v1/crear-girador-natural")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::POST.new(url)
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["content-type"] = 'application/json'
request.body = "{\n \"girador\": {\n \"nombresNat_Nat\": \"Nombre\",\n \"correoElectronico\": \"prueba@example.com\",\n \"primerApellido_Nat\": \"Apellido 1\",\n \"segundoApellido_Nat\": \"Apellido 2\",\n \"numeroCelular\": \"2348458734\",\n \"estadoCivil\": \"soltero\",\n \"direccion1PersonaGrupo_PGP\": \"Domicilio 1\",\n \"telefono1PersonaGrupo_PGP\": \"3495852343\",\n \"fechaExpedicion_Nat\": \"2021-09-01\",\n \"fechaNacimiento_Nat\": \"2021-09-01\",\n \"fkIdDepartamentoExpedicion_Nat\": \"11\",\n \"fkIdCiudadExpedicion_Nat\": \"11001\",\n \"fkIdTipoDocumento\": \"1\",\n \"numeroDocumento\": \"523642456\"\n }\n}"
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = "{\n \"girador\": {\n \"nombresNat_Nat\": \"Nombre\",\n \"correoElectronico\": \"prueba@example.com\",\n \"primerApellido_Nat\": \"Apellido 1\",\n \"segundoApellido_Nat\": \"Apellido 2\",\n \"numeroCelular\": \"2348458734\",\n \"estadoCivil\": \"soltero\",\n \"direccion1PersonaGrupo_PGP\": \"Domicilio 1\",\n \"telefono1PersonaGrupo_PGP\": \"3495852343\",\n \"fechaExpedicion_Nat\": \"2021-09-01\",\n \"fechaNacimiento_Nat\": \"2021-09-01\",\n \"fkIdDepartamentoExpedicion_Nat\": \"11\",\n \"fkIdCiudadExpedicion_Nat\": \"11001\",\n \"fkIdTipoDocumento\": \"1\",\n \"numeroDocumento\": \"523642456\"\n }\n}"
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
'content-type': "application/json"
}
conn.request("POST", "/deceval/v1/crear-girador-natural", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request POST \
--url https://api.stg.keynua.com/deceval/v1/crear-girador-natural \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'content-type: application/json' \
--data '{
"girador": {
"nombresNat_Nat": "Nombre",
"correoElectronico": "prueba@example.com",
"primerApellido_Nat": "Apellido 1",
"segundoApellido_Nat": "Apellido 2",
"numeroCelular": "2348458734",
"estadoCivil": "soltero",
"direccion1PersonaGrupo_PGP": "Domicilio 1",
"telefono1PersonaGrupo_PGP": "3495852343",
"fechaExpedicion_Nat": "2021-09-01",
"fechaNacimiento_Nat": "2021-09-01",
"fkIdDepartamentoExpedicion_Nat": "11",
"fkIdCiudadExpedicion_Nat": "11001",
"fkIdTipoDocumento": "1",
"numeroDocumento": "523642456"
}
}'
const https = require("https");
const data = JSON.stringify({
girador: {
nombresNat_Nat: 'Nombre',
correoElectronico: 'prueba@example.com',
primerApellido_Nat: 'Apellido 1',
segundoApellido_Nat: 'Apellido 2',
numeroCelular: '2348458734',
estadoCivil: 'soltero',
direccion1PersonaGrupo_PGP: 'Domicilio 1',
telefono1PersonaGrupo_PGP: '3495852343',
fechaExpedicion_Nat: '2021-09-01',
fechaNacimiento_Nat: '2021-09-01',
fkIdDepartamentoExpedicion_Nat: '11',
fkIdCiudadExpedicion_Nat: '11001',
fkIdTipoDocumento: '1',
numeroDocumento: '523642456'
}
});
const options = {
method: "POST",
hostname: "api.stg.keynua.com",
path: "/deceval/v1/crear-girador-natural",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE",
"content-type": "application/json",
"content-length": data.length
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
Los participantes del Pagaré deben ser registrados como giradores antes de crear un proceso de firma con Deceval.
HTTP Request
POST /deceval/v1/crear-girador-natural
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Content-Type | application/json |
Body
Para crear el girador, se tiene que enviar la data como un objeto JSON
Atributo | Tipo | Descripción |
---|---|---|
nombresNat_Nat | string | Nombres |
correoElectronico | string | Correo electrónico |
primerApellido_Nat | string | Primer apellido |
segundoApellido_Nat | string | Segundo apellido |
fkIdTipoDocumento | string | Tipo de documento. Puede tener los siguientes valores: "1" (CEDULA DE CIUDADANIA) , "2" (CEDULA DE EXTRANJERIA) |
numeroDocumento | string | Número de documento |
numeroCelular | string | Número de celular |
estadoCivil | string | Estado civil |
direccion1PersonaGrupo_PGP | string | Dirección de domicilio |
telefono1PersonaGrupo_PGP | string | Teléfono |
fechaNacimiento_Nat | string | Fecha de nacimiento. Formato: YYYY-MM-dd |
fechaExpedicion_Nat | string | Fecha de expedición. Formato: YYYY-MM-dd |
fkIdDepartamentoExpedicion_Nat | string | Departamento de expedición |
fkIdCiudadExpedicion_Nat | string | Cuidad de expedición |
Consultar girador
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/deceval/v1/obtener-girador")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::POST.new(url)
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["content-type"] = 'application/json'
request.body = "{\n \"idClasePersona\": \"1\",\n \"tipoDocumento\": \"1\",\n \"numeroDocumento\": \"523642456\"\n }"
response = http.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = "{\n \"idClasePersona\": \"1\",\n \"tipoDocumento\": \"1\",\n \"numeroDocumento\": \"523642456\"\n }"
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
'content-type': "application/json"
}
conn.request("POST", "/deceval/v1/crear-girador-natural", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request POST \
--url https://api.stg.keynua.com/deceval/v1/obtener-girador \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'content-type: application/json' \
--data '{
"idClasePersona": "1",
"tipoDocumento": "1",
"numeroDocumento": "523642456",
}'
const https = require("https");
const data = JSON.stringify({
"idClasePersona": "1",
"tipoDocumento": "1",
"numeroDocumento": "523642456",
});
const options = {
method: "POST",
hostname: "api.stg.keynua.com",
path: "deceval/v1/obtener-girador",
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE",
"content-type": "application/json",
"content-length": data.length
}
};
const req = https.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
HTTP Request
POST /deceval/v1/obtener-girador
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Content-Type | application/json |
Body
Para obtener el girador, se tiene que enviar la data como un objeto JSON
Atributo | Tipo | Descripción |
---|---|---|
idClasePersona | string | Tipo de girador. Puede tener los siguientes valores: "1" (NATURAL) , "2" (JURIDICO) |
numeroDocumento | string | Número de documento |
tipoDocumento | string | Tipo de documento. Puede tener los siguientes valores: "1" (CEDULA DE CIUDADANIA) , "2" (CEDULA DE EXTRANJERIA) |
Estructura del Pagaré
decevalData
{
"flags": {
"decevalData": {
"promissoryNote": {
"tipoPagare": "2",
"numCredito": "964234",
"fechaVencimientoFinanciero": "2021-08-13",
"numReferencia": "985462",
"numPagareEntidad": "642345",
"creditoReembolsableEn": 2,
"valorPesosDesembolso": 10000,
"valorPesosDesembolsoLetras": "DIEZ MIL",
"otorganteNumId": "444332323",
"otorganteTipoId": "1",
"apoderadoNumId": "754345789",
"apoderadoTipoId": "1",
"listaCodeudoresAvalistasPagare": [
{
"giradorNumId": "048918289",
"idRol": "6",
"giradorTipoId": "1"
},
{
"giradorNumId": "453456345",
"idRol": 7,
"giradorTipoId": "1"
}
],
"ciudadCreacion": "11001",
"deptoCreacion": "11",
"paisCreacion": "CO"
}
}
}
}
users
{
"users": [
{
"groups": [ "signers" ],
"prefilledItems": [
{
"target": "documentNumber",
"value": { "text": "444332323" }
}
],
"name": "Nombres y Apellidos 1",
"email": "correo1@ejemplo.com"
},
{
"groups": [ "signers" ],
"prefilledItems": [
{
"target": "documentNumber",
"value": { "text": "754345789" }
}
],
"name": "Nombres y Apellidos 2",
"email": "correo2@ejemplo.com"
},
{
"groups": [ "signers" ],
"prefilledItems": [
{
"target": "documentNumber",
"value": { "text": "048918289" }
}
],
"name": "Nombres y Apellidos 3",
"email": "correo3@ejemplo.com"
},
{
"groups": [ "signers" ],
"prefilledItems": [
{
"target": "documentNumber",
"value": { "text": "453456345" }
}
],
"name": "Nombres y Apellidos 4",
"email": "correo4@ejemplo.com"
}
]
}
promissoryNote:
Detalle del pagaré. El elemento está compuesto por:
Atributo | Tipo | Descripción |
---|---|---|
tipoPagare | string | Tipo de Pagaré. Puede tener los siguientes valores: "1" (Diligenciado) , "2" (En blanco con carta de instrucciones) . |
numCredito | string | Número de crédito |
fechaVencimientoFinanciero | string | Fecha de vencimiento. Formato: YYYY-MM-dd |
numReferencia | string | Número de referencia |
numPagareEntidad | string | Número del Pagaré de la entidad |
creditoReembolsableEn | integer | Indica el tipo de moneda del desembolso. Puede tener los siguientes valores: 1 (EnURV) , 2 (En Pesos) , 3 (En Dólares) , 4 (Otros) |
valorPesosDesembolso | integer | Valor de desembolso |
valorPesosDesembolsoLetras | string | Valor de desembolso representado en texto |
otorganteTipoId | string | Tipo de documento del apoderado. Puede tener los siguientes valores: "1" (CEDULA DE CIUDADANIA) , "2" (CEDULA DE EXTRANJERIA) . |
otorganteNumId | string | Número de documento del otorgante |
apoderadoTipoId | string | Tipo de documento del apoderado. Puede tener los siguientes valores: "1" (CEDULA DE CIUDADANIA) , "2" (CEDULA DE EXTRANJERIA) . |
apoderadoNumId | string | Número de documento del apoderado |
ciudadCreacion | string | Cuidad de creacion del Pagaré |
deptoCreacion | string | Departamento de creación del Pagaré |
paisCreacion | string | Pais de creación del Pagaré |
listaCodeudoresAvalistasPagare | CodeudoresAvalistas[] | Lista de codeudores y avalistas |
CodeudoresAvalistas
El codeudor o avalista del pagaré. El elemento está compuesto por:
Atributo | Tipo | Descripción |
---|---|---|
giradorTipoId | string | Tipo de documento del apoderado. Puede tener los siguientes valores: "1" (CEDULA DE CIUDADANIA) , "2" (CEDULA DE EXTRANJERIA) . |
idRol | string | Rol del participante. Puede tener los siguientes valores: "6" (Codeudor) , "7" (Avalista) |
giradorNumId | string | Nùmero de documento del participante |
Verificación de identidad
Permite crear, listar y obtener verificaciones de identidad.
Propiedades de una verificación de identidad
{
"userRealName": "JOHN, DOE",
"status": "done",
"finishedAt": "2021-04-26T23:03:50.272Z",
"language": "es",
"reference": "123456789",
"expirationInHours": 0,
"startedAt": "2021-04-26T23:02:08.500Z",
"contractId": "6afe9bb0-a6e3-11eb-9a2c-11fc3348624ae1",
"documentNumber": "123456789",
"id": "88b93325-82c4-40aa-9606-f49c757382ae",
"accountId": "48101c38-f770-4ea8-88ab-258e672d88bd",
"userEmail": "user_email@gmail.com",
"countryCode": "pe",
"userToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...ZlOWJiMC1hNmUzLTExZWItOWEyYy0xMWZjMzM0ODYyNGFlMS",
"createdAt": "2021-04-26T23:02:02.309Z",
"accountEmail": "user@keynua.com",
"organizationId": "48101c38-f770-4ea8-88ab-258e672d88bd",
"updatedAt": "2021-05-18T22:40:05.851Z",
"userFullName": null,
"accountName": "Patrick Star",
"timezone": "America/Lima",
"title": "Identification 123456789",
"userIdInfo": {
"type": "pe-id",
"idNumber": "12345678",
"verificationDigit": "9",
"names": "Juan",
"lastName": "Perez Alvarez",
"birthDate": "1992-11-20",
"expirationDate": "2026-03-17"
"address": "Some address",
"reniecInfo": {
"names": "Juan",
"lastName": "Garcia",
"mothersLastName": "Perez",
"marriedLastName": null,
"sex": "1", // 1: Masculino, 2: Femenino
"civilStatus": "1", // 1: Soltero, 2: Casado, 3: Viudo, 4: Divorciado
"birthplace": {
"code": "140133",
"department": "LIMA",
"province": "LIMA",
"district": "JESUS MARIA"
},
"department": "LIMA",
"province": "LIMA",
"district": "LIMA"
}
},
"items": ContractItem[]
}
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
userRealName | string | No | Nombre completo del usuario |
status | string | No | pending , pending_input , pending_approval , working , error , done , deleted , max_attempts , o expired |
finishedAt | string | Sí | Fecha y hora de finalización en formato ISO |
language | string | No | Lenguaje con el cual se completará el proceso de identificación |
reference | string | Sí | Campo libre. Útil para realizar búsquedas. |
expirationInHours | string | Sí | En cuantas horas luego de la creación, la verificación expirará. 0 no expira. |
startedAt | string | Sí | Fecha y hora en formato ISO del momento en que la verificación está lista para ser completada. |
contractId | string | No | Id interno |
documentNumber | string | No | Número de documento nacional de identificación |
id | string | No | Identificador único de la verificación |
accountId | string | No | Id de la cuenta que creó la verificación |
userEmail | string | Sí | Email del verificante en el cual recibirá el link de inicio del proceso |
userPhone | string | Sí | Teléfono celular del verificante en el cual recibirá el link de inicio del proceso |
countryCode | string | No | Código del país en el que se realiza la verificación |
userToken | string | No | Token con el cual se puede armar el link donde se realizará la verificación. Por ejemplo: https://sign.keynua.com/index.html?token={token} |
createdAt | string | No | Fecha y hora de creación en formato ISO |
accountEmail | string | No | Email de la cuenta que creó la verificación |
organizationId | string | Sí | Id de la organización en la que se creó la verificación |
updatedAt | string | No | Última fecha y hora en formato ISO en la que se realizó alguna modificación |
userFullName | string | Sí | Nombre completo de la persona |
accountName | string | No | Nombre de la cuenta que creó la verificación |
timezone | string | No | Huso horario utilizado en notificaciones y mensajes |
title | string | No | Título de la verificación |
userIdInfo | string | Sí | Información obtenida del OCR del documento enviado por el firmante. Esta información se devolverá solamente cuando la Identificación haya finalizado y de momento solo aplica para las Identificaciones Peruanas. Toda información referente a la dirección y ubigeo, se devolverá solamente si el usuario también envía la parte trasera del DNI |
items | ContractItem[] | No | Lista de pasos que sigue la verificación. |
Crear verificación de identidad
curl --location --request PUT 'https://api.keynua.com/identity-verification/v1' \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'Content-Type: application/json' \
--data-raw '{
"documentNumber": "12345678",
"userPhone": "51123456789",
"userFullName": "Patrick Star",
"title": "Identification 12345678",
"type": "video",
"documentType": "pe-dni",
"disableInitialNotification": false,
}'
require "uri"
require "net/http"
url = URI("https://api.keynua.com/identity-verification/v1")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Put.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["Content-Type"] = "application/json"
request.body = "{\n \"documentNumber\": \"12345678\",\n \"userPhone\": \"51123456789\",\n \"userFullName\": \"Patrick Star\",\n \"title\": \"Identification 12345678\",\n \"type\": \"video\",\n \"documentType\": \"pe-dni\",\n \"disableInitialNotification\": \"false\",\n \"validateDocument\": \"true\"\n}"
response = https.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("api.keynua.com")
payload = json.dumps({
"documentNumber": "12345678",
"userPhone": "51123456789",
"userFullName": "Patrick Star",
"title": "Identification 12345678",
"type": "video",
"documentType": "pe-dni",
"disableInitialNotification", "false",
"validateDocument": "true",
})
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
'Content-Type': 'application/json'
}
conn.request("PUT", "/identity-verification/v1", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
const http = require("https");
const options = {
"method": "PUT",
"hostname": "api.keynua.com",
"path": "/identity-verification/v1",
"headers": {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE",
"Content-Type": "application/json"
}
};
const req = http.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
var postData = JSON.stringify({
"documentNumber": "12345678",
"userPhone": "51123456789",
"userFullName": "Patrick Star",
"title": "Identification 12345678",
"type": "video",
"documentType": "pe-dni",
"disableInitialNotification": false
"validateDocument": true
});
req.write(postData);
req.end();
Si la plantilla fue creada satisfactoriamente, el API retorna un Json estructurado como aparece en la sección de verificación de identidad.
{
"userRealName": "JOHN, DOE",
"status": "done",
"finishedAt": "2021-04-26T23:03:50.272Z",
"language": "es",
"reference": "123456789",
"expirationInHours": 0,
"startedAt": "2021-04-26T23:02:08.500Z",
"contractId": "6afe9bb0-a6e3-11eb-9a2c-11fc3348624ae1",
"documentNumber": "123456789",
"id": "88b93325-82c4-40aa-9606-f49c757382ae",
"accountId": "48101c38-f770-4ea8-88ab-258e672d88bd",
"userEmail": "user_email@gmail.com",
"countryCode": "pe",
"userToken": "eyJ0eXAiOiJKV...9TstTqlChryW4mZGyAgHE9Y",
"createdAt": "2021-04-26T23:02:02.309Z",
"accountEmail": "account_email@keynua.com",
"organizationId": "48101c38-f770-4ea8-88ab-258e672d88bd",
"updatedAt": "2021-05-19T20:55:48.186Z",
"userFullName": null,
"accountName": "Patrick Star",
"timezone": "America/Lima",
"title": "Identification 123456789",
"items": [
{
"id": 0,
"version": 1,
"state": "success",
"userId": 0,
"reference": "signersemail",
"title": "Invitación de inicio de firma",
"type": "usernotifier",
"stageIndex": 0,
"value": {},
"allowsManualUpdate": false,
"allowsRetry": false,
"hideOnWebApp": false
},
{
"id": 1,
"version": 1,
"state": "success",
"userId": 0,
"reference": "terms",
"title": "Aceptación de Términos",
"type": "terms",
"stageIndex": 0,
"value": {
"termsAndConditionsUrl": "https://www.keynua.com/legal/terms-and-conditions/",
"privacypolicyUrl": "https://www.keynua.com/legal/privacy-policy/",
"viewedAt": "2021-04-26T23:03:13.928Z"
},
"allowsManualUpdate": false,
"allowsRetry": false,
"hideOnWebApp": false
},
...
]
}
HTTP Request
PUT /identity-verification/v1
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
Authorization | your-api-token |
Request body
Nombre | Tipo | Opcional | Descripción |
---|---|---|---|
title | string | No | Nombre que se le quiera dar a la verificación |
documentNumber | string | No | Número de documento nacional de identificación de la persona |
documentType | string | No | Tipo de documento nacional. Por ahora soportamos ch-cedula , br-denatran , cl-cedula , co-cedula , mx-ife , pe-ce , pe-dni , pe-dni-ce , sv-dui , pa-id , br-id ,ar-id , bo-id , cr-id , cu-id , ec-id , gt-id , hn-id , ni-id , pr-id , py-id , do-id , us-id ,uy-id y ve-id . |
userFullName | string | Sí | Nombre completo de la persona |
userEmail | string | Sí | Email de la persona. Si se envía, no enviar el campo userPhone también. |
userPhone | string | Sí | Teléfono celular de la persona. Si se envía, no enviar el campo userEmail también. |
reference | string | Sí | Campo útil para realizar búsquedas entre verificaciones creadas |
type | string | Sí | selfie , video , smile o liveness . selfie solo pide un selfie y valida esa imagen con RENIEC. video además de lo anterior, solicita que se grabe un video diciendo un código de 6 dígitos, y realiza una prueba de vida utilizando el video. smile solicita que se grabe un video sonriendo, y realiza una prueba de vida utilizando el video (BETA). liveness realiza una prueba de vida 3D. |
disableInitialNotification | boolean | Sí | Opción para desactivar la notificación inicial que se envía a la persona. |
documentSide | front o both |
Sí | SOLO PARA DNI DE PERÚ. Opción para indicar qué lados del DNI validar. Si no es enviado no se hará ninguna validación. |
documentScanVersion | number | Sí | La versión de escaneo del documento puede ser 1 para escaneo simple o 2 para escaneo 3D. |
countries | array | Sí | Indica los países cuyos documentos de identidad son aceptados. Solo disponible para OCR 3D. Los valores permitidos deben cumplir con la convención ISO 3166-1 alpha-3. |
idTypes | array | Sí | Indica los tipos de documentos aceptados. Solo disponible para OCR 3D. Los valores permitidos son: ID Card , Driver License , Passport . |
language | string | Sí | Lenguaje con el cual se creará el proceso de identificación |
accountName | string | Sí | Nombre de cuenta que se usará al crear el proceso de identificación. De no ser enviado, se usará el nombre de la cuenta que está creando la identificación. |
Combinaciones no soportadas por defecto
Por ahora los paises que soportamos para selfie
y video
son sv-dui
, mx-ife
, cl-cedula
, pe-dni
, br-denatran
y co-cedula
. En caso se cree una identificación con selfie
o video
con algún país que no esté en esta lista, automáticamente se considerará el documento como global
. La lista completa sí está soportada con el type liveness
.
Response body
Listar verificaciones de identidad
curl --location --request GET 'https://api.keynua.com/identity-verification/v1/list' \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE'
require "uri"
require "net/http"
url = URI("https://api.keynua.com/identity-verification/v1/list")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
response = https.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.keynua.com")
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
}
conn.request("GET", "/identity-verification/v1/list", None, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
const http = require("https");
const options = {
"method": "GET",
"hostname": "api.keynua.com",
"path": "/identity-verification/v1/list",
"headers": {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
}
};
const req = http.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Response
{
"items": [
{
"id": "88b93325-82c4-40aa-9606-f49c757382ae",
"status": "done",
"accountEmail": "user@keynua.com",
"createdAt": "2021-04-26T23:02:02.309Z",
"documentNumber": "12345678",
"title": "Identification 70671142",
"userEmail": "user_email@gmail.com"
},
{
"id": "565b0132-ef7d-4a27-aa8c-f0f96a2d74b1",
"status": "done",
"accountEmail": "user@keynua.com",
"createdAt": "2021-04-24T00:10:50.237Z",
"documentNumber": "12345678",
"title": "Identification 123456789",
"userPhone": "51123456789"
}
],
"next": "eyJhY2NvdW50SWQi...jIwMjEtMDQtMjRUMDA6MTA6NTAuMjM3WiJ9"
}
Permite obtener una lista de verificaciones de identidad creadas.
HTTP Request
GET /identity-verification/v1/list
obtiene las de tu cuenta
GET /identity-verification/v1/list-org
obtiene las de tu organización
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
Authorization | your-api-token |
Search params
Nombre | Tipo | Opcional | Descripción |
---|---|---|---|
startKey | string | Sí | Sirve para obtener la siguiente porción de items en la lista. Recibe el valor de next que se obtiene en la respuesta. |
startDate | string | Sí | Enviar necesariamente junto con endDate para listar las verificaciones dentro de un rango de fechas. Debe estar en formato ISO. |
endDate | string | Sí | Enviar necesariamente junto con startDate para listar las verificaciones dentro de un rango de fechas. Debe estar en formato ISO. |
limit | number | Sí | La cantidad máxima de items que el api debe devolver. Si no se envía, el api devuelve alrededor de 1 MB de datos. |
expanded | boolean | Sí | true si se quiere más detalle en cada item de la lista. |
Response body
Nombre | Tipo | Descripción |
---|---|---|
items | VerificationItem[] | Lista de verificaciones |
next | string | Opcional Envía este valor en startKey para obtener la siguiente porción de la lista. Si no se encuentra en la respuesta, entonces no quedan más items en la lista. |
Response body VerificationItem
Nombre | Tipo | Requiere expanded | Descripción |
---|---|---|---|
id | string | No | Identificador único de la verificación |
status | string | No | pending , pending_input , pending_approval , working , error , done , deleted , o expired |
accountEmail | string | No | Email de la cuenta que creó la verificación |
createdAt | string | No | Fecha y hora de creación en formato ISO |
documentNumber | string | No | Número de documento |
title | string | No | Título de la verificación |
userEmail | string | No | Opcional Email del verificante en el cual recibirá el link de inicio del proceso |
userPhone | string | No | Opcional Teléfono celular del verificante en el cual recibirá el link de inicio del proceso |
accountId | string | Sí | Id de la cuenta que creó la verificación |
organizationId | string | Sí | Id de la organización en la que se creó la verificación |
countryCode | string | Sí | Código del país en el que realiza la verificación |
language | string | Sí | Lenguaje con el cual se completará el proceso de identificación |
expirationInHours | string | Sí | En cuantas horas luego de la creación la verificación expirará. 0 no expira. |
startedAt | string | Sí | Fecha y hora en formato ISO del momento en que el verificante ingresa todos sus datos |
userFullName | string | Sí | Nombre completo de la persona |
accountName | string | Sí | Nombre de la cuenta que creó la verificación |
Obtener verificación de identidad
curl --location --request GET 'https://api.keynua.com/identity-verification/v1/{verification_id}' \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE'
require "uri"
require "net/http"
url = URI("https://api.keynua.com/identity-verification/v1/{verification_id}")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
response = https.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.keynua.com")
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
}
conn.request("GET", "/identity-verification/v1/{verification_id}", None, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
const http = require("https");
const options = {
"method": "GET",
"hostname": "api.keynua.com",
"path": "/identity-verification/v1/{verification_id}",
"headers": {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
}
};
const req = http.request(options, function (res) {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Si la plantilla fue obtenida satisfactoriamente, el API retorna un Json estructurado como aparece en la sección de verificación de identidad.
{
"userRealName": "JOHN, DOE",
"status": "done",
"finishedAt": "2021-04-26T23:03:50.272Z",
"language": "es",
"reference": "123456789",
"expirationInHours": 0,
"startedAt": "2021-04-26T23:02:08.500Z",
"contractId": "6afe9bb0-a6e3-11eb-9a2c-11fc3348624ae1",
"documentNumber": "123456789",
"id": "88b93325-82c4-40aa-9606-f49c757382ae",
"accountId": "48101c38-f770-4ea8-88ab-258e672d88bd",
"userEmail": "user_email@gmail.com",
"countryCode": "pe",
"userToken": "eyJ0eXAiOiJKV...9TstTqlChryW4mZGyAgHE9Y",
"createdAt": "2021-04-26T23:02:02.309Z",
"accountEmail": "account_email@keynua.com",
"organizationId": "48101c38-f770-4ea8-88ab-258e672d88bd",
"updatedAt": "2021-05-19T20:55:48.186Z",
"userFullName": null,
"accountName": "Patrick Star",
"timezone": "America/Lima",
"title": "Identification 123456789",
"userIdInfo": {
"type": "pe-id",
"idNumber": "12345678",
"verificationDigit": "9",
"names": "Juan",
"lastName": "Perez Alvarez",
"birthDate": "1992-11-20",
"expirationDate": "2026-03-17"
"address": "Some address",
},
"items": [
{
"id": 0,
"version": 1,
"state": "success",
"userId": 0,
"reference": "signersemail",
"title": "Invitación de inicio de firma",
"type": "usernotifier",
"stageIndex": 0,
"value": {},
"allowsManualUpdate": false,
"allowsRetry": false,
"hideOnWebApp": false
},
{
"id": 1,
"version": 1,
"state": "success",
"userId": 0,
"reference": "terms",
"title": "Aceptación de Términos",
"type": "terms",
"stageIndex": 0,
"value": {
"termsAndConditionsUrl": "https://www.keynua.com/legal/terms-and-conditions/",
"privacypolicyUrl": "https://www.keynua.com/legal/privacy-policy/",
"viewedAt": "2021-04-26T23:03:13.928Z"
},
"allowsManualUpdate": false,
"allowsRetry": false,
"hideOnWebApp": false
},
...
]
}
Permite obtener una verificación de identidad
HTTP Request
GET /identity-verification/v1/{verification_id}
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
Authorization | your-api-token |
Response body
Plantillas de documento
Permite listar, obtener y rellenar plantillas de documentos PDF.
Propiedades de una plantilla de documento
{
"templateId": "2021-05-07T22:10:14.935Z8f8bc671-626d-4212-9c8c-c5d5f9464fa6",
"accountId": "48101c38-f770-4ea8-88ab-248e672d88bd",
"name": "A document template",
"creatorEmail": "creator@keynua.com",
"fields": DocumentTemplateField[],
"files": DocumentTemplateFile[],
"updatedAt": "2021-05-07T22:10:14.935Z",
"createdAt": "2021-05-07T22:10:14.935Z"
}
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
templateId | string | No | El id de la plantilla de documento |
accountId | string | No | El id del usuario que creó la plantilla de documento |
name | string | No | El nombre de la plantilla de documento |
creatorEmail | string | No | El email del usuario que creó la plantilla de documento |
fields | DocumentTemplateField[] | No | Contiene las reglas para cada campo de la plantilla de documento. Los valores de estos campos serán utilizados para generar los archivos finales. |
files | DocumentTemplateFile[] | No | Los archivos pdf que serán utilizados como base para generar los archivos que incluyan los valores de los campos |
updatedAt | string | No | La fecha y hora de la última modificación en formato ISO |
createdAt | string | No | La fecha y hora de creación en formato ISO |
Propiedades de DocumentTemplateField
{
"id": "email-0",
"name": "Email",
"type": "string",
"required": true,
"default": "default value",
"minLength": 2,
"maxLength": 10,
"regex": "^\\d?$",
"placeholder": "A placeholder"
}
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
id | string | No | El id del campo |
name | string | No | El nombre del campo |
type | string | No | El tipo del campo. string , date o number . |
required | boolean | No | Si el campo es obligatorio |
default | string | Sí | Un valor por defecto para el campo |
minLength | number | Sí | La longitud mínima para campos de tipo string |
maxLength | number | Sí | La longitud máxima para campos de tipo string |
regex | string | Sí | Regex para validar campos de tipo string |
placeholder | string | Sí | Texto adicional |
Propiedades de DocumentTemplateFile
{
"url": "https://s3.amazonaws.com/48101c38-f770-4ea8-88ab-25",
"id": "b5d1b359-3736-424b-b83d-f0d0da910a89",
"name": "isotype_stamp.pdf",
"size": 3708
}
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
url | string | No | Url que contiene el documento original |
id | string | No | Id del archivo |
name | boolean | No | Nombre del archivo |
size | number | No | Tamaño del archivo |
Listar plantillas de documento
require "uri"
require "net/http"
url = URI("https://api.stg.keynua.com/contract-manager-document-templates/api")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
response = https.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
}
conn.request("GET", "/contract-manager-document-templates/api", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --location --request GET 'https://api.stg.keynua.com/contract-manager-document-templates/api' \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE'
const https = require("https");
var options = {
'method': 'GET',
'hostname': 'api.stg.keynua.com',
'path': '/contract-manager-document-templates/api',
'headers': {
'x-api-key': 'YOUR-API-KEY-HERE',
'authorization': 'YOUR-API-TOKEN-HERE'
},
};
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
res.on("error", function (error) {
console.error(error);
});
});
req.end();
Success response
{
"templates": [
{
"templateId": "2021-05-07T22:10:14.935Z8f8bc671-626d-4212-9c8c-c5d5f9464fa6",
"accountId": "48101c38-f570-4ea8-88ab-258e672d88bd",
"name": "test 1",
"creatorEmail": "creator@keynua.com",
"fileCount": 5,
"fieldCount": 2,
"updatedAt": "2021-05-07T22:10:14.935Z",
"createdAt": "2021-05-07T22:10:14.935Z"
},
{
"templateId": "2021-02-11T21:18:18.463Z962ce87f-d3b7-4cbb-afa0-04e85e2791b2",
"accountId": "48101c38-f770-4e28-88ab-258e672d88bd",
"name": "test 2",
"creatorEmail": "creator@keynua.com",
"fileCount": 1,
"fieldCount": 1,
"updatedAt": "2021-02-11T21:18:18.463Z",
"createdAt": "2021-02-11T21:18:18.463Z"
}
],
"next": "eyJwayI6IjQ4MTAxYzM4LWY3NzAtNGVhOC04OGFiLTI1OGU2NzJkODhiZDp0ZW1wbGF0ZSIsInJrIjoiMjAyMS0wMi0wMlQyMToxMzozNy42NDhaNGE3YWZiZDEtMTQ0Yi00YmRmLWI1NTUtOWFlZTQ2MDMxZGE1In0="
}
Permite obtener una lista de las plantillas de documento que pertenecen al usuario o a su organización.
HTTP Request
GET /contract-manager-document-templates/api
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Search params
Nombre | Tipo | Opcional | Descripción |
---|---|---|---|
limit | number | Sí | La cantidad máxima de items que el api debe devolver. Si no se envía, el api devuelve todos. |
start | string | Sí | Sirve para obtener la siguiente porción de items en la lista. Recibe el valor de next que se obtiene en la respuesta. |
organizational | boolean | Sí | true si se quiere las plantillas de documento de la organización |
Response body
Atributo | Tipo | Descripción |
---|---|---|
templates | TemplateItem | Lista de plantillas de documento |
next | string | opcional Envía este valor en start para obtener la siguiente porción de la lista. Si no se encuentra en la respuesta, entonces no quedan más items en la lista. |
Response body TemplateItem
Atributo | Tipo | Descripción |
---|---|---|
templateId | string | El id de la plantilla de documento |
accountId | string | El id del usuario que creó la plantilla de documento |
name | string | El nombre de la plantilla de documento |
creatorEmail | string | El email del usuario que creó la plantilla de documento |
fileCount | number | Cantidad de archivos en la plantilla |
fieldCount | number | Cantidad de campos en la plantilla |
updatedAt | string | La fecha y hora de la última modificación en formato ISO |
createdAt | string | La fecha y hora de creación en formato ISO |
Obtener plantilla de documento
require "uri"
require "net/http"
url = URI("https://api.stg.keynua.com/contract-manager-document-templates/api/{templateId}")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
response = https.request(request)
puts response.read_body
import http.client
conn = http.client.HTTPSConnection("api.stg.keynua.com")
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
}
conn.request("GET", "/contract-manager-document-templates/api/{templateId}", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --location --request GET 'https://api.stg.keynua.com/contract-manager-document-templates/api/{templateId}' \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE'
const https = require("https");
var options = {
'method': 'GET',
'hostname': 'api.keynua.com',
'path': '/contract-manager-document-templates/api/{templateId}',
'headers': {
'x-api-key': 'YOUR-API-KEY-HERE',
'authorization': 'YOUR-API-TOKEN-HERE'
},
};
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
res.on("error", function (error) {
console.error(error);
});
});
req.end();
Si la plantilla fue obtenida satisfactoramente, el API retorna un Json estructurado como aparece en la sección de Plantilla de documento
Permite obtener una plantilla de documento.
HTTP Request
GET /contract-manager-document-templates/api/{templateId}
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Generar documentos rellenados
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://api.stg.keynua.com/contract-manager-document-templates/api/create-filled-files/{templateId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
request["authorization"] =
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["Content-Type"] = "application/json"
request.body = "{\n \"fieldValues\": [\n {\n \"name\": \"email-0\",\n \"value\": \"user@mail.com\"\n },\n {\n \"name\": \"date-0\",\n \"value\": \"2020-10-09\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = json.dumps({
"fieldValues": [
{
"name": "email-0",
"value": "user@mail.com"
},
{
"name": "date-0",
"value": "2020-10-09"
}
]
})
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
'Content-Type': 'application/json'
}
conn.request("POST", "/contract-manager-document-templates/api/create-filled-files/{templateId}", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --location --request POST 'https://api.stg.keynua.com/contract-manager-document-templates/api/create-filled-files/{templateId} \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE'
--header 'Content-Type: application/json' \
--data-raw '{
"fieldValues": [
{
"name": "email-0",
"value": "user@mail.com"
},
{
"name": "date-0",
"value": "2020-10-09"
}
]
}'
const https = require("https");
var options = {
method: 'POST',
hostname: 'api.stg.keynua.com',
path: '/contract-manager-document-templates/api/create-filled-files/{templateId',
headers: {
"x-api-key": "YOUR-API-KEY-HERE",
"authorization": "YOUR-API-TOKEN-HERE"
"Content-Type": "application/json"
},
};
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
res.on("error", function (error) {
console.error(error);
});
});
var postData = JSON.stringify({
"fieldValues": [
{
"name": "email-0",
"value": "user@mail.com"
},
{
"name": "date-0",
"value": "2020-10-09"
}
]
});
req.write(postData);
req.end();
Success response:
{
"files": [
{
"id": "b5d1b359-3736-424b-b83d-f0d0da910a89",
"storageId": "eyJidWNrZXQiOiJjb250cmFjdC1tYW5hZ2VyLWRvY3Vt",
"url": "https://s3.amazonaws.com/id-del-documento",
"size": 8568,
"sha256": "edd34e53e6b709fc4344f6799a8c228320e879fd7f92c95ed6ad8d7c4e0cd812"
},
{
"id": "428c25aa-6d9e-405e-9c19-9fafc9f1a3ec",
"storageId": "eyJidWNrZXQiOiJjb250cmFjdC1tYW5hZ2VyLWRvY3Vt",
"url": "https://s3.amazonaws.com/id-del-documento",
"size": 56628,
"sha256": "b4b488d71896341ff6520881e56da7e5cfe41a603de5f16eef68114c2c9acda3"
}
]
}
En base a cada documento de una plantilla, este API genera otros documentos pdf que incluyen el valor de cada campo enviado.
HTTP Request
POST /contract-manager-document-templates/api/create-filled-files/{templateId}
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Content-Type | application/json |
Body
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
fieldValues | FieldValues[] | No | Lista de items que contienen el id y valor de cada campo |
Propiedades de FieldValues
Atributo | Tipo | Descripción |
---|---|---|
name | string | Id que indica a qué DocumentTemplateField de la plantilla corresponde value |
value | string | Valor del campo que es validado con las reglas de DocumentTemplateField |
Response body item
Atributo | Tipo | Descripción |
---|---|---|
id | string | Id del archivo dentro de la plantilla |
storageId | string | Id de almacenamiento. Se puede utilizar para crear contratos. |
url | string | Url para descargar el documento generado |
size | number | Tamaño en bytes del documento generado |
sha256 | string | Hash sha256 del documento generado |
Webhooks
Los Webhooks permiten suscribirte a ciertos eventos de un Contrato o de una Verificación de identidad. Por ejemplo cuando un contrato es creado, cuando ocurre un error en el proceso de firma o el contrato ha sido firmado satisfactoriamente. Cuando ocurre uno de estos eventos, enviaremos un request HTTP POST a la API configurada en el webhook.
Configuración del Webhook
Una vez ya tengas una cuenta en el ambiente de pruebas de Keynua, puedes acceder a la sección Developers y configurar tu Webhook.
Si tu API necesita unos headers específicos, puedes agregarlo en la configuración del Webhook y nosotros lo enviaremos en cada request. También puedes desactivar las notificaciones de eventos para las verificaciones de identidad luego de crear el webhook.
Los eventos son disparados por las mismas circunstancias para contratos y para verificación de identidad. Entre los eventos que puedes escoger están:
Evento | Descripción |
---|---|
Created | Serás notificado cuando un contrato o verificación de identidad fue creado satisfactoriamente |
Started | Serás notificado cuando un contrato o verificación de identidad fue creado satisfactoriamente y está listo para ser firmado o completado. Recomendamos usar este evento en lugar del evento Created ya que este evento te notificará cuando el contrato está listo para comenzar el proceso de firma |
Finished | Serás notificado cuando el contrato o verificación de identidad ha sido completado por todos y finalizó correctamente |
Deleted | Serás notificado cuando el contrato ha sido eliminado |
InputProvided | Serás notificado cuando se asigne el valor del atributo inputProvidedAt del contrato. Este evento solo se notifica la primera vez que el contrato se inicia |
ItemWorking | Serás notificado cada vez que se comienza a procesar un Item |
ItemSuccess | Serás notificado cada vez que un Item ha concluído satisactoriamente |
ItemError | Serás notificado cada vez que ocurre un error en un Item |
OTPCreated | Serás notificado cada vez que se envíe un OTP de tipo webhook al usuario |
Una vez configurado el Webhook, te llegará un email de confirmación al correo que ingresaste. Luego, debes seleccionar la opción Habilitar para poder activar el Webhook. Keynua enviará un HTTP POST al API configurado y será activado si cumple estos requisitos:
- El API debe ser de acceso público
- El API debe ser HTTPS
- El API debe retornar status code 200 y el body del response debe ser
KEYNUA
Una vez tengas habilitado tu Webhook, puedes comenzar a escuchar las notificaciones de tus contratos siguiendo la siguiente Especificación del Webhook.
Especificación del Webhook
El request tendrá la siguiente estructura
Headers
{
"headers": {
"Content-Type": "application/json",
"X-Keynua-Webhook-Type": "ContractFinished",
"X-Keynua-Webhook-TS": "1604957455847",
"X-Keynua-Webhook-Token": "12fafbc...",
"X-Keynua-Webhook-Sig": "ec7584cb...",
"X-Keynua-Webhook-SigV2": "f2a13aa..."
}
}
Key | Value |
---|---|
Content-Type | application/json |
x-keynua-webhook-sig | Firma del request para el control de la manipulación de la petición. Para más información revisa la sección de Verificar Keynua Signature Webhook |
x-keynua-webhook-sigV2 | Firma del request V2 para el control de la manipulación de la petición. Para más información revisa la sección de Verificar Keynua Signature Webhook V2 |
x-keynua-webhook-ts | Numero de milisegundos desde UNIX Epoch (01/01/1970) cuando se envió el evento |
x-keynua-webhook-type | Nombre del evento emitido |
x-keynua-webhook-token | Token unico generado por request con una integridad de 24 horas |
Body
{
"type": "ContractFinished",
"accountId": "d6c5ce27-fa63-4fb8-8f0f-83278c6b7985",
"payload": { ... }
}
Atributo | Tipo | Descripción |
---|---|---|
type | string | Nombre del tipo de evento emitido. Puede ser ContractCreated , ContractStarted , ContractItemUpdated , ContractFinished , ContractDeleted , IdentityVerificationCreated , IdentityVerificationStarted , IdentityVerificationFinished , IdentityVerificationItemUpdated , o OTPCreated |
accountId | string | Codigo de la cuenta propietaria del webhook |
payload | object | Datos del evento que varian segun el valor de type |
Tipos de Eventos Webhook
Keynua enviará un request a tu API configurado por cada Evento registrado. En esta tabla podrás ver la relación que existe entre cada evento registrado y los tipos de eventos disponibles
Evento del Webhook | Tipo de Evento |
---|---|
Created | ContractCreated o IdentityVerificationCreated |
Started | ContractStarted o IdentityVerificationStarted |
Finished | ContractFinished o IdentityVerificationFinished |
Deleted | ContractDeleted |
InputProvided | ContractInputProvided |
ItemWorking | ContractItemUpdated o IdentityVerificationItemUpdated. Item.state working |
ItemSuccess | ContractItemUpdated o IdentityVerificationItemUpdated. Item.state success |
ItemError | ContractItemUpdated o IdentityVerificationItemUpdated. Item.state error |
OTPCreated | OTPCreated |
Propiedades de ContractCreated
Ejemplo de Body
{
"type": "ContractCreated",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"contractId": "00000000-0000-0000-0000-000000000001",
"reference": "",
"title": "Mi primer webhook",
"description": "Ejemplo de mi primer webhook",
"language": "es",
"createdAt": "2020-01-01T00:00:00.000Z",
"docCount": 0,
"itemCount": 0,
"userCount": 1,
"metadata": {}
}
}
Se emite cuando el contrato ha sido creado.
Atributo | Tipo | Descripción |
---|---|---|
contractId | string | Codigo del contrato |
reference | string | Referencia del contrato |
title | string | Titulo del contrato |
templateId | string | Identificador del Template |
description | string | Descripcion del contrato |
language | string | Idima del contrato |
createdAt | string | Fecha de creacion del contrato |
docCount | integer | Cantidad de documentos que tiene el contrato |
itemCount | integer | Cantidad de items que tiene el contrato |
userCount | integer | Cantidad de usuarios que tiene el contrato |
metadata | integer | Metada del contrato. Esta Metadata será la misma que se envió al crear un Contrato |
Propiedades de ContractStarted
Ejemplo de Body
{
"type": "ContractStarted",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"contractId": "00000000-0000-0000-0000-000000000001",
"reference": null,
"title": "Mi primer webhook",
"language": "es",
"createdAt": "2020-01-01T00:00:00.000Z",
"startedAt": "2020-01-01T01:00:00.000Z",
"docCount": 1,
"itemCount": 14,
"userCount": 1,
"longCode": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"shortCode": "123456",
"metadata": {},
"users": [
{
"id": 0,
"name": "John Doe",
"email": "example@keynua.com",
"phone": null,
"ref": null,
"groups": [
"signers"
]
}
],
"documents": [
{
"name": "sample.pdf",
"type": "application/pdf",
"size": 3028,
"url": "https..."
}
]
}
}
Se emite cuando el contrato está listo para ser firmado.
Atributo | Tipo | Descripción |
---|---|---|
contractId | string | Código del contrato |
reference | string | Referencia del contrato |
title | string | Titulo del contrato |
templateId | string | Identificador del Template |
description | string | Descripción del contrato |
language | string | Idioma del contrato |
createdAt | string | Fecha de creación del contrato |
startedAt | string | Fecha de inicio del proceso de firma del contrato |
docCount | integer | Cantidad de documentos que tiene el contrato |
itemCount | integer | Cantidad de items que tiene el contrato |
userCount | integer | Cantidad de usuarios que tiene el contrato |
metadata | integer | Metadata del contrato. Esta Metadata será la misma que se envió al crear un Contrato |
longCode | string | Código largo del contrato |
shortCode | string | Código corto del contrato para facilitar su identificación |
users | array | Arreglo de Usuarios del Contrato |
documents | array | Arreglo de Documentos del contrato |
Propiedades de ContractFinished
Ejemplo de Body
{
"type": "ContractFinished",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"contractId": "00000000-0000-0000-0000-000000000001",
"reference": null,
"title": "Testing WH CC",
"language": "es",
"createdAt": "2020-01-01T00:00:00.000Z",
"startedAt": "2020-01-01T01:00:00.000Z",
"finishedAt": "2020-01-01T02:00:00.000Z",
"docCount": 1,
"itemCount": 14,
"userCount": 1,
"longCode": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"shortCode": "123456",
"metadata": {},
"users": [
{
"id": 0,
"name": "John Doe",
"email": "example@keynua.com",
"phone": null,
"ref": null,
"groups": [
"signers"
],
"idInfo": {
"type": "pe-id",
"idNumber": "12345678",
"verificationDigit": "9",
"names": "Juan",
"lastName": "Perez Alvarez",
"birthDate": "1992-11-20",
"expirationDate": "2026-03-17"
"address": "Some address",
}
}
],
"documents": [
{
"name": "sample.pdf",
"type": "application/pdf",
"size": 3028,
"url": "https..."
}
],
"pdfItems": [
{
"title": "Certificado y documentos",
"url": "https://cmfiles.keynua.com/contracts/48ae1990...",
"individuals": [
{
"title": "pdf.24.1.test_contract_1.pdf",
"url": "https://cmfiles.keynua.com/contracts/48ae1990...",
"userIds": [0]
},
{
"title": "pdf.24.1.test_contract_2.pdf",
"url": "https://cmfiles.keynua.com/contracts/48ae1990...",
"userIds": [1]
}
]
}
],
"alerts": [
{
"type": "reniec",
"data": {
"code": "dniExpired",
"userId": 0,
"dni": "12345678"
}
}
]
}
}
Se emite cuando el contrato ha sido firmado por todos y ha finalizado correctamente.
Atributo | Tipo | Descripción |
---|---|---|
contractId | string | Código del contrato |
reference | string | Referencia del contrato |
title | string | Titulo del contrato |
templateId | string | Identificador del Template |
description | string | Descripción del contrato |
language | string | Idioma del contrato |
createdAt | string | Fecha de creación del contrato |
startedAt | string | Fecha de inicio del proceso de firma del contrato |
finishedAt | string | Fecha de finalización del proceso de firma del contrato |
docCount | integer | Cantidad de documentos que tiene el contrato |
itemCount | integer | Cantidad de items que tiene el contrato |
userCount | integer | Cantidad de usuarios que tiene el contrato |
metadata | integer | Metadata del contrato. Esta Metadata será la misma que se envió al crear un Contrato |
longCode | string | Código largo del contrato |
shortCode | string | Código corto del contrato para facilitar su identificación |
users | array | Arreglo de Usuarios del Contrato |
documents | array | Arreglo de Documentos del contrato. Acá encontrarás los documentos originales del contrato, NO el documento final de firma. Si lo que quieres es el documento final de firma, podrás obtenerlo desde el Item PDF en ContractItemUpdated |
pdfItems | array | Arreglo de PDF Items. Este incluirá información sobre los documentos finales del contrato y te permitirá descargarlos. Para identificaciones este atributo no existe. |
alerts | array | Arreglo de Alertas del contrato |
Propiedades de un PDF item
Contiene datos que permiten obtener los documentos finales del contrato.
Atributo | Tipo | Descripción |
---|---|---|
title | string | Título del item |
url | string | URL que permite descargar el documento. Expira en 12 horas |
individuals | array | Arreglo de documentos individuales cada uno con las firmas de las personas correspondientes. Solo es incluído en contratos configurados para producir documentos individuales. |
Propiedades de un documento individual
Atributo | Tipo | Descripción |
---|---|---|
title | string | Nombre del documento |
url | string | URL que permite descargar el documento. Expira en 12 horas |
userIds | array | Arreglo de números. Son los ids de los usuarios que firmaron el documento individual. Si el contrato no ha sido configurado para tener firmantes por documento, entonces este atributo no será incluido y se puede asumir que todos los firmantes han firmado este documento. |
Propiedades de ContractDeleted
Ejemplo de Body
{
"type": "ContractDeleted",
"accountId": "3c6ed45d-93e7-49b1-a6e4-99e274dffe15",
"payload": {
"language": "es",
"reference": "ref",
"contractId": "0a957760-910e-11ec-a9d7-d9cff2a71c0ee1",
"accountId": "3c6ed45d-93e7-49b1-a6e4-99e274dffe15",
"createdAt": "2022-02-18T22:56:43.478Z",
"startedAt": "2022-02-18T22:56:46.506Z",
"accountEmail": "john.doe@gmail.com",
"organizationId": "48101c38-f770-41a8-88ab-258e672d88bd",
"accountName": "John Doe",
"title": "Rent contract",
"templateId": "rent-template",
"docCount": 1,
"itemCount": 23,
"userCount": 1,
"metadata": {
"customAttr": "customData"
},
"deletedAt": "2022-02-24T00:00:18.622Z"
}
}
Se emite cuando el contrato ha sido eliminado.
Atributo | Tipo | Descripción |
---|---|---|
language | string | Idima del contrato |
reference | string | Referencia del contrato |
contractId | string | Código del contrato |
accountId | string | Código de la cuenta propietaria del webhook |
createdAt | string | Fecha de creacion del contrato |
startedAt | string | Fecha de inicio del proceso de firma del contrato |
accountEmail | string | Email de la cuenta creadora del contrato |
organizationId | string o undefined | Código de la organización de la cuenta creadora del contrato |
accountName | string | Nombre de la persona creadora del contrato |
title | string | Titulo del contrato |
templateId | string | Identificador del Template |
docCount | integer | Cantidad de documentos que tiene el contrato |
itemCount | integer | Cantidad de items que tiene el contrato |
userCount | integer | Cantidad de usuarios que tiene el contrato |
metadata | integer | Metada del contrato. Esta Metadata será la misma que se envió al crear un Contrato |
deletedAt | string | Fecha de eliminación del contrato |
Propiedades de ContractItemUpdated
Ejemplo de Body
{
"type": "ContractItemUpdated",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"contractId": "00000000-0000-0000-0000-000000000001",
"reference": null,
"title": "Testing WH CC",
"language": "es",
"createdAt": "2020-01-01T00:00:00.000Z",
"startedAt": "2020-01-01T01:00:00.000Z",
"docCount": 1,
"itemCount": 14,
"userCount": 1,
"longCode": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"shortCode": "123456",
"metadata": {},
"item": {
"id": 0,
"refId": "signersemail",
"state": "working",
"version": 1,
"stageIndex": 0,
"type": "email",
"title": "Mail de inicio de firma",
"value": null
},
"user": {
"id": 0,
"name": "John Doe",
"email": "example@keynua.com",
"phone": null,
"ref": null,
"groups": [
"signers"
]
}
}
}
Se emite cuando un elemento del contrato ha cambiado de estado. Los estados pueden ser working
, success
, error
Atributo | Tipo | Descripción |
---|---|---|
contractId | string | Código del contrato |
reference | string | Referencia del contrato |
title | string | Titulo del contrato |
templateId | string | Identificador del Template |
description | string | Descripción del contrato |
language | string | Idioma del contrato |
createdAt | string | Fecha de creación del contrato |
startedAt | string | Fecha de inicio del proceso de firma del contrato |
docCount | integer | Cantidad de documentos que tiene el contrato |
itemCount | integer | Cantidad de items que tiene el contrato |
userCount | integer | Cantidad de usuarios que tiene el contrato |
metadata | integer | Metadata del contrato. Esta Metadata será la misma que se envió al crear un Contrato |
longCode | string | Código largo del contrato |
shortCode | string | Código corto del contrato para facilitar su identificación |
item | object | Item del contrato que ha cambiado de estado |
user | object | Usuario al que pertenece el elemento modificado. Si el valor es null el elemento le pertenece a todos los usuarios |
Propiedades de ContractInputProvided
Ejemplo de Body
{
"type": "ContractInputProvided",
"accountId": "00000000-0000-0000-0000-000000000001",
"payload":{
"contractId": "00000000-0000-0000-0000-000000000001",
"reference": null,
"title": "Contrato de trabajo",
"templateId": "draw-simple",
"language": "es",
"createdAt": "2024-05-06T17:53:58.549Z",
"startedAt": "2024-05-06T17:53:59.093Z",
"inputProvidedAt": "2024-05-06T17:55:36.246Z",
"docCount": 1,
"itemCount": 7,
"userCount": 1,
"longCode": "8dc1757e94522e4719a635b7a7532052b24431632a01622cf4ee5cb2552db28b",
"shortCode": "817579",
}
}
Se emite cuando se asigna el valor del atributo inputProvidedAt
del contrato.
Atributo | Tipo | Descripción |
---|---|---|
accountId | string | Identificador único de la cuenta con la que se creó el contrato |
contractId | string | Identificador único del contrato |
reference | string | Referencia del contrato |
title | string | Titulo del contrato |
templateId | string | Identificador del Template |
language | string | Idioma del contrato |
createdAt | string | Fecha de creación del contrato |
startedAt | string | Fecha de inicio del proceso de firma del contrato |
inputProvidedAt | string | Fecha de inicio del proceso de firma del contrato |
docCount | integer | Cantidad de documentos que tiene el contrato |
itemCount | integer | Cantidad de items que tiene el contrato |
userCount | integer | Cantidad de usuarios que tiene el contrato |
longCode | string | Código largo del contrato |
shortCode | string | Código corto del contrato para facilitar su identificación |
metadata | object | Metadata del contrato |
Propiedades de IdentityVerificationCreated
Ejemplo de Body
{
"type": "IdentityVerificationCreated",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"language": "es",
"reference": "12345678",
"contractId": "00000000-0000-0000-0000-000000000000",
"documentNumber": "12345678",
"id": "00000000-0000-0000-0000-000000000000",
"accountId": "00000000-0000-0000-0000-000000000000",
"createdAt": "2020-01-01T00:00:00.000Z",
"accountEmail": "account@mail.com",
"organizationId": "00000000-0000-0000-0000-000000000000",
"accountName": "Patrick Star",
"title": "Identificación de 12345678"
}
}
Se emite cuando una verificación de identidad ha sido creada.
Atributo | Tipo | Descripción |
---|---|---|
language | string | Lenguaje con el cual se completará el proceso de identificación |
reference | string | Campo libre. Útil para realizar búsquedas. |
contractId | string | Id interno |
documentNumber | string | Número de documento nacional de identificación |
id | string | Identificador único de la verificación |
accountId | string | Id de la cuenta que creó la verificación |
createdAt | string | Fecha y hora de creación en formato ISO |
accountEmail | string | Email de la cuenta que creó la verificación |
organizationId | string | Id de la organización en la que se creó la verificación |
accountName | string | Nombre de la cuenta que creó la verificación |
title | string | Título de la verificación |
Propiedades de IdentityVerificationStarted
Ejemplo de Body
{
"type": "IdentityVerificationStarted",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"language": "es",
"reference": "12345678",
"contractId": "00000000-0000-0000-0000-000000000000",
"documentNumber": "12345678",
"id": "00000000-0000-0000-0000-000000000000",
"accountId": "00000000-0000-0000-0000-000000000000",
"createdAt": "2020-01-01T00:00:00.000Z",
"startedAt": "2020-01-01T00:00:00.000Z",
"accountEmail": "account@mail.com",
"organizationId": "00000000-0000-0000-0000-000000000000",
"accountName": "Patrick Star",
"title": "Identificación de 12345678",
"userEmail": "user@mail.com",
"userPhone": "23456789",
"userToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...ZlOWJiMC1hNmUzLTExZWItOWEyYy0xMWZjMzM0ODY"
}
}
Se emite cuando una verificación de identidad está lista para ser completada.
Atributo | Tipo | Descripción |
---|---|---|
language | string | Lenguaje con el cual se completará el proceso de identificación |
reference | string | Campo libre. Útil para realizar búsquedas. |
contractId | string | Id interno |
documentNumber | string | Número de documento nacional de identificación |
id | string | Identificador único de la verificación |
accountId | string | Id de la cuenta que creó la verificación |
createdAt | string | Fecha y hora de creación en formato ISO |
startedAt | string | Fecha y hora en formato ISO del momento en que la verificación está lista para ser completada. |
accountEmail | string | Email de la cuenta que creó la verificación |
organizationId | string | Id de la organización en la que se creó la verificación |
accountName | string | Nombre de la cuenta que creó la verificación |
title | string | Título de la verificación |
userEmail | string | Email del verificante en el cual recibirá el link de inicio del proceso |
userPhone | string | Teléfono celular del verificante en el cual recibirá el link de inicio del proceso |
userToken | string | Token con el cual se puede armar el link donde se realizará la verificación. Por ejemplo: https://sign.keynua.com/index.html?token={token} |
Propiedades de IdentityVerificationFinished
Ejemplo de Body
{
"type": "IdentityVerificationFinished",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"language": "es",
"reference": "12345678",
"contractId": "00000000-0000-0000-0000-000000000000",
"documentNumber": "12345678",
"id": "00000000-0000-0000-0000-000000000000",
"accountId": "00000000-0000-0000-0000-000000000000",
"createdAt": "2020-01-01T00:00:00.000Z",
"startedAt": "2020-01-01T00:00:00.000Z",
"accountEmail": "account@mail.com",
"organizationId": "00000000-0000-0000-0000-000000000000",
"accountName": "Patrick Star",
"title": "Identificación de 12345678",
"userEmail": "user@mail.com",
"userPhone": "23456789",
"userToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...ZlOWJiMC1hNmUzLTExZWItOWEyYy0xMWZjMzM0ODY",
"userIdInfo": {
"type": "pe-id",
"idNumber": "12345678",
"verificationDigit": "9",
"names": "Juan",
"lastName": "Perez Alvarez",
"birthDate": "1992-11-20",
"expirationDate": "2026-03-17"
"address": "Some address",
},
"alerts": [
{
"type": "reniec",
"data": {
"code": "dniExpired",
"userId": 0,
"dni": "12345678"
}
}
]
}
}
Se emite cuando una verificación de identidad ha sido completada por la persona y ha finalizado correctamente.
Atributo | Tipo | Descripción |
---|---|---|
language | string | Lenguaje con el cual se completará el proceso de identificación |
reference | string | Campo libre. Útil para realizar búsquedas. |
contractId | string | Id interno |
documentNumber | string | Número de documento nacional de identificación |
id | string | Identificador único de la verificación |
accountId | string | Id de la cuenta que creó la verificación |
createdAt | string | Fecha y hora de creación en formato ISO |
startedAt | string | Fecha y hora en formato ISO del momento en que la verificación está lista para ser completada. |
accountEmail | string | Email de la cuenta que creó la verificación |
organizationId | string | Id de la organización en la que se creó la verificación |
accountName | string | Nombre de la cuenta que creó la verificación |
title | string | Título de la verificación |
userEmail | string | Email del verificante en el cual recibirá el link de inicio del proceso |
userPhone | string | Teléfono celular del verificante en el cual recibirá el link de inicio del proceso |
userToken | string | Token con el cual se puede armar el link donde se realizará la verificación. Por ejemplo: https://sign.keynua.com/index.html?token={token} |
userIdInfo | string | Información obtenida del OCR del documento enviado por el firmante. De momento, esta información se devolverá solamente para Identificaciones Peruanas. La información de la dirección (address) se devolverá solamente si el usuario también envía la parte trasera del DNI |
alerts | array | Arreglo de Alertas de la identificación. |
Propiedades de IdentityVerificationItemUpdated
Ejemplo de Body
{
"type": "IdentityVerificationItemUpdated",
"accountId": "00000000-0000-0000-0000-000000000000",
"payload": {
"language": "es",
"reference": "12345678",
"contractId": "00000000-0000-0000-0000-000000000000",
"documentNumber": "12345678",
"id": "00000000-0000-0000-0000-000000000000",
"accountId": "00000000-0000-0000-0000-000000000000",
"createdAt": "2020-01-01T00:00:00.000Z",
"startedAt": "2020-01-01T00:00:00.000Z",
"accountEmail": "account@mail.com",
"organizationId": "00000000-0000-0000-0000-000000000000",
"accountName": "Patrick Star",
"title": "Identificación de 12345678",
"userEmail": "user@mail.com",
"userPhone": "23456789",
"userToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...ZlOWJiMC1hNmUzLTExZWItOWEyYy0xMWZjMzM0ODY",
"item": {
"id": 0,
"reference": "signersemail",
"state": "working",
"version": 1,
"stageIndex": 0,
"type": "email",
"title": "Mail de inicio de firma",
"value": null
}
}
}
Se emite cuando un item de una verificación de identidad cambia de estado. Los estados pueden ser working
, success
, error
.
Atributo | Tipo | Descripción |
---|---|---|
language | string | Lenguaje con el cual se completará el proceso de identificación |
reference | string | Campo libre. Útil para realizar búsquedas. |
contractId | string | Id interno |
documentNumber | string | Número de documento nacional de identificación |
id | string | Identificador único de la verificación |
accountId | string | Id de la cuenta que creó la verificación |
createdAt | string | Fecha y hora de creación en formato ISO |
startedAt | string | Fecha y hora en formato ISO del momento en que la verificación está lista para ser completada. |
accountEmail | string | Email de la cuenta que creó la verificación |
organizationId | string | Id de la organización en la que se creó la verificación |
accountName | string | Nombre de la cuenta que creó la verificación |
title | string | Título de la verificación |
userEmail | string | Email del verificante en el cual recibirá el link de inicio del proceso |
userPhone | string | Teléfono celular del verificante en el cual recibirá el link de inicio del proceso |
userToken | string | Token con el cual se puede armar el link donde se realizará la verificación. Por ejemplo: https://sign.keynua.com/index.html?token={token} |
item | object | Item del contrato que ha cambiado de estado |
Propiedades de OTPCreated
Ejemplo de Body
{
"type": "OTPCreated",
"accountId": "00000000-0000-0000-0000-000000000001",
"payload": {
"refId": "00000000-0000-0000-0000-000000000002",
"userId": "0",
"accountId": "00000000-0000-0000-0000-000000000001",
"organizationId": "00000000-0000-0000-0000-000000000001",
"reference": "Referencia",
"userName": "Manuel Silva",
"code": "55sm9z",
"resendInSec": 480,
"availableAttempts": 5,
"language": "es",
"metadata": {}
}
}
Se emite cuando se envía un OTP de tipo webhook al usuario.
Atributo | Tipo | Descripción |
---|---|---|
refId | string | Identificador único del contrato |
userId | string | Identificador único del usuario en el contrato |
accountId | string | Identificador único de la cuenta con la que se creó el contrato |
organizationId | string | Identificador único de la organización con la que se creó el contrato |
reference | string | Referencia del contrato |
userName | string | El nombre del usuario |
code | string | Código OTP generado |
resendInSec | integer | En cuantos segundos se podrá solicitar el envío de un nuevo código |
availableAttempts | integer | Cuantos intentos aún quedan disponibles |
language | string | Lenguaje del contrato |
metadata | object | Metadata del contrato |
Propiedades de un Usuario Webhook
{
"id": 0,
"name": "John Doe",
"email": "example@keynua.com",
"phone": null,
"ref": null,
"groups": [
"signers"
]
}
Atributo | Tipo | Descripción |
---|---|---|
id | integer | Identificador único del usuario en el contrato |
name | string | El nombre del usuario |
string | El correo electrónico del usuario | |
phone | string | El teléfono del usuario |
groups | array | Nombre de los grupos a los que pertenece el usuario |
Propiedades de un Documento Webhook
{
"name": "sample.pdf",
"type": "application/pdf",
"size": 3028,
"url": "https..."
}
Atributo | Tipo | Descripción |
---|---|---|
name | string | Nombre del documento |
type | string | Tipo del documento en formato MIME |
size | integer | Peso del documento en bytes |
url | integer | Link del documento. Expira en 12 horas |
Propiedades de una Alerta
Atributo | Tipo | Descripción |
---|---|---|
type | string | Tipo de alerta. reniec |
data | object | Información de la alerta |
La información de la alerta tiene las siguientes propiedades:
Atributo | Tipo | Descripción |
---|---|---|
code | string | Codigo de la alerta. dniExpired |
userId | integer | ID del usuario, para las identificaciones siempre es 0 ya que el flujo solo tiene un participante. |
dni | string | Número del documento expirado |
Verificar Keynua Signature Webhook
SHA_256(requestPayloadAsString + ts + webHookSecret)
Si quieres verificar la integridad del payload y asegurarte de que Keynua es quién está golpeando tu API Webhook, debes verificar el Signature que envía Keynua en el header X-Keynua-Webhook-Sig
Para verificar este valor necesitas:
- El object payload del body
body.payload
como string - El valor del header
X-Keynua-Webhook-TS
- El valor del
secret
que obtuviste al crear el webhook
Luego de ello debes concatenar todos estos valores y aplicarle SHA256, el resultado debe ser el mismo que el valor del header X-Keynua-Webhook-Sig
Verificar Keynua Signature Webhook V2
SHA_256(webhookToken + ts + webHookSecret)
Si quieres verificar que Keynua es quien está golpeando tu API Webhook, debes verificar el SignatureV2 que envía Keynua en el header X-Keynua-Webhook-SigV2
Para verificar este valor necesitas:
- El valor del header
X-Keynua-Webhook-Token
- El valor del header
X-Keynua-Webhook-TS
- El valor del
secret
que obtuviste al crear el webhook
Luego de ello debes concatenar todos estos valores y aplicarle SHA256, el resultado debe ser el mismo que el valor del header X-Keynua-Webhook-SigV2
OTP
Conjunto de APIs que permiten enviar, verificar y revisar códigos de un solo uso para realizar la firma de documentos.
Métodos de envío
Existen diferentes canales de comunicación por OTP y los firmantes. El canal es definido en el template y tiene los siguientes valores:
Canal | Descripción |
---|---|
sms | Se envía el código al número del firmante a través de un sms. |
Se envía el código al correo del firmante. | |
webhook | Se envía el código al webhook definido por la cuenta que creo el contrato a través del evento OTPCreated |
Propiedades de Auth
ContractAuth
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
type | contract |
No | Tipo de autenticación. |
token | string | No | El token del usuario dado al crear el contrato. |
OwnerAuth
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
type | owner |
No | Tipo de autenticación. |
contractId | string | No | Identificador único del contrato |
userId | string | No | Identificador único del usuario en el contrato |
GenericAuth
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
type | generic |
No | Tipo de autenticación. |
id | string | No | Identificador genérico. |
Enviar OTP
require "uri"
require "net/http"
url = URI("https://api.stg.keynua.com/send-otp/v1")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n\t\"auth\": {\n\t\t\"type\": \"contract\",\n\t\t\"token\": \"eyJ0eXAiOiJ...Dq_5VSiZo\"\n\t}\n}"
response = https.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = json.dumps({
{
"auth": {
"type": "contract",
"token": "eyJ0eXAiOiJ...Dq_5VSiZo"
}
}
})
headers = {
'Content-Type': 'application/json'
}
conn.request("PUT", "/send-otp/v1", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request PUT \
--url https://api.stg.keynua.com/send-otp/v1 \
--header 'Content-Type: application/json' \
--data '{
"auth": {
"type": "contract",
"token": "eyJ0eXAiOiJKV1Q...Dq_5VSiZo"
}
}'
const data = JSON.stringify({
"auth": {
"type": "contract",
"token": "eyJ0eXA..._2iDq_5VSiZo"
}
});
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
}
});
xhr.open("PUT", "https://api.stg.keynua.com/send-otp/v1");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
Success response
{
"sent": true,
"channel": "sms",
"resendInSec": 60,
"availableAttempts": 3
}
Permite enviar un código OTP al usuario dueño del token.
HTTP Request
PUT https://api.stg.keynua.com/send-otp/v1
Request body
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
auth | ContractAuth | No | Permite identificar el OTP del usuario y contrato |
Response body
Atributo | Tipo | Descripción |
---|---|---|
sent | boolean | Si el código OTP se envió o no. |
channel | string | Por qué medio se realizó el envío del código. |
resendInSec | number | En cuantos segundos se podrá solicitar el envío de un nuevo código. |
availableAttempts | number | Cuantos intentos aún quedan disponibles. |
Crear código OTP como Owner
require "uri"
require "net/http"
url = URI("https://api.stg.keynua.com/send-otp/v1/create-code-as-owner")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = 'YOUR-API-KEY-HERE'
request["authorization"] = 'YOUR-API-TOKEN-HERE'
request["Content-Type"] = 'application/json'
request.body = "{\n\t\"type\": \"owner\",\n\t\"contractId\": \"00000000-0000-0000-0000-000000000001\",\n\t\"userId\": \"0\"\n}"
response = https.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = json.dumps({
{
"auth": {
"type": "owner",
"contractId": "00000000-0000-0000-0000-000000000001",
"userId": "0"
}
}
})
headers = {
'x-api-key': "YOUR-API-KEY-HERE",
'authorization': "YOUR-API-TOKEN-HERE",
'Content-Type': 'application/json'
}
conn.request("POST", "/send-otp/v1/create-code-as-owner", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request POST \
--url https://api.stg.keynua.com/send-otp/v1/create-code-as-owner \
--header 'x-api-key: YOUR-API-KEY-HERE' \
--header 'authorization: YOUR-API-TOKEN-HERE' \
--header 'Content-Type: application/json' \
--data '{
"auth": {
"type": "owner",
"contractId": "00000000-0000-0000-0000-000000000001",
"userId": "0"
}
}'
const data = JSON.stringify({
"auth": {
"type": "owner",
"contractId": "00000000-0000-0000-0000-000000000001",
"userId": "0"
}
});
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://api.stg.keynua.com/send-otp/v1/create-code-as-owner");
xhr.setRequestHeader("x-api-key", "YOUR-API-KEY-HERE");
xhr.setRequestHeader("authorization", "YOUR-API-TOKEN-HERE");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
Success response
{
"code": "qwe123",
"resendInSec": 60,
"availableAttempts": 3
}
Permite crear y obtener un nuevo código OTP (Sin enviarle el código al usuario). De manera similar al endpoint anterior y según la configuración del contrato, se limita la cantidad de códigos generados en un lapso de tiempo.
HTTP Request
POST https://api.stg.keynua.com/send-otp/v1/create-code-as-owner
Headers
Key | Value |
---|---|
x-api-key | your-api-key |
authorization | your-api-token |
Content-Type | application/json |
Request body
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
auth | OwnerAuth o ContractAuth | No | Permite identificar el OTP del usuario y contrato |
Response body
Atributo | Tipo | Descripción |
---|---|---|
code | string | El código OTP |
resendInSec | number | En cuantos segundos se podrá solicitar un nuevo código. |
availableAttempts | number | Cuantos intentos aún quedan disponibles. |
Verificar OTP
require "uri"
require "net/http"
url = URI("https://api.stg.keynua.com/send-otp/v1")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n\t\"auth\": {\n\t\t\"type\": \"contract\",\n\t\t\"token\": \"eyJ0eXA...2iDq_5VSiZo\"\n\t},\n\t\"code\": \"GtEyfgCb\"\n}"
response = https.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = json.dumps({
{
"auth": {
"type": "contract",
"token": "eyJ0eXAiOiJ...Dq_5VSiZo"
},
"code": "as34Er"
}
})
headers = {
'Content-Type': 'application/json'
}
conn.request("POST", "/send-otp/v1", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request POST \
--url https://api.stg.keynua.com/send-otp/v1 \
--header 'Content-Type: application/json' \
--data '{
"auth": {
"type": "contract",
"token": "eyJ0..._5VSiZo"
},
"code": "GtEyfgCb"
}'
const data = JSON.stringify({
"auth": {
"type": "contract",
"token": "eyJ0eXA..._2iDq_5VSiZo"
},
"code": "GtEyfgCb"
});
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://api.stg.keynua.com/send-otp/v1");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
Success response
{
"otpToken": "eyJ0eXA...qivpYpLm9R7LHid3w"
}
Permite verificar si el código OTP ingresado es correcto o no.
HTTP Request
POST https://api.stg.keynua.com/send-otp/v1
Request body
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
auth | ContractAuth | No | Permite identificar el OTP del usuario y contrato |
code | string | No | Código OTP ingresado por el firmante. |
Response body
Atributo | Tipo | Descripción |
---|---|---|
otpToken | string | Token que debe ser enviado en el Paso 3 al actualizar el valor de un item para demostrar que se ingresó correctamente el código OTP. |
Obtener información
require "uri"
require "net/http"
url = URI("https://api.stg.keynua.com/send-otp/v1/details")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n\t\"auth\": {\n\t\t\"type\": \"contract\",\n\t\t\"token\": \"eyJ0eXAiOiJ...Dq_5VSiZo\"\n\t}\n}"
response = https.request(request)
puts response.read_body
import http.client
import json
conn = http.client.HTTPSConnection("api.stg.keynua.com")
payload = json.dumps({
{
"auth": {
"type": "contract",
"token": "eyJ0eXAiOiJ...Dq_5VSiZo"
}
}
})
headers = {
'Content-Type': 'application/json'
}
conn.request("POST", "/send-otp/v1/details", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
curl --request POST \
--url https://api.stg.keynua.com/send-otp/v1/details \
--header 'Content-Type: application/json' \
--data '{
"auth": {
"type": "contract",
"token": "eyJ0eXAiOiJKV1Q...Dq_5VSiZo"
}
}'
const data = JSON.stringify({
"auth": {
"type": "contract",
"token": "eyJ0eXA..._2iDq_5VSiZo"
}
});
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://api.stg.keynua.com/send-otp/v1/details");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
Success response
{
"sent": true,
"channel": "sms",
"resendInSec": 55,
"availableAttempts": 3
}
Permite revisar el estado del código actual.
HTTP Request
POST https://api.stg.keynua.com/send-otp/v1/details
Request body
Atributo | Tipo | Opcional | Descripción |
---|---|---|---|
auth | ContractAuth | No | Permite identificar el OTP del usuario y contrato |
Response body
Atributo | Tipo | Descripción |
---|---|---|
sent | boolean | Si el código OTP se envió o no. |
channel | string | Por qué medio se realizó el envío del código. |
resendInSec | number | En cuantos segundos se podrá solicitar el envío de un nuevo código. |
availableAttempts | number | Cuantos intentos aún quedan disponibles. |
Errores
Code | Descripción |
---|---|
OUT_OF_DELIVERIES |
Se ha excedido la cantidad permitida de notificaciones. |
CODE_SENT_RECENTLY |
El código ya se envió y necesario esperar el tiempo definido en la configuración para poder solicitar uno nuevo. |
INVALID_AUTH |
Los valores enviados en auth no son correctos. |
USED_CODE |
Ya se verificó correctamente el código enviado. Es necesario solicitar uno nuevo para realizar otra verificación. |
EXPIRED_CODE |
El último código enviado ya venció. Es necesario solicitar uno nuevo para realizar otra verificación. |
OUT_OF_ATTEMPTS |
La configuración de OTP ya no permite más intentos. |
WRONG_CODE |
El código enviado no es el correcto. |
INVALID_TOKEN |
El token enviado dentro de auth no es el correcto. |
Errors
El API de Keynua usa los siguientes códigos de errores.
Error Code | Meaning |
---|---|
400 | Bad Request -- Tu request no es válido. |
401 | Unauthorized -- Las credenciales no son válidas o pueden haber expirado. |
403 | Forbidden -- Acceso denegado, es probable que no estés enviando las credenciales o sean incorrectas. |
404 | Not Found -- El Item que estás buscando no existe.. |
429 | Too Many Requests -- Tus request son muy consecutivos, baja la velocidad de los request! |
500 | Internal Server Error -- Tenemos problemas en nuestro servidores, intenta más tarde por favor. |
503 | Service Unavailable -- Estamos temporalmente fuera de servicio, intenta más tarde por favor. |