Ir al contenido

PIN-RUT Verificación de Identidad

El servicio PIN-RUT permite verificar la identidad de personas mediante un PIN numérico personal vinculado a su RUT chileno. La persona crea su PIN una sola vez y lo usa para autorizar operaciones solicitadas por tu sistema.

Casos de uso típicos:

  • Firma de contratos o documentos
  • Autorización de transacciones financieras
  • Confirmación de identidad en procesos de onboarding
  • Validación de operaciones sensibles

Antes de usar la API necesitas:

  1. Una API Key con rol FULL-API
  2. El tenant debe tener el servicio PIN_RUT habilitado
  3. Una integración PIN-RUT configurada con las URLs permitidas

Antes de crear transacciones, debes configurar una integración desde el panel de administración:

Configuración → PIN-RUT → Integraciones

CampoDescripción
SlugIdentificador único inmutable (ej: mi_app_prod). Se usa en cada request.
NombreNombre descriptivo que la persona verá en la pantalla de verificación
URIs de redirectURLs HTTPS donde el browser redirige tras completar la verificación
URLs de callbackURLs HTTPS donde se envían webhooks con el resultado
Orígenes iframeURLs HTTPS autorizadas para embeber la pantalla PIN en un iframe
URI de redirect defaultRedirect por defecto si no se especifica en cada transacción
CampoValor
Slugmi_app_prod
NombreMi Aplicación
Redirect URIshttps://miapp.cl/pin-callback
Callback URLshttps://miapp.cl/webhooks/pin
Redirect defaulthttps://miapp.cl/pin-callback

Tu Sistema Redcumbre Persona
│ │ │
│── POST /pin/transactions ──▶│ │
│ (Bearer token + body) │ │
│ │ │
│◀── authorize_url ──────────│ │
│ (+ transaction_id) │ │
│ │ │
│── Redirige browser ────────▶│ │
│ a authorize_url │ │
│ │── Pantalla de PIN ────────▶│
│ │ │
│ │◀── Persona ingresa PIN ───│
│ │ │
│◀── Webhook (callback_url) ─│ │
│ pin.transaction.authorized │
│ │ │
│ │── Redirect a redirect_uri ▶│
│ │ ?transaction_id=X │
│ │ &status=authorized │
│ │ &state=Y │
│ │ │
│── GET /result ─────────────▶│ │
│ (verificar estado final) │ │
│◀── { status: authorized } ─│ │

Pasos:

  1. Tu sistema crea una transacción con los datos de la operación
  2. Rediriges al usuario a la authorize_url retornada
  3. La persona ve los datos de la operación e ingresa su PIN
  4. Tu sistema recibe el resultado vía webhook y/o redirect
  5. Opcionalmente, consultas el resultado vía API

POST /{tenantSlug}/pin/transactions
Authorization: Bearer {api_key}
Content-Type: application/json
{
"integration_slug": "mi_app_prod",
"rut": "12.345.678-9",
"operation_type": "firma_contrato",
"operation_label": "Firmar Contrato de Servicios N° 2026-042",
"operation_detail": "Contrato por 12 meses",
"redirect_uri": "https://miapp.cl/pin-callback",
"callback_url": "https://miapp.cl/webhooks/pin",
"state": "session-abc-123"
}
CampoTipoRequeridoDescripción
integration_slugstringSlug de la integración configurada
rutstringRUT chileno de la persona (ej: 12.345.678-9 o 12345678-9)
operation_typestringTipo de operación en snake_case (máx. 50 chars)
operation_labelstringDescripción visible para la persona (máx. 200 chars)
operation_detailstringNoDetalle adicional de la operación
fullNamestringNoNombre completo de la persona (si no existe en el sistema)
redirect_uristringNoURL HTTPS de redirect. Debe estar en las URIs permitidas de la integración
callback_urlstringNoURL HTTPS para webhook. Debe estar en las URLs permitidas de la integración
statestringNoValor opaco devuelto sin modificar en redirect y webhook (máx. 2048 chars)
Ventana de terminal
curl -X POST "https://api.redcumbre.cl/{tenantSlug}/pin/transactions" \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{
"integration_slug": "mi_app_prod",
"rut": "12.345.678-9",
"operation_type": "firma_contrato",
"operation_label": "Firmar Contrato N° 2026-042",
"redirect_uri": "https://miapp.cl/pin-callback",
"callback_url": "https://miapp.cl/webhooks/pin",
"state": "session-abc-123"
}'
{
"success": true,
"data": {
"transaction_id": "cedd740a-e5a3-43a2-9896-5ac45dfdb4dc",
"authorize_url": "/p/pin/authorize/cedd740a-e5a3-43a2-9896-5ac45dfdb4dc",
"expires_at": "2026-05-09T23:35:04.594Z",
"operation_hash": "06860b21052299ad...",
"person_status": "has_pin"
}
}
CampoTipoDescripción
transaction_idstring (UUID)Identificador único de la transacción
authorize_urlstringRuta relativa para redirigir a la persona. Prefijar con la URL base de la plataforma
expires_atstring (ISO 8601)Fecha de expiración de la transacción
operation_hashstringHash SHA-256 de la operación (para verificación de integridad)
person_statusstring"has_pin" si la persona ya tiene PIN, "needs_creation" si debe crear uno primero

