Prueba con una ruta, método HTTP o código de error diferente.
Inicio rápido
Esta API permite autenticar integraciones servidor a servidor mediante claves pertenecientes a un partner, emitir certificados nativos, digitalizar certificados existentes y configurar webhooks salientes.
Para integrar sin afectar datos ni cupos reales, consulta la guía del sandbox. El mismo contrato y URL base se usan con claves 3i_test_....
URL base
Todos los endpoints comparten la siguiente URL base (los ejemplos de esta guía ya la incluyen):
https://institutodeingenieria.org/api/v1/partner
Todas las respuestas de la API utilizan JSON.
Correlación de solicitudes
Todas las rutas bajo /api/v1/partner aceptan X-Request-Id con 8 a 100 caracteres alfanuméricos o ., _, :, -. Si falta o es inválido, el servidor genera req_<uuid>. Todas las respuestas devuelven el identificador efectivo en X-Request-Id; los errores lo incluyen además como request_id.
El identificador original se conserva en emisiones idempotentes, digitalizaciones y eventos webhook. De este modo puede seguirse una operación desde la petición API hasta los intentos de entrega y los logs JSON.
Sandbox
El sandbox permite probar emisiones, digitalizaciones y webhooks con el contrato de /api/v1/partner sin consumir cupo ni crear certificados reales. Se selecciona automáticamente con una clave 3i_test_...; no existe una URL base distinta.
Activación y credenciales
Todo partner aceptado puede crear hasta 10 claves sandbox activas desde API e integraciones, aun cuando no tenga un plan activo. Si el ambiente sandbox todavía no está habilitado, la API responde 403 sin procesar la operación.
Todas las respuestas autenticadas incluyen X-3i-Environment: sandbox y environment: "sandbox". Un prefijo inválido o una clave de otro ambiente devuelve 401.
Datos aislados
Los cursos, alumnos y plantillas del partner son catálogos reales de solo lectura. Los certificados, idempotencias y operaciones de digitalización se almacenan exclusivamente en tablas sandbox. Por ello:
no se escriben filas en certificados;
no se consume plan ni se modifican métricas, perfiles o búsquedas live;
un código o Idempotency-Key puede coexistir en Live y Sandbox;
no existe promoción automática de Sandbox a Live.
Las fuentes, registros y artefactos sandbox vencen a los 30 días. Después de la limpieza diaria, sus endpoints y páginas públicas responden 404.
Emisión y digitalización
Usa los mismos endpoints y cuerpos documentados en documentación principal. La emisión conserva la semántica de Idempotency-Key; la digitalización sigue siendo asíncrona y usa las colas existentes.
El QR siempre apunta a la primera URL. La página pública muestra un banner permanente y cada página del PDF o imagen lleva la marca SANDBOX · SIN VALIDEZ. Las respuestas públicas incluyen X-Robots-Tag: noindex, nofollow y caché limitada.
Notificaciones
El bloque notification y los endpoints /notify se validan normalmente, pero nunca encolan correos. Responden 200:
Solo se conserva el conteo de destinatarios necesario para depuración; no se persisten sus direcciones en tablas sandbox ni se escriben en logs.
Webhooks
Las claves sandbox solo ven y administran endpoints sandbox. Los eventos sandbox se entregan únicamente a esos endpoints e incluyen environment: "sandbox" en el sobre. La entrega es real y conserva firma HMAC-SHA256, protección SSRF, rotación con solapamiento, reintentos y reenvío manual.
El secreto whsec_... se muestra una sola vez y debe guardarse en un gestor de secretos. Nunca debe almacenarse en el repositorio, documentación o logs. Para verificar una firma, usa exactamente el cuerpo recibido y el procedimiento descrito en firma y autenticidad.
Autenticación
Envía la clave en el encabezado HTTP Authorization usando el esquema Bearer:
No envíes la clave en la URL, el cuerpo de la solicitud ni parámetros de consulta.
El servidor responde con X-3i-Environment: live|sandbox y añade environment al sobre JSON. El ambiente lo determina únicamente el prefijo de la clave.
El acceso a la API debe ser habilitado internamente por 3i (esta documentación es pública, pero crear claves y consumir los endpoints requiere la habilitación). Por el momento esta opción no es configurable desde ningún panel. Desactivarlo no elimina sus claves ni configuraciones, pero todas las claves quedan temporalmente bloqueadas con 403 partner_api_disabled hasta que el acceso sea reactivado.
Lista las plantillas activas del partner. variables describe exactamente las entradas aceptadas dentro de template_values; participante, curso, fecha, documento, código y contadores son autoritativos y no se exponen como editables.
Crea un certificado nativo de forma síncrona. El código se genera siempre en el servidor. Idempotency-Key es obligatorio, debe tener entre 8 y 100 caracteres y solo puede contener letras, números, ., _, : o -.
Modalidad
Diseño
Comportamiento
exam
diseño asignado
Omite design; usa la plantilla activa del curso o el clásico si no tiene
exam
override
Envía design.type=classic o una plantilla activa del partner
free
classic
Requiere nombre manual de la certificación y diseño clásico
free
template
Requiere nombre manual, template_id y las variables de la plantilla
Campos principales:
issuance_type: exam o free.
course_id: obligatorio y autoritativo para exam; no se acepta en free.
user_id o holder_name: debe enviarse exactamente uno. El usuario debe figurar en el catálogo de alumnos.
certificate_name: obligatorio para free; no se acepta en exam, donde siempre se usa el nombre del curso.
issued_at: fecha obligatoria YYYY-MM-DD.
design: { "type": "classic" } o { "type": "template", "template_id": 18 }. Solo puede omitirse en exam.
template_values: claves publicadas como variables editables por la plantilla.
Personalización opcional:
language: es o en; por defecto es.
issuance_place, academic_hours, training_start_date, training_end_date, document_type y document_number.
Para diseño clásico: name_font_size y course_font_size.
El copy clásico se selecciona automáticamente: sin horas/fechas = 1, solo horas = 2, horas y fechas = 3, solo fechas = 4. No envíes copy_id.
notification: emails —entre 1 y 10 direcciones únicas—, subject opcional de hasta 150 caracteres y message opcional de hasta 2000. Solo se notifican los correos explícitos. Cuando se incluye, la respuesta 201 lo confirma con "notification": {"status": "queued", "recipients_count": N} (en Sandbox, suppressed); los replays idempotentes no reenvían correos y omiten el bloque.
Repetir el mismo payload y clave devuelve el mismo certificado con 200 OK e Idempotency-Replayed: true; no consume cupo, contador ni reenvía correos. Otro payload con la misma clave devuelve 409 idempotency_key_conflict.
El certificado está activo desde el 201. El PDF y JPG se generan al abrir sus URL; las emisiones no usan polling ni estados de renderizado.
Vista previa visual
La respuesta permite mostrar inmediatamente el mismo certificado renderizado que se ve en el modal de emisión del panel. Una integración puede implementar su botón Vista previa abriendo:
thumbnail_url dentro de una imagen o modal para una vista rápida de la primera página;
pdf_url para ver el documento completo;
web_url para abrir la página pública de verificación.
El portal de documentación no ejecuta la emisión ni solicita claves, por lo que no muestra un certificado real dentro de la guía. El botón o modal de la integración debe usar las URLs devueltas por su propia solicitud. En Sandbox las mismas propiedades apuntan a las rutas sandbox y el documento conserva la marca SANDBOX · SIN VALIDEZ.
Esquema de solicitud desde el panel
Al previsualizar una emisión, el panel muestra el botón Ver JSON API junto a la vista previa. Genera el cuerpo POST /api/v1/partner/certificates equivalente con los valores seleccionados (modalidad, titular, curso o plantilla, fecha, variables y notificación), listo para copiar. Es una referencia práctica al contrato completo con el que se emitirá el certificado; el botón solo aparece cuando el partner tiene la API activada.
Devuelve el mismo objeto normalizado del POST, para cualquier certificado del partner autenticado: nativo (emitido por API, por el panel o por un alumno al aprobar un examen del partner) o digitalizado. Un certificado ajeno o inexistente devuelve 404 certificate_not_found.
Lista los certificados del partner autenticado, del más reciente al más antiguo. Usa la misma paginación que los catálogos (search, page, per_page); search busca por código, titular o nombre del certificado. Cada elemento tiene el mismo formato normalizado del POST más el campo type.
Parámetro type (opcional):
Valor
Contenido
all (predeterminado)
Todo el inventario del partner
native
Certificados nativos: emitidos por API, desde el panel, o por un alumno al aprobar un examen del partner
digitized
Certificados digitalizados (creados por API o desde el panel de digitalización)
En los elementos digitized, los campos que describen una emisión nativa (issuance_type, design, copy_id) son null, y status puede ser active, borrador o inactivo según el estado en el panel de digitalización.
Envía (o reenvía) el certificado por correo. Es un paso independiente de la emisión y puede invocarse las veces que se necesite, igual que el botón Notificar del panel. El cuerpo usa el mismo contrato de notification, sin envoltorio:
{
"emails": ["[email protected]"],
"subject": "Tu certificado está listo",
"message": "Felicitaciones por completar el programa"
}
Los correos se procesan en la cola default. Aplica a certificados nativos y digitalizados del partner; un certificado ajeno o inexistente devuelve 404 certificate_not_found, y un digitalizado que aún no está activo (borrador o inactivo) devuelve 409 certificate_not_active. El correo del digitalizado usa la misma plantilla del flujo de digitalización.
Elimina definitivamente un certificado del partner autenticado — nativo o digitalizado — con el mismo efecto que la eliminación desde el panel:
El documento y sus renders públicos (verificación, PDF, miniatura) dejan de resolver de inmediato.
El code queda disponible de nuevo (una digitalización futura puede reutilizarlo; check-code volverá a responder available: true).
El cupo del plan se recalcula automáticamente.
Si el certificado provenía de una digitalización por API, la operación se conserva como registro histórico con certificate.deleted: true.
No emite webhooks (igual que la eliminación desde el panel).
No hay papelera ni restauración: la eliminación es irreversible. Un certificado ajeno o inexistente devuelve 404 certificate_not_found (repetir el DELETE sobre el mismo id también responde 404, porque ya no existe). En Sandbox elimina el certificado sandbox y sus recursos aislados.
Comprueba si un código puede usarse antes de subir el PDF, equivalente a la validación en vivo del editor web. El código se normaliza a mayúsculas; un formato inválido devuelve 422 validation_error.
La consulta es informativa y no reserva el código: la creación puede seguir respondiendo 409 certificate_code_conflict si otra operación lo toma entre ambas llamadas.
Importante: este endpoint NO lista certificados; lista el historial de operaciones (trámites) de digitalización enviadas por la API, incluidas las que fallaron. Para ver los certificados digitalizados vigentes — vengan de la API o del panel web — usa la sección Listar certificados emitidos con GET /api/v1/partner/certificates?type=digitized (o type=all para el inventario completo).
GET/api/v1/partner/digitizations
Lista las operaciones de digitalización del partner autenticado, de la más reciente a la más antigua, con el mismo objeto del endpoint de consulta. Admite search (por código o nombre), status (queued, processing, completed o failed), page y per_page (25 por defecto, máximo 100).
Detalles del alcance de esta bitácora:
Solo registra trámites iniciados por la API; las digitalizaciones creadas desde el panel web no aparecen aquí (sus certificados sí aparecen en Listar certificados emitidos).
Una operación es el proceso, no el documento. Sirve para hacer polling, auditar reintentos y diagnosticar fallos.
status: completed es un hecho histórico. Si el certificado se elimina después desde el panel, la operación se conserva con certificate.deleted: true, certificate.id: null y sin URLs dentro del bloque certificate (los enlaces de nivel superior dejan de resolver).
Recibe un formulario multipart/form-data y crea una operación asíncrona. Requiere:
pdf: archivo PDF de hasta 25 MB y 20 páginas.
code: identificador público único de 4 a 32 letras, números o guiones. Se normaliza a mayúsculas.
name: título del certificado, máximo 255 caracteres.
template_id: identificador obtenido del listado de plantillas.
user_id (opcional): identificador de un alumno del catálogo certificate-students. El certificado queda vinculado y a nombre del alumno; un alumno ajeno al partner devuelve 422 student_not_found.
Idempotency-Key: encabezado único de 8 a 100 caracteres para poder reintentar sin duplicar.
notification (opcional): mismo contrato usado por la API de emisión; se encola únicamente si la digitalización termina correctamente.
notification.emails: entre 1 y 10 correos únicos.
notification.subject: asunto opcional de hasta 150 caracteres.
notification.message: mensaje adicional opcional de hasta 2000 caracteres.
La orientación de la primera página debe coincidir con la plantilla. El layout y el QR se aplican solamente a la portada; las páginas adicionales se conservan sin elementos añadidos.
La respuesta incluye Idempotency-Replayed: false. Si se repite exactamente la misma solicitud con la misma clave, devuelve la operación original y el encabezado cambia a true; en ese caso el estado es 202 Accepted mientras la operación siga en curso, y 200 OK si ya terminó. Reutilizar la clave con contenido diferente responde 409 idempotency_key_conflict.
links está disponible desde que se acepta la operación. Mientras el certificado se encuentra en queued o processing, web_url muestra una página de espera que se actualiza cada 5 segundos, pdf_url redirige a esa página y thumbnail_url devuelve una imagen temporal. Los recursos temporales no se almacenan en caché. Si la operación falla, las mismas rutas muestran un estado público genérico sin revelar el detalle interno.
Vista previa visual
El modal de digitalización del panel utiliza el resultado renderizado de la operación. Una integración puede ofrecer el mismo botón Vista previa usando links.thumbnail_url mientras consulta status_url. Durante queued o processing se verá el estado temporal; cuando status sea completed, la URL mostrará la portada definitiva. Para revisar todas las páginas debe abrir links.pdf_url, y para la validación pública debe usar links.web_url.
No debe construirse la URL manualmente: se recomienda conservar siempre las propiedades links entregadas por la API. En Sandbox apuntan automáticamente a las rutas aisladas y muestran la marca de agua correspondiente.
Esquema de solicitud desde el panel
El panel de digitalización incluye el botón Ver cURL API, que genera el comando POST /api/v1/partner/digitizations equivalente a la operación que se está componiendo (PDF, código, nombre, plantilla y alumno opcional). Es una referencia práctica para reproducir la misma solicitud por API y solo aparece cuando el partner tiene la API activada; el comando se completa al seleccionar una plantilla guardada (template_id).
Al aceptar la operación se reserva un certificado del cupo del partner. Las operaciones queued y processing cuentan como reservas, por lo que solicitudes simultáneas no pueden superar el límite del plan. Una operación fallida libera automáticamente su reserva.
Si se solicitó correo, notification.status transiciona de pending a queued después de completar el certificado. Si la digitalización falla pasa a cancelled; si no fue posible encolar las notificaciones pasa a failed. El correo se procesa en la cola default y un fallo de entrega no revierte ni invalida el certificado.
{
"data": {
"operation_id": "0198a345-8129-72ef-b805-6ecb73a85a40",
"status": "failed",
"status_url": "https://institutodeingenieria.org/api/v1/partner/digitizations/0198a345-8129-72ef-b805-6ecb73a85a40",
"links": {
"web_url": "https://institutodeingenieria.org/sandbox/certificados/verificar/CERT-2026-0001",
"pdf_url": "https://institutodeingenieria.org/sandbox/certificados/CERT-2026-0001/ver",
"thumbnail_url": "https://institutodeingenieria.org/sandbox/certificados/CERT-2026-0001/image?page=1"
},
"error": {
"code": "processing_failed",
"message": "The certificate could not be processed."
}
}
}
Se recomienda consultar cada 2 a 5 segundos y detener el polling al recibir completed o failed. El polling sigue siendo la fuente de estado para integraciones automáticas; las páginas públicas de links están orientadas a personas y vistas previas.
Envía (o reenvía) el certificado digitalizado por correo una vez que la operación está completed; en cualquier otro estado responde 409 operation_not_completed. Es un paso independiente y re-invocable, con el mismo cuerpo del endpoint de notificación de emisión (emails, subject opcional, message opcional) y la misma respuesta {"status": "queued", "recipients_count": N}.
Este endpoint no modifica el bloque notification de la operación: ese bloque documenta únicamente la solicitud de correo hecha al crearla.
La clave de idempotencia se reutilizó con otro contenido
422
invalid_idempotency_key
Falta el encabezado o su formato no es válido
422
invalid_pdf
El archivo no es un PDF procesable
422
encrypted_pdf
El PDF está protegido con contraseña
422
too_many_pages
El PDF tiene más de 20 páginas
422
orientation_mismatch
La portada no coincide con la orientación de la plantilla
422
template_without_qr
La plantilla no contiene el elemento QR requerido
422
student_not_found
El alumno de user_id no está vinculado al partner
422
invalid_template
La plantilla no contiene un diseño válido
422
plan_limit_reached
El certificado excedería el cupo disponible del partner
422
validation_error
Falta un campo obligatorio o su formato no es válido
429
rate_limit_exceeded
Se superó el límite de solicitudes
503
upload_failed
El servidor no pudo almacenar el PDF recibido
503
queue_unavailable
El servidor no pudo encolar el procesamiento
503
pdf_processing_unavailable
El servidor no tiene disponibles las herramientas PDF
Las respuestas 422 validation_error y 422 invalid_pdf incluyen además un objeto errors con el detalle por campo.
Webhooks salientes
Los webhooks notifican a sistemas externos cuando una operación iniciada mediante la API pública alcanza un resultado relevante. Son complementarios al polling y a los correos; no sustituyen ninguno de ellos.
La entrega es al menos una vez. El receptor debe deduplicar usando el campo id del evento o el header Webhook-Id.
Reglas generales:
Solo se generan eventos para emisiones y digitalizaciones originadas con una clave de API.
Las acciones equivalentes realizadas desde el panel web no generan webhooks.
Cada partner puede configurar hasta 10 endpoints por ambiente.
Los eventos Live solo se entregan a endpoints Live y los eventos Sandbox solo a endpoints Sandbox.
Un evento se distribuye a todos los endpoints que estaban active y suscritos a ese tipo al momento de crearlo.
Cada endpoint recibe una entrega independiente; el fallo de uno no afecta a los demás.
No existe backfill: un endpoint creado después del evento no recibe eventos anteriores.
Los replays idempotentes no generan un segundo evento.
Los correos solicitados por la operación continúan funcionando independientemente de los webhooks.
Eventos disponibles
Evento
Se produce cuando
Suscribible
certificate.issued
Una emisión síncrona mediante API se confirma
Sí
digitization.completed
Una digitalización mediante API termina correctamente
Sí
digitization.failed
Una digitalización mediante API termina con error
Sí
webhook.test
Se solicita verificar un endpoint
No; lo genera internamente la acción de verificación
webhook.test se envía únicamente al endpoint que se está verificando; no se distribuye a los demás destinos del partner.
UUID estable del evento; se conserva entre reintentos y endpoints
type
Tipo de evento
api_version
Versión del contrato del webhook; actualmente v1
created_at
Fecha de creación en ISO 8601
partner_id
Partner propietario de la operación
environment
Ambiente del evento: live o sandbox
request_id
Identificador de correlación original; para eventos históricos se deriva de forma estable desde id
data
Payload específico del evento
No existe garantía de orden entre eventos o endpoints. data representa el estado al ocurrir el evento; para conocer el estado actual debe consultarse la API. Los eventos pueden repetirse. Los cambios aditivos permanecen en v1; cualquier cambio incompatible requiere v2.
El payload se construye desde los datos persistidos y se serializa de forma estable, sin escapar barras ni caracteres Unicode. Para validar la firma debe utilizarse el cuerpo HTTP crudo recibido, no un JSON parseado y vuelto a serializar.
Los payloads no incluyen correos, destinatarios de notificación, números de documento, valores de plantilla ni secretos.
Firma y autenticidad del webhook
Cada endpoint tiene un secreto independiente con formato:
whsec_<base64url-de-32-bytes>
El secreto lo genera 3i al crear o rotar el endpoint, se muestra una sola vez y se almacena cifrado en el servidor. No existe negociación automática: el receptor debe guardar el valor que entrega 3i.
Responde 202 Accepted con una entrega pending. El worker envía webhook.test; solamente una respuesta 2xx cambia el endpoint a active y establece verified_at.
Una verificación fallida termina después del primer intento y debe ejecutarse nuevamente de forma manual. Las verificaciones no usan el calendario automático de reintentos de eventos normales.
POST /api/v1/partner/webhook-endpoints/14/rotate-secret
Devuelve el nuevo signing_secret una sola vez y previous_secret_valid_until. Durante 24 horas cada envío incluye dos valores, primero la firma nueva y luego la anterior:
El receptor debe aceptar cualquier firma válida de la lista. Un endpoint active permanece activo y conserva verified_at; uno pendiente continúa pendiente y uno desactivado continúa desactivado. Al vencer la ventana, mantenimiento elimina el secreto anterior cifrado y solo se envía la firma nueva. El endpoint expone la fecha como secret_overlap_expires_at, pero nunca el secreto anterior. Cambiar la URL sí continúa exigiendo verificación.
GET /api/v1/partner/webhook-endpoints/14/deliveries?per_page=25&page=1
per_page admite de 1 a 100. También pueden combinarse status, event_type, from y to; las fechas usan ISO 8601. Sin filtros se conserva la forma anterior de la respuesta. Ejemplo:
Una entrega representa la combinación endpoint-evento. attempt_count cuenta el ciclo actual; total_attempt_count nunca se reinicia y redelivery_count cuenta los ciclos manuales. El objeto conserva además la última respuesta o error para compatibilidad.
Devuelve el mismo resumen más el evento inmutable y attempts. Cada intento contiene secuencia global, ciclo, número dentro del ciclo, estado, inicio/fin, latencia, IP resuelta, HTTP, headers permitidos, respuesta truncada, categoría de error y próximo reintento. Los headers persistidos se limitan a Retry-After, Content-Type y X-Request-Id.
POST /api/v1/partner/webhook-deliveries/55e8c9d4-57d3-47e2-908b-08d3460d2bb3/redeliver
Responde 202 Accepted, inicia un ciclo, reinicia solo attempt_count, incrementa redelivery_count y conserva total_attempt_count y todos los intentos históricos. Para eventos normales el endpoint debe estar active; una entrega de verificación puede reenviarse aunque todavía esté pendiente.
Esperando su primer intento o un reintento programado
processing
Un worker tomó la entrega
delivered
El receptor devolvió 2xx
terminal
Fallo no reintentable o calendario agotado
El modelo también define failed por compatibilidad con vistas y reenvío manual, pero el job actual mantiene los fallos reintentables en pending y utiliza terminal para el resultado definitivo.
Se considera éxito únicamente cualquier respuesta 2xx. Se reintentan:
Errores de red, DNS o timeout.
HTTP 408.
HTTP 429.
HTTP 5xx.
Los demás 4xx son terminales inmediatamente. El calendario base después de cada intento fallido es:
Reintento
Espera
1
1 minuto
2
5 minutos
3
30 minutos
4
2 horas
5
6 horas
6
12 horas
7
24 horas
Cada espera recibe jitter aleatorio de ±20 %. Para 429 y 503, Retry-After puede expresarse en segundos o como fecha HTTP: se usa el mayor valor entre el backoff y el header, con un máximo de 24 horas. Un header inválido se ignora.
Esto permite hasta ocho intentos por ciclo: el inicial, siete reintentos y luego estado terminal si el último también falla. terminal funciona como DLQ lógica y el reenvío manual es la reinyección.
Parámetros de transporte:
Timeout de conexión: 3 segundos.
Timeout total HTTP: 10 segundos.
Timeout del job: 20 segundos.
No se siguen redirecciones.
El cuerpo de respuesta o mensaje de error se trunca a 4096 caracteres.
Cada intento envía Webhook-Attempt desde 1; Webhook-Delivery permanece estable entre intentos y ciclos.
La cola utilizada es default; cada job tiene un solo intento a nivel de Laravel porque el calendario se controla en la propia entrega.
Seguridad de destinos
La URL se valida al crearla, cuando cambia y nuevamente antes de cada envío:
Debe utilizar https:// y tener host válido.
No puede contener usuario ni contraseña embebidos.
El puerto debe estar entre 1 y 65535; por defecto es 443.
Se resuelven registros IPv4 e IPv6.
Todas las direcciones resueltas deben ser públicas; se bloquean redes privadas y reservadas.
El DNS se reevalúa en cada intento para mitigar DNS rebinding.
Cuando cURL lo permite, la conexión se fija a la IP pública validada mediante CURLOPT_RESOLVE.
La validación TLS permanece activa y las redirecciones están deshabilitadas.
El secreto está oculto en serializaciones y cifrado mediante el cast encrypted de Laravel. No debe registrarse en logs ni incluirse en errores.
Errores de administración de webhooks
Estado
Código
Motivo
403
insufficient_scope
La clave no tiene * ni webhooks:manage
404
webhook_endpoint_not_found
El endpoint no existe o pertenece a otro partner
404
webhook_delivery_not_found
La entrega no existe o pertenece a otro partner
409
webhook_endpoint_not_active
Se intentó reenviar un evento normal a un endpoint no activo
422
validation_error
Nombre, URL, eventos o formato inválidos
Al alcanzar el límite de 10 endpoints, la respuesta es 422 y el error se asocia al campo endpoints. Los errores de URL explican si falta HTTPS, no se pudo resolver el host o se detectó una red privada/reservada.
Errores
Todas las respuestas de error usan el mismo sobre plano: message con una descripción legible en inglés, code con un identificador estable, request_id para correlación y errors cuando hay validación por campo. Programa siempre contra code; el texto de message puede cambiar.
Clave inválida — 401 Unauthorized
Se devuelve cuando falta la credencial, su formato fue alterado, venció o fue revocada.
{
"message": "The API key is invalid, expired or revoked.",
"code": "invalid_api_key",
"request_id": "req_018f0f2451544c10997cdf8ad7e45188"
}
Partner no habilitado — 403 Forbidden
Una clave válida no permite operar si el partner asociado ya no está aceptado, es decir si status deja de ser accepted.
{
"message": "The partner associated with this key is not enabled.",
"code": "partner_not_active",
"request_id": "req_018f0f2451544c10997cdf8ad7e45188"
}
API del partner deshabilitada — 403 Forbidden
Una clave puede seguir vigente aunque el administrador haya desactivado temporalmente la API y la documentación del partner.
{
"message": "Partner API access is disabled.",
"code": "partner_api_disabled",
"request_id": "req_018f0f2451544c10997cdf8ad7e45188"
}
Límite excedido — 429 Too Many Requests
{
"message": "Too many requests. Please try again later.",
"code": "rate_limit_exceeded",
"retry_after": 42,
"request_id": "req_018f0f2451544c10997cdf8ad7e45188"
}
La respuesta incluye también el encabezado Retry-After, expresado en segundos.
Límites de tráfico
Cada clave válida admite hasta 120 solicitudes por minuto.
La emisión de certificados admite hasta 30 solicitudes por minuto por clave.
La creación de digitalizaciones admite hasta 10 solicitudes por minuto por clave.
Los endpoints de notificación admiten hasta 30 solicitudes por minuto por clave.
Los intentos con credenciales inválidas se limitan a 20 por minuto por dirección IP.
Las respuestas exitosas incluyen X-RateLimit-Limit y X-RateLimit-Remaining (límite global de la clave).
Las rutas con límite propio (emisión, digitalización, notificación) incluyen además X-RateLimit-Endpoint-Limit y X-RateLimit-Endpoint-Remaining.
Cuando se excede un límite, espera los segundos indicados en Retry-After antes de reintentar.
Expiración, revocación y rotación
Una clave deja de funcionar inmediatamente cuando vence o es revocada. No existe período de gracia ni reactivación.
Siete días antes del vencimiento, el sistema envía una única notificación al propietario y a los administradores activos del partner. La revisión se ejecuta diariamente a las 09:00 en la zona horaria configurada por la aplicación, normalmente America/Lima.
Para rotar una credencial sin interrumpir el servicio:
Crea una nueva clave desde API e integraciones.
Guárdala en el gestor de secretos de la aplicación consumidora.
Despliega o configura la aplicación para utilizar la nueva clave.
Comprueba la nueva credencial mediante GET /api/v1/partner/me.
Revoca manualmente la clave anterior.
La revocación es permanente. Las claves no se editan ni se eliminan físicamente para conservar su trazabilidad.
Recomendaciones de seguridad
Conserva la clave en variables de entorno o en un gestor de secretos.
No la incluyas en repositorios, capturas de pantalla, tickets ni registros de aplicación.
Utiliza una clave diferente para cada sistema consumidor, con un nombre descriptivo.
Prefiere claves con vencimiento frente a claves sin expiración.
Rota inmediatamente una clave si existe sospecha de exposición.