Learning Objectives:
The WIA-SENIOR-008 Reminder API provides a comprehensive, standards-compliant interface for creating, managing, and delivering memory assistance reminders. Built on REST principles with GraphQL alternatives for complex queries, the API prioritizes reliability, security, and ease of integration.
| Principle | Description | Implementation | Benefit |
|---|---|---|---|
| Resource-Oriented | RESTful resources for reminders, users, schedules | Noun-based endpoints, HTTP verbs | Intuitive, predictable API structure |
| Stateless | Each request contains all necessary information | JWT tokens, no server-side sessions | Horizontal scalability, reliability |
| Versioned | API version in URL path | /v1/, /v2/ prefixes | Backward compatibility, safe evolution |
| HATEOAS | Hypermedia links in responses | _links object with related resources | Self-documenting, client discoverability |
| Idempotent | Repeated requests have same effect | Idempotency keys for POST requests | Safe retries, fault tolerance |
// WIA-SENIOR-008 Reminder API - Base Configuration
const API_BASE_URL = 'https://api.wia-senior.org/v1';
// API Resource Structure
interface ReminderAPI {
// Core Resources
reminders: '/reminders', // Reminder CRUD operations
users: '/users', // User management
schedules: '/schedules', // Recurring schedules
templates: '/templates', // Reminder templates
// Supporting Resources
medications: '/medications', // Medication database
contacts: '/contacts', // Emergency contacts
events: '/events', // Calendar events
// Analytics & Reporting
analytics: '/analytics', // Usage analytics
reports: '/reports', // Adherence reports
// Real-time
websocket: 'wss://ws.wia-senior.org/v1', // WebSocket endpoint
// Administration
admin: '/admin', // Admin operations
health: '/health' // System health check
}
// Standard Response Format
interface APIResponse<T> {
success: boolean;
data?: T;
error?: {
code: string;
message: string;
details?: any;
};
meta: {
timestamp: string;
requestId: string;
version: string;
};
_links?: {
self: string;
related?: Record<string, string>;
};
}
// Pagination
interface PaginatedResponse<T> extends APIResponse<T[]> {
pagination: {
page: number;
pageSize: number;
totalPages: number;
totalItems: number;
hasNext: boolean;
hasPrevious: boolean;
};
_links: {
self: string;
first: string;
last: string;
next?: string;
previous?: string;
};
}
Memory assistance systems handle sensitive health information requiring robust security measures. The WIA-SENIOR-008 API implements multiple layers of security including OAuth 2.0, JWT tokens, API keys, and comprehensive audit logging.
| Method | Use Case | Security Level | Implementation |
|---|---|---|---|
| OAuth 2.0 | User-facing applications | High - delegated authorization | Authorization Code flow with PKCE |
| JWT Tokens | Mobile apps, SPAs | High - stateless, signed | RS256 signed, short-lived access tokens |
| API Keys | Server-to-server integration | Medium - requires secure storage | UUID v4, rate-limited, IP-restricted |
| mTLS | High-security enterprise | Very High - certificate-based | Client certificates, bi-directional SSL |
// OAuth 2.0 Authentication Flow
class ReminderAPIClient {
private accessToken: string | null = null;
private refreshToken: string | null = null;
// Step 1: Initiate OAuth flow
async initiateOAuth(): Promise<string> {
const params = new URLSearchParams({
client_id: this.clientId,
response_type: 'code',
redirect_uri: this.redirectUri,
scope: 'reminders:read reminders:write users:read',
state: this.generateState(),
code_challenge: this.generateCodeChallenge(),
code_challenge_method: 'S256'
});
return `${this.authUrl}/authorize?${params.toString()}`;
}
// Step 2: Exchange authorization code for tokens
async exchangeCodeForTokens(code: string): Promise<TokenResponse> {
const response = await fetch(`${this.authUrl}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: this.redirectUri,
client_id: this.clientId,
code_verifier: this.codeVerifier
})
});
const tokens = await response.json();
this.accessToken = tokens.access_token;
this.refreshToken = tokens.refresh_token;
// Schedule token refresh before expiration
this.scheduleTokenRefresh(tokens.expires_in);
return tokens;
}
// Step 3: Refresh access token
async refreshAccessToken(): Promise<TokenResponse> {
if (!this.refreshToken) {
throw new Error('No refresh token available');
}
const response = await fetch(`${this.authUrl}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: this.refreshToken,
client_id: this.clientId
})
});
const tokens = await response.json();
this.accessToken = tokens.access_token;
if (tokens.refresh_token) {
this.refreshToken = tokens.refresh_token;
}
this.scheduleTokenRefresh(tokens.expires_in);
return tokens;
}
// Make authenticated API request
async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<APIResponse<T>> {
// Ensure we have valid access token
if (!this.accessToken || this.isTokenExpired()) {
await this.refreshAccessToken();
}
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
'X-Request-ID': this.generateRequestId()
}
});
if (response.status === 401) {
// Token expired, refresh and retry
await this.refreshAccessToken();
return this.request(endpoint, options);
}
return response.json();
}
}
// Security Headers
const SECURITY_HEADERS = {
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Content-Security-Policy': "default-src 'self'",
'Referrer-Policy': 'strict-origin-when-cross-origin'
};
The core functionality of the Reminder API revolves around creating, reading, updating, and deleting reminders. These operations support both simple one-time reminders and complex recurring schedules.
// Complete Reminder Resource Definition
interface Reminder {
// Identity
id: string; // UUID v4
userId: string; // Owner user ID
createdAt: string; // ISO 8601 timestamp
updatedAt: string;
version: number; // Optimistic locking
// Core Properties
title: string; // Max 200 chars
description?: string; // Max 2000 chars
category: ReminderCategory; // medication, appointment, task, etc.
priority: 'low' | 'medium' | 'high' | 'urgent';
// Timing
scheduledTime: string; // ISO 8601 timestamp
timezone: string; // IANA timezone
duration?: number; // Duration in minutes
leadTime?: number; // Advance notice in minutes
// Recurrence
recurrence?: {
pattern: 'daily' | 'weekly' | 'monthly' | 'custom';
interval: number; // Every N days/weeks/months
daysOfWeek?: number[]; // 0=Sunday, 6=Saturday
daysOfMonth?: number[]; // 1-31
endDate?: string; // When recurrence stops
exceptions?: string[]; // Dates to skip
};
// Location
location?: {
name?: string;
address?: string;
coordinates?: {
latitude: number;
longitude: number;
};
radius?: number; // Geofence radius in meters
trigger?: 'arrival' | 'departure' | 'proximity';
};
// Delivery
delivery: {
channels: DeliveryChannel[]; // phone, email, sms, push, voice, etc.
escalation?: {
enabled: boolean;
steps: EscalationStep[];
};
confirmation?: {
required: boolean;
timeout: number; // Seconds before escalation
};
};
// Content Customization
content?: {
message?: string; // Custom message text
audioUrl?: string; // Custom audio file
imageUrl?: string; // Visual reminder image
actionUrl?: string; // Deep link or URL
};
// Medication-Specific (if category === 'medication')
medication?: {
name: string;
dosage: string;
form: 'pill' | 'liquid' | 'injection' | 'inhaler';
instructions?: string;
refillDate?: string;
prescriberId?: string;
ndc?: string; // National Drug Code
};
// Status & Tracking
status: 'active' | 'completed' | 'snoozed' | 'cancelled' | 'missed';
completionHistory?: {
timestamp: string;
status: 'completed' | 'missed' | 'snoozed';
respondedAt?: string;
method?: string;
}[];
// Metadata
tags?: string[];
metadata?: Record<string, any>; // Extensibility
// Links
_links: {
self: string;
user: string;
schedule?: string;
analytics?: string;
};
}
// Create Reminder Request
interface CreateReminderRequest {
title: string;
category: ReminderCategory;
scheduledTime: string;
// ... other optional fields from Reminder interface
}
// Update Reminder Request
interface UpdateReminderRequest {
version: number; // For optimistic locking
// Any Reminder fields to update (except id, userId, createdAt)
}
// CREATE - POST /v1/reminders
async function createReminder(
data: CreateReminderRequest
): Promise<APIResponse<Reminder>> {
const response = await client.request('/reminders', {
method: 'POST',
body: JSON.stringify(data)
});
return response;
}
// Example: Create medication reminder
const medicationReminder = await createReminder({
title: 'Take morning blood pressure medication',
category: 'medication',
priority: 'high',
scheduledTime: '2025-01-15T08:00:00-05:00',
timezone: 'America/New_York',
recurrence: {
pattern: 'daily',
interval: 1,
endDate: '2025-12-31T23:59:59-05:00'
},
delivery: {
channels: ['push', 'voice'],
escalation: {
enabled: true,
steps: [
{ delay: 300, channels: ['push', 'sms'] },
{ delay: 900, channels: ['voice', 'caregiver_alert'] }
]
},
confirmation: {
required: true,
timeout: 600
}
},
medication: {
name: 'Lisinopril',
dosage: '10mg',
form: 'pill',
instructions: 'Take with food and full glass of water'
}
});
// READ - GET /v1/reminders/:id
async function getReminder(id: string): Promise<APIResponse<Reminder>> {
return await client.request(`/reminders/${id}`);
}
// LIST - GET /v1/reminders with filters
async function listReminders(filters: {
status?: string[];
category?: string[];
startDate?: string;
endDate?: string;
page?: number;
pageSize?: number;
}): Promise<PaginatedResponse<Reminder>> {
const params = new URLSearchParams();
if (filters.status) params.append('status', filters.status.join(','));
if (filters.category) params.append('category', filters.category.join(','));
if (filters.startDate) params.append('start_date', filters.startDate);
if (filters.endDate) params.append('end_date', filters.endDate);
params.append('page', String(filters.page || 1));
params.append('page_size', String(filters.pageSize || 50));
return await client.request(`/reminders?${params.toString()}`);
}
// UPDATE - PUT /v1/reminders/:id
async function updateReminder(
id: string,
updates: UpdateReminderRequest
): Promise<APIResponse<Reminder>> {
return await client.request(`/reminders/${id}`, {
method: 'PUT',
body: JSON.stringify(updates)
});
}
// PATCH - PATCH /v1/reminders/:id (partial update)
async function patchReminder(
id: string,
patches: Partial<Reminder>
): Promise<APIResponse<Reminder>> {
return await client.request(`/reminders/${id}`, {
method: 'PATCH',
body: JSON.stringify(patches)
});
}
// DELETE - DELETE /v1/reminders/:id
async function deleteReminder(id: string): Promise<APIResponse<void>> {
return await client.request(`/reminders/${id}`, {
method: 'DELETE'
});
}
// BATCH OPERATIONS - POST /v1/reminders/batch
async function batchCreateReminders(
reminders: CreateReminderRequest[]
): Promise<APIResponse<{
created: Reminder[];
failed: { index: number; error: string }[];
}>> {
return await client.request('/reminders/batch', {
method: 'POST',
body: JSON.stringify({ reminders })
});
}
Webhooks enable event-driven architecture where external systems receive real-time notifications about reminder events. This is essential for integrating memory assistance systems with caregiving platforms, healthcare systems, and family portals.
| Event Type | Trigger | Payload Includes | Typical Use Case |
|---|---|---|---|
| reminder.created | New reminder created | Complete reminder object | Sync with calendar, notify caregivers |
| reminder.delivered | Reminder sent to user | Reminder ID, delivery method, timestamp | Track delivery success rates |
| reminder.acknowledged | User confirms seeing reminder | Reminder ID, response time, method | Update adherence tracking |
| reminder.completed | Task marked as done | Reminder ID, completion time, proof | Healthcare compliance reporting |
| reminder.missed | Reminder not acknowledged in time | Reminder ID, scheduled time, severity | Alert caregivers, escalate |
| reminder.escalated | Escalation step triggered | Reminder ID, escalation level, contacts | Emergency notifications |
// Webhook Configuration
interface WebhookConfig {
id: string;
url: string; // HTTPS endpoint to receive events
events: string[]; // Event types to subscribe to
secret: string; // For HMAC signature verification
active: boolean;
retryPolicy: {
maxAttempts: number;
backoffMultiplier: number;
maxBackoffSeconds: number;
};
filters?: {
userId?: string[]; // Only events for these users
category?: string[]; // Only specific reminder categories
priority?: string[]; // Only certain priorities
};
headers?: Record<string, string>; // Custom HTTP headers
}
// Webhook Payload Structure
interface WebhookPayload {
event: string; // e.g., "reminder.completed"
timestamp: string; // ISO 8601 timestamp
data: {
reminder: Reminder;
previousState?: Partial<Reminder>; // For update events
metadata?: any; // Event-specific data
};
signature: string; // HMAC-SHA256 signature
}
// Verify Webhook Signature
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const crypto = require('crypto');
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Handle Webhook Event (Express.js example)
app.post('/webhooks/reminder-events', (req, res) => {
const signature = req.headers['x-wia-signature'];
const payload = JSON.stringify(req.body);
// Verify signature
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process event
const event: WebhookPayload = req.body;
switch (event.event) {
case 'reminder.missed':
// Alert caregiver
alertCaregiver(event.data.reminder);
break;
case 'reminder.completed':
// Update adherence records
updateAdherenceRecord(event.data.reminder);
break;
case 'reminder.escalated':
// Send emergency notification
sendEmergencyNotification(event.data.reminder);
break;
}
// Acknowledge receipt
res.status(200).json({ received: true });
});
// Register Webhook
async function registerWebhook(
config: Omit<WebhookConfig, 'id' | 'secret'>
): Promise<APIResponse<WebhookConfig>> {
return await client.request('/webhooks', {
method: 'POST',
body: JSON.stringify(config)
});
}
To ensure fair usage and system stability, the WIA-SENIOR-008 API implements comprehensive rate limiting. Understanding these limits is essential for building robust, production-ready integrations.
| Tier | Requests/Minute | Requests/Hour | Burst Allowance | Use Case |
|---|---|---|---|---|
| Free | 60 | 1,000 | 10 | Development, testing |
| Basic | 300 | 10,000 | 50 | Small practices, individual caregivers |
| Professional | 1,200 | 50,000 | 200 | Medium organizations, care facilities |
| Enterprise | Custom | Custom | Custom | Large healthcare systems, research institutions |