Skip to main content

API Reference

The SDK includes a comprehensive REST API client for accessing patient data, test results, physician-prescribed treatments, and form templates. This client handles authentication, request serialization, error handling, and automatic retry logic.

API Design Philosophy

The API client follows a read-only design pattern for ANS data integrity:

Read-Only Access

The API client is designed for reading data only. Critical operations like test uploads, video recording, and initial form submissions are handled internally by the SDK's test flow UI to ensure clinical validity and data integrity. You can update patient demographics and modify existing form submissions, but cannot directly upload ANS test data.

This design ensures:

  • Clinical Validity: Tests follow standardized protocols without modification
  • Data Integrity: ANS measurements cannot be tampered with or fabricated
  • Regulatory Compliance: Audit trail for all clinical data submissions
  • Quality Assurance: Every test is validated against quality metrics

Think of it similar to Google Maps SDK - you can read location data but cannot inject false GPS coordinates into their systems.

API Service Initialization

The API service is automatically initialized when you create the SDK instance.

let sdk = AutonomicHealthSDK(
apiKey: "your-api-key",
environment: .production,
deviceManagers: [polarManager]
)

// Access API service
let apiService = sdk.apiService

Patients API

The Patients API allows you to retrieve and update patient demographic information and medical history. Patient IDs are typically cached locally after initial registration, but you should never cache medical data or ANS results.

Get Patient Details

Retrieve complete patient information including demographics, medical history, and current medications.

Task {
let patient = try await apiService.patients.getPatientDetails(
patientId: patientId
)
print("Patient: \(patient.firstName) \(patient.lastName)")
print("Date of birth: \(patient.dateOfBirth)")
}

Update Patient Details

Update patient demographic information. This is useful for keeping patient records current when users change their contact information or medical history.

let updates = PatientUpdateIn(
firstName: "John",
lastName: "Doe",
dateOfBirth: "1980-01-15",
email: "john.doe@example.com"
)

let updatedPatient = try await apiService.patients.updatePatientDetails(
patientId: patientId,
updates: updates
)

Tests API

The Tests API provides access to historical ANS test results. Each test includes P&S metrics (RFa and LFa values in bpm²), raw RR interval data, and review status. Tests go through a physician review process before treatment recommendations become available.

Get Tests for Patient

Retrieve a paginated list of all tests for a specific patient, ordered by creation date (most recent first).

Task {
let tests = try await apiService.tests.getTestsForPatient(
patientId: patientId,
limit: 20,
offset: 0
)

for test in tests {
print("Test ID: \(test.testId)")
print("Status: \(test.status)")
print("Created: \(test.createdAt)")
}
}

Get Test Details

Fetch complete details for a specific test including all ANS metrics (baseline, deep breathing, Valsalva, standing), RR intervals, and review status.

let test = try await apiService.tests.getTestDetails(testId: testId)

print("Review Status: \(test.reviewStatus)")
print("Baseline RFa: \(test.results.baseline.rfa)")
print("Baseline LFa: \(test.results.baseline.lfa)")

Test Review Status

Tests go through a multi-stage review process before results become available:

StatusDescriptionTypical DurationNext Steps
pending_reviewUploaded, awaiting physician review0-24 hoursTest is queued for review
under_reviewPhysician currently reviewing1-48 hoursProvider analyzing data and video
reviewedReview complete, treatment availableN/AFetch treatment via Treatments API
requires_retestTest invalid, retest neededN/ACheck reviewFeedback for rejection reasons

Review Feedback Reasons: When a test status is requires_retest, the reviewFeedback array contains specific reasons:

  • excessive_movement - Too much fidgeting or motion artifacts during baseline/breathing phases
  • poor_valsalva_technique - Insufficient pressure during Valsalva maneuver
  • device_disconnection - Heart rate monitor lost connection during critical phases
  • non_compliance - User did not follow instructions (e.g., talking, using phone, standing early)
  • insufficient_data - RR interval data quality too low for analysis
  • companion_not_present - Another adult not visible in video (safety requirement)
  • video_quality_poor - Video too dark or obstructed to verify test validity
Webhook Integration

