Helios delivers analysis results to your webhook URL asynchronously. This guide covers webhook payloads, signature verification, and best practices.
How Webhooks Work
When you submit a request to the Helios API:
You receive an immediate response with a runId
Analysis runs in the background (5-8 minutes for Light Agent, 10-13 minutes for Deep Agent, 3-6 minutes for Lab Results Agent)
Results are delivered to your webhookUrl via HTTP POST
Your endpoint should return 200 OK to acknowledge receipt
Every webhook includes these headers for security and tracking:
Header Description Example X-Helios-SignatureHMAC-SHA256 signature sha256=a1b2c3...X-Helios-TimestampUnix timestamp (seconds) 1705320000X-Helios-Run-IDUnique run identifier 550e8400-e29b-...Content-TypeAlways JSON application/json
Webhook Payloads
Success Payload (Light Agent)
When Light Agent analysis completes successfully:
{
"runId" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "completed" ,
"agent" : "light" ,
"timestamp" : "2025-01-15T12:01:30.000Z" ,
"sequenceNumber" : 7 ,
"result" : {
"selectedElements" : [
{
"item" : "Hemoglobin A1c" ,
"category" : "Laboratory Value" ,
"patient_value" : "7.2%" ,
"matching_reason" : "Elevated HbA1c indicates suboptimal glycemic control"
}
],
"patientResponse" : "Your recent lab results show..." ,
"clinicianResponse" : "The patient presents with..." ,
"citations" : {
"patient" : {
"1" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/12345678/" ,
"title" : "Glycemic Control in Type 2 Diabetes" ,
"metadata" : { "type" : "pubmed" }
},
"2" : {
"url" : "https://doi.org/10.2337/dc24-S006" ,
"title" : "ADA Standards of Care in Diabetes — Glycemic Goals and Hypoglycemia" ,
"metadata" : {
"type" : "guideline" ,
"source" : "ADA" ,
"author" : "American Diabetes Association" ,
"doi" : "10.2337/dc24-S006" ,
"pubdate" : "2024-01-01" ,
"abstract_snippet" : "Glycemic management is primarily assessed with the A1C test..." ,
"specialties" : [ "Endocrinology" ]
}
}
},
"clinician" : {
"1" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/87654321/" ,
"title" : "ADA Standards of Care 2025" ,
"metadata" : { "type" : "pubmed" }
},
"2" : {
"url" : "https://doi.org/10.2337/dc24-S009" ,
"title" : "ADA Standards of Care — Pharmacologic Approaches to Glycemic Treatment" ,
"metadata" : {
"type" : "guideline" ,
"source" : "ADA" ,
"doi" : "10.2337/dc24-S009" ,
"specialties" : [ "Endocrinology" ]
}
}
}
}
}
}
Success Payload (Deep Agent)
Deep Agent responses include additional research task information:
{
"runId" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "completed" ,
"agent" : "deep" ,
"timestamp" : "2025-01-15T12:15:30.000Z" ,
"sequenceNumber" : 9 ,
"result" : {
"selectedElements" : [
{
"item" : "Hemoglobin A1c" ,
"category" : "Laboratory Value" ,
"patient_value" : "7.2%" ,
"matching_reason" : "Elevated HbA1c indicates suboptimal glycemic control"
}
],
"patientResponse" : "Your recent lab results show..." ,
"clinicianResponse" : "The patient presents with..." ,
"researchTasks" : [
"Research current ADA guidelines for glycemic control in Type 2 Diabetes" ,
"Investigate medication intensification strategies for patients with HbA1c > 7%" ,
"Analyze cardiovascular risk factors and preventive measures"
],
"citations" : {
"patient" : {
"1" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/12345678/" ,
"title" : "Glycemic Control in Type 2 Diabetes" ,
"metadata" : { "type" : "pubmed" }
},
"2" : {
"url" : "https://doi.org/10.2337/dc24-S006" ,
"title" : "ADA Standards of Care — Glycemic Goals and Hypoglycemia" ,
"metadata" : {
"type" : "guideline" ,
"source" : "ADA" ,
"doi" : "10.2337/dc24-S006" ,
"specialties" : [ "Endocrinology" ]
}
}
},
"clinician" : {
"1" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/87654321/" ,
"title" : "ADA Standards of Care 2025" ,
"metadata" : { "type" : "pubmed" }
},
"2" : {
"url" : "https://doi.org/10.1161/CIR.0000000000001168" ,
"title" : "2023 AHA/ACC Guideline for Heart Failure Management" ,
"metadata" : {
"type" : "guideline" ,
"source" : "ACC/AHA" ,
"doi" : "10.1161/CIR.0000000000001168" ,
"specialties" : [ "Cardiology" ]
}
}
}
}
}
}
Success Payload (Lab Results Agent)
Lab Results Agent responses include the analyzed labs and metadata:
{
"runId" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "completed" ,
"agent" : "lab-results" ,
"timestamp" : "2025-01-15T12:05:00.000Z" ,
"sequenceNumber" : 8 ,
"result" : {
"labResults" : [
{
"name" : "Creatinine" ,
"value" : "1.8 mg/dL" ,
"flag" : "High" ,
"referenceRange" : "0.7-1.3 mg/dL" ,
"date" : "2025-01-15" ,
"category" : "Renal"
}
],
"patientResponse" : "Your kidney function tests show..." ,
"clinicianResponse" : "The patient demonstrates Stage 3b CKD..." ,
"citations" : {
"patient" : {
"1" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/12345678/" ,
"title" : "KDIGO Guidelines for CKD Management" ,
"metadata" : { "type" : "pubmed" }
},
"2" : {
"url" : "https://doi.org/10.1016/j.kint.2024.01.006" ,
"title" : "KDIGO 2024 Clinical Practice Guideline for CKD Evaluation and Management" ,
"metadata" : {
"type" : "guideline" ,
"source" : "KDIGO" ,
"doi" : "10.1016/j.kint.2024.01.006" ,
"specialties" : [ "Nephrology" ]
}
},
"3" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/34567890/" ,
"title" : "Creatinine Clearance as a Marker of GFR in CKD" ,
"metadata" : {
"type" : "insight" ,
"source" : "pubmed.ncbi.nlm.nih.gov" ,
"author" : "Published in Kidney International" ,
"pubdate" : "2023"
}
}
},
"clinician" : {
"1" : {
"url" : "https://pubmed.ncbi.nlm.nih.gov/87654321/" ,
"title" : "CKD Progression Risk Factors" ,
"metadata" : { "type" : "pubmed" }
},
"2" : {
"url" : "https://doi.org/10.1016/j.kint.2024.01.006" ,
"title" : "KDIGO 2024 Clinical Practice Guideline for CKD Evaluation and Management" ,
"metadata" : {
"type" : "guideline" ,
"source" : "KDIGO" ,
"doi" : "10.1016/j.kint.2024.01.006" ,
"specialties" : [ "Nephrology" ]
}
}
}
},
"metadata" : {
"labsReceived" : 15 ,
"labsAnalyzed" : 15 ,
"insightsMatched" : 8
}
}
}
Lab Results Agent does not include selectedElements since all provided labs are analyzed directly. Instead, it includes labResults (the labs that were analyzed) and metadata with processing statistics.
Error Payload
When analysis fails:
{
"runId" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "error" ,
"timestamp" : "2025-01-15T12:01:30.000Z" ,
"sequenceNumber" : 3 ,
"error" : {
"code" : "VALIDATION_ERROR" ,
"message" : "Invalid health data format"
}
}
Status Update Payload
During processing, you receive status updates at each step:
{
"runId" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "processing" ,
"agent" : "light" ,
"step" : 2 ,
"stepName" : "Analyzing health data" ,
"timestamp" : "2025-01-15T12:00:45.000Z" ,
"sequenceNumber" : 2
}
Important: The sequenceNumber field is a monotonically increasing number that allows you to order webhooks correctly. Webhooks may arrive out of order due to network conditions, but you can sort them by sequenceNumber to reconstruct the correct sequence. The timestamp field can also be used as a fallback for ordering.
Processing Steps
The following steps are sent during processing:
Light Agent Steps:
Step Name 1 Processing started 2 Analyzing health data 3 Selecting relevant elements 4 Researching medical literature and clinical guidelines 5 Generating patient response 6 Generating clinician response 7 Finalizing results 8 Delivering final results
Deep Agent Steps:
Step Name Description 1 Processing started Request received and validated 2 Analyzing health data Extracting insights from EHR data 3 Selecting relevant elements AI selecting important health elements 4 Routing to Deep Agent Handing off to research agent 5 Starting research tasks Beginning parallel literature and guideline research 6 Research complete All research tasks finished 7 Generating responses Creating clinician and patient reports 8 Finalizing results Preparing final output
Steps 1-4 are sent by the initial API server. Steps 5-8 and the final result are sent by the Deep Agent research processor. This architecture allows the Deep Agent to run for up to 16 minutes without timeout constraints.
Lab Results Agent Steps:
Step Name 1 Processing started 2 Analyzing lab results 3 Prioritizing findings 4 Generating search queries 5 Searching medical literature and clinical guidelines 6 Processing search results 7 Generating responses 8 Final webhook delivered
Error Codes
Code Description VALIDATION_ERRORInvalid request data AUTH_ERRORAuthentication failed RATE_LIMIT_ERRORToo many requests CONCURRENCY_LIMIT_ERRORToo many concurrent requests VERTEX_AI_ERRORAI service error LITSENSE_ERRORLiterature search error EXA_ERRORResearch search error FIREBASE_ERRORDeep Agent processing error ELEMENT_SELECTION_ERRORFailed to select relevant health elements CLINICIAN_RESPONSE_ERRORFailed to generate clinician response PATIENT_RESPONSE_ERRORFailed to generate patient response TIMEOUT_ERRORAnalysis timed out INTERNAL_ERRORServer error NO_DATAInsufficient health data provided
Signature Verification
Always verify webhook signatures in production to ensure requests are authentic and haven’t been tampered with.
Verification Steps
Get the raw request body - Use the raw body string, not parsed JSON
Check the timestamp - Reject webhooks older than 5 minutes
Compute the expected signature - sha256=HMAC-SHA256(webhook_secret, raw_body)
Compare signatures - Use timing-safe comparison
Implementation Examples
import { createHmac , timingSafeEqual } from 'crypto' ;
function verifyWebhook ( rawBody , signature , timestamp , webhookSecret ) {
// Check timestamp is recent (within 5 minutes)
const now = Math . floor ( Date . now () / 1000 );
const webhookTime = parseInt ( timestamp , 10 );
if ( Math . abs ( now - webhookTime ) > 300 ) {
console . error ( 'Webhook timestamp too old' );
return false ;
}
// Compute expected signature
const expected = 'sha256=' + createHmac ( 'sha256' , webhookSecret )
. update ( rawBody )
. digest ( 'hex' );
// Timing-safe comparison
if ( expected . length !== signature . length ) {
return false ;
}
return timingSafeEqual (
Buffer . from ( expected ),
Buffer . from ( signature )
);
}
// Express.js example
app . post ( '/webhook/helios' , express . raw ({ type: 'application/json' }), ( req , res ) => {
const rawBody = req . body . toString ();
const signature = req . headers [ 'x-helios-signature' ];
const timestamp = req . headers [ 'x-helios-timestamp' ];
if ( ! verifyWebhook ( rawBody , signature , timestamp , process . env . WEBHOOK_SECRET )) {
return res . status ( 401 ). send ( 'Invalid signature' );
}
const payload = JSON . parse ( rawBody );
// Process webhook...
res . status ( 200 ). send ( 'OK' );
});
Retry Policy
Helios retries failed webhook deliveries with exponential backoff:
Attempt Delay Total Time 1 Immediate 0s 2 5 seconds 5s 3 15 seconds 20s
After 3 failed attempts, the webhook is logged but not retried further.
Your webhook endpoint should return a 2xx status code within 30 seconds to be considered successful.
Best Practices
Process webhooks asynchronously. Return 200 OK immediately, then handle the data in a background job. app . post ( '/webhook/helios' , ( req , res ) => {
// Acknowledge immediately
res . status ( 200 ). send ( 'OK' );
// Process in background
processWebhookAsync ( req . body );
});
In rare cases, you may receive the same webhook twice. Use the runId to deduplicate: const processedRuns = new Set ();
if ( processedRuns . has ( payload . runId )) {
return ; // Already processed
}
processedRuns . add ( payload . runId );
Webhooks may arrive out of order due to network conditions. Use the sequenceNumber field to sort them correctly: const webhooks = [];
// Store webhooks as they arrive
app . post ( '/webhook/helios' , ( req , res ) => {
const payload = req . body ;
webhooks . push ( payload );
// Sort by sequenceNumber to get correct order
webhooks . sort (( a , b ) => ( a . sequenceNumber || 0 ) - ( b . sequenceNumber || 0 ));
res . status ( 200 ). send ( 'OK' );
});
The sequenceNumber starts at 1 and increments for each webhook sent during a run. The final completed or error webhook will have the highest sequenceNumber.
Log all incoming webhooks for debugging and audit purposes. Store the runId, status, and timestamp.
Your webhook endpoint must use HTTPS in production. Self-signed certificates are not supported.
Getting Your Webhook Secret
Your webhook secret is used to verify webhook signatures and ensure requests are authentic.
To generate your webhook secret:
Log in to your Helios Dashboard
Go to Settings (API Keys page)
In the Webhook Secret section, click Generate Secret
Copy and securely store the secret—it will only be shown once
If you regenerate your webhook secret, the previous secret is immediately invalidated. Make sure to update your server configuration before regenerating.
Next Steps
EHR Agent Full EHR Agent request and response reference.
Lab Results Agent Full Lab Results Agent request and response reference.
API Overview Shared concepts: auth, errors, privacy.
Dashboard View your API usage and logs.