Ir al contenido

PINRUT Verificación de Identidad

El servicio PINRUT 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 PINRUT configurada con las URLs permitidas

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

Configuración → PINRUT → 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
Datos personales que recibe (sharedPersonalData)Los datos de la persona que la integración recibe de cada transacción autorizada. Hoy sólo full_name, el nombre completo leído de la cédula. Apagado por defecto

Si tu integración necesita identificar a la persona en la operación o documento que autorizó, puedes activar Nombre completo leído de la cédula en la integración (en la API, sharedPersonalData: ["full_name"] al crearla o actualizarla). Está apagado por defecto y la finalidad es una sola: identificar a la persona en la operación o documento que autorizó.

Con el dato activo:

  • Cada transacción debe indicar su callback_url. Sin ella, crear la transacción responde 422 con code: "callback_url_required". Por eso activarlo exige que la integración tenga al menos una URL de callback permitida: si no, la configuración responde 400 con code: "shared_personal_data_requires_callback_url".
  • La pantalla de autorización se lo dice a la persona antes de que autorice: «Al autorizar, compartiremos con {nombre de tu integración} tu nombre completo, tal como aparece en tu cédula, para identificarte en esta operación.»
  • El valor de operation_label se muestra como rótulo de la tarjeta de la operación, arriba del aviso, y no dentro de una frase. Por eso puede ser una etiqueta corta del tipo de operación —«Firma electrónica simple»— y ya no necesita ser un sintagma con artículo que calce dentro del texto del aviso.
  • El nombre llega sólo con la transacción autorizada, en el webhook pin.transaction.authorized y en la consulta de resultado, como full_name, y en el comprobante como el claim nombreCompleto.
  • Lo que cuenta es lo declarado al crear la transacción: si desactivas el dato antes de que la persona autorice, esa transacción no lo entrega; si lo activas después de crearla, tampoco.
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 autorización ▶│
│ │ │
│ │◀── Se autentica: PIN o cara│
│ │ │
│◀── 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 y la modalidad con que la persona autoriza
  2. Rediriges al usuario a la authorize_url retornada
  3. La persona ve los datos de la operación y se autentica con la modalidad que pediste
  4. Tu sistema recibe el resultado vía webhook y/o redirect
  5. Opcionalmente, consultas el resultado vía API
authentication_methodLa persona autoriza conCuándo usarla
pinSu PIN de 6 dígitos. Si todavía no tiene PIN, lo crea después de autenticarse con su cara, y crearlo autoriza la operaciónOperaciones frecuentes, donde el PIN basta
faceUna prueba de vida contra el reconocimiento facial de su identidad acreditada. El PIN no interviene: no se pide, y un PIN bloqueado no la impideOperaciones donde necesitas presencia de la persona, no sólo conocimiento

En las dos, si la persona no tiene su identidad acreditada, la plataforma la guía primero a acreditarla —cédula por ambos lados y prueba de vida— y después sigue con la modalidad que pediste. No haces nada distinto: es la misma URL.