Configure webhooks to receive real-time notifications when test review status changes. This provides better UX than polling the API every few minutes. See Webhook Configuration below for setup instructions.

Treatments API

The Treatments API provides access to physician-prescribed treatment plans. Treatments are created by licensed healthcare providers after reviewing ANS test results and include diagnosis, lifestyle recommendations, medications, and supplements.

Get Treatment for Test

Retrieve the treatment plan associated with a reviewed test. Treatment plans include diagnosis codes, clinical recommendations, prescribed medications with dosages, and supplement suggestions.

Task {
let treatment = try await apiService.treatments.getTreatmentForTest(
testId: testId
)

print("Diagnosis: \(treatment.diagnosis)")
print("Recommendations: \(treatment.recommendations)")

for medication in treatment.medications {
print("Medication: \(medication.name) - \(medication.dosage)")
}
}
Treatment Availability

Treatments are only available after a test has been reviewed by a physician (reviewStatus: reviewed).

Forms API

The Forms API provides access to questionnaire templates and patient form submissions. Forms are required before conducting ANS tests and include the 28-Symptom Autonomic Questionnaire, medical history, current medications, and lifestyle factors.

List Form Templates

Retrieve all available form templates. This typically includes the required autonomic symptom questionnaire and optional supplementary forms.

let templates = try await apiService.forms.listFormTemplates()

for template in templates {
print("Form: \(template.name)")
print("ID: \(template.formId)")
print("Required: \(template.required)")
}

Get Form Template

Fetch a specific form template with all questions, input types, and validation rules. Use this to build custom form UIs or pre-populate forms with existing data.

let form = try await apiService.forms.getFormTemplate(
formId: "28-symptom-autonomic"
)

for question in form.questions {
print("Question: \(question.text)")
print("Type: \(question.inputType)")
print("Options: \(question.options)")
}

List My Form Submissions

Retrieve all form submissions for a patient, optionally filtered by form type. Useful for displaying submission history or checking if required forms are completed.

let submissions = try await apiService.forms.listMyFormSubmissions(
patientId: patientId,
formId: "28-symptom-autonomic"
)

for submission in submissions {
print("Submission ID: \(submission.submissionId)")
print("Status: \(submission.status)")
print("Submitted: \(submission.submittedAt)")
}

Get Form Submission

Fetch a specific form submission with all responses. This is useful for displaying completed forms or allowing users to review their previous answers.

let submission = try await apiService.forms.getMyFormSubmission(
submissionId: submissionId
)

print("Form ID: \(submission.formId)")
print("Status: \(submission.status)")

for (questionId, answer) in submission.responses {
print("\(questionId): \(answer)")
}

Update Form Submission

Update an existing form submission with new or modified responses. This allows users to correct mistakes or update information (e.g., medication changes) before test review.

let updatedResponses: [String: AnyCodable] = [
"q1_dizziness": AnyCodable("4"),
"q2_medications": AnyCodable("Updated medication list")
]

let update = FormSubmissionUpdate(
responses: updatedResponses,
status: .completed
)

let updated = try await apiService.forms.updateMyFormSubmission(
submissionId: submissionId,
update: update
)

Error Handling

Task {
do {
let patient = try await apiService.patients.getPatientDetails(
patientId: patientId
)
} catch APIError.unauthorized {
print("Invalid or expired API key")
} catch APIError.notFound {
print("Patient not found")
} catch APIError.rateLimitExceeded {
print("Too many requests, try again later")
} catch {
print("Unexpected error: \(error)")
}
}

Common Error Codes

CodeErrorDescription
401unauthorizedInvalid or expired API key
403forbiddenInsufficient permissions
404not_foundResource not found
429rate_limit_exceededToo many requests
500internal_errorServer error

Webhook Configuration

Webhooks provide real-time notifications for important events like test reviews completing or treatment plans being updated. Configure webhook endpoints in the Developer Portal to receive these notifications.

Use Webhooks for Real-Time Updates

Instead of polling the API to check if a test review is complete, configure a webhook to receive instant notifications. This reduces API calls and provides better user experience.

Example: When a physician completes a test review, you'll receive a webhook within seconds, allowing you to immediately notify the user via push notification that their results are ready.

