13 KiB
13 KiB
Keys for All API Workflow Plan
Overview
The Keys for All API enables applications to manage user keys and feature unlocking dynamically. Users can unlock features with their keys and re-lock features to unlock different ones at any time.
Core Concepts
1. Keys and Feature Requirements
- Each user can have multiple keys in their account
- Features can require 1 or more keys to unlock
- Basic features: 1 key
- Premium features: 2-3 keys
- Advanced features: 4+ keys
- Users can allocate/deallocate keys to features dynamically
2. Feature States
- Locked: Feature is not accessible (insufficient keys allocated)
- Unlocked: Feature is active with required keys allocated
- Available: Feature can be unlocked (user has enough unallocated keys)
- Unavailable: Feature cannot be unlocked (insufficient total keys)
3. Key States
- Active: Key is validated and can be used
- Allocated: Key is currently assigned to a feature
- Unallocated: Key is available to be assigned to features
- Expired: Key has passed its expiration date
- Revoked: Key has been disabled by the app owner
API Workflows
1. Load User's Keys and Status
POST /api/users/load-keys
Headers: X-API-Key: {app_api_key}
Body: {
"keys": ["XXXX-XXXX-XXXX-XXXX", "YYYY-YYYY-YYYY-YYYY"],
"device_id": "unique-device-id",
"device_info": {
"platform": "ios",
"version": "1.0.0"
}
}
Response: {
"user_id": "uuid",
"keys": [
{
"key": "XXXX-XXXX-XXXX-XXXX",
"key_id": "uuid1",
"status": "active",
"allocated_to": "voice_changer",
"expires_at": null
},
{
"key": "YYYY-YYYY-YYYY-YYYY",
"key_id": "uuid2",
"status": "active",
"allocated_to": "voice_changer",
"expires_at": null
}
],
"total_keys": 2,
"allocated_keys": 2,
"unallocated_keys": 0,
"features": {
"unlocked": [
{
"id": "voice_changer",
"keys_required": 2,
"keys_allocated": 2
}
],
"available": [
{
"id": "echo_effect",
"keys_required": 1
}
],
"unavailable": [
{
"id": "premium_reverb",
"keys_required": 3,
"reason": "insufficient_keys"
}
]
}
}
2. Get User's Feature Status
GET /api/users/{user_id}/features
Headers: X-API-Key: {app_api_key}
Response: {
"user_id": "uuid",
"total_keys": 5,
"allocated_keys": 3,
"unallocated_keys": 2,
"features": [
{
"id": "voice_changer",
"name": "Voice Changer",
"category": "audio_effects",
"keys_required": 2,
"keys_allocated": 2,
"status": "unlocked",
"allocated_key_ids": ["uuid1", "uuid2"],
"unlocked_at": "2024-01-15T10:00:00Z"
},
{
"id": "echo_effect",
"name": "Echo Effect",
"category": "audio_effects",
"keys_required": 1,
"keys_allocated": 1,
"status": "unlocked",
"allocated_key_ids": ["uuid3"],
"unlocked_at": "2024-01-15T10:05:00Z"
},
{
"id": "pitch_shift",
"name": "Pitch Shift",
"category": "audio_effects",
"keys_required": 1,
"keys_allocated": 0,
"status": "available",
"allocated_key_ids": []
},
{
"id": "premium_reverb",
"name": "Premium Reverb",
"category": "premium_effects",
"keys_required": 3,
"keys_allocated": 0,
"status": "unavailable",
"allocated_key_ids": []
}
]
}
3. Unlock a Feature (Allocate Keys)
POST /api/users/{user_id}/features/unlock
Headers: X-API-Key: {app_api_key}
Body: {
"feature_id": "pitch_shift",
"auto_allocate": true // Automatically select unallocated keys
}
Response: {
"success": true,
"feature": {
"id": "pitch_shift",
"status": "unlocked",
"keys_required": 1,
"keys_allocated": 1,
"allocated_key_ids": ["uuid4"],
"unlocked_at": "2024-01-20T14:30:00Z"
},
"key_summary": {
"total_keys": 5,
"allocated_keys": 4,
"unallocated_keys": 1
}
}
// Manual key allocation
POST /api/users/{user_id}/features/unlock
Headers: X-API-Key: {app_api_key}
Body: {
"feature_id": "premium_reverb",
"key_ids": ["uuid4", "uuid5", "uuid6"] // Manually specify which keys
}
Error Response (insufficient keys): {
"error": "INSUFFICIENT_KEYS",
"message": "Feature requires 3 keys but only 1 unallocated keys available",
"required_keys": 3,
"available_keys": 1
}
4. Lock a Feature (Deallocate Keys)
POST /api/users/{user_id}/features/lock
Headers: X-API-Key: {app_api_key}
Body: {
"feature_id": "echo_effect"
}
Response: {
"success": true,
"feature": {
"id": "echo_effect",
"status": "locked",
"keys_deallocated": 1,
"deallocated_key_ids": ["uuid3"],
"locked_at": "2024-01-20T14:35:00Z"
},
"key_summary": {
"total_keys": 5,
"allocated_keys": 2,
"unallocated_keys": 3
}
}
5. Reallocate Keys Between Features
POST /api/users/{user_id}/features/reallocate
Headers: X-API-Key: {app_api_key}
Body: {
"from_feature_id": "voice_changer",
"to_feature_id": "premium_reverb",
"key_count": 2 // Move 2 keys from voice_changer to premium_reverb
}
Response: {
"success": true,
"from_feature": {
"id": "voice_changer",
"status": "locked", // Now locked since it had only 2 keys
"keys_deallocated": 2,
"keys_remaining": 0
},
"to_feature": {
"id": "premium_reverb",
"status": "unlocked", // Still needs 1 more key for full unlock
"keys_allocated": 2,
"keys_required": 3,
"partial_unlock": true
},
"key_summary": {
"total_keys": 5,
"allocated_keys": 3,
"unallocated_keys": 2
}
}
6. Real-time Feature Check (for app runtime)
POST /api/users/{user_id}/features/check
Headers: X-API-Key: {app_api_key}
Body: {
"feature_ids": ["voice_changer", "echo_effect", "pitch_shift", "premium_reverb"]
}
Response: {
"features": {
"voice_changer": {
"available": true,
"keys_allocated": 2,
"keys_required": 2
},
"echo_effect": {
"available": false,
"keys_allocated": 0,
"keys_required": 1
},
"pitch_shift": {
"available": true,
"keys_allocated": 1,
"keys_required": 1
},
"premium_reverb": {
"available": false,
"keys_allocated": 0,
"keys_required": 3
}
},
"user_status": "active"
}
Database Schema Extensions
users Table (to track user accounts)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
app_id UUID REFERENCES apps(id),
external_user_id VARCHAR(255), -- App's internal user ID
device_id VARCHAR(255),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
last_seen_at TIMESTAMP WITH TIME ZONE,
UNIQUE(app_id, external_user_id),
INDEX idx_users_device_id (device_id)
);
user_keys Table (associate keys with users)
CREATE TABLE user_keys (
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
key_id UUID REFERENCES keys(id) ON DELETE CASCADE,
added_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, key_id),
INDEX idx_user_keys_user_id (user_id)
);
feature_allocations Table (tracks which keys are allocated to features)
CREATE TABLE feature_allocations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
key_id UUID REFERENCES keys(id) ON DELETE CASCADE,
feature_id VARCHAR(100) NOT NULL,
allocated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
deallocated_at TIMESTAMP WITH TIME ZONE,
is_active BOOLEAN DEFAULT true,
UNIQUE(key_id) WHERE is_active = true, -- A key can only be actively allocated to one feature
INDEX idx_allocations_user_feature (user_id, feature_id, is_active)
);
features_metadata Table (app-specific features)
CREATE TABLE features_metadata (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
app_id UUID REFERENCES apps(id),
feature_id VARCHAR(100) NOT NULL,
name VARCHAR(255) NOT NULL,
category VARCHAR(100),
description TEXT,
icon_url VARCHAR(500),
keys_required INTEGER DEFAULT 1, -- How many keys this feature needs
sort_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(app_id, feature_id)
);
Implementation Guidelines
1. Caching Strategy
- Cache user's feature allocation status in Redis with TTL of 5 minutes
- Key patterns:
- User's keys:
user:{app_id}:{user_id}:keys - Feature status:
user:{app_id}:{user_id}:features:{feature_id} - Allocation map:
user:{app_id}:{user_id}:allocations
- User's keys:
- Invalidate cache on any allocation/deallocation operation
2. Validation Rules
- Always validate all keys' status before any operation
- Ensure user owns all keys they're trying to allocate
- Verify feature exists in app's feature list
- Check that user has enough unallocated keys for the feature
- Prevent partial allocations (all-or-nothing for multi-key features)
3. Event Tracking
- Log all key allocation/deallocation events
- Track feature usage patterns and popular combinations
- Monitor key utilization rates
- Track reallocation patterns to understand user behavior
4. Error Handling
- Return clear error codes for common scenarios:
KEY_EXPIRED: One or more keys have expiredKEY_REVOKED: One or more keys have been revokedINSUFFICIENT_KEYS: Not enough unallocated keysFEATURE_NOT_FOUND: Feature doesn't existKEYS_NOT_OWNED: User doesn't own specified keysALLOCATION_CONFLICT: Key already allocated to another featureINVALID_KEY_COUNT: Wrong number of keys for feature
5. Security Considerations
- Rate limit allocation operations (20 changes per hour per user)
- Validate app ownership of features
- Audit log all allocation state changes
- Implement request signing for critical operations
- Prevent key enumeration attacks
Client SDK Usage Example
// Initialize the Keys for All client
const kfa = new KeysForAllClient({
apiKey: 'app_api_key',
baseUrl: 'https://api.keysforall.com'
});
// Load user's keys
const userInfo = await kfa.loadUserKeys({
keys: ['XXXX-XXXX-XXXX-XXXX', 'YYYY-YYYY-YYYY-YYYY'],
deviceId: 'unique-device-id',
deviceInfo: { platform: 'ios', version: '1.0.0' }
});
// Get current feature status
const features = await kfa.getUserFeatures(userInfo.user_id);
// Unlock a feature (auto-allocate keys)
if (features.unallocated_keys >= 1) {
await kfa.unlockFeature(userInfo.user_id, 'pitch_shift', {
autoAllocate: true
});
}
// Unlock a premium feature with specific keys
await kfa.unlockFeature(userInfo.user_id, 'premium_reverb', {
keyIds: ['uuid4', 'uuid5', 'uuid6']
});
// Reallocate keys between features
await kfa.reallocateKeys(userInfo.user_id, {
fromFeature: 'voice_changer',
toFeature: 'premium_reverb',
keyCount: 2
});
// Check feature access in real-time
const featureStatus = await kfa.checkFeatures(userInfo.user_id, [
'voice_changer', 'premium_reverb'
]);
if (featureStatus.features.premium_reverb.available) {
// Enable premium reverb in the app
}
Migration Plan
- Phase 1: Add user and allocation tables to existing schema
- Phase 2: Implement user key loading and association endpoints
- Phase 3: Build feature allocation/deallocation logic
- Phase 4: Add caching layer for performance
- Phase 5: Implement analytics and tracking
- Phase 6: Release client SDKs with allocation support
Success Metrics
- Key allocation/deallocation response time < 100ms
- 99.9% uptime for feature validation
- Support for 10,000+ concurrent feature checks
- Real-time allocation state synchronization
- Zero allocation conflicts or race conditions
Key Management UI Requirements
The user's key management panel should display:
-
Key Overview Section
- Total keys owned
- Keys currently allocated
- Keys available for allocation
- List of all keys with their status
-
Feature Grid/List
- Feature name and icon
- Category (Basic, Premium, Advanced)
- Keys required for the feature
- Current allocation status:
- ✅ Unlocked (X keys allocated)
- 🔒 Locked (0 keys allocated)
- ⚠️ Partial (Y of X keys allocated)
- 🚫 Unavailable (insufficient keys)
- Lock/Unlock action buttons
-
Allocation Actions
- Quick allocate button (auto-selects keys)
- Manual allocation mode (drag & drop keys)
- Bulk reallocation tool
- Lock all / Unlock favorites options
-
Visual Feedback
- Real-time updates when allocations change
- Loading states during API calls
- Clear error messages for failures
- Success animations for unlocks