Clinical API Reference

Programmatic access to GeneOS Token Vault for EHR and CRM integration. Requires a clinical account and an API key.

Authentication

All API endpoints are authenticated via the X-GeneOS-Key HTTP header. API keys are available to accounts with Clinical Access enabled. Generate keys from the Token Vault → API Access section.

API Key format: gxk_ followed by 48 hex characters (52 chars total).
Keys are shown once at creation — store them securely in your environment variables.
# Every request must include:
X-GeneOS-Key: gxk_a1b2c3d4e5f6...

Base URL

https://geneos.app/api/ideas

All endpoint paths below are relative to this base URL. For example: https://geneos.app/api/ideas/geneos/api/v1/tokens

Rate Limits

Each API key is limited to 1,000 requests per day (UTC). Exceeding this returns HTTP 429.

# 429 response body:
{
  "ok": false,
  "error": "Rate limit exceeded: 1000 requests/day per key."
}

Error Format

All responses include "ok": true on success and "ok": false on error. HTTP status codes follow REST conventions.

StatusMeaning
200Success
400Bad request (missing or invalid field)
401Missing or invalid API key
403Access denied (wrong owner or no clinical access)
404Resource not found
429Rate limit exceeded
500Internal server error

List API Keys

GET /geneos/api/keys Requires browser session (not API key)
{
  "ok": true,
  "keys": [
    {
      "prefix": "gxk_a1b2c3d4",
      "label": "EHR Integration",
      "created_at": "2026-07-14T12:00:00+00:00",
      "last_used": "2026-07-14T15:30:00+00:00"
    }
  ]
}

Generate API Key

POST /geneos/api/keys Generate a new API key — shown once
{ "label": "EHR Integration" }
{
  "ok": true,
  "key": "gxk_a1b2c3d4e5f6...",      // full key — shown ONCE
  "prefix": "gxk_a1b2c3d4",
  "label": "EHR Integration",
  "created_at": "2026-07-14T12:00:00+00:00",
  "note": "Store this key securely — it will not be shown again."
}
⚠️ Save this key immediately. The full key is returned only once and is never stored in plaintext.

Revoke API Key

DELETE /geneos/api/keys/{prefix} Revoke a key by its prefix
{ "ok": true, "revoked": "gxk_a1b2c3d4" }

List Tokens

GET /geneos/api/v1/tokens ?status=&q=&limit=50&offset=0
ParamDefaultDescription
status(all)Filter: created · kit_issued · sample_received · processing · complete
q(none)Search alias, token fragment (first 6 chars), or lab accession
limit50Max 200
offset0Pagination offset
{
  "ok": true,
  "total": 142,
  "limit": 50,
  "offset": 0,
  "tokens": [
    {
      "token": "a1b2c3d4e5f6...",
      "alias": "Client #001",
      "status": "complete",
      "fulgent_accession": "FUL-2026-001",
      "created_at": "2026-07-14T12:00:00+00:00",
      "health_data_loaded": true,
      "order_id": "WHL-ABC123"
    }
  ]
}

Create Token

POST /geneos/api/v1/tokens Create one token
{ "alias": "Client #001" }
{
  "ok": true,
  "token": "a1b2c3d4...",
  "alias": "Client #001",
  "status": "created",
  "created_at": "2026-07-14T12:00:00+00:00",
  "health_data_loaded": false
}

Bulk Create Tokens

POST /geneos/api/v1/tokens/bulk Create up to 100 tokens at once
{
  "count": 25,
  "alias_prefix": "Client #"   // optional → Client #1, Client #2, ...
}
{
  "ok": true,
  "created": 25,
  "tokens": [...]
}

Get Token

GET /geneos/api/v1/tokens/{token} Full token record

createdkit_issuedsample_receivedprocessingcomplete

{
  "ok": true,
  "token": "a1b2c3d4e5f6...",
  "alias": "Client #001",
  "owner_email": "[email protected]",
  "status": "complete",
  "fulgent_accession": "FUL-2026-001",
  "health_data_loaded": true,
  "created_at": "2026-07-01T09:00:00+00:00",
  "sample_received_at": "2026-07-05T14:22:00+00:00",
  "complete_at": "2026-07-14T10:00:00+00:00",
  "notes": ""
}

Update Token

PATCH /geneos/api/v1/tokens/{token} Update alias or notes
{
  "alias": "Jane Doe — Rm 12",
  "notes": "Expedited processing requested"
}
{ "ok": true, "token": "a1b2...", "alias": "Jane Doe — Rm 12", ... }

Link Lab Accession

POST /geneos/api/v1/tokens/{token}/link-accession Advance status to sample_received
{ "fulgent_accession": "FUL-2026-001" }
{
  "ok": true,
  "token": "a1b2c3d4...",
  "status": "sample_received",
  "fulgent_accession": "FUL-2026-001"
}

Also fires registered sample_received webhooks.

Get Report

GET /geneos/api/v1/tokens/{token}/report Full genomic report JSON
{
  "ok": true,
  "report": { /* full report JSON — structure varies */ }
}
{ "ok": false, "error": "No report available yet" }

Get Health Profile

GET /geneos/api/v1/tokens/{token}/profile Structured health profile JSON
{
  "ok": true,
  "profile": { /* biomarkers, conditions, medications, ... */ }
}

