Integrations / API
Folklore API
Submit a VCF from your application and retrieve a PDF report, structured analysis results, or both.
Get an API key
Contact Helena to agree API access, data sources and billing. Helena issues your key after the integration agreement.
Keep the key on your backend. Send it as a bearer credential on every request. Contact Helena to rotate or revoke it.
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $FOLKLORE_API_KEY" \
https://api.helena.bio/folklore/v1/contextBase URL: https://api.helena.bio/folklore/v1
Choose who pays
The same key can use partner-funded and client-funded arrangements. Call GET /context and select the returned context_binding_id for the intended case workspace, S3 source and payer.
| Funding | Prepaid account | Approval |
|---|---|---|
| Partner-funded | Your integration partner | Agreed partner spending allowance |
| Client-funded | Your client | Approved client spending mandate |
Credits are reserved before computation and settled separately from analysis status. One Case Credit is 1000 integer units. Set max_cost_units to your approved ceiling; with credits:read, use the current price and balance returned by context. available_units already excludes reserved credits. A missing billing projection is unavailable, not a zero balance. Submit the context ID, not a payer UUID.
Prepare the input
Supply one single-sample .vcf or .vcf.gz object from an approved S3 source. Include its immutable version_id. The input must remain accessible while Folklore imports it.
| Field | Value |
|---|---|
| profile | singleton-germline-v2 |
| input | S3 connection, bucket, object key and version |
| clinical_profile | Explicit sex, clinical context and module choices |
| outputs | ["pdf"], ["json"] or ["json", "pdf"] |
| max_cost_units | Integer cost ceiling |
HPO identifiers drive phenotype matching. Clinical notes, indication and family history retain additional context. Screening and literature are explicit choices. Screening requires recorded consent. Supplied panel IDs must be authorized.
Clinical fields
Provide collected clinical information in clinical_profile. Omit uncollected optional fields; use unknown only when sex is unknown. Unknown fields are rejected.
| Field | Accepted values |
|---|---|
| demographics | sex: male, female or unknown (required). Optional age_years ≥0 or age_days 0–365; do not supply both. Optional age_group. |
| phenotype | hpo_ids: up to 200 HP identifiers. clinical_notes: up to 20,000 characters. |
| clinical_context | indication, indication_details and family_history (affected relatives, consanguinity and details). |
| ethnicity | primary, populations and note. |
| reproductive | is_pregnant, gestational_age_weeks and family_planning. |
| sample_info | singleton sample type, parental-sample and affected-sibling metadata. |
| modules | enable_screening and enable_literature, both false by default. |
| consent | secondary_findings and carrier_results must each be explicitly true or false when screening is enabled. pharmacogenomics is retained consent only. |
| panel_ids | Up to 64 authorized panel UUIDs. Screening must be enabled. |
| custom_genes | Up to 500 entries: gene_symbol, priority_score 0–1, age_group_relevance (neonatal, pediatric, adult or all), optional disease_name and notes. Screening must be enabled. |
| filtering_preset | strict (default), balanced or permissive. |
| language | en. |
Create an analysis
Save the request and one unique Idempotency-Key before sending it. Reuse both after a timeout. A 202 response means the command was accepted; import and analysis continue asynchronously.
Save this synthetic example as analysis-request.json and replace the identifiers and source version with your provisioned values. The 1000-unit ceiling is illustrative; submitting an analysis can spend credits.
{
"context_binding_id": "44444444-4444-4444-8444-444444444444",
"profile": "singleton-germline-v2",
"external_reference": "SYNTHETIC-CASE-001",
"input": {
"kind": "s3_object",
"connection_id": "66666666-6666-4666-8666-666666666666",
"bucket": "synthetic-cases",
"key": "approved/SYNTHETIC-CASE-001.vcf.gz",
"version_id": "REPLACE_WITH_IMMUTABLE_OBJECT_VERSION"
},
"clinical_profile": {
"demographics": {
"sex": "unknown"
},
"modules": {
"enable_screening": false,
"enable_literature": false
},
"phenotype": {
"hpo_ids": []
},
"filtering_preset": "strict",
"language": "en"
},
"outputs": [
"json"
],
"max_cost_units": 1000
}
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $FOLKLORE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: synthetic-host-action-001" \
-d @analysis-request.json \
https://api.helena.bio/folklore/v1/analysesExample 202 response:
{
"analysis_id": "11111111-1111-4111-8111-111111111111",
"case_id": "22222222-2222-4222-8222-222222222222",
"status": "queued",
"stage": "import",
"created_at": "2030-01-01T12:00:00+00:00",
"updated_at": "2030-01-01T12:00:00+00:00",
"error": null,
"cost": {
"reserved_units": null
},
"billing": {
"state": "not_reserved"
},
"warnings": [],
"links": {
"self": "/folklore/v1/analyses/11111111-1111-4111-8111-111111111111",
"results": "/folklore/v1/analyses/11111111-1111-4111-8111-111111111111/results",
"folklore": "https://folklore.helena.bio/app/analysis/22222222-2222-4222-8222-222222222222"
}
}Follow progress
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $FOLKLORE_API_KEY" \
"https://api.helena.bio/folklore/v1/analyses/$ANALYSIS_ID"Read status, stage, error and billing. Status is queued, running, succeeded or failed. Stages are import, validation, admission, analysis, publication and complete. A successful HTTP status can still contain a failed analysis. Continue polling while billing is settlement_pending, even after analysis succeeds, until billing becomes consumed or released. A failed analysis with not_reserved incurred no reservation. Do not submit another analysis to settle credits. Preserve warnings such as optional_stage_failed and the state of each optional result collection.
Example completed status after credit settlement:
{
"analysis_id": "11111111-1111-4111-8111-111111111111",
"case_id": "22222222-2222-4222-8222-222222222222",
"status": "succeeded",
"stage": "complete",
"created_at": "2030-01-01T12:00:00+00:00",
"updated_at": "2030-01-01T12:05:00+00:00",
"error": null,
"cost": {
"reserved_units": 1000
},
"billing": {
"state": "consumed"
},
"warnings": [],
"links": {
"self": "/folklore/v1/analyses/11111111-1111-4111-8111-111111111111",
"results": "/folklore/v1/analyses/11111111-1111-4111-8111-111111111111/results",
"folklore": "https://folklore.helena.bio/app/analysis/22222222-2222-4222-8222-222222222222"
}
}Download results
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $FOLKLORE_API_KEY" \
"https://api.helena.bio/folklore/v1/analyses/$ANALYSIS_ID/results" \
-o manifest.jsonAfter the analysis succeeds, request GET /analyses/{analysis_id}/results. The manifest supplies the generation, retention deadline and requested artifacts. Download each artifact through its authenticated route. Require HTTP success, then verify its exact byte length and SHA-256 before ingestion.
| Output | Contents |
|---|---|
| Selected interpretation and report for the frozen generation | |
| JSON | Processed variants, phenotype matches, screening results, literature results, gene summaries and provenance |
JSON schema version "2" covers processed variants after the selected filtering preset. It retains recorded classification and available evidence from that generation. Module state and row counts distinguish unrequested or failed modules from successful empty results.
Set ANALYSIS_ID from the create response and ARTIFACT_ID from the chosen manifest entry. This example selects the JSON artifact; use result.pdf for a PDF artifact. Use the same credential. Download before expires_at. Keep the manifest and ingestion receipt. The Folklore case link opens the same case under normal sign-in and case permissions.
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $FOLKLORE_API_KEY" \
"https://api.helena.bio/folklore/v1/analyses/$ANALYSIS_ID/artifacts/$ARTIFACT_ID" \
-o result.jsonSynthetic JSON-only manifest. Its size and hashes match the downloadable example bytes.
{
"analysis_id": "11111111-1111-4111-8111-111111111111",
"case_id": "22222222-2222-4222-8222-222222222222",
"generation_id": "33333333-3333-4333-8333-333333333333",
"schema_version": "2",
"report_id": null,
"summary": {
"classifier_version": "synthetic-example",
"classifier_version_label": "Synthetic example",
"pathogenic_count": 0,
"likely_pathogenic_count": 0
},
"artifacts": [
{
"artifact_id": "ab485dd5-b951-54b7-93c3-59286b1d2e2c",
"kind": "json",
"content_type": "application/json",
"size_bytes": 3182,
"sha256": "1250f4fd3957c4172480090fb5f27e2eefde8ba0c9fec2b2dcc222e440faf19e",
"download_url": "/folklore/v1/analyses/11111111-1111-4111-8111-111111111111/artifacts/ab485dd5-b951-54b7-93c3-59286b1d2e2c"
}
],
"warnings": [],
"expires_at": "2030-01-31T12:00:00+00:00",
"manifest_sha256": "2ad7b57e1df16b620f7c041ee65bdf0c71a60d093a27204c5adb33bc45204e10"
}For manifest verification, remove manifest_sha256 and serialize the rest as compact UTF-8 JSON with recursively sorted keys and ASCII escaping. Compute SHA-256 over those bytes. Artifact hashes cover the exact downloaded bytes.
Shortened schema2 response from a synthetic empty processed generation:
{
"schema_version": "2",
"profile": "singleton-germline-v2",
"analysis_id": "11111111-1111-4111-8111-111111111111",
"case_id": "22222222-2222-4222-8222-222222222222",
"generation_id": "33333333-3333-4333-8333-333333333333",
"coverage": {
"filtering_preset": "strict",
"raw_input_variants": false,
"variant_identity": "variant_idx_is_generation_local; allele_fields_are_recorded",
"variants": "all_processed_rows_after_filtering_preset"
},
"collections": {
"literature_results": {
"row_count": 0,
"state": "not_requested"
},
"phenotype_matches": {
"row_count": 0,
"state": "not_requested"
},
"screening_results": {
"row_count": 0,
"state": "not_requested"
},
"variants": {
"row_count": 0
}
}
}Download complete JSON example · Download result field reference
| Collection | Meaning |
|---|---|
| variants | Allele identity, genotype and quality, annotations, population frequency, predictors, recorded ACMG criteria/evidence and available mitochondrial evidence. variant_idx is generation-local. |
| phenotype_matches | Scores, matched terms, individual HPO matches, priority, tier and inheritance notes. |
| screening_results | Screening tier, scores, actionability, panel disease and recorded justification. |
| literature_results | Publication identifiers, citations, abstracts, evidence matches and relevance scores. |
| gene_summaries | Metadata, gene aggregates and completion records. |
collections.variants contains row_count and unavailable_fields. Phenotype, screening and literature collections also carry state. Preserve not_requested, skipped and failed; a zero count alone does not mean a successful negative result. Missing fields stay null. Frozen provenance includes the accepted clinical profile, request hash and profile hash; later human annotation changes do not rewrite this export.
Retries and errors
| HTTP | Action |
|---|---|
| 401 | Replace an expired or revoked credential. |
| 403 | Resolve the denied permission or arrangement. |
| 409 | Reconcile an idempotency conflict, or continue polling if results are not ready. |
| 404 | The analysis or artifact is unavailable in the admitted context. |
| 410 | The artifact retention deadline has passed. |
| 422 | Correct the invalid request. |
| 503 | Retry with backoff while preserving the saved command. |
Handled request errors contain error.code, error.message, error.retryable and request_id. A failed analysis status instead contains error.code and error.message; it can report input_validation_failed, insufficient_case_credits or cost_limit_exceeded.
Retain request_id for support. Changing the file version, clinical input, outputs, context or cost ceiling under an existing idempotency key creates a conflict. Retry downloads and host imports without submitting another analysis.
Endpoint reference
| Method and path | Scope |
|---|---|
| GET /context | Current credential |
| POST /analyses | analyses:create |
| GET /analyses/{analysis_id} | analyses:read |
| GET /analyses/{analysis_id}/results | results:read |
| GET /analyses/{analysis_id}/artifacts/{artifact_id} | results:read |
Existing human integrations retain OpenID Connect Authorization Code with S256 PKCE. Existing singleton-germline-v1 retains its clinical input and gene-summary JSON. New structured results and PDF-only requests use v2.
These profiles accept singleton VCF inputs. Clients poll for completion; batch, family, FASTQ and BAM/CRAM submission are outside this contract.