Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt

Use this file to discover all available pages before exploring further.

The Synheart Core Runtime needs a small set of bootstrap values to start: who your app is (app_id), who issued it (org_id), and an API key to authenticate against the platform (app_api_key). All three are issued by the Synheart Platform. This guide explains where to find them and how to thread them into the runtime.

Required values

The runtime accepts these in SynheartConfig. The first three come from the platform; the fourth is set per-user at runtime.
FieldSourceNotes
app_idPlatform — App detail page, or credentials JSONPlatform-issued identifier, e.g. app_focus_and_kB8mPx. Sent in every ingest call.
org_idPlatform — Org switcher, or credentials JSONIdentifier of the organization that owns the app, e.g. org_focus_kB8mPx.
app_api_keyPlatform — App → API keys tab, one-time creation dialogThe secret key. Shown once when you create the key — not included in the credentials JSON download. Treat it like any other credential.
subject_idYour app, at runtimeThe end-user identifier. Never bake this into synheart.json. Pass it via with_subject_id(...) (or SynheartConfig(subjectId: ...) on mobile) per session.
Auto-detected by the SDK (you don’t set these): device_id, platform, app_version. Source: synheart_config.rs:148-176. The portal exposes two different credentials JSON downloads:
  • The app detail page lets you download a four-field identifiers-only file — org_id, tenant_id, project_id, app_id. No secrets:
    {
      "org_id": "org_focus_kB8mPx",
      "tenant_id": "ten_focus_kB8mPx_dev_a1b2c3",
      "project_id": "prj_focus_kB8mPx_PJI2AxsO",
      "app_id": "app_focus_and_kB8mPx"
    }
    
  • The Generate API Key one-time success dialog offers a richer download that bundles the new key with the identifiers — adds secret_key (your app_api_key) and, when issued, signing_secret. This file appears once and never again — save it to your secret manager immediately.
Either way, the runtime only reads org_id, app_id, and app_api_key (which maps from secret_key). tenant_id and project_id are useful for direct REST calls into the platform (ingestion, data deletion) but are not parsed into SynheartConfig. The signing_secret is not for the SDK — see the next section.

Where to find them on the platform

  1. Sign in at platform.synheart.ai and switch to the right organization.
  2. Open the project that owns your app, then open the app.
  3. On the app detail page you can download the credentials JSONorg_id, tenant_id, project_id, app_id. No secrets are in this file.
  4. Open the API keys tab → Generate API Key. In the side panel:
    • Choose App — pick the app this key authorises (one key, one app).
    • Key TypeProduction, Development, Staging, Testing, or Other. Used for your own bookkeeping; mint a separate key per environment so you can revoke them independently.
    • Scopes — tick at least one of Read, Write, Delete, Admin. The form blocks submission until one is selected.
  5. The portal returns the secret key and a signing secret in a one-time dialog. Copy both into your secret manager before closing — they are stored hashed and cannot be recovered. The secret key is your app_api_key, sent on every request as the x-api-key header.
Full walkthrough: Platform — API keys. Ingestion access for biosignals is gated separately by an app-level allowlist — see the Ingestion access section.

Packaging into synheart.json

The runtime reads from a synheart.json file baked into your app bundle. This is the recommended path on every platform.
{
  "app_id": "app_focus_and_kB8mPx",
  "org_id": "org_focus_kB8mPx",
  "app_api_key": "sk_live_abc123..."
}
Take the four-field credentials JSON from the portal and add app_api_key from the one-time secret dialog. You can also keep tenant_id and project_id in the file — the runtime ignores them, but having them in one place is convenient if your backend code reads the same file. Where the runtime looks for it (in order; source: synheart_config.rs:212-246):
  1. Explicit path passed to SynheartConfig::from_file(Some("…/synheart.json")).
  2. ./synheart.json in the process’s current working directory.
  3. On desktop builds only: the platform data directory (~/.synheart/synheart-core/synheart.json and equivalents).