Get QR Code

GET /geneos/api/v1/tokens/{token}/qr.png QR code PNG — public endpoint

Returns a image/png QR code encoding the patient wizard URL for this token. The token itself is the credential, so this endpoint can be used without an API key (for printing kits).

https://geneos.app/geneos/health-wizard-v2.html?token={token}

Register Webhook

POST /geneos/api/v1/webhooks Subscribe to vault events
{
  "url": "https://your-ehr.example.com/webhook/geneos",
  "events": ["results_ready", "sample_received", "kit_issued"]
}
EventFired when
sample_receivedLab accession linked to token
results_readyReport processed and loaded
kit_issuedToken moves to kit_issued status
{ "ok": true, "id": "abc12345", "url": "https://...", "events": [...] }

List Webhooks

GET /geneos/api/v1/webhooks List registered webhooks
{
  "ok": true,
  "webhooks": [
    { "id": "abc12345", "url": "https://...", "events": [...], "created_at": "..." }
  ]
}

Delete Webhook

DELETE /geneos/api/v1/webhooks/{id} Remove a webhook by id
{ "ok": true, "deleted": "abc12345" }

Webhook Payload Schema

All webhook payloads share the same envelope. Delivery is attempted twice with an 8-second timeout per attempt. Failed deliveries are logged server-side.

{
  "event": "sample_received",
  "timestamp": "2026-07-14T15:00:00+00:00",
  "token": "a1b2c3d4...",
  "alias": "Client #001",
  "status": "sample_received",
  "fulgent_accession": "FUL-2026-001"  // present for sample_received event
}

Your endpoint should respond with HTTP 2xx within 8 seconds. If the first attempt fails, one retry is made immediately. Subsequent failures are not retried.

Code Examples

List tokens with pagination:

BASE=https://geneos.app/api/ideas
KEY=gxk_your_key_here

# List tokens
curl -H "X-GeneOS-Key: $KEY" \
  "$BASE/geneos/api/v1/tokens?limit=50&offset=0"

# Create a token
curl -X POST -H "X-GeneOS-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"alias":"Client #001"}' \
  "$BASE/geneos/api/v1/tokens"

# Bulk create 25 tokens
curl -X POST -H "X-GeneOS-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"count":25,"alias_prefix":"Client #"}' \
  "$BASE/geneos/api/v1/tokens/bulk"

# Link a lab accession
curl -X POST -H "X-GeneOS-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"fulgent_accession":"FUL-2026-001"}' \
  "$BASE/geneos/api/v1/tokens/TOKEN_HERE/link-accession"

# Poll for report
curl -H "X-GeneOS-Key: $KEY" \
  "$BASE/geneos/api/v1/tokens/TOKEN_HERE/report"

# Register webhook
curl -X POST -H "X-GeneOS-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-ehr.com/webhook","events":["results_ready","sample_received"]}' \
  "$BASE/geneos/api/v1/webhooks"

Using the requests library:

import requests

BASE = "https://geneos.app/api/ideas"
API_KEY = "gxk_your_key_here"
HEADERS = {"X-GeneOS-Key": API_KEY, "Content-Type": "application/json"}

# List all complete tokens
resp = requests.get(
    f"{BASE}/geneos/api/v1/tokens",
    headers=HEADERS,
    params={"status": "complete", "limit": 100},
)
data = resp.json()
print(f"Total: {data['total']}, returned: {len(data['tokens'])}")

# Create 10 tokens with prefix
resp = requests.post(
    f"{BASE}/geneos/api/v1/tokens/bulk",
    headers=HEADERS,
    json={"count": 10, "alias_prefix": "Study-2026-"},
)
tokens = resp.json()["tokens"]
print(f"Created {len(tokens)} tokens")

# Poll for results (EHR integration pattern)
def get_report(token_id):
    r = requests.get(
        f"{BASE}/geneos/api/v1/tokens/{token_id}/report",
        headers=HEADERS,
    )
    if r.status_code == 200:
        return r.json()["report"]
    return None  # not ready yet

Using fetch (Node.js or browser):

const BASE = 'https://geneos.app/api/ideas';
const API_KEY = 'gxk_your_key_here';
const headers = {
  'X-GeneOS-Key': API_KEY,
  'Content-Type': 'application/json',
};

// List tokens
async function listTokens(status = '', query = '') {
  const params = new URLSearchParams({ limit: '100' });
  if (status) params.set('status', status);
  if (query) params.set('q', query);
  const res = await fetch(`${BASE}/geneos/api/v1/tokens?${params}`, { headers });
  return res.json();
}

// Create token
async function createToken(alias) {
  const res = await fetch(`${BASE}/geneos/api/v1/tokens`, {
    method: 'POST', headers,
    body: JSON.stringify({ alias }),
  });
  return res.json();
}

// Bulk create
async function bulkCreate(count, prefix = '') {
  const res = await fetch(`${BASE}/geneos/api/v1/tokens/bulk`, {
    method: 'POST', headers,
    body: JSON.stringify({ count, alias_prefix: prefix }),
  });
  return res.json();
}

// Register webhook
async function registerWebhook(url, events) {
  const res = await fetch(`${BASE}/geneos/api/v1/webhooks`, {
    method: 'POST', headers,
    body: JSON.stringify({ url, events }),
  });
  return res.json();
}