POST /{tenantSlug}/pin/transactions
Authorization: Bearer {api_key}
Content-Type: application/json
{
"integration_slug": "mi_app_prod",
"rut": "12.345.678-9",
"authentication_method": "pin",
"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_slugstringSíSlug de la integración configurada
rutstringSíRUT chileno de la persona natural que va a autorizar (ej: 12.345.678-9 o 12345678-9). Nunca el RUT de una empresa: ver PINRUT es sólo para personas naturales
authentication_methodstringSíCon qué autoriza la persona: pin o face. No tiene valor por defecto: sin él, 400
operation_typestringSíTipo de operación en snake_case (máx. 50 chars)
operation_labelstringSíDescripción visible para la persona (máx. 200 chars)
operation_detailstringNoDescribe la operación que la persona va a autorizar (máx. 500 chars). No incluyas datos personales de otras personas ni datos sensibles, como información de salud. Se conserva como evidencia de la autorización y se anonimiza junto con ella.
operation_referencestringNoLa referencia que declara tu integración para esta operación, en formato sha256:<64 hex en minúsculas> (71 chars exactos). No se le muestra a la persona. Entra en el operation_hash y, cuando la envías, en el comprobante firmado; te vuelve en el webhook y en la consulta de resultado. No se normaliza ni se recorta: cualquier otro formato responde 400.
redirect_uristringNoURL HTTPS de redirect. Debe estar en las URIs permitidas de la integración
callback_urlstringNo*URL HTTPS para webhook. Debe estar en las URLs permitidas de la integración. *Obligatorio si la integración recibe datos personales (422 callback_url_required)
statestringNoValor opaco devuelto sin modificar en redirect y webhook (máx. 2048 chars)

PINRUT verifica la identidad de personas naturales: el rut que envías en el body tiene que ser el de la persona que va a autorizar, nunca el RUT de una empresa. Si envías un RUT de persona jurídica, la creación de la transacción responde:

HTTP/1.1 400 Bad Request
{
"code": "rut_de_persona_juridica",
"message": "PINRUT es sólo para personas naturales: el RUT ingresado corresponde a una persona jurídica (una empresa). Usa el RUT personal del titular, el de su cédula de identidad."
}
  • No se crea ninguna transacción ni queda rastro de la operación: el rechazo ocurre antes de cualquier escritura, antes de cualquier cobro y antes del 423 por PIN bloqueado.
  • El código rut_de_persona_juridica es estable: tu integración puede distinguirlo de otras causas de 400 (ver Códigos de Error) y mostrarle a quien opera tu sistema que el RUT ingresado no corresponde a una persona.
  • La clasificación es por rango de RUT: cualquier RUT cuyo cuerpo (sin dígito verificador) sea igual o mayor a 50.000.000 se trata como de persona jurídica. Es la misma regla que usa la verificación de identidad del resto de la plataforma; no consulta al SII.
  • Si tu sistema recibe el RUT de un formulario o de otro sistema, valida que corresponda a una persona antes de llamar a este endpoint, para no gastar un intento de creación con un RUT que nunca se va a poder verificar.
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",
"authentication_method": "face",
"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": "https://app.pinrut.cl/p/pin/authorize/7f3b9a61-2c4e-4d8f-b1a0-5e6d7c8b9a0f",
"expires_at": "2026-05-18T23:30:04.594Z",
"operation_hash": "06860b21052299ad..."
},
"sandbox": false
}
CampoTipoDescripción
transaction_idstring (UUID)Identificador único de la transacción
authorize_urlstring (URL)Dirección absoluta, en el dominio de PINRUT, a la que rediriges a la persona. Úsala tal cual: no le agregues nada delante. Contiene un identificador propio del enlace, distinto de transaction_id: no lo extraigas ni lo construyas
expires_atstring (ISO 8601)Límite absoluto de la transacción: la creación más 7 días y 48 horas, igual para toda transacción. Puede vencer antes (ver expiration_reason)
operation_hashstringHash SHA-256 de la operación (para verificación de integridad)

Redirige al usuario a authorize_url tal como viene en la respuesta: ya es la dirección completa, en el dominio de PINRUT. Por ejemplo:

https://app.pinrut.cl/p/pin/authorize/7f3b9a61-2c4e-4d8f-b1a0-5e6d7c8b9a0f

La pantalla le muestra primero la operación y quién la pide, y después la lleva por lo que le falte:

  • Con pin y PIN: ingresa su PIN.
  • Con face, o con pin y sin PIN: se autentica con su cara. Con pin, después crea su PIN, y crearlo autoriza.
  • Sin identidad acreditada, en las dos modalidades: la acredita primero —consentimiento, cédula por ambos lados y prueba de vida— y vuelve al mismo punto.

Los plazos cortos corren desde que la persona abre el enlace, no desde que creas la transacción: 5 minutos para ingresar el PIN y 30 minutos para la prueba de vida. La acreditación de identidad tiene el plazo de su sesión: hasta la creación más 7 días y 48 horas. Si nadie abre el enlace en 7 días, la transacción vence con not_started.

Al acreditar la identidad, la cédula que presenta la persona tiene que ser del RUT que declaraste al crear la transacción. Se compara apenas se lee la cédula, antes de la prueba de vida. Si es de otro RUT:

  • la transacción pasa de inmediato a failed con failure_reason: "rut_mismatch", y recibes pin.transaction.failed;
  • la persona ve que esa cédula no corresponde a quien debe autorizar la operación, y vuelve a tu sitio;
  • no hay reintento dentro de la misma transacción. Si corresponde, abre una transacción nueva (por ejemplo, con el RUT corregido si lo habías declarado mal);
  • no recibes ningún dato de la cédula presentada: ni el RUT que se leyó ni el nombre. Sólo el motivo.

