Evidence Preservation
When decisions are contested—whether by users, regulators, or in court—you need the complete picture. Vettly preserves evidence in a GDPR-compliant manner.
What Gets Preserved
Decision Records
Every decision automatically preserves:
- Decision ID and timestamp
- Policy version in effect
- Provider scores and classifications
- Action taken
- Context metadata (user, session, IP)
- Input content hash
Content Preservation
For flagged/blocked content, optionally preserve the actual content:
typescript
const vettly = new VettlyClient({
apiKey: 'your-api-key',
evidence: {
preserveContent: true,
preserveFor: ['flag', 'block'], // Only preserve non-allowed content
storage: {
type: 's3',
bucket: 'evidence-storage',
encryption: 'AES-256'
}
}
})Context Snapshots
Preserve additional context at decision time:
typescript
const decision = await vettly.check({
content: post.body,
context: {
userId: user.id,
sessionId: session.id,
ipAddress: request.ip,
userAgent: request.headers['user-agent'],
// Snapshot user state
userContext: {
accountAge: user.createdAt,
previousViolations: user.violationCount,
verificationStatus: user.verified
},
// Snapshot content context
contentContext: {
parentPostId: post.parentId,
threadId: post.threadId,
mentions: post.mentions
}
}
})GDPR Compliance
Right to Access
Users can request their decision history:
typescript
// Generate user data export
const export = await vettly.exportUserData({
userId: 'user_123',
format: 'json',
includeDecisions: true,
includeAppeals: true
})Right to Erasure
Delete user data while preserving anonymized records:
typescript
await vettly.deleteUserData({
userId: 'user_123',
reason: 'GDPR erasure request',
options: {
// Keep anonymized decision stats for reporting
preserveAnonymizedStats: true,
// Keep content hashes for verification
preserveContentHashes: true,
// Remove all PII
removePersonalData: true
}
})Data Minimization
Only preserve what you need:
typescript
await vettly.configureEvidence({
// Only preserve blocked content
preserveFor: ['block'],
// Auto-delete after retention period
retention: {
default: '30d',
blocked: '90d',
legalHold: 'indefinite'
},
// Exclude sensitive fields
exclude: ['userAgent', 'ipAddress']
})Retention Policies
By Action Type
typescript
await vettly.setRetentionPolicy({
allow: '7d', // Short retention for allowed content
warn: '30d', // Medium for warnings
flag: '90d', // Longer for flagged
block: '365d', // Longest for blocked
appeal: '365d' // Keep appealed decisions
})By Category
typescript
await vettly.setRetentionPolicy({
byCategory: {
csam: '7y', // Legal requirement
terrorism: '5y', // Regulatory requirement
harassment: '90d', // Standard retention
spam: '30d' // Short retention
}
})Legal Hold
Override retention for litigation:
typescript
await vettly.setLegalHold({
name: 'Case #12345 - Smith v. Platform',
scope: {
// Hold specific decisions
decisionIds: ['dec_abc...', 'dec_def...'],
// Or hold all decisions matching criteria
filter: {
userId: 'user_123',
dateRange: {
from: '2024-01-01',
to: '2024-03-31'
}
}
},
expiry: '2026-12-31', // Or 'indefinite'
reason: 'Litigation hold per legal counsel'
})Storage Security
Encryption
All evidence is encrypted:
typescript
await vettly.configureEvidence({
encryption: {
atRest: 'AES-256',
inTransit: 'TLS-1.3',
keyRotation: '90d'
}
})Access Control
typescript
await vettly.setEvidenceAccess({
roles: {
'moderation-team': {
canView: true,
canExport: false,
canDelete: false
},
'compliance-team': {
canView: true,
canExport: true,
canDelete: false
},
'legal-team': {
canView: true,
canExport: true,
canDelete: false,
canSetLegalHold: true
}
}
})Audit Logging
All access is logged:
typescript
const accessLog = await vettly.getEvidenceAccessLog({
decisionId: 'dec_abc123',
from: '2024-01-01'
})
// Returns:
[
{ action: 'viewed', user: 'admin@...', timestamp: '...', ip: '...' },
{ action: 'exported', user: 'legal@...', timestamp: '...', ip: '...' },
]Verification
Content Integrity
Verify content hasn't changed since decision:
typescript
const verification = await vettly.verifyEvidence({
decisionId: 'dec_abc123',
currentContent: currentContentFromDb
})
// Returns:
{
verified: true, // or false if content changed
originalHash: 'abc123...',
currentHash: 'abc123...',
decision: { /* original decision */ }
}Chain of Custody
Document evidence handling:
typescript
const chain = await vettly.getEvidenceChain('dec_abc123')
// Returns:
[
{ event: 'decision_made', timestamp: '...', hash: '...' },
{ event: 'content_preserved', timestamp: '...', location: 's3://...' },
{ event: 'legal_hold_set', timestamp: '...', user: 'legal@...', reason: '...' },
{ event: 'exported', timestamp: '...', user: 'legal@...', destination: '...' }
]Export for Legal
Complete Evidence Package
typescript
const package = await vettly.exportEvidencePackage({
decisionId: 'dec_abc123',
format: 'pdf', // or 'json'
include: [
'decision',
'content',
'context',
'policyVersion',
'providerResponse',
'chainOfCustody',
'verificationSignature'
]
})Bulk Export
typescript
const export = await vettly.exportEvidencePackage({
filter: {
userId: 'user_123',
dateRange: {
from: '2024-01-01',
to: '2024-03-31'
}
},
format: 'json',
destination: {
type: 'download' // or 's3', 'email'
}
})Next Steps
- Decision Records - Understand what's preserved
- Audit Trails - Track all access
- Legal Discovery - Prepare for litigation