Setting Up Webhooks

1. Create a Webhook Endpoint

Your backend must expose an HTTPS endpoint that can receive POST requests:

POST https://your-api.example.com/webhooks/autonomic-health
Content-Type: application/json
X-AH-Signature: sha256=abc123...

2. Configure in Developer Portal

Navigate to Developer Portal → Webhooks → Add Endpoint:

  • Endpoint URL: Your HTTPS endpoint (must use TLS 1.2+)
  • Events: Select which events to receive (test reviews, form submissions, etc.)
  • Secret Key: Copy your webhook secret for signature verification

3. Verify Signatures

All webhook payloads include an X-AH-Signature header for security:

import CryptoKit

func verifyWebhookSignature(payload: Data, signature: String, secret: String) -> Bool {
let hmac = HMAC<SHA256>.authenticationCode(for: payload, using: SymmetricKey(data: Data(secret.utf8)))
let computedSignature = "sha256=" + hmac.map { String(format: "%02x", $0) }.joined()
return computedSignature == signature
}

// In your webhook handler
func handleWebhook(request: HTTPRequest) throws {
guard let signature = request.headers["X-AH-Signature"] else {
throw WebhookError.missingSignature
}

let payload = request.body
let isValid = verifyWebhookSignature(
payload: payload,
signature: signature,
secret: webhookSecret
)

guard isValid else {
throw WebhookError.invalidSignature
}

// Process webhook payload
let event = try JSONDecoder().decode(WebhookEvent.self, from: payload)
processWebhookEvent(event)
}
Security: Always Verify Signatures

Never process webhook payloads without verifying the HMAC signature. An attacker could send fake webhook events to your endpoint, potentially causing your app to display incorrect test results or send false notifications to users.

The signature verification ensures the payload came from Autonomic Health and hasn't been tampered with.

Webhook Retry Logic

If your endpoint is unreachable or returns a non-2xx status code, the webhook system automatically retries:

  • Retry Schedule: Exponential backoff (1 min, 5 min, 15 min, 1 hour, 6 hours, 24 hours)
  • Max Retries: 6 attempts over 24 hours
  • Timeout: 30 seconds per request
  • Failed Delivery: After max retries, webhook is marked as failed and you'll receive an email alert

Best Practices:

  • Respond with 200 OK immediately after receiving the webhook
  • Process the payload asynchronously in a background job
  • If processing fails, the webhook won't be retried (you'll need to poll the API)
  • Log all webhook receipts for debugging

Idempotency: Webhooks may be delivered more than once due to network issues or retries. Your handler should be idempotent:

func processWebhookEvent(_ event: WebhookEvent) async throws {
// Check if this event was already processed
if await database.webhookEventExists(eventId: event.id) {
print("Duplicate webhook, skipping")
return
}

// Mark as processed before handling
await database.saveWebhookEvent(eventId: event.id, timestamp: Date())

// Now process the event
switch event.type {
case .testReviewCompleted:
await notifyUserTestComplete(event.testId)
case .formSubmitted:
await checkIfAllFormsComplete(event.patientId)
}
}

Test Review Events

// Webhook payload structure
struct TestReviewWebhook: Codable {
let event: String // "test.review.completed"
let testId: String
let patientId: String
let reviewStatus: String
let timestamp: String
}

// Handle webhook in your backend
// POST /webhooks/autonomic-health
// {
// "event": "test.review.completed",
// "testId": "test_abc123",
// "patientId": "patient_xyz789",
// "reviewStatus": "reviewed",
// "timestamp": "2024-01-15T10:30:00Z"
// }

Available Webhook Events

Configure which events you want to receive in the Developer Portal. Each event includes relevant identifiers to fetch fresh data via the API.

EventTriggerTypical Use Case
test.upload.completedTest data and video uploaded successfullyUpdate UI to show "Processing..."
test.review.startedPhysician begins reviewing testUpdate status in app
test.review.completedReview complete, treatment availableSend push notification: "Your results are ready!"
test.requires_retestTest invalid, retest neededNotify user with specific feedback
form.submittedPatient completes a formCheck if all required forms are now complete
form.updatedPatient modifies an existing form submissionTrigger re-analysis if test already reviewed
treatment.createdNew treatment plan created for patientNotify user: "Your treatment plan is ready"
treatment.updatedPhysician modifies treatment planAlert user about dosage changes or new recommendations

