Integra NextsID en tu sistema
API REST completa, documentada con OpenAPI 3.0. Valida conductores y vehículos desde tu TMS, ERP o cualquier aplicación.
Empieza en 3 pasos
Autentícate
POST /auth/login con tus credenciales devuelve un access token
Registra a la persona
POST /personas con el documento — devuelve el id que usa el estudio
Crea el estudio
POST /checks con ese id y el consentimiento confirmado
# Copiá y pegá el bloque entero: cada paso deja lo que el siguiente necesita.
API=https://api.nexts.id
# 1. Autenticarse. El access token dura 15 min; el refresh, 7 días.
ACCESS_TOKEN=$(curl -sS -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{ "email": "integracion@tuempresa.com", "password": "..." }' \
| jq -r .access_token)
# 2. Registrar a la persona. Devuelve el id que usa el estudio.
SUBJECT_ID=$(curl -sS -X POST "$API/api/v1/personas" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"document_type": "co_cedula",
"document_number": "80123456",
"country": "CO",
"first_name": "Juan",
"last_name": "Perez",
"role": "conductor"
}' | jq -r .id)
# 3. Crear el estudio sobre esa persona.
CHECK_ID=$(curl -sS -X POST "$API/api/v1/checks" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"subject_id\": \"$SUBJECT_ID\",
\"subject_type\": \"persona\",
\"consent_confirmed\": true,
\"role\": \"conductor\"
}" | jq -r .id)
# 4. ESPERAR — Y RAMIFICAR POR ESTADO. No alcanza con esperar
# "sources_completed": si la ETAPA PREVIA encuentra algo crítico, el estudio
# termina en pre_validation_failed y NUNCA llega a ese estado. Un lazo que
# sólo espere el caso feliz gira para siempre y el integrador jamás ve el
# hallazgo — que es justamente el peor resultado posible acá.
INTENTOS=0
while :; do
ESTADO=$(curl -sS -w '\n%{http_code}' "$API/api/v1/checks/$CHECK_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN")
CODIGO=$(printf '%s' "$ESTADO" | tail -1)
CUERPO=$(printf '%s' "$ESTADO" | sed '$d')
# El access token dura 900s. Si venció, renovalo con POST /auth/refresh.
[ "$CODIGO" = "401" ] && { echo "token vencido: renová con /auth/refresh"; exit 1; }
[ "$CODIGO" = "200" ] || { echo "error HTTP $CODIGO: $CUERPO"; exit 1; }
case "$(printf '%s' "$CUERPO" | jq -r .stage)" in
sources_completed)
# LOS HALLAZGOS SE MIRAN ACÁ TAMBIÉN, no sólo cuando el estudio se
# detiene en la etapa previa. Una coincidencia PEP real llega hasta acá:
# su severidad es
# "none" —porque es informativa y no mueve el veredicto— pero su
# counts_as_finding es true. Si sólo se miran los hallazgos del camino
# que falla, ese caso no se ve NUNCA. Y el paso 5 devuelve el puntaje,
# que no trae la lista.
printf '%s' "$CUERPO" | jq '.findings[] | select(.counts_as_finding)'
break ;;
pre_validation_failed)
# HALLAZGO CRÍTICO EN LA PREVALIDACIÓN. Es un resultado, no un error:
# el estudio se detuvo porque encontró algo. Mostralo.
printf '%s' "$CUERPO" | jq '.findings[] | select(.counts_as_finding)'
exit 2 ;;
*)
: ;; # pending, pre_validating, running, completed, partial: seguir esperando
esac
INTENTOS=$((INTENTOS + 1))
[ "$INTENTOS" -gt 100 ] && { echo "el estudio no terminó en ~5 min"; exit 1; }
sleep 3
done
# 5. Puntuar el estudio. ESTE PASO ES OBLIGATORIO: el paso 4 devuelve el estudio
# con sus fuentes, no un veredicto. Sin este POST no hay score ni PDF.
curl -sS -X POST "$API/api/v1/checks/$CHECK_ID/score" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# 6. ESPERAR el certificado. El PDF se genera en una tarea aparte DESPUÉS de que
# el paso 5 respondió, así que pedirlo enseguida devuelve 404 —no un error de
# permisos: todavía no existe.
#
# Ojo: /report NO devuelve el PDF, devuelve un JSON con una URL firmada.
INTENTOS=0
while :; do
RESP=$(curl -sS -w '\n%{http_code}' "$API/api/v1/checks/$CHECK_ID/report" \
-H "Authorization: Bearer $ACCESS_TOKEN")
CODIGO=$(printf '%s' "$RESP" | tail -1)
CUERPO=$(printf '%s' "$RESP" | sed '$d')
[ "$CODIGO" = "200" ] && break
[ "$CODIGO" = "401" ] && { echo "token vencido: renová con /auth/refresh"; exit 1; }
[ "$CODIGO" = "404" ] || { echo "error HTTP $CODIGO: $CUERPO"; exit 1; }
INTENTOS=$((INTENTOS + 1))
[ "$INTENTOS" -gt 60 ] && { echo "el PDF no se generó en ~3 min"; exit 1; }
sleep 3
done
# Y el PDF, desde la URL firmada.
curl -sS -o certificado.pdf "$(printf '%s' "$CUERPO" | jq -r .download_url)"{
"background_check_id": "019fea9a-eb20-7f21-bb50-e539b48b6573",
"final_verdict": "aprobado",
"verdict_reason": "Score: 1.00, Unavailable sources: 0, Unfinished sources: 0",
"composite_score": 1.0,
"category_scores": {
"criminal_record": { "score": 1.0, "worst_severity": "none", "finding_count": 0 },
"legal_background": { "score": 1.0, "worst_severity": "none", "finding_count": 0 },
"international_background": { "score": 1.0, "worst_severity": "none", "finding_count": 0 },
"personal_identity": { "score": 1.0, "worst_severity": "none", "finding_count": 0 }
},
"unavailable_sources": [],
"business_rules_triggered": [],
"scored_at": "2026-08-10T14:23:15Z"
}No filtres los hallazgos por severidad
Quién decide si un hallazgo cuenta no es su severidad, sino el campo counts_as_finding, que viaja en cada hallazgo. Leer la severidad sola miente en las dos direcciones:
- Un resultado limpio puede traer un hallazgo. Ocho fuentes colombianas expresan “sin antecedentes” emitiendo un hallazgo con severidad
none— Procuraduría emite literalmente “No registra antecedentes”. Contar la lista pinta de rojo una consulta limpia. - Y una coincidencia REAL puede tener severidad
none. Es el caso de PEP (Personas Expuestas Políticamente): la coincidencia es cierta y es informativa, no mueve el veredicto, perocounts_as_findingestrue. Si filtrás por severidad, la escondés.
Por eso el ejemplo de arriba imprime los hallazgos también cuando el estudio termina bien, y no sólo cuando se detiene en la etapa previa: un estudio aprobado puede traer un hallazgo que tenés que mostrar.
Autenticación JWT
Login con credenciales. El access token dura 15 minutos y se renueva con el refresh token.
Consulta del resultado
Un estudio consulta 16 fuentes, así que no responde en el mismo request: se consulta su estado por id.
JSON everywhere
Request y response en JSON. Swagger UI en /swagger-ui con el listado de endpoints.
Rate limiting
Protección inteligente con límites por tenant. Headers X-RateLimit-* en cada response.
Endpoints principales
/api/v1/checks/api/v1/checks/:id/api/v1/batches/api/v1/checks/api/v1/vehicles/api/v1/vehicles/api/v1/checks/{id}/score/api/v1/auditSwagger UI interactivo: Explora y prueba todos los endpoints en /swagger-ui después de iniciar sesión.
¿Listo para integrar?
Solicitá tus credenciales de integración y empezá a validar conductores desde tu sistema.