Folklore

Integrations / API

Folklore API

Submit a VCF from your application and retrieve a PDF report, structured analysis results, or both.

Contact Helena

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/context

Base 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.

FundingPrepaid accountApproval
Partner-fundedYour integration partnerAgreed partner spending allowance
Client-fundedYour clientApproved 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.

FieldValue
profilesingleton-germline-v2
inputS3 connection, bucket, object key and version
clinical_profileExplicit sex, clinical context and module choices
outputs["pdf"], ["json"] or ["json", "pdf"]
max_cost_unitsInteger 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

Download request field schema

Provide collected clinical information in clinical_profile. Omit uncollected optional fields; use unknown only when sex is unknown. Unknown fields are rejected.

FieldAccepted values
demographicssex: male, female or unknown (required). Optional age_years ≥0 or age_days 0–365; do not supply both. Optional age_group.
phenotypehpo_ids: up to 200 HP identifiers. clinical_notes: up to 20,000 characters.
clinical_contextindication, indication_details and family_history (affected relatives, consanguinity and details).
ethnicityprimary, populations and note.
reproductiveis_pregnant, gestational_age_weeks and family_planning.
sample_infosingleton sample type, parental-sample and affected-sibling metadata.
modulesenable_screening and enable_literature, both false by default.
consentsecondary_findings and carrier_results must each be explicitly true or false when screening is enabled. pharmacogenomics is retained consent only.
panel_idsUp to 64 authorized panel UUIDs. Screening must be enabled.
custom_genesUp 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_presetstrict (default), balanced or permissive.
languageen.

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/analyses

Example 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.json

After 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.

OutputContents
PDFSelected interpretation and report for the frozen generation
JSONProcessed 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.json

Synthetic 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

CollectionMeaning
variantsAllele identity, genotype and quality, annotations, population frequency, predictors, recorded ACMG criteria/evidence and available mitochondrial evidence. variant_idx is generation-local.
phenotype_matchesScores, matched terms, individual HPO matches, priority, tier and inheritance notes.
screening_resultsScreening tier, scores, actionability, panel disease and recorded justification.
literature_resultsPublication identifiers, citations, abstracts, evidence matches and relevance scores.
gene_summariesMetadata, 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

HTTPAction
401Replace an expired or revoked credential.
403Resolve the denied permission or arrangement.
409Reconcile an idempotency conflict, or continue polling if results are not ready.
404The analysis or artifact is unavailable in the admitted context.
410The artifact retention deadline has passed.
422Correct the invalid request.
503Retry 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 pathScope
GET /contextCurrent credential
POST /analysesanalyses:create
GET /analyses/{analysis_id}analyses:read
GET /analyses/{analysis_id}/resultsresults: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.