Construye la URL completa y redirige al usuario:

https://app.redcumbre.cl{authorize_url}

Por ejemplo:

https://app.redcumbre.cl/p/pin/authorize/cedd740a-e5a3-43a2-9896-5ac45dfdb4dc

Si person_status es "needs_creation", la plataforma guiará a la persona a crear su PIN antes de la verificación. No requiere acción adicional de tu parte.


GET /{tenantSlug}/pin/transactions/{transaction_id}/result
Authorization: Bearer {api_key}
{
"success": true,
"data": {
"transaction_id": "cedd740a-e5a3-43a2-9896-5ac45dfdb4dc",
"status": "authorized",
"integration_slug": "mi_app_prod",
"rut": "12.345.678-9",
"operation_type": "firma_contrato",
"operation_label": "Firmar Contrato N° 2026-042",
"created_at": "2026-05-09T23:30:04.594Z",
"authorized_at": "2026-05-09T23:33:01.538Z",
"expires_at": "2026-05-09T23:35:04.594Z",
"state": "session-abc-123"
}
}

Cancela una transacción pendiente antes de que la persona la complete:

POST /{tenantSlug}/pin/transactions/{transaction_id}/cancel
Authorization: Bearer {api_key}
{
"success": true,
"data": {
"success": true
}
}

Solo transacciones en estado pending pueden cancelarse. Si la transacción ya está en un estado terminal, recibirás un error 409.


EstadoTerminalDescripción
pendingNoPersona aún no completó la verificación
authorizedPIN ingresado correctamente — identidad verificada
failedPIN incorrecto reiterado o RUT bloqueado
expiredLa persona no completó antes del TTL
cancelledCancelada por el integrador o por la persona

Si configuraste un callback_url, recibirás webhooks cuando la transacción cambie a un estado terminal.

EventoCuándo
pin.transaction.authorizedPersona ingresó PIN correcto
pin.transaction.failedPIN incorrecto 5 veces o RUT bloqueado
pin.transaction.expiredTTL cumplido sin completar
pin.transaction.cancelledCancelada por integrador o persona
{
"event": "pin.transaction.authorized",
"timestamp": "2026-05-09T23:38:01.577Z",
"data": {
"transaction_id": "cedd740a-e5a3-43a2-9896-5ac45dfdb4dc",
"integration_id": "702191e3-e415-41dc-ac1b-0b66d2edccf9",
"rut": "12.345.678-9",
"operation_type": "firma_contrato",
"operation_label": "Firmar Contrato N° 2026-042",
"operation_hash": "06860b21052299ad...",
"authorized_at": "2026-05-09T23:38:01.538Z",
"status": "authorized",
"state": "session-abc-123",
"failure_reason": null
}
}
EventoCampos adicionales en data
pin.transaction.authorizedauthorized_at
pin.transaction.failedfailure_reason ("max_attempts_reached", "rate_limit_exceeded")
pin.transaction.expired
pin.transaction.cancelled

