๐ API Reference
Complete REST API endpoint documentation for the rPPG platform.
Base URL
https://api.yourdomain.com/api
All endpoints are prefixed with /v1 for versioning.
Authentication
All requests require a Bearer token in the Authorization header:
Authorization: Bearer your-api-key-here
See Authentication for details.
Endpoints
POST /v1/scan-session
Create a new scan session.
Request:
POST /v1/scan-session HTTP/1.1
Host: api.yourdomain.com
Authorization: Bearer rppg_live_xxx
Content-Type: application/json
Response: 201 Created
{
"session_id": "sess_20251026123456_abc123",
"created_at": "2025-10-26T12:34:56.789Z",
"owner": "user_xyz"
}
Response Fields:
session_id(string): Unique identifier for this sessioncreated_at(string): ISO 8601 timestampowner(string): API key owner identifier
Example with cURL:
curl -X POST https://api.yourdomain.com/api/v1/scan-session \
-H "Authorization: Bearer rppg_live_xxx" \
-H "Content-Type: application/json"
Example with JavaScript:
const response = await fetch('https://api.yourdomain.com/api/v1/scan-session', {
method: 'POST',
headers: {
'Authorization': 'Bearer rppg_live_xxx',
'Content-Type': 'application/json'
}
});
const session = await response.json();
console.log('Session ID:', session.session_id);
Error Responses:
401 Unauthorized: Invalid or missing API key429 Too Many Requests: Rate limit exceeded500 Internal Server Error: Server error
POST /v1/scan-session/{session_id}/video
Upload a video file for analysis.
Request:
POST /v1/scan-session/sess_xxx/video HTTP/1.1
Host: api.yourdomain.com
Authorization: Bearer rppg_live_xxx
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="video.mp4"
Content-Type: video/mp4
[binary video data]
------WebKitFormBoundary--
Parameters:
session_id(path): Session ID from/v1/scan-session
Request Body:
file(multipart file): Video file to analyze
Video Requirements:
- Max size: 100MB
- Formats: MP4, WebM, MOV, AVI
- Duration: 10-30 seconds recommended
- Face clearly visible with good lighting
Response: 202 Accepted
{
"session_id": "sess_20251026123456_abc123",
"status": "processing",
"message": "Video uploaded successfully and is being processed"
}
Example with cURL:
curl -X POST https://api.yourdomain.com/api/v1/scan-session/sess_xxx/video \
-H "Authorization: Bearer rppg_live_xxx" \
-F "file=@video.mp4"
Example with JavaScript:
const formData = new FormData();
formData.append('file', videoFile);
const response = await fetch(
`https://api.yourdomain.com/api/v1/scan-session/${sessionId}/video`,
{
method: 'POST',
headers: {
'Authorization': 'Bearer rppg_live_xxx'
},
body: formData
}
);
const result = await response.json();
console.log('Status:', result.status);
Error Responses:
400 Bad Request: Invalid file format or size401 Unauthorized: Invalid or missing API key404 Not Found: Session ID not found413 Payload Too Large: File exceeds 100MB422 Unprocessable Entity: Invalid video content429 Too Many Requests: Rate limit exceeded500 Internal Server Error: Server error
GET /v1/scan-session/{session_id}/vitals
Retrieve vital signs for a session.
Request:
GET /v1/scan-session/sess_xxx/vitals HTTP/1.1
Host: api.yourdomain.com
Authorization: Bearer rppg_live_xxx
Parameters:
session_id(path): Session ID
Response (Processing): 200 OK
{
"status": "processing",
"session_id": "sess_20251026123456_abc123"
}
Response (Completed): 200 OK
{
"status": "completed",
"session_id": "sess_20251026123456_abc123",
"vitals": {
"heart_rate": 72.5,
"respiratory_rate": 16.2,
"hrv": 45.3,
"blood_pressure": null,
"confidence": 0.89,
"timestamp": "2025-10-26T12:35:30.123Z",
"processing_time_ms": 32450,
"signal_quality": {
"snr": 12.5,
"stability": 0.92,
"periodicity": 0.88
}
}
}
Response (Failed): 200 OK
{
"status": "failed",
"session_id": "sess_20251026123456_abc123",
"error": "No face detected in video"
}
Vitals Fields:
heart_rate(number): Heart rate in beats per minute (bpm)respiratory_rate(number): Respiratory rate in breaths per minutehrv(number | null): Heart rate variabilityblood_pressure(string | null): Blood pressure (systolic/diastolic)confidence(number | null): Confidence score (0-1)timestamp(string): ISO 8601 timestamp of analysisprocessing_time_ms(number): Processing duration in millisecondssignal_quality(object): Signal quality metricssnr(number): Signal-to-noise ratiostability(number): Signal stability (0-1)periodicity(number): Signal periodicity (0-1)
Status Values:
pending: Session created, no video uploadedprocessing: Video uploaded and being analyzedcompleted: Analysis complete, vitals availablefailed: Analysis failed (seeerrorfield)
Example with cURL:
curl -X GET https://api.yourdomain.com/api/v1/scan-session/sess_xxx/vitals \
-H "Authorization: Bearer rppg_live_xxx"
Example with JavaScript (Polling):
async function pollForVitals(sessionId) {
const maxAttempts = 40; // 2 minutes at 3 second intervals
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.yourdomain.com/api/v1/scan-session/${sessionId}/vitals`,
{
headers: {
'Authorization': 'Bearer rppg_live_xxx'
}
}
);
const result = await response.json();
if (result.status === 'completed') {
return result.vitals;
} else if (result.status === 'failed') {
throw new Error(result.error);
}
// Wait 3 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 3000));
}
throw new Error('Polling timeout');
}
Error Responses:
401 Unauthorized: Invalid or missing API key404 Not Found: Session ID not found or expired429 Too Many Requests: Rate limit exceeded500 Internal Server Error: Server error
GET /health
Health check endpoint (no authentication required).
Request:
GET /health HTTP/1.1
Host: api.yourdomain.com
Response: 200 OK
{
"status": "ok",
"timestamp": "2025-10-26T12:34:56.789Z",
"service": "rppg-backend"
}
Response Headers
All responses include standard headers:
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1635264000
Rate Limit Headers:
X-RateLimit-Limit: Total requests allowed per minuteX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when limit resets
Error Responses
All errors follow a consistent format:
{
"detail": "Error message describing what went wrong"
}
Common Error Codes
| Status Code | Meaning | Common Causes | |-------------|---------|---------------| | 400 | Bad Request | Invalid input, malformed data | | 401 | Unauthorized | Missing or invalid API key | | 403 | Forbidden | API key lacks permissions | | 404 | Not Found | Resource doesn't exist | | 413 | Payload Too Large | File exceeds size limit | | 422 | Unprocessable Entity | Invalid video format or content | | 429 | Too Many Requests | Rate limit exceeded | | 500 | Internal Server Error | Server-side error | | 503 | Service Unavailable | Service temporarily down |
Webhooks
๐ง Coming Soon: Webhook support for real-time notifications when processing completes.
See Webhooks for details.
Pagination
Current API endpoints do not support pagination. Sessions are ephemeral and results are accessed individually by session ID.
Versioning
The API uses URL-based versioning:
- Current version:
/v1 - All endpoints are prefixed with
/v1/
Future versions will be introduced as /v2/, /v3/, etc., with backwards compatibility maintained for at least 12 months after a new version is released.
Next Steps
- Code Examples โ - See implementation patterns
- Webhooks โ - Set up event notifications
- Rate Limits โ - Understand usage quotas