On mobile, ship the file inside your app’s resources and pass its path explicitly:
// Flutter
final cfg = await rootBundle.loadString('assets/synheart.json');
await Synheart.initialize(
  config: SynheartConfig.fromJson(cfg).copyWith(subjectId: currentUserId),
);
// Swift
let url = Bundle.main.url(forResource: "synheart", withExtension: "json")!
let json = try String(contentsOf: url)
let config = SynheartConfig.fromJson(json).withSubjectId(currentUserId)
try await Synheart.initialize(config: config)
// Kotlin
val json = context.assets.open("synheart.json").bufferedReader().use { it.readText() }
val config = SynheartConfig.fromJson(json).copy(subjectId = currentUserId)
Synheart.initialize(context = context, config = config)

Resolution order

When the same field is set in multiple places, the runtime takes the highest-priority source (source: synheart_config.rs:121-126):
  1. Values passed directly to SynheartConfig (highest priority — overrides everything).
  2. synheart.json (recommended for app_id / app_api_key / org_id).
  3. SYNHEART_API_URL environment variable (only for api_base_url).
  4. Compiled defaults (lowest — api_base_url defaults to https://api.synheart.ai).
This means: in development you can override app_api_key from a constructor argument or environment variable in your own code, while production builds read everything from synheart.json. The runtime itself only reads one OS env (SYNHEART_API_URL).

Enterprise / self-hosted overrides

For customers running their own Synheart infrastructure, every service URL can be overridden independently. Add an enterprise block to synheart.json (source: synheart_config.rs:92-101):
{
  "app_id": "...",
  "app_api_key": "...",
  "org_id": "...",
  "enterprise": {
    "auth_url": "https://auth.synheart.example.com",
    "sync_url": "https://sync.synheart.example.com",
    "consent_url": "https://consent.synheart.example.com",
    "cloud_url": "https://cloud.synheart.example.com",
    "platform_url": "https://platform.synheart.example.com",
    "lab_url": "https://lab.synheart.example.com",
    "capabilities_url": "https://capabilities.synheart.example.com"
  }
}
Any field left out falls back to the resolved api_base_url. If you only need to redirect everything to a single mirror, set SYNHEART_API_URL=https://api.example.com and skip the enterprise block.

What about the signing secret?

The Generate API Key dialog issues a signing_secret alongside the secret_key. The on-device SDK doesn’t use it. There is no field for it in SynheartConfig, and adding one to synheart.json is a no-op. The two secrets target different callers (RFC dual-mode auth):
SecretUsed byHow
secret_key (your app_api_key)EveryoneSent on every request as the x-api-key header.
signing_secretServer-to-server callers onlyHMAC-SHA256 over timestamp + raw_body, sent as X-Synheart-Signature (Mode B).
On device, the SDK signs ingest requests with an ECDSA P-256 device key that synheart-auth auto-registers on first launch — not with signing_secret. So unless your backend calls the platform REST API directly (a Postman flow, a server-side ingest pipeline, a custom integration), you can ignore the signing secret entirely. If you do need it server-side, keep it out of the mobile bundle and store it next to your other backend credentials.

Capability tokens

Capability tokens are separate from the app API key. The API key authenticates your app to the platform; capability tokens authorise specific modules and channels (focus estimation, emotion estimation, research export) for a given subject. They flow into the same synheart.json:
{
  "app_id": "...",
  "app_api_key": "...",
  "org_id": "...",
  "capability_token": "eyJ...",
  "capability_secret": "..."
}
For development you can pass allowUnsignedCapabilities: true instead, and the runtime will run without a signed token (with a warning). Don’t ship that flag to production. See Capability System for the full token shape, signing model, and what each capability unlocks.

Common mistakes

  • Committing synheart.json to a public repo. The app_api_key is a long-lived secret. Add the file to .gitignore and ship it via your build pipeline’s secret store.
  • Re-using one key across environments. Mint a separate key per environment tag (development, staging, production) so you can revoke them independently. Revocation is immediate (401 on the next request).
  • Putting subject_id in synheart.json. That file is baked into the bundle and shared across every install; the subject is per-user and must be set at runtime.
  • Expecting SYNHEART_API_URL to override anything else. It only resolves api_base_url. To override individual service URLs, use the enterprise block.
  • Forgetting the ingestion allowlist. A valid key still gets 403 if the app hasn’t been allowlisted for biosignal ingestion. Email Synheart with the app_id to request access — there’s no self-service flow today.
  • Using allowUnsignedCapabilities in production. It skips capability verification entirely. Use a signed capability_token instead.