Sessions
Sessions represent a single vital signs measurement workflow. A session is created, receives an upload of preprocessed tensor data, processes it through the inference engine, and returns calibrated vital signs.
Session Lifecycle
Section titled “Session Lifecycle”-
Create a session via
POST /sdk/session/start— returns a session ID, secure upload URL, and fallback config. -
Upload the preprocessed tensor to the upload URL via a
PUTrequest. -
Notify the backend via
POST /sdk/session/upload-complete— triggers inference processing and returns results directly in the response. -
Retrieve results via
GET /sdk/session/result/{sessionId}— only needed whenPERSIST_VITALS=trueis configured for async/polling workflows.
Create a Session
Section titled “Create a Session”POST /sdk/session/startHeaders:
X-API-Key: ck_test_your_key_hereContent-Type: application/jsonRequest body (optional):
{ "demographics": { "age": 35, "sex": "M", "fitzpatrick": 3 }}Demographics are optional but improve measurement accuracy when provided.
Response 200 OK:
{ "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "expires_at": 1712001800, "upload_url": "https://upload.circadify.com/uploads/a1b2c3.../video.webm?signature=...", "fallback_config": { "heart_rate": { "min": 62, "max": 98 }, "hrv": { "min": 25, "max": 70 }, "respiratory_rate": { "min": 13, "max": 19 }, "spo2": { "min": 96, "max": 99 }, "systolic_bp": { "min": 109, "max": 134 }, "diastolic_bp_offset": { "min": 51, "max": 66 }, "confidence": 0.0 }}Response headers:
X-RateLimit-Limit: 300X-RateLimit-Remaining: 299X-RateLimit-Reset: 1712005400X-Usage-Current: 42X-Usage-Limit: 500X-Usage-Remaining: 458| Field | Type | Description |
|---|---|---|
session_id | string | Unique session identifier (UUID) |
expires_at | number | Unix timestamp when the session expires |
upload_url | string | Presigned URL for uploading the preprocessed tensor |
fallback_config | object | Ranges for generating fallback vitals if inference fails |
Upload Tensor Data
Section titled “Upload Tensor Data”Upload the preprocessed tensor directly to the upload_url returned from session creation:
curl -X PUT "$UPLOAD_URL" \ -H "Content-Type: video/webm" \ --data-binary @tensor.binThe upload goes directly to secure cloud storage — it does not pass through the API layer. The Content-Type is video/webm for compatibility, but the payload is the binary tensor produced by the SDK’s preprocessing pipeline.
See Data Flow for the exact tensor binary format.
Notify Upload Complete
Section titled “Notify Upload Complete”POST /sdk/session/upload-completeHeaders:
X-API-Key: ck_test_your_key_hereContent-Type: application/jsonRequest body:
{ "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}Response 200 OK:
{ "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "completed", "vitals": { "heart_rate": 72, "respiratory_rate": 16, "hrv": 45.2, "spo2": 98.1, "systolic_bp": 122, "diastolic_bp": 78, "confidence": 0.87 }, "processing_time_ms": 74200}This endpoint triggers backend inference and returns results synchronously when processing completes. Vital sign results are included directly in the response body. The response always has status completed — if inference fails, fallback vitals with confidence: 0.0 are returned instead of an error.
By default (PERSIST_VITALS=false), no health data is stored server-side after this response is delivered. Session metadata is cleaned up immediately. When PERSIST_VITALS=true is configured, results are also cached for retrieval via the polling endpoint.
| Field | Type | Description |
|---|---|---|
session_id | string | Session identifier |
status | string | Always completed |
vitals | object | Vital signs measurement results |
processing_time_ms | number | Processing time in milliseconds (present on successful inference) |
Retrieve Results
Section titled “Retrieve Results”GET /sdk/session/result/{sessionId}Headers:
X-API-Key: ck_test_your_key_hereResponse 200 OK (completed):
{ "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "completed", "vitals": { "heart_rate": 72, "respiratory_rate": 16, "hrv": 45.2, "spo2": 98.1, "systolic_bp": 122, "diastolic_bp": 78, "confidence": 0.87 }, "completed_at": 1712001900}Response 200 OK (still processing):
{ "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "processing"}When polling, check the status field:
processing— Inference is still running. Poll again in 2 seconds.completed— Vitals are available in thevitalsfield.failed— Processing failed. Fallback vitals withconfidence: 0.0may be present.
Session Statuses
Section titled “Session Statuses”| Status | Description |
|---|---|
created | Session initialized, awaiting upload |
uploading | Upload in progress |
processing | Inference running on backend |
completed | Results available |
failed | Processing failed (fallback vitals may be provided) |
expired | Session timed out before completion |
Errors
Section titled “Errors”| Status | Error Code | Description |
|---|---|---|
400 | INVALID_REQUEST | Missing session_id or invalid parameters |
401 | API_KEY_INVALID | Invalid, revoked, or missing API key |
403 | FORBIDDEN | Session does not belong to this developer |
404 | SESSION_NOT_FOUND | Session ID does not exist |
429 | RATE_LIMIT_EXCEEDED | Hourly rate limit exceeded |
429 | QUOTA_EXCEEDED | Monthly scan quota exceeded |
See Errors for the full error reference.
Next Steps
Section titled “Next Steps”- Results — Interpret vital signs data
- Rate Limits — Understand rate and quota limits
- Data Flow — Full pipeline walkthrough