El sistema determina dónde enviar el webhook con esta prioridad:

  1. callback_url enviado en la transacción (per-request)
  2. URL global del webhook configurado en el tenant (fallback)
  3. Si ninguno existe → no se envía webhook (solo redirect)

Los headers personalizados configurados en el webhook global del tenant se incluyen siempre, independientemente de si el URL es per-request o global.


Cuando la persona completa la verificación (o cancela), el browser redirige a la redirect_uri con query parameters:

https://miapp.cl/pin-callback?transaction_id=cedd740a-...&status=authorized&state=session-abc-123
ParámetroDescripción
transaction_idUUID de la transacción
statusEstado final: authorized, cancelled
stateValor opaco que enviaste al crear la transacción

CódigoDescripciónCausa
400Validación fallidaRUT inválido, redirect_uri no en lista permitida, callback_url no permitida, máximo de pendientes alcanzado
401No autorizadoAPI key inválida, expirada o revocada
403ProhibidoServicio PIN_RUT no habilitado o rol insuficiente
404No encontradoIntegración no existe o está inactiva, transacción no encontrada
409ConflictoTransacción no está en estado pending (al cancelar)
422No procesableNo hay redirect_uri y la integración no tiene default
423BloqueadoRUT bloqueado por demasiados intentos fallidos
{
"message": "Integración activa con slug \"mi_app_prod\" no encontrada",
"error": "Not Found",
"statusCode": 404
}
{
"code": "pin_blocked",
"message": "RUT is blocked due to too many failed attempts",
"statusCode": 423
}

El sistema implementa un rate limit global de intentos fallidos:

  • Máximo 10 intentos fallidos por RUT en 1 hora (cross-tenant)
  • Al superar el límite, el PIN del RUT se bloquea inmediatamente
  • Transacciones nuevas para un RUT bloqueado retornan 423 Locked
  • El bloqueo es global: protege contra ataques distribuidos desde múltiples integraciones

ConceptoLímite
Transacciones pendientes por RUT × integración3
Intentos de PIN por transacción5
Intentos fallidos globales por RUT/hora10
TTL de transacción (persona con PIN)5 minutos
TTL de transacción (persona sin PIN)30 minutos
Tamaño máximo de state2048 caracteres
Tamaño máximo de operation_label200 caracteres

// 1. Crear transacción
const response = await fetch(
`https://api.redcumbre.cl/${tenantSlug}/pin/transactions`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
integration_slug: 'mi_app_prod',
rut: '12.345.678-9',
operation_type: 'firma_contrato',
operation_label: 'Firmar Contrato N° 2026-042',
redirect_uri: 'https://miapp.cl/pin-callback',
callback_url: 'https://miapp.cl/webhooks/pin',
state: sessionId,
}),
}
);
const { data } = await response.json();
// 2. Redirigir al usuario
window.location.href = `https://app.redcumbre.cl${data.authorize_url}`;
// 3. En la página de callback, verificar resultado
const params = new URLSearchParams(window.location.search);
const txId = params.get('transaction_id');
const status = params.get('status');
if (status === 'authorized') {
// Verificar server-side antes de tomar acción
const result = await fetch(
`https://api.redcumbre.cl/${tenantSlug}/pin/transactions/${txId}/result`,
{ headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const { data: tx } = await result.json();
if (tx.status === 'authorized') {
// Identidad verificada — proceder con la operación
}
}
app.post('/webhooks/pin', (req, res) => {
const { event, data } = req.body;
switch (event) {
case 'pin.transaction.authorized':
console.log(`✓ Identidad verificada: RUT=${data.rut}, tx=${data.transaction_id}`);
// Procesar autorización
break;
case 'pin.transaction.failed':
console.log(`✗ Verificación fallida: ${data.failure_reason}`);
break;
case 'pin.transaction.expired':
console.log(`⏰ Transacción expirada: ${data.transaction_id}`);
break;
case 'pin.transaction.cancelled':
console.log(`↩ Transacción cancelada: ${data.transaction_id}`);
break;
}
res.json({ received: true });
});