Si la diferencia se descubre más tarde —por ejemplo, cuando una persona de nuestro equipo revisa la verificación—, la transacción termina igual en rut_mismatch, con su webhook: nunca queda pendiente sin desenlace.


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",
"operation_reference": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"authentication_method": "face",
"created_at": "2026-05-09T23:30:04.594Z",
"authorized_at": "2026-05-09T23:33:01.538Z",
"expires_at": "2026-05-18T23:30:04.594Z",
"state": "session-abc-123",
"expiration_reason": null,
"failure_reason": null,
"receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6Ii4uLiJ9.eyJ0cmFuc2FjY2lvbklkIjoiLi4uIn0.MEUCIQ...",
"enrollment_charge": {
"available": true,
"price": 350,
"currency": "CLP",
"includesIva": false,
"note": "Valores netos + IVA. Precio de lista del plan vigente, no una liquidación: la factura manda.",
"desglose": [
{ "metrica": "kyc_enrolamiento_iniciado", "price": 150 },
{ "metrica": "kyc_enrolamiento_logrado", "price": 200 }
]
},
"face_authentication_charge": {
"available": false,
"includesIva": false,
"message": "El plan actual no tiene una tarifa unitaria resoluble para la autenticación facial. El cargo se aplica igual y el monto lo determina la factura."
}
},
"sandbox": false
}

failure_reason viene siempre: es el mismo valor que el webhook pin.transaction.* de esa transacción entrega en su failure_reason.

Estadofailure_reason
pending, authorizednull
failed"max_attempts_reached", "rate_limit_exceeded", "face_not_verified" o "rut_mismatch"
expired"transaction_expired" (el detalle va en expiration_reason)
cancelled"cancelled_by_integrator" o "cancelled_by_user"

Así sabes por qué falló la transacción aunque no hayas recibido el webhook. rut_mismatch se explica en La cédula no corresponde al RUT.

receipt es el comprobante de la autorización: un JWS compacto que firma la transacción, el hash de la operación, la modalidad, el instante de la autorización y la verificación que la respalda. Llega sólo con la transacción authorized; en cualquier otro estado la clave no existe.

Se verifica sin relación con nosotros, contra las claves públicas de /.well-known/kyc-jwks.json: toma el kid del encabezado del JWS, busca esa clave en el JWKS y valida la firma con cualquier biblioteca JOSE. Guárdalo junto a tu operación: es la prueba de que la persona la autorizó.

Si enviaste operation_reference al crear la transacción, el comprobante suma el claim operationReference con ese mismo valor. Aparece sólo cuando lo mandaste: el comprobante de una transacción sin referencia es idéntico al de siempre, sin la clave — un claim en null no atestiguaría nada.

Si tu integración recibe el nombre de la persona, el comprobante suma el claim nombreCompleto, firmado junto con lo demás, y la respuesta trae full_name con el mismo valor.

Sólo si tu integración tiene activado Nombre completo leído de la cédula al crear la transacción y al autorizarse (ver Recibir el nombre de la persona):

  • full_name aparece sólo con la transacción authorized, con el nombre completo leído de la cédula, rectificado si la persona lo rectificó. En cualquier otro estado, o sin el dato activo, la clave no existe.
  • Es null cuando el comprobante ya no está: la persona fue anonimizada o la evidencia se retiró por antigüedad.
  • Sólo la credencial (API key) que creó la transacción puede consultarla: cualquier otra credencial de tu cuenta recibe 404, igual que si la transacción no existiera.

enrollment_charge informa el cargo de la acreditación de identidad que esta transacción gatilló.

  • Es null cuando esa persona ya estaba acreditada y no hubo acreditación. null significa no hubo cargo, no el cargo fue cero.
  • Cuando la tarifa del plan no se puede resolver, llega con "available": false y su message, sin monto. Nunca vas a recibir un cero por un cargo que sí ocurre.
  • El cargo de la transacción no se informa acá: está asumido en tu contrato y no cambia. El de la acreditación aparece a veces sí y a veces no —depende de si esa persona ya estaba acreditada—, y por eso es el único que te informamos por transacción.

face_authentication_charge informa el cargo de la autenticación facial de esta transacción, con la misma forma que enrollment_charge: las métricas pin_validacion_facial_iniciada y pin_validacion_facial_lograda que devengó, con su precio de lista.

  • Es null cuando la transacción no tuvo autenticación facial: la autorizó el PIN, o la acreditación de identidad.
  • Sin tarifa unitaria resoluble en tu plan llega con "available": false y su message, sin monto. Nunca un cero.

Las dos advertencias del monto son las mismas que para la acreditación: es precio de lista del plan vigente, no una liquidación —la factura manda—, y supone una tarifa unitaria plana.

expiration_reason dice por qué venció una transacción:

