Skip to main content

Delete API Key

Expires (deactivates) an API key, preventing it from being used for future API requests. This is also called "revoking" a key.

Endpoint​

DELETE /api/v1/api-keys/{api_key_id}

Authentication​

Requires JWT token (Bearer authentication).

Path Parameters​

ParameterTypeRequiredDescription
api_key_idUUIDYesThe ID of the API key to expire

Response​

Success Response (200 OK)​

{
"message": "API key expired successfully",
"success": true
}

Examples​

curl -X DELETE https://api.callcov.com/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

What Happens When a Key is Expired​

  1. Marked as inactive: is_active set to false
  2. API requests fail: Key can no longer authenticate
  3. Cannot be reactivated: Expiration is permanent
  4. Retained in history: Key remains in database for audit purposes
  5. Frees up slot: Allows creating new keys (max 10 active)

Use Cases​

Revoke Compromised Key​

def revoke_compromised_key(access_token, key_id):
"""Immediately revoke a compromised API key"""
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("⚠️ Compromised key revoked!")
print("Create a new key and update your applications immediately.")
return True
return False

Key Rotation​

def rotate_api_key(access_token, old_key_id, description):
"""Rotate an API key: create new, expire old"""
# Create new key
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"βœ… New key created: {new_key}")
print("⚠️ SAVE THIS KEY NOW!")

# Expire old key
delete_url = f"https://api.callcov.com/api/v1/api-keys/{old_key_id}"
requests.delete(delete_url, headers=headers)

print("βœ… Old key expired")
return new_key

return None

Cleanup Unused Keys​

def cleanup_unused_keys(access_token):
"""Expire all API keys that have never been used"""
headers = {"Authorization": f"Bearer {access_token}"}

# Get all keys
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"Found {len(unused_keys)} unused keys")

for key in unused_keys:
# Ask for confirmation
confirm = input(f"Expire {key['key_prefix']} ({key['description']})? (y/n): ")

if confirm.lower() == 'y':
delete_url = f"https://api.callcov.com/api/v1/api-keys/{key['id']}"
requests.delete(delete_url, headers=headers)
print(f" βœ… Expired {key['key_prefix']}")
else:
print(f" ⏭️ Skipped {key['key_prefix']}")

Errors​

400 Bad Request​

Key is already expired:

{
"detail": "API key is already expired"
}

404 Not Found​

API key not found or doesn't belong to you:

{
"detail": "API key not found"
}

401 Unauthorized​

Invalid or missing JWT token:

{
"detail": "Could not validate credentials"
}

When to Expire an API Key​

βœ… Expire immediately when:​

  • Compromised: Key was exposed or leaked
  • No longer needed: Integration is decommissioned
  • Rotation: Implementing regular key rotation policy
  • Security breach: Precautionary measure
  • Employee offboarding: Key was used by someone who left

⏸️ Consider before expiring:​

  • In use: Check last_used_at to see if actively used
  • Impact: Will this break any running integrations?
  • Replacement: Do you have a new key ready?
  • Communication: Have you notified team members?

Best Practices​

Regular Key Rotation​

# Rotate keys every 90 days
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 days old

# Check all keys
keys = get_api_keys(access_token)
for key in keys:
if should_rotate(key):
print(f"⚠️ Key {key['key_prefix']} is {age.days} days old - consider rotating")

Emergency Revocation Process​

  1. Identify compromised key (by prefix or description)
  2. Revoke immediately (don't wait)
  3. Create new key (if still needed)
  4. Update applications (deploy new key)
  5. Verify old key blocked (test that it fails)
  6. Document incident (for security audit)

Before Expiring​

# Verify key exists and is active before expiring
def safe_expire_key(access_token, key_id):
"""Safely expire a key with verification"""
headers = {"Authorization": f"Bearer {access_token}"}

# First, verify the key exists
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("❌ Key not found")
return False

if not key_to_expire['is_active']:
print("⚠️ Key is already expired")
return False

print(f"About to expire:")
print(f" Prefix: {key_to_expire['key_prefix']}")
print(f" Description: {key_to_expire['description']}")
print(f" Created: {key_to_expire['created_at']}")
print(f" Last used: {key_to_expire['last_used_at'] or 'Never'}")

confirm = input("Proceed? (yes/no): ")

if confirm.lower() == 'yes':
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("βœ… Key expired successfully")
return True

print("❌ Expiration cancelled")
return False

Security​

  • User isolation: You can only expire your own keys
  • Permanent action: Cannot be undone
  • Immediate effect: Key stops working instantly
  • Audit trail: Expired keys remain in history

Difference Between Expire and Delete​

This endpoint expires (soft deletes) the key:

  • βœ… Key is deactivated
  • βœ… Key remains in database
  • βœ… Shows in history with include_expired=true
  • βœ… Audit trail preserved

The key is NOT permanently deleted:

  • ❌ Key is not removed from database
  • ❌ Cannot reuse the same key