Eliminar Clave de API
Expira (desactiva) una clave de API, evitando que sea usada para futuros requests de API. Esto también se llama "revocar" una clave.
Endpoint
DELETE /api/v1/api-keys/{api_key_id}
Autenticación
Requiere token JWT (autenticación Bearer).
Parámetros de Path
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
api_key_id | UUID | Sí | El ID de la clave de API a expirar |
Response
Response Exitoso (200 OK)
{
"message": "Clave de API expirada exitosamente",
"success": true
}
Ejemplos
curl -X DELETE https://api.callcov.com/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000 \-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Qué Sucede Cuando una Clave Expira
- Marcada como inactiva:
is_activese establece enfalse - Los requests de API fallan: La clave ya no puede autenticar
- No puede reactivarse: La expiración es permanente
- Se mantiene en historial: La clave permanece en la base de datos para propósitos de auditoría
- Libera un espacio: Permite crear nuevas claves (máx 10 activas)
Casos de Uso
Revocar Clave Comprometida
def revoke_compromised_key(access_token, key_id):
"""Revocar inmediatamente una clave de API comprometida"""
url = f"https://api.callcov.com/api/v1/api-keys/{key_id}"
headers = {"Authorization": f"Bearer {access_token}"}
response = requests.delete(url, headers=headers)
if response.status_code == 200:
print("⚠️ ¡Clave comprometida revocada!")
print("Crea una nueva clave y actualiza tus aplicaciones inmediatamente.")
return True
return False
Rotación de Claves
def rotate_api_key(access_token, old_key_id, description):
"""Rotar una clave de API: crear nueva, expirar vieja"""
# Crear nueva clave
create_url = "https://api.callcov.com/api/v1/api-keys/"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
new_key_response = requests.post(
create_url,
headers=headers,
json={"description": description}
)
if new_key_response.status_code == 201:
new_key = new_key_response.json()['api_key']
print(f"✅ Nueva clave creada: {new_key}")
print("⚠️ ¡GUARDA ESTA CLAVE AHORA!")
# Expirar clave vieja
delete_url = f"https://api.callcov.com/api/v1/api-keys/{old_key_id}"
requests.delete(delete_url, headers=headers)
print("✅ Clave vieja expirada")
return new_key
return None
Limpiar Claves Sin Usar
def cleanup_unused_keys(access_token):
"""Expirar todas las claves de API que nunca se han usado"""
headers = {"Authorization": f"Bearer {access_token}"}
# Obtener todas las claves
list_url = "https://api.callcov.com/api/v1/api-keys/"
response = requests.get(list_url, headers=headers)
keys = response.json()['api_keys']
unused_keys = [k for k in keys if k['last_used_at'] is None]
print(f"Se encontraron {len(unused_keys)} claves sin usar")
for key in unused_keys:
# Pedir confirmación
confirm = input(f"¿Expirar {key['key_prefix']} ({key['description']})? (s/n): ")
if confirm.lower() == 's':
delete_url = f"https://api.callcov.com/api/v1/api-keys/{key['id']}"
requests.delete(delete_url, headers=headers)
print(f" ✅ Expirada {key['key_prefix']}")
else:
print(f" ⏭️ Omitida {key['key_prefix']}")
Errores
400 Bad Request
La clave ya está expirada:
{
"detail": "La clave de API ya está expirada"
}
404 Not Found
Clave de API no encontrada o no te pertenece:
{
"detail": "Clave de API no encontrada"
}
401 Unauthorized
Token JWT inválido o faltante:
{
"detail": "No se pudieron validar las credenciales"
}
Cuándo Expirar una Clave de API
✅ Expirar inmediatamente cuando:
- Comprometida: La clave fue expuesta o filtrada
- Ya no se necesita: La integración fue dada de baja
- Rotación: Implementando política de rotación regular de claves
- Brecha de seguridad: Medida de precaución
- Offboarding de empleado: La clave fue usada por alguien que se fue
⏸️ Considerar antes de expirar:
- En uso: Verificar
last_used_atpara ver si se usa activamente - Impacto: ¿Esto romperá alguna integración en ejecución?
- Reemplazo: ¿Tienes una nueva clave lista?
- Comunicación: ¿Notificaste a los miembros del equipo?
Mejores Prácticas
Rotación Regular de Claves
# Rotar claves cada 90 días
from datetime import datetime, timedelta
def should_rotate(key):
created = datetime.fromisoformat(key['created_at'].replace('Z', '+00:00'))
age = datetime.now(timezone.utc) - created
return age.days >= 90 # 90 días de antigüedad
# Verificar todas las claves
keys = get_api_keys(access_token)
for key in keys:
if should_rotate(key):
print(f"⚠️ La clave {key['key_prefix']} tiene {age.days} días - considerar rotar")
Proceso de Revocación de Emergencia
- Identificar clave comprometida (por prefijo o descripción)
- Revocar inmediatamente (no esperar)
- Crear nueva clave (si aún se necesita)
- Actualizar aplicaciones (deployar nueva clave)
- Verificar bloqueo de clave vieja (probar que falla)
- Documentar incidente (para auditoría de seguridad)
Antes de Expirar
# Verificar que la clave existe y está activa antes de expirar
def safe_expire_key(access_token, key_id):
"""Expirar una clave de forma segura con verificación"""
headers = {"Authorization": f"Bearer {access_token}"}
# Primero, verificar que la clave existe
list_url = "https://api.callcov.com/api/v1/api-keys/"
response = requests.get(list_url, headers=headers)
keys = response.json()['api_keys']
key_to_expire = next((k for k in keys if k['id'] == key_id), None)
if not key_to_expire:
print("❌ Clave no encontrada")
return False
if not key_to_expire['is_active']:
print("⚠️ La clave ya está expirada")
return False
print(f"A punto de expirar:")
print(f" Prefijo: {key_to_expire['key_prefix']}")
print(f" Descripción: {key_to_expire['description']}")
print(f" Creada: {key_to_expire['created_at']}")
print(f" Último uso: {key_to_expire['last_used_at'] or 'Nunca'}")
confirm = input("¿Proceder? (si/no): ")
if confirm.lower() == 'si':
delete_url = f"https://api.callcov.com/api/v1/api-keys/{key_id}"
response = requests.delete(delete_url, headers=headers)
if response.status_code == 200:
print("✅ Clave expirada exitosamente")
return True
print("❌ Expiración cancelada")
return False
Seguridad
- Aislamiento de usuarios: Solo puedes expirar tus propias claves
- Acción permanente: No se puede deshacer
- Efecto inmediato: La clave deja de funcionar instantáneamente
- Registro de auditoría: Las claves expiradas permanecen en el historial
Diferencia Entre Expirar y Eliminar
Este endpoint expira (elimina de forma lógica) la clave:
- ✅ La clave se desactiva
- ✅ La clave permanece en la base de datos
- ✅ Se muestra en historial con
include_expired=true - ✅ Se preserva el registro de auditoría
La clave NO se elimina permanentemente:
- ❌ La clave no se elimina de la base de datos
- ❌ No se puede reutilizar la misma clave
Relacionado
- Crear Clave de API - Generar nueva clave de API
- Listar Claves de API - Ver todas tus claves de API
- Guía de Autenticación - Usar claves de API