18 KiB
API Specification Document - Maternal Organization App
API Architecture Overview
Base Configuration
- Base URL:
https://api.{domain}/api/v1 - GraphQL Endpoint:
https://api.{domain}/graphql - WebSocket:
wss://api.{domain}/ws - API Style: Hybrid (REST for CRUD, GraphQL for complex queries)
- Versioning: URL path versioning (
/api/v1/) - Rate Limiting: 100 requests/minute per user
- Pagination: Cursor-based with consistent structure
Standard Headers
Content-Type: application/json
Accept: application/json
Accept-Language: en-US,en;q=0.9
X-Client-Version: 1.0.0
X-Device-ID: uuid-device-fingerprint
X-Timezone: America/New_York
Authorization: Bearer {access_token}
X-Refresh-Token: {refresh_token}
Device Fingerprinting
{
"deviceId": "uuid",
"platform": "ios|android",
"model": "iPhone14,2",
"osVersion": "16.5",
"appVersion": "1.0.0",
"pushToken": "fcm_or_apns_token"
}
Authentication Endpoints
POST /api/v1/auth/register
Create new user account with family setup.
Request Body:
{
"email": "user@example.com",
"password": "SecurePass123!",
"phone": "+1234567890",
"name": "Jane Doe",
"locale": "en-US",
"timezone": "America/New_York",
"deviceInfo": {
"deviceId": "uuid",
"platform": "ios",
"model": "iPhone14,2",
"osVersion": "16.5"
}
}
Response 201:
{
"success": true,
"data": {
"user": {
"id": "usr_2n4k8m9p",
"email": "user@example.com",
"name": "Jane Doe",
"locale": "en-US",
"emailVerified": false
},
"family": {
"id": "fam_7h3j9k2m",
"shareCode": "ABC123",
"role": "parent"
},
"tokens": {
"accessToken": "eyJhbGc...",
"refreshToken": "eyJhbGc...",
"expiresIn": 3600
},
"deviceRegistered": true
}
}
POST /api/v1/auth/login
Authenticate existing user with device registration.
Request Body:
{
"email": "user@example.com",
"password": "SecurePass123!",
"deviceInfo": {
"deviceId": "uuid",
"platform": "ios",
"model": "iPhone14,2",
"osVersion": "16.5"
}
}
Response 200:
{
"success": true,
"data": {
"user": {
"id": "usr_2n4k8m9p",
"email": "user@example.com",
"families": ["fam_7h3j9k2m"]
},
"tokens": {
"accessToken": "eyJhbGc...",
"refreshToken": "eyJhbGc...",
"expiresIn": 3600
},
"requiresMFA": false,
"deviceTrusted": true
}
}
POST /api/v1/auth/refresh
Refresh access token using refresh token.
Request Body:
{
"refreshToken": "eyJhbGc...",
"deviceId": "uuid"
}
Response 200:
{
"success": true,
"data": {
"accessToken": "eyJhbGc...",
"refreshToken": "eyJhbGc...",
"expiresIn": 3600
}
}
POST /api/v1/auth/logout
Logout and revoke tokens for specific device.
Request Body:
{
"deviceId": "uuid",
"allDevices": false
}
Response 200:
{
"success": true,
"message": "Successfully logged out"
}
Family Management Endpoints
POST /api/v1/families/invite
Generate invitation for family member.
Request Body:
{
"email": "partner@example.com",
"role": "parent|caregiver|viewer",
"permissions": {
"canAddChildren": true,
"canEditChildren": true,
"canLogActivities": true,
"canViewReports": true
},
"message": "Join our family on the app!"
}
Response 201:
{
"success": true,
"data": {
"invitationId": "inv_8k3m9n2p",
"shareCode": "XYZ789",
"expiresAt": "2024-01-15T00:00:00Z",
"invitationUrl": "app://join/XYZ789"
}
}
POST /api/v1/families/join
Join family using share code.
Request Body:
{
"shareCode": "XYZ789"
}
Response 200:
{
"success": true,
"data": {
"familyId": "fam_7h3j9k2m",
"familyName": "The Doe Family",
"role": "parent",
"members": [
{
"id": "usr_2n4k8m9p",
"name": "Jane Doe",
"role": "parent"
}
],
"children": []
}
}
GET /api/v1/families/{familyId}/members
Get all family members with their permissions.
Response 200:
{
"success": true,
"data": {
"members": [
{
"id": "usr_2n4k8m9p",
"name": "Jane Doe",
"email": "jane@example.com",
"role": "parent",
"permissions": {
"canAddChildren": true,
"canEditChildren": true,
"canLogActivities": true,
"canViewReports": true
},
"joinedAt": "2024-01-01T00:00:00Z",
"lastActive": "2024-01-10T15:30:00Z"
}
]
}
}
Children Management Endpoints
POST /api/v1/children
Add a new child to the family.
Request Body:
{
"familyId": "fam_7h3j9k2m",
"name": "Emma",
"birthDate": "2023-06-15",
"gender": "female",
"bloodType": "O+",
"allergies": ["peanuts", "dairy"],
"medicalConditions": ["eczema"],
"pediatrician": {
"name": "Dr. Smith",
"phone": "+1234567890"
},
"photo": "base64_encoded_image"
}
Response 201:
{
"success": true,
"data": {
"id": "chd_9m2k4n8p",
"familyId": "fam_7h3j9k2m",
"name": "Emma",
"birthDate": "2023-06-15",
"ageInMonths": 7,
"developmentalStage": "infant",
"photoUrl": "https://storage.api/photos/chd_9m2k4n8p.jpg"
}
}
GET /api/v1/children/{childId}
Get child details with calculated metrics.
Response 200:
{
"success": true,
"data": {
"id": "chd_9m2k4n8p",
"name": "Emma",
"birthDate": "2023-06-15",
"ageInMonths": 7,
"developmentalStage": "infant",
"currentWeight": {
"value": 8.2,
"unit": "kg",
"percentile": 75,
"recordedAt": "2024-01-10T10:00:00Z"
},
"currentHeight": {
"value": 68,
"unit": "cm",
"percentile": 80,
"recordedAt": "2024-01-10T10:00:00Z"
},
"todaySummary": {
"feedings": 5,
"sleepHours": 14.5,
"diapers": 6,
"lastFeedingAt": "2024-01-10T14:30:00Z",
"lastSleepAt": "2024-01-10T13:00:00Z"
}
}
}
Activity Tracking Endpoints (REST)
POST /api/v1/activities/feeding
Log a feeding activity.
Request Body:
{
"childId": "chd_9m2k4n8p",
"type": "breast|bottle|solid",
"startTime": "2024-01-10T14:30:00Z",
"endTime": "2024-01-10T14:45:00Z",
"details": {
"breastSide": "left|right|both",
"amount": 120,
"unit": "ml|oz",
"foodType": "formula|breastmilk|puree"
},
"notes": "Good feeding session",
"mood": "happy|fussy|sleepy"
}
Response 201:
{
"success": true,
"data": {
"id": "act_3k9n2m4p",
"childId": "chd_9m2k4n8p",
"type": "feeding",
"timestamp": "2024-01-10T14:30:00Z",
"duration": 15,
"createdBy": "usr_2n4k8m9p",
"syncedToFamily": true
}
}
POST /api/v1/activities/sleep
Log sleep activity.
Request Body:
{
"childId": "chd_9m2k4n8p",
"startTime": "2024-01-10T13:00:00Z",
"endTime": "2024-01-10T14:30:00Z",
"type": "nap|night",
"location": "crib|stroller|car|bed",
"quality": "good|restless|interrupted",
"notes": "Went down easily"
}
POST /api/v1/activities/diaper
Log diaper change.
Request Body:
{
"childId": "chd_9m2k4n8p",
"timestamp": "2024-01-10T15:00:00Z",
"type": "wet|dirty|both",
"consistency": "normal|loose|hard",
"color": "normal|green|yellow",
"hasRash": false,
"notes": "Applied diaper cream"
}
GET /api/v1/activities
Get activities with cursor pagination.
Query Parameters:
childId: Filter by child (required)type: Filter by activity typestartDate: ISO date stringendDate: ISO date stringcursor: Pagination cursorlimit: Items per page (default: 20, max: 100)
Response 200:
{
"success": true,
"data": {
"activities": [
{
"id": "act_3k9n2m4p",
"childId": "chd_9m2k4n8p",
"type": "feeding",
"timestamp": "2024-01-10T14:30:00Z",
"details": {},
"createdBy": "usr_2n4k8m9p"
}
],
"cursor": {
"next": "eyJpZCI6ImFjdF8za...",
"hasMore": true,
"total": 150
}
}
}
AI Assistant Endpoints
POST /api/v1/ai/chat
Send message to AI assistant.
Request Body:
{
"message": "Why won't my baby sleep?",
"childId": "chd_9m2k4n8p",
"conversationId": "conv_8n2k4m9p",
"context": {
"includeRecentActivities": true,
"includeSleepPatterns": true,
"includeDevelopmentalInfo": true
},
"locale": "en-US"
}
Response 200:
{
"success": true,
"data": {
"conversationId": "conv_8n2k4m9p",
"messageId": "msg_7k3n9m2p",
"response": "Based on Emma's recent sleep patterns...",
"suggestions": [
"Try starting bedtime routine 15 minutes earlier",
"Check room temperature (ideal: 68-72°F)"
],
"relatedArticles": [
{
"title": "7-Month Sleep Regression",
"url": "/resources/sleep-regression-7-months"
}
],
"confidenceScore": 0.92
}
}
POST /api/v1/ai/voice
Process voice command.
Request Body (multipart/form-data):
audio: [audio file - wav/mp3]
childId: chd_9m2k4n8p
locale: en-US
Response 200:
{
"success": true,
"data": {
"transcription": "Baby fed 4 ounces at 3pm",
"interpretation": {
"action": "log_feeding",
"childId": "chd_9m2k4n8p",
"parameters": {
"amount": 4,
"unit": "oz",
"time": "15:00"
}
},
"executed": true,
"activityId": "act_9k2m4n3p"
}
}
Analytics & Insights Endpoints
GET /api/v1/insights/{childId}/patterns
Get AI-detected patterns for a child.
Response 200:
{
"success": true,
"data": {
"sleepPatterns": {
"averageNightSleep": 10.5,
"averageDaySleep": 3.5,
"optimalBedtime": "19:30",
"wakeWindows": [90, 120, 150, 180],
"trend": "improving",
"insights": [
"Emma sleeps 45 minutes longer when put down before 7:30 PM",
"Morning wake time is consistently between 6:30-7:00 AM"
]
},
"feedingPatterns": {
"averageIntake": 28,
"feedingIntervals": [2.5, 3, 3, 4],
"preferredSide": "left",
"insights": [
"Feeding intervals increasing - may be ready for longer stretches"
]
}
}
}
GET /api/v1/insights/{childId}/predictions
Get predictive suggestions.
Response 200:
{
"success": true,
"data": {
"nextNapTime": {
"predicted": "2024-01-10T16:30:00Z",
"confidence": 0.85,
"wakeWindow": 120
},
"nextFeedingTime": {
"predicted": "2024-01-10T17:30:00Z",
"confidence": 0.78
},
"growthSpurt": {
"likelihood": 0.72,
"expectedIn": "5-7 days",
"symptoms": ["increased feeding", "fussiness", "disrupted sleep"]
}
}
}
GraphQL Queries for Complex Data
GraphQL Endpoint
POST https://api.{domain}/graphql
Family Dashboard Query
query FamilyDashboard($familyId: ID!, $date: Date!) {
family(id: $familyId) {
id
name
children {
id
name
age
todaySummary(date: $date) {
feedings {
count
totalAmount
lastAt
}
sleep {
totalHours
naps
nightSleep
currentStatus
}
diapers {
count
lastAt
}
}
upcomingEvents {
type
scheduledFor
description
}
aiInsights {
message
priority
actionable
}
}
members {
id
name
lastActive
recentActivities(limit: 5) {
type
childName
timestamp
}
}
}
}
Weekly Report Query
query WeeklyReport($childId: ID!, $startDate: Date!, $endDate: Date!) {
child(id: $childId) {
weeklyReport(startDate: $startDate, endDate: $endDate) {
sleep {
dailyAverages {
date
nightHours
napHours
totalHours
}
patterns {
consistentBedtime
averageWakeTime
longestStretch
}
}
feeding {
dailyTotals {
date
numberOfFeedings
totalVolume
}
trends {
direction
averageInterval
}
}
growth {
measurements {
date
weight
height
percentiles
}
}
milestones {
achieved {
name
achievedAt
}
upcoming {
name
expectedBy
}
}
}
}
}
WebSocket Events
Connection
// Client connects with auth
ws.connect('wss://api.{domain}/ws', {
headers: {
'Authorization': 'Bearer {access_token}',
'X-Device-ID': 'uuid'
}
});
Family Room Events
// Join family room
ws.emit('join-family', { familyId: 'fam_7h3j9k2m' });
// Activity logged by family member
ws.on('activity-logged', {
activityId: 'act_3k9n2m4p',
childId: 'chd_9m2k4n8p',
type: 'feeding',
loggedBy: 'usr_2n4k8m9p',
timestamp: '2024-01-10T14:30:00Z'
});
// Real-time timer sync
ws.on('timer-started', {
timerId: 'tmr_8k3m9n2p',
type: 'feeding',
childId: 'chd_9m2k4n8p',
startedBy: 'usr_2n4k8m9p',
startTime: '2024-01-10T14:30:00Z'
});
// AI insight generated
ws.on('insight-available', {
childId: 'chd_9m2k4n8p',
type: 'pattern_detected',
message: 'New sleep pattern identified',
priority: 'medium'
});
Error Responses
Standard Error Format
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": {
"field": "email",
"reason": "Invalid email format"
},
"timestamp": "2024-01-10T15:30:00Z",
"traceId": "trace_8k3m9n2p"
}
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Invalid or expired token |
FORBIDDEN |
403 | Insufficient permissions |
NOT_FOUND |
404 | Resource not found |
VALIDATION_ERROR |
400 | Invalid input data |
RATE_LIMITED |
429 | Too many requests |
FAMILY_FULL |
400 | Family member limit reached |
CHILD_LIMIT |
400 | Free tier child limit reached |
AI_QUOTA_EXCEEDED |
429 | AI query limit reached |
SYNC_CONFLICT |
409 | Data sync conflict |
SERVER_ERROR |
500 | Internal server error |
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704903000
Retry-After: 3600
Localization
Supported Locales
en-US- English (United States)es-ES- Spanish (Spain)es-MX- Spanish (Mexico)fr-FR- French (France)fr-CA- French (Canada)pt-BR- Portuguese (Brazil)zh-CN- Chinese (Simplified)
Locale-Specific Responses
All error messages, AI responses, and notifications are returned in the user's selected locale based on the Accept-Language header or user profile setting.
Date/Time Formatting
Dates are returned in ISO 8601 format but should be displayed according to user's locale:
- US: MM/DD/YYYY, 12-hour clock
- EU: DD/MM/YYYY, 24-hour clock
- Time zones always included in responses
Measurement Units
{
"measurement": {
"value": 8.2,
"unit": "kg",
"display": "8.2 kg",
"imperial": {
"value": 18.08,
"unit": "lbs",
"display": "18 lbs 1 oz"
}
}
}
Security Considerations
Authentication Flow
- User provides credentials + device fingerprint
- Server validates and issues access token (1 hour) + refresh token (30 days)
- Device fingerprint stored and validated on each request
- Refresh token rotation on use
- All tokens revoked on suspicious activity
Data Encryption
- All API communication over HTTPS/TLS 1.3
- Sensitive fields encrypted at rest (AES-256)
- PII data anonymized in logs
- No sensitive data in URL parameters
COPPA/GDPR Compliance
- Parental consent required for child profiles
- Data minimization enforced
- Right to deletion implemented
- Data portability via export endpoints
- Audit logs for all data access
Request Signing (Optional Enhanced Security)
X-Signature: HMAC-SHA256(request-body + timestamp + nonce)
X-Timestamp: 1704903000
X-Nonce: unique-request-id
Testing Endpoints
Health Check
GET /api/v1/health
Response 200:
{
"status": "healthy",
"version": "1.0.0",
"timestamp": "2024-01-10T15:30:00Z",
"services": {
"database": "connected",
"redis": "connected",
"ai": "operational"
}
}
Test Notifications
POST /api/v1/test/notification
Request Body:
{
"type": "test",
"deviceId": "uuid"
}
SDK Usage Examples
JavaScript/TypeScript
import { MaternalAPI } from '@maternal/sdk';
const api = new MaternalAPI({
baseUrl: 'https://api.maternal.app',
version: 'v1'
});
// Authentication
const { tokens, user } = await api.auth.login({
email: 'user@example.com',
password: 'password',
deviceInfo: getDeviceInfo()
});
// Set tokens for subsequent requests
api.setTokens(tokens);
// Log activity
const activity = await api.activities.logFeeding({
childId: 'chd_9m2k4n8p',
type: 'bottle',
amount: 120,
unit: 'ml'
});
// Subscribe to real-time updates
api.websocket.on('activity-logged', (data) => {
console.log('New activity:', data);
});
React Native
import { useMaternalAPI } from '@maternal/react-native';
function FeedingScreen() {
const { logFeeding, isLoading } = useMaternalAPI();
const handleLogFeeding = async () => {
await logFeeding({
childId: currentChild.id,
type: 'breast',
duration: 15
});
};
}