ValorCuándo
"not_started"La persona no empezó: nadie abrió el enlace en 7 días, o abrió una acreditación de identidad y no aceptó el consentimiento
"not_completed"La persona empezó y no terminó a tiempo: abrió el enlace y no ingresó el PIN, no completó la prueba de vida o no terminó la acreditación
nullLa transacción todavía no venció

No existe un tercer valor: expiration_reason no te dice cómo terminó la acreditación ni la prueba de vida —aprobada, rechazada o en revisión—, sólo si la persona empezó.

Cuando los datos de la transacción ya se anonimizaron

Sección titulada «Cuando los datos de la transacción ya se anonimizaron»

La plataforma no conserva los datos personales de una transacción para siempre. Pasado su plazo, los anonimiza y conserva el hecho: la transacción, su estado, su modalidad, su tipo, su etiqueta y sus fechas siguen respondiendo. operation_hash no viene en esta consulta: lo recibes al crear la transacción y en sus webhooks, y tu copia es la que sirve para verificar la integridad de la operación.

TransacciónCuándoQué cambia en la consulta
No autorizada (expired, failed o cancelled)90 días después de su desenlace (cuando quedó expired, failed o cancelled)rut, state y operation_reference llegan en null
Autorizada6 años después de authorized_atreceipt llega en null
De una persona cuyo registro vencióAl anonimizar el registro de la personarut, state, operation_reference y receipt llegan en null

Guarda tu copia del comprobante cuando lo recibes. Tu copia sigue siendo verificable con el JWKS por su kid, y la plataforma conserva la prueba de que lo emitió y cuándo aunque ya no lo entregue.


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
},
"sandbox": false
}

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
authorizedSíLa persona se autenticó con la modalidad pedida — trae receipt
failedSíPIN incorrecto reiterado, PIN bloqueado, la verificación facial agotó sus intentos (face_not_verified), o la cédula presentada es de otro RUT (rut_mismatch)
expiredSíLa persona no completó a tiempo; expiration_reason dice si empezó o no
cancelledSíCancelada por el integrador o por la persona

Recibirás webhooks cuando la transacción cambie a un estado terminal: en el callback_url de la transacción, siempre, o, si no lo enviaste, en la URL por defecto de tu empresa según su interruptor y su lista de eventos (ver Resolución del Webhook URL). Todos van firmados; cada entrega queda en el historial de la pestaña Configuración → Webhooks del panel de PINRUT.

EventoCuándo
pin.transaction.authorizedLa persona se autenticó con la modalidad pedida
pin.transaction.failedPIN incorrecto 5 veces, PIN bloqueado o verificación facial no completada
pin.transaction.expiredLa transacción venció sin completarse; expiration_reason dice si la persona empezó o no
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",
"authentication_method": "pin",
"operation_type": "firma_contrato",
"operation_label": "Firmar Contrato N° 2026-042",
"operation_hash": "06860b21052299ad...",
"operation_reference": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"authorized_at": "2026-05-09T23:38:01.538Z",
"status": "authorized",
"state": "session-abc-123",
"failure_reason": null,
"expiration_reason": null,
"receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6Ii4uLiJ9.eyJ0cmFuc2FjY2lvbklkIjoiLi4uIn0.MEUCIQ..."
}
}

Si tu integración recibe el nombre de la persona, la autorización suma full_name al final de data, con el mismo valor que el claim nombreCompleto del receipt. Ese webhook va sólo a la callback_url de la transacción:

{
"event": "pin.transaction.authorized",
"data": {
"transaction_id": "cedd740a-e5a3-43a2-9896-5ac45dfdb4dc",
"status": "authorized",
"receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6Ii4uLiJ9.eyJ0cmFuc2FjY2lvbklkIjoiLi4uIn0.MEUCIQ...",
"full_name": "María José Pérez Soto"
}
}

(Resumido: llegan también las demás claves del evento.)

Cuando vence una transacción cuya persona empezó y no terminó a tiempo:

{
"event": "pin.transaction.expired",
"timestamp": "2026-05-12T10:14:02.101Z",
"data": {
"transaction_id": "cedd740a-e5a3-43a2-9896-5ac45dfdb4dc",
"integration_id": "702191e3-e415-41dc-ac1b-0b66d2edccf9",
"rut": "12.345.678-9",
"authentication_method": "face",
"operation_type": "firma_contrato",
"operation_label": "Firmar Contrato N° 2026-042",
"operation_hash": "06860b21052299ad...",
"operation_reference": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"authorized_at": null,
"status": "expired",
"state": "session-abc-123",
"failure_reason": "transaction_expired",
"expiration_reason": "not_completed"
}
}

