GDPR & Data Deletion
KAPEX is designed for GDPR and CCPA compliance from the ground up. User data can be bulk-erased, suppressed, or exported. This page documents the compliance features available through the API.
Data Deletion (Article 17 -- Right to Erasure)
Delete All Data for a User
Erase everything KAPEX knows about a user. This is an atomic operation that removes all memory nodes, entity nodes, facets, themes, interests, edges, domain memberships, processing history, salience scores, and cached retrieval results.
curl -X DELETE https://api.getkapex.ai/api/v1/users/user_123 \
-H "X-API-Key: $KAPEX_API_KEY"
{
"status": "deleted",
"user_id": "user_123",
"nodes_deleted": 47
}
What Gets Deleted
When a user is deleted, the following data is permanently removed:
| Data Type | Deleted |
|---|---|
| Memory node content (topic, summary) | Yes |
| Salience scores (current and historical) | Yes |
| Processing events and counts | Yes |
| All edges to/from user's nodes | Yes |
| Entity nodes | Yes |
| Facet, theme, and interest nodes | Yes |
| Domain nodes and memberships | Yes |
| Cached retrieval results | Invalidated |
| Temporal patterns | Yes |
| Cross-domain co-activation records | Yes |
Deletion is immediate and irreversible. There is no soft-delete, no recycle bin, and no recovery mechanism. Once deleted, the data cannot be restored.
Topic Suppression
Users can instruct KAPEX to never store or retrieve memories about a specific topic. This goes beyond deletion -- it prevents future storage.
When a topic is suppressed:
- Existing nodes matching the suppressed topic are excluded from retrieval (they are not deleted, but they will never appear in LLM context)
- New information about the suppressed topic is not stored -- it is discarded during the async write path
- Suppression is persistent -- it survives across sessions until explicitly lifted
Note: Topic suppression is managed through the safety pin system. Contact support for suppression API details.
Data Portability (Article 20)
Users have the right to receive their personal data in a structured, machine-readable format.
curl "https://api.getkapex.ai/api/v1/context/user_123" \
-H "X-API-Key: $KAPEX_API_KEY" \
-o user_123_export.json
The export includes all data KAPEX holds for the user:
{
"user_id": "user_123",
"exported_at": "2026-05-19T12:00:00Z",
"domains": [
{
"name": "work",
"entities": [
{
"name": "KAPEX Project",
"facets": [
{
"topic": "Tech stack",
"summary": "Uses PostgreSQL, Redis, and Amazon Bedrock",
"salience": 0.61,
"created_at": "2026-03-01T09:00:00Z"
}
],
"themes": [],
"interests": []
}
]
}
],
"suppressed_topics": ["divorce proceedings"],
"total_nodes": 347,
"total_edges": 892
}
Audit Trail
KAPEX logs deletion events for compliance verification. The audit log records:
- What was deleted -- node ID(s) or user ID
- When it was deleted -- timestamp
- Who requested it -- API key or user identifier
- How many records were affected -- node count, edge count
The audit log retains only the fact that a deletion occurred. It does not retain any of the deleted content. This allows you to prove compliance with an erasure request without re-storing the erased data.
PII Handling
KAPEX includes an automatic PII scrubber that runs during the ingestion pipeline. The following categories of extreme PII are detected and redacted before any data is written to the database:
| PII Type | Example | Action |
|---|---|---|
| Social Security Numbers | 123-45-6789 | Redacted before storage |
| Credit card numbers | 4111-1111-1111-1111 | Redacted before storage |
| CVV codes | 3-4 digit card verification codes | Redacted before storage |
| Bank account numbers | Detected via pattern matching | Redacted before storage |
| Routing numbers | 9-digit ABA routing numbers | Redacted before storage |
| Passport numbers | Country-specific formats | Redacted before storage |
| Driver's license numbers | State/country-specific formats | Redacted before storage |
PII scrubbing is automatic and cannot be disabled. It runs on all node content before it reaches the database, regardless of how the node was created (automatic extraction or API call).
Data Residency and Encryption
| Property | Details |
|---|---|
| Data location | AWS us-east-1 (N. Virginia) |
| Encryption at rest | AES-256 (RDS, ElastiCache, S3) |
| Encryption in transit | TLS 1.2+ (all API traffic via CloudFront) |
| Database | Amazon RDS PostgreSQL (encrypted storage, automated backups) |
| Cache | Amazon ElastiCache Redis (encrypted, in-transit encryption enabled) |
| Backup retention | Configurable per deployment |
Data Retention
KAPEX does not automatically delete data based on age. Memories persist in the graph until:
- They are explicitly deleted via the API (node deletion or user deletion)
- They are suppressed via topic suppression
- They are compressed by the lifecycle manager (old, low-salience memories are consolidated into summary nodes -- the summaries are retained, the originals are removed)
You control what stays and what goes. There is no automatic expiration unless you configure it.
Compliance Workflow Examples
Handling a "Right to Be Forgotten" Request
import requests
API_BASE = "https://api.getkapex.ai/api/v1"
HEADERS = {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
def handle_erasure_request(user_id: str) -> dict:
"""Handle a GDPR Article 17 erasure request."""
# Step 1: Export user data for compliance records (optional)
export = requests.get(
f"{API_BASE}/export/{user_id}",
headers=HEADERS
)
# Store export in your compliance archive if required
# Step 2: Delete all user data from KAPEX
response = requests.delete(
f"{API_BASE}/users/{user_id}",
headers=HEADERS
)
result = response.json()
print(f"Deleted {result['nodes_deleted']} nodes for user {user_id}")
return result
Finding Memories Before Deletion
To review what KAPEX stores for a user before deleting, use the entities endpoint:
def review_user_data(user_id: str):
"""Review all entities stored for a user."""
response = requests.get(
f"{API_BASE}/context/{user_id}",
headers=HEADERS
)
data = response.json()
for domain in data.get("domains", []):
print(f"\nDomain: {domain['name']}")
for entity in domain.get("entities", []):
print(f" - {entity['name']} (salience: {entity['salience']:.2f})")
print(f"\nTotal: {data['total_entities']} entities across {data['total_domains']} domains")
return data