Verificar Email de Registro
Paso 2 del proceso de registro: verificar el código de 6 dígitos enviado al email para confirmar la propiedad de la cuenta.
Información General
Este endpoint es el Paso 2 del proceso de registro v1. Verifica el código de 6 dígitos enviado al email del usuario para confirmar que el email es válido y accesible por el usuario.
/auth/register/verify?token={token}Verifica el código de verificación enviado por email y habilita al usuario para completar el registro con su contraseña
📋 Parámetros
tokenstringrequeridoToken de sesión UUID obtenido en el Paso 1 del registro
codestringrequeridoCódigo de 6 dígitos numéricos recibido por email
📤 Respuesta
{
"code": 3001,
"message": "Email verified successfully",
"data": null
}Validaciones
Código de Verificación
- Debe ser exactamente 6 dígitos numéricos
- No se permiten letras ni caracteres especiales
- Es sensible a cada dígito (no es case-sensitive porque solo son números)
- Regex de validación:
/^\\d{6}$/
Token de Sesión
- Debe ser un token UUID válido obtenido en el Paso 1
- Tiene una validez de 10 minutos desde su emisión
- Debe existir en Redis con los datos de sesión correspondientes
- No debe haber sido verificado previamente
Respuestas
Respuesta Exitosa
Email Verificado Exitosamente
Código 3001 - El código de verificación es correcto y el email ha sido confirmado.
{
"code": 3001,
"message": "Email verified successfully",
"data": null
}
Siguiente paso: Después de esta respuesta, el usuario puede proceder al Paso 3: completar el registro estableciendo su contraseña.
Cambios en el sistema:
- Se marca el token como verificado en Redis
- Se establece la clave
verify:{token}con valor'true' - El token permanece válido por 10 minutos para el Paso 3
Errores
Datos Faltantes o Inválidos
Código 4006 - Faltan campos requeridos o el formato del código es inválido.
{
"code": 4006,
"message": "Missing required data"
}
Causas posibles:
- No se proporcionó el código en el body
- El código no tiene exactamente 6 dígitos
- No se proporcionó el token en query params
- El formato del código incluye caracteres no numéricos
Token de Sesión Inválido
Código 4015 - El token de sesión no existe, expiró o es inválido.
{
"code": 4015,
"message": "Invalid session token"
}
Causas posibles:
- El token expiró (más de 10 minutos desde el Paso 1)
- Token malformado o no válido
- La sesión fue eliminada de Redis
- Token usado en una verificación anterior
Solución: El usuario debe reiniciar el proceso de registro desde el Paso 1.
Código de Verificación Incorrecto
Código 4005 - El código proporcionado no coincide con el código enviado.
{
"code": 4005,
"message": "Invalid verification code"
}
Causas posibles:
- Código ingresado incorrectamente
- Código de un email anterior (si se solicitó reenvío)
- Typo en algún dígito
Solución:
- Verificar el email nuevamente
- Solicitar reenvío del código si es necesario
- Intentar nuevamente con el código correcto
Token de Verificación Inválido
Código 4004 - El token de verificación interno no existe o expiró.
{
"code": 4004,
"message": "The verification token is invalid"
}
Causas posibles:
- El código de verificación expiró en Redis
- La sesión de verificación fue limpiada
- Error interno del sistema
Solución: Solicitar un nuevo código usando el endpoint de reenvío.
Ejemplos de Implementación
JavaScript/TypeScript
const verifyRegistrationEmail = async (token, code) => {
try {
const response = await fetch(
`https://api.swapbits.co/auth/register/verify?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ code })
}
);
const result = await response.json();
if (result.code === 3001) {
console.log('Email verificado exitosamente');
// Redirigir al paso 3: establecer contraseña
return {
success: true,
message: 'Email verificado. Ahora establece tu contraseña.'
};
} else if (result.code === 4005) {
console.error('Código incorrecto');
return {
success: false,
error: 'INVALID_CODE',
message: 'El código ingresado es incorrecto. Intenta nuevamente.'
};
} else if (result.code === 4015) {
console.error('Sesión expirada');
return {
success: false,
error: 'SESSION_EXPIRED',
message: 'Tu sesión ha expirado. Reinicia el registro.'
};
} else if (result.code === 4004) {
console.error('Código expirado');
return {
success: false,
error: 'CODE_EXPIRED',
message: 'El código ha expirado. Solicita uno nuevo.'
};
}
return { success: false, error: result.message };
} catch (error) {
console.error('Error verificando email:', error);
return { success: false, error: error.message };
}
};
// Validación del código en el frontend
const validateCode = (code) => {
const regex = /^\d{6}$/;
return regex.test(code);
};
// Uso
const token = sessionStorage.getItem('registrationToken');
const code = '123456';
if (validateCode(code)) {
const result = await verifyRegistrationEmail(token, code);
if (result.success) {
// Mostrar formulario de contraseña
showPasswordForm();
} else {
// Mostrar error al usuario
showError(result.message);
}
} else {
console.error('Formato de código inválido');
}
TypeScript con manejo de tipos
interface VerifyEmailResponse {
code: number;
message: string;
data: null;
}
interface VerifyResult {
success: boolean;
error?: string;
message?: string;
}
const verifyRegistrationEmail = async (
token: string,
code: string
): Promise<VerifyResult> => {
// Validación previa
if (!/^\d{6}$/.test(code)) {
return {
success: false,
error: 'INVALID_FORMAT',
message: 'El código debe tener exactamente 6 dígitos'
};
}
try {
const response = await fetch(
`https://api.swapbits.co/auth/register/verify?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ code }),
}
);
const result: VerifyEmailResponse = await response.json();
switch (result.code) {
case 3001:
return {
success: true,
message: 'Email verificado exitosamente'
};
case 4005:
return {
success: false,
error: 'INVALID_CODE',
message: 'Código incorrecto'
};
case 4015:
return {
success: false,
error: 'SESSION_EXPIRED',
message: 'Sesión expirada'
};
case 4004:
return {
success: false,
error: 'CODE_EXPIRED',
message: 'Código expirado'
};
default:
return {
success: false,
error: 'UNKNOWN',
message: result.message
};
}
} catch (error) {
return {
success: false,
error: 'NETWORK_ERROR',
message: error instanceof Error ? error.message : 'Error de red'
};
}
};
// Componente de ejemplo con manejo de estados
const VerificationForm = () => {
const [code, setCode] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleVerify = async () => {
setLoading(true);
setError(null);
const token = sessionStorage.getItem('registrationToken');
if (!token) {
setError('No se encontró el token de sesión');
setLoading(false);
return;
}
const result = await verifyRegistrationEmail(token, code);
if (result.success) {
// Navegar al siguiente paso
navigate('/register/complete');
} else {
setError(result.message || 'Error desconocido');
}
setLoading(false);
};
return (
<div>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
maxLength={6}
pattern="\d{6}"
placeholder="123456"
/>
<button onClick={handleVerify} disabled={loading || code.length !== 6}>
{loading ? 'Verificando...' : 'Verificar'}
</button>
{error && <div className="error">{error}</div>}
</div>
);
};
Python
import requests
import re
def validate_code_format(code: str) -> bool:
"""Validar formato del código"""
return bool(re.match(r'^\d{6}$', code))
def verify_registration_email(token: str, code: str) -> dict:
"""
Verificar código de email para registro
Args:
token: Token de sesión del paso 1
code: Código de 6 dígitos
Returns:
Resultado de la verificación
"""
# Validación previa
if not validate_code_format(code):
return {
'success': False,
'error': 'INVALID_FORMAT',
'message': 'El código debe tener exactamente 6 dígitos numéricos'
}
url = 'https://api.swapbits.co/auth/register/verify'
params = {'token': token}
data = {'code': code}
try:
response = requests.post(url, params=params, json=data, timeout=10)
result = response.json()
if result['code'] == 3001:
print("Email verificado exitosamente")
return {
'success': True,
'message': 'Email verificado. Procede a establecer tu contraseña.'
}
elif result['code'] == 4005:
print("Código incorrecto")
return {
'success': False,
'error': 'INVALID_CODE',
'message': 'El código ingresado es incorrecto'
}
elif result['code'] == 4015:
print("Sesión expirada")
return {
'success': False,
'error': 'SESSION_EXPIRED',
'message': 'Tu sesión ha expirado. Reinicia el registro.'
}
elif result['code'] == 4004:
print("Código expirado")
return {
'success': False,
'error': 'CODE_EXPIRED',
'message': 'El código ha expirado. Solicita uno nuevo.'
}
elif result['code'] == 4006:
return {
'success': False,
'error': 'MISSING_DATA',
'message': 'Datos faltantes o inválidos'
}
else:
return {
'success': False,
'error': 'UNKNOWN',
'message': result.get('message', 'Error desconocido')
}
except requests.exceptions.RequestException as e:
print(f"Error de conexión: {e}")
return {
'success': False,
'error': 'NETWORK_ERROR',
'message': str(e)
}
# Ejemplo de uso con interfaz CLI
def main():
token = input("Ingresa el token de registro: ")
while True:
code = input("Ingresa el código de 6 dígitos: ")
if not validate_code_format(code):
print("Error: El código debe tener exactamente 6 dígitos")
continue
result = verify_registration_email(token, code)
if result['success']:
print(f"Éxito: {result['message']}")
break
else:
print(f"Error: {result['message']}")
if result['error'] == 'SESSION_EXPIRED':
print("Debes reiniciar el proceso de registro")
break
elif result['error'] == 'CODE_EXPIRED':
retry = input("¿Solicitar nuevo código? (s/n): ")
if retry.lower() != 's':
break
else:
retry = input("¿Intentar nuevamente? (s/n): ")
if retry.lower() != 's':
break
if __name__ == '__main__':
main()
cURL
# Verificación básica
curl -X POST \
'https://api.swapbits.co/auth/register/verify?token=550e8400-e29b-41d4-a716-446655440000' \
-H 'Content-Type: application/json' \
-d '{
"code": "123456"
}'
# Script bash con manejo de respuesta
#!/bin/bash
TOKEN="550e8400-e29b-41d4-a716-446655440000"
CODE="123456"
response=$(curl -s -X POST \
"https://api.swapbits.co/auth/register/verify?token=$TOKEN" \
-H 'Content-Type: application/json' \
-d "{\"code\": \"$CODE\"}")
code=$(echo $response | jq -r '.code')
message=$(echo $response | jq -r '.message')
case $code in
3001)
echo "Éxito: Email verificado"
echo "Procede al paso 3: establecer contraseña"
;;
4005)
echo "Error: Código incorrecto"
;;
4015)
echo "Error: Sesión expirada - Reinicia el registro"
;;
4004)
echo "Error: Código expirado - Solicita uno nuevo"
;;
*)
echo "Error: $message"
;;
esac
Flujo de Verificación
graph TD
A[POST /auth/register/verify] --> B{Validar formato código}
B -->|Inválido| C[Error 4006]
B -->|Válido| D{Token existe?}
D -->|No| E[Error 4015]
D -->|Sí| F{Código de verificación existe?}
F -->|No| G[Error 4004]
F -->|Sí| H{Código coincide?}
H -->|No| I[Error 4005]
H -->|Sí| J[Marcar como verificado]
J --> K[Retornar éxito 3001]
K --> L[Usuario puede proceder al Paso 3]
Manejo de Errores Común
Sistema de Reintentos
const verifyWithRetry = async (token, code, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
console.log(`Intento ${attempt} de ${maxRetries}`);
const result = await verifyRegistrationEmail(token, code);
if (result.success) {
return result;
}
// No reintentar si el error no es recuperable
if (result.error === 'SESSION_EXPIRED' || result.error === 'CODE_EXPIRED') {
return result;
}
// Esperar antes del siguiente intento
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
return {
success: false,
error: 'MAX_RETRIES',
message: 'Se alcanzó el máximo de intentos'
};
};
Consideraciones de Seguridad
Seguridad del Código de Verificación
Medidas implementadas:
- Códigos de un solo uso (se invalidan después de verificación exitosa)
- Expiración de 10 minutos desde la emisión
- Cooldown de 30 segundos entre reenvíos
- Validación estricta de formato (solo 6 dígitos numéricos)
- Los códigos se almacenan en Redis con TTL automático
- No hay límite de intentos por código (considera implementar rate limiting en producción)
Recomendaciones:
- Implementar rate limiting por IP/usuario
- Considerar bloqueo temporal después de múltiples intentos fallidos
- Registrar intentos de verificación para análisis de seguridad
Notas Importantes
Flujo de Registro Completo
Este endpoint es el Paso 2 de 3 en el proceso de registro v1:
- Paso 1: Iniciar Registro - Enviar email
- Paso 2: Verificar Email (este endpoint) - Confirmar código
- Paso 3: Completar Registro - Establecer contraseña
Después de verificar exitosamente, el usuario tiene 10 minutos para completar el Paso 3 antes de que expire la sesión.
Reenvío de Código
Si el código no llega o expira, utiliza el endpoint de reenvío de código para solicitar un nuevo código.
- Cooldown de 30 segundos entre reenvíos
- El nuevo código invalida el anterior
- Requiere el mismo token de sesión
Probar esta API
¿Quieres probar este endpoint de forma interactiva con tus propios datos?