Ningún evento lleva el identificador interno de la persona: es propio de la plataforma y la correlacionaría entre integradores. Todos llevan authentication_method, y receipt va sólo en pin.transaction.authorized: en los demás eventos la clave no existe. Lo mismo full_name, que además exige que tu integración reciba el nombre.

pin.transaction.expired llega a lo sumo una vez por transacción.

EventoCampos adicionales en data
pin.transaction.authorizedauthorized_at, receipt
pin.transaction.failedfailure_reason ("max_attempts_reached", "rate_limit_exceeded", "face_not_verified" o "rut_mismatch")
pin.transaction.expiredfailure_reason ("transaction_expired"), expiration_reason ("not_started" o "not_completed")
pin.transaction.cancelled—

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

  1. callback_url enviado en la transacción. El webhook va sólo ahí, sin mirar la lista de eventos ni el interruptor «Enviar a esta URL»: declarar la URL ya es pedir el aviso.
  2. URL por defecto de tu empresa, si la transacción no envió callback_url. Va sólo si existe, si «Enviar a esta URL» está encendido y si Eventos habilitados deja pasar el evento (vacía = todos).
  3. Ninguna de las dos → no se envía webhook (sólo redirect), y el historial lo muestra como «no enviada» con su motivo.

Los headers personalizados y la firma de tu configuración se aplican siempre, vaya el webhook al callback_url o a la URL por defecto.

Para no recibir los webhooks de una transacción en una URL propia, no declares callback_url. Para no recibirlos en la URL por defecto, quita los eventos pin.transaction.* de Eventos habilitados o apaga «Enviar a esta URL». El detalle está en A dónde va cada aviso.


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, failed o cancelled
stateValor opaco que enviaste al crear la transacción

CódigoDescripciónCausa
400Validación fallidaFalta authentication_method o no es pin ni face, RUT inválido, redirect_uri no en lista permitida, callback_url no permitida, máximo de pendientes alcanzado, o el rut es de una persona jurídica (code: rut_de_persona_juridica; ver PINRUT es sólo para personas naturales)
401No autorizadoAPI key inválida, expirada o revocada
402Pago requeridoTu plan no incluye la métrica de PINRUT (code: METRIC_NOT_IN_PLAN)
403ProhibidoServicio PIN_RUT no habilitado o rol insuficiente
404No encontradoIntegración no existe o está inactiva, transacción no encontrada. También al consultar con otra credencial una transacción que entrega datos personales
409ConflictoTransacción no está en estado pending (al cancelar); o se envió un PIN a una transacción face (code: face_authentication_required)
422No procesableNo hay redirect_uri y la integración no tiene default (code: no_redirect_uri); o la integración recibe datos personales y no enviaste callback_url (code: callback_url_required)
423BloqueadoSólo con authentication_method: "pin": el PIN del RUT está bloqueado por demasiados intentos fallidos. Con face el PIN no interviene y no hay 423
503No disponibleEl dominio de PINRUT no está disponible para la pantalla de autorización: no se creó la transacción y la respuesta no trae ninguna dirección. Reintenta más tarde
{
"message": "Integración activa con slug \"mi_app_prod\" no encontrada",
"error": "Not Found",
"statusCode": 404
}

Ejemplo de Error 400 (RUT de Persona Jurídica)

Sección titulada «Ejemplo de Error 400 (RUT de Persona Jurídica)»
{
"code": "rut_de_persona_juridica",
"message": "PINRUT es sólo para personas naturales: el RUT ingresado corresponde a una persona jurídica (una empresa). Usa el RUT personal del titular, el de su cédula de identidad."
}
{
"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 del PIN:

  • Máximo 10 intentos fallidos de PIN por RUT en 1 hora (cross-tenant). Las verificaciones faciales fallidas no cuentan: no bloquean el PIN
  • 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 de verificación facial por transacción3
Intentos fallidos globales de PIN por RUT/hora10
Plazo para abrir el enlace7 días desde la creación
Plazo para ingresar el PIN, desde que se abre el enlace5 minutos
Plazo para la prueba de vida, desde que se abre el enlace30 minutos
Plazo de una acreditación de identidadHasta la creación más 7 días y 48 horas (expires_at)
Tamaño máximo de state2048 caracteres
Tamaño máximo de operation_label200 caracteres
Tamaño máximo de operation_detail500 caracteres
Formato y tamaño de operation_referencesha256:<64 hex en minúsculas>, 71 caracteres exactos

// 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 = data.authorize_url; // ya es la dirección completa
// 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 });
});