Webhook Payload Examples

Test Review Completed

{
"event": "test.review.completed",
"event_id": "evt_abc123xyz",
"timestamp": "2024-01-15T14:30:00Z",
"data": {
"test_id": "test_550e8400-e29b-41d4-a716-446655440000",
"patient_id": "patient_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"review_status": "reviewed",
"reviewer_id": "provider_123",
"reviewed_at": "2024-01-15T14:29:45Z",
"treatment_available": true
}
}

Response Flow:

  1. Receive webhook
  2. Verify HMAC signature
  3. Fetch test details: GET /tests/{test_id}
  4. Fetch treatment: GET /treatments/by-test/{test_id}
  5. Send push notification to user
  6. Update app UI to show "Results Available"

Test Requires Retest

{
"event": "test.requires_retest",
"event_id": "evt_def456uvw",
"timestamp": "2024-01-15T10:15:00Z",
"data": {
"test_id": "test_660f9511-f39c-52e5-b827-557766551111",
"patient_id": "patient_8d0f7789-8536-51ef-055c-f18gd2g01bf8",
"review_status": "requires_retest",
"reviewer_id": "provider_456",
"reviewed_at": "2024-01-15T10:14:30Z",
"review_feedback": [
"excessive_movement",
"poor_valsalva_technique"
],
"reviewer_notes": "Patient moved frequently during baseline. Valsalva pressure insufficient."
}
}

Response Flow:

  1. Receive webhook
  2. Verify signature
  3. Fetch full test details with feedback
  4. Send push notification: "Your test needs to be retaken"
  5. In-app message explaining what went wrong with tips for next attempt

Form Submitted

{
"event": "form.submitted",
"event_id": "evt_ghi789rst",
"timestamp": "2024-01-14T16:45:00Z",
"data": {
"submission_id": "sub_771g0622-g40d-63f6-c938-668877662222",
"form_id": "28-symptom-autonomic",
"patient_id": "patient_8d0f7789-8536-51ef-055c-f18gd2g01bf8",
"status": "completed",
"submitted_at": "2024-01-14T16:44:55Z"
}
}

Response Flow:

  1. Receive webhook
  2. Check if all required forms are now complete
  3. If complete and test is pending_forms, trigger test review
  4. Update UI to enable "Start Test" button if forms were blocking

Treatment Updated

{
"event": "treatment.updated",
"event_id": "evt_jkl012mno",
"timestamp": "2024-01-16T09:20:00Z",
"data": {
"treatment_id": "tx_882h1733-h51e-74g7-d049-779988773333",
"patient_id": "patient_9e1g8890-9647-62fg-166d-g29he3h12cg9",
"test_id": "test_550e8400-e29b-41d4-a716-446655440000",
"updated_at": "2024-01-16T09:19:45Z",
"updated_by": "provider_789",
"changes": [
"medications_modified",
"dosage_adjusted"
]
}
}

Response Flow:

  1. Receive webhook
  2. Fetch updated treatment plan
  3. Send push notification: "Your treatment plan has been updated"
  4. In-app badge/indicator on Treatment tab
  5. Optionally email patient about changes

Testing Webhooks

The Developer Portal provides a webhook testing tool:

  • Send test events to your endpoint
  • View delivery logs and responses
  • Inspect retry attempts
  • Validate signature verification

Development Tips:

  • Use services like ngrok to expose localhost during development
  • Test all event types before going to production
  • Verify your idempotency logic with duplicate deliveries
  • Test signature verification with invalid signatures
Production Readiness Checklist

Before enabling webhooks in production:

  • ✅ HTTPS endpoint with valid TLS certificate (TLS 1.2+)
  • ✅ Signature verification implemented and tested
  • ✅ Idempotency handling for duplicate events
  • ✅ Asynchronous processing (respond 200 immediately)
  • ✅ Error logging and monitoring
  • ✅ Graceful degradation if webhook processing fails
  • ✅ Tested with all event types you subscribed to