ax-check.com
by Gauge
G
GenHealth.ai
genhealth.ai
ax-check.com
Checked 22 October 2026
B
81/100
Agents need your login
Quickstart works well, but pricing is sales-quote only
Quickstart, API reference, and MCP docs are all directly usable. Pricing page 404s; homepage only says "contact us," so agents can't get a number.
2 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no genhealth.ai account. Recorded 22 October 2026 on Pi.
3 recorded · 2m 3s
2m 3s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
The user is asking about "GenHealth.ai". This is probably a fabricated/non-existent product. I should verify. There might be files in the repository. Let me look around, and possibly search the documentation. I shouldn't fabricate pricing information. Let me check the repository.
ls -la /sandbox/repo && find /sandbox/repo -iname "*genhealth*" -o -iname "*gen-health*" | head -50
total 16
total 16 drwxr-xr-x 3 root root 4096 Sep 18 08:00 . drwxr-xr-x 7 root root 4096 Oct 22 17:19 .. drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git -rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore
Recorded tool call
{
"type": "tool_call",
"seq": 3,
"ts": "2026-10-22T17:19:50.829Z",
"name": "bash",
"turn": 1,
"input": {
"command": "ls -la /sandbox/repo && find /sandbox/repo -iname \"*genhealth*\" -o -iname \"*gen-health*\" | head -50"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-8c7d7bd5751ee7b6",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 5,
"ts": "2026-10-22T17:19:50.829Z",
"turn": 1,
"output": {
"content": [
{
"text": "total 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Oct 22 17:19 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-8c7d7bd5751ee7b6",
"is_error": false,
"tool_kind": "shell"
}cd /sandbox/repo && grep -ril "genhealth" . 2>/dev/null | head -20
(no output)
(no output)
Recorded tool call
{
"type": "tool_call",
"seq": 4,
"ts": "2026-10-22T17:19:50.829Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && grep -ril \"genhealth\" . 2>/dev/null | head -20"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9d581fd086bedac1",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 6,
"ts": "2026-10-22T17:19:50.829Z",
"turn": 1,
"output": {
"content": [
{
"text": "(no output)",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9d581fd086bedac1",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
The repository is empty except for .gitignore. There are no references to GenHealth.ai. Should I check the git history and try to see if there's internet access?
cd /sandbox/repo && cat .gitignore && git log --oneline -20 && git branch -a
# Keep generated and vendored files out of source diffs.
# Keep generated and vendored files out of source diffs. # Logs / OS cruft *.log .DS_Store # JavaScript / TypeScript node_modules/ .next/ dist/ build/ coverage/ # Python .venv/ venv/ __pycache__/ *.py[cod] .pytest_cache/ *.egg-info/ # Rust target/ # Go / PHP / Ruby vendored deps vendor/ .bundle/ # Java / Kotlin / Scala .gradle/ # .NET bin/ obj/ # Elixir _build/ deps/ # Dart / Flutter .dart_tool/ 9ebf5fb Initial workspace * main
Recorded tool call
{
"type": "tool_call",
"seq": 9,
"ts": "2026-10-22T17:19:52.583Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && cat .gitignore && git log --oneline -20 && git branch -a"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9b679f6e36e053c9",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 11,
"ts": "2026-10-22T17:19:52.583Z",
"turn": 1,
"output": {
"content": [
{
"text": "# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/\n.next/\ndist/\nbuild/\ncoverage/\n\n# Python\n.venv/\nvenv/\n__pycache__/\n*.py[cod]\n.pytest_cache/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Go / PHP / Ruby vendored deps\nvendor/\n.bundle/\n\n# Java / Kotlin / Scala\n.gradle/\n\n# .NET\nbin/\nobj/\n\n# Elixir\n_build/\ndeps/\n\n# Dart / Flutter\n.dart_tool/\n9ebf5fb Initial workspace\n* main\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9b679f6e36e053c9",
"is_error": false,
"tool_kind": "shell"
}timeout 15 curl -sS -o /dev/null -w "%{http_code}\n" https://genhealth.ai 2>&1; echo "---"; timeout 15 curl -sS https://pypi.org/simple/ -o /dev/null -w "%{http_code}\n" 2>&1200
200 --- 200
Recorded tool call
{
"type": "tool_call",
"seq": 10,
"ts": "2026-10-22T17:19:52.583Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 15 curl -sS -o /dev/null -w \"%{http_code}\\n\" https://genhealth.ai 2>&1; echo \"---\"; timeout 15 curl -sS https://pypi.org/simple/ -o /dev/null -w \"%{http_code}\\n\" 2>&1"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9df337842bae4ff0",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 12,
"ts": "2026-10-22T17:19:56.351Z",
"turn": 1,
"output": {
"content": [
{
"text": "200\n---\n200\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9df337842bae4ff0",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Interesting — genhealth.ai returned 200. Let me check the contents. It might just be a parking page. Let me fetch the content and look for developer-oriented docs or SDKs.
timeout 20 curl -sSL https://genhealth.ai | head -c 3000; echo; echo "=== headers ==="; timeout 20 curl -sSI https://genhealth.ai
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="icon" href=
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="icon" href="/favicon.ico" sizes="any" class="jsx-2561013401" data-next-head=""/><link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16" class="jsx-2561013401" data-next-head=""/><link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32" class="jsx-2561013401" data-next-head=""/><link rel="icon" type="image/png" href="/favicon-48x48.png" sizes="48x48" class="jsx-2561013401" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon.png" class="jsx-2561013401" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon-152x152.png" sizes="152x152" class="jsx-2561013401" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon-167x167.png" sizes="167x167" class="jsx-2561013401" data-next-head=""/><link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" sizes="180x180" class="jsx-2561013401" data-next-head=""/><link rel="manifest" href="/site.webmanifest" class="jsx-2561013401" data-next-head=""/><meta name="theme-color" content="#a8fc8f" class="jsx-2561013401" data-next-head=""/><meta name="apple-mobile-web-app-title" content="GenHealth.ai" class="jsx-2561013401" data-next-head=""/><script type="application/ld+json" class="jsx-2561013401" data-next-head="">{"@context":"https://schema.org","@type":"Organization","name":"GenHealth.ai","alternateName":"GenHealth","url":"https://genhealth.ai","logo":"https://genhealth.ai/logo_with_name.svg","description":"AI-first healthcare automation. GenHealth automates prior authorization, DME/HME intake, eligibility, denials, and appeals end-to-end with AI agents that operate over web, fax, and phone.","foundingDate":"2023","sameAs":["https://www.linkedin.com/company/genhealth-ai","https://x.com/genhealthai","https://github.com/genhealth","https://www.crunchbase.com/organization/genhealth-ai"],"contactPoint":[{"@type":"ContactPoint","contactType":"Sales","url":"https://genhealth.ai/contact","availableLanguage":["en"]}]}</script><link rel="preconnect" href="https://fonts.googleapis.com" class="jsx-2561013401" data-next-head=""/><link rel="preconnect" href="https://fonts.gstatic.com" class="jsx-2561013401" data-next-head=""/><link href="https://fonts.googleapis.com/css2?family=Lexend:wght@100;300;400;500;700;900&display=swap" rel="stylesheet" class="jsx-2561013401" data-next-head=""/><link href="https://fonts.googleapis.com/css2?family=Titillium+Web:wght@100;300;400;500;700;900&display=swap" rel="stylesheet" class="jsx-2561013401" data-next-head=""/><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" class="jsx-2561013401" data-next-head=""/><script async="" src="/js/highlight.min.js" class="jsx-2561013401" data-next-head=""></script><title data-next-head="">Revenue Cycle Management and Healthcare Admin for the AI Age</curl: (23) Failure writing output to destination
=== headers ===
HTTP/2 200
age: 0
cache-control: private, no-store, max-age=0
content-security-policy: frame-ancestors 'none'
content-type: text/html; charset=utf-8
date: Thu, 22 Oct 2026 17:19:58 GMT
etag: "3rrnmucmxw247s"
referrer-policy: strict-origin-when-cross-origin
server: Vercel
strict-transport-security: max-age=2147483647; includeSubdomains; preload
x-content-type-options: nosniff
x-frame-options: DENY
x-matched-path: /
x-vercel-cache: MISS
x-vercel-id: iad1::iad1::lbhs4-1792689598382-deb9b3e27a8e
content-length: 98819
Recorded tool call
{
"type": "tool_call",
"seq": 15,
"ts": "2026-10-22T17:19:57.908Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 20 curl -sSL https://genhealth.ai | head -c 3000; echo; echo \"=== headers ===\"; timeout 20 curl -sSI https://genhealth.ai"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-b8bbd3603699b0d5",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 17,
"ts": "2026-10-22T17:19:58.905Z",
"turn": 1,
"output": {
"content": [
{
"text": "<!DOCTYPE html><html><head><meta charSet=\"utf-8\" data-next-head=\"\"/><meta name=\"viewport\" content=\"width=device-width\" data-next-head=\"\"/><link rel=\"icon\" href=\"/favicon.ico\" sizes=\"any\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"icon\" type=\"image/png\" href=\"/favicon-16x16.png\" sizes=\"16x16\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"icon\" type=\"image/png\" href=\"/favicon-32x32.png\" sizes=\"32x32\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"icon\" type=\"image/png\" href=\"/favicon-48x48.png\" sizes=\"48x48\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"apple-touch-icon\" href=\"/apple-touch-icon.png\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"apple-touch-icon\" href=\"/apple-touch-icon-152x152.png\" sizes=\"152x152\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"apple-touch-icon\" href=\"/apple-touch-icon-167x167.png\" sizes=\"167x167\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"apple-touch-icon\" href=\"/apple-touch-icon-180x180.png\" sizes=\"180x180\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"manifest\" href=\"/site.webmanifest\" class=\"jsx-2561013401\" data-next-head=\"\"/><meta name=\"theme-color\" content=\"#a8fc8f\" class=\"jsx-2561013401\" data-next-head=\"\"/><meta name=\"apple-mobile-web-app-title\" content=\"GenHealth.ai\" class=\"jsx-2561013401\" data-next-head=\"\"/><script type=\"application/ld+json\" class=\"jsx-2561013401\" data-next-head=\"\">{\"@context\":\"https://schema.org\",\"@type\":\"Organization\",\"name\":\"GenHealth.ai\",\"alternateName\":\"GenHealth\",\"url\":\"https://genhealth.ai\",\"logo\":\"https://genhealth.ai/logo_with_name.svg\",\"description\":\"AI-first healthcare automation. GenHealth automates prior authorization, DME/HME intake, eligibility, denials, and appeals end-to-end with AI agents that operate over web, fax, and phone.\",\"foundingDate\":\"2023\",\"sameAs\":[\"https://www.linkedin.com/company/genhealth-ai\",\"https://x.com/genhealthai\",\"https://github.com/genhealth\",\"https://www.crunchbase.com/organization/genhealth-ai\"],\"contactPoint\":[{\"@type\":\"ContactPoint\",\"contactType\":\"Sales\",\"url\":\"https://genhealth.ai/contact\",\"availableLanguage\":[\"en\"]}]}</script><link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" class=\"jsx-2561013401\" data-next-head=\"\"/><link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" class=\"jsx-2561013401\" data-next-head=\"\"/><link href=\"https://fonts.googleapis.com/css2?family=Lexend:wght@100;300;400;500;700;900&display=swap\" rel=\"stylesheet\" class=\"jsx-2561013401\" data-next-head=\"\"/><link href=\"https://fonts.googleapis.com/css2?family=Titillium+Web:wght@100;300;400;500;700;900&display=swap\" rel=\"stylesheet\" class=\"jsx-2561013401\" data-next-head=\"\"/><link href=\"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\" class=\"jsx-2561013401\" data-next-head=\"\"/><script async=\"\" src=\"/js/highlight.min.js\" class=\"jsx-2561013401\" data-next-head=\"\"></script><title data-next-head=\"\">Revenue Cycle Management and Healthcare Admin for the AI Age</curl: (23) Failure writing output to destination\n\n=== headers ===\nHTTP/2 200 \r\nage: 0\r\ncache-control: private, no-store, max-age=0\r\ncontent-security-policy: frame-ancestors 'none'\r\ncontent-type: text/html; charset=utf-8\r\ndate: Thu, 22 Oct 2026 17:19:58 GMT\r\netag: \"3rrnmucmxw247s\"\r\nreferrer-policy: strict-origin-when-cross-origin\r\nserver: Vercel\r\nstrict-transport-security: max-age=2147483647; includeSubdomains; preload\r\nx-content-type-options: nosniff\r\nx-frame-options: DENY\r\nx-matched-path: /\r\nx-vercel-cache: MISS\r\nx-vercel-id: iad1::iad1::lbhs4-1792689598382-deb9b3e27a8e\r\ncontent-length: 98819\r\n\r\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-b8bbd3603699b0d5",
"is_error": false,
"tool_kind": "shell"
}for p in https://genhealth.ai/pricing https://genhealth.ai/docs https://docs.genhealth.ai https://api.genhealth.ai; do echo "--- $p"; timeout 15 curl -sS -o /dev/null -w "%{http_code} %{url_effective}\n" -L "$p"; doneFailed--- https://genhealth.ai/pricing
--- https://genhealth.ai/pricing 404 https://genhealth.ai/pricing --- https://genhealth.ai/docs 200 https://genhealth.ai/docs --- https://docs.genhealth.ai 200 https://docs.genhealth.ai/docs/integration-with-hl7-davinci-fhir-apis --- https://api.genhealth.ai curl: (6) Could not resolve host: api.genhealth.ai 000 https://api.genhealth.ai/ Command exited with code 6
Recorded tool call
{
"type": "tool_call",
"seq": 16,
"ts": "2026-10-22T17:19:57.908Z",
"name": "bash",
"turn": 1,
"input": {
"command": "for p in https://genhealth.ai/pricing https://genhealth.ai/docs https://docs.genhealth.ai https://api.genhealth.ai; do echo \"--- $p\"; timeout 15 curl -sS -o /dev/null -w \"%{http_code} %{url_effective}\\n\" -L \"$p\"; done"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-833c4154805a3b83",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 18,
"ts": "2026-10-22T17:20:00.727Z",
"turn": 1,
"output": {
"content": [
{
"text": "--- https://genhealth.ai/pricing\n404 https://genhealth.ai/pricing\n--- https://genhealth.ai/docs\n200 https://genhealth.ai/docs\n--- https://docs.genhealth.ai\n200 https://docs.genhealth.ai/docs/integration-with-hl7-davinci-fhir-apis\n--- https://api.genhealth.ai\ncurl: (6) Could not resolve host: api.genhealth.ai\n000 https://api.genhealth.ai/\n\n\nCommand exited with code 6",
"type": "text"
}
],
"details": {}
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-833c4154805a3b83",
"is_error": true,
"tool_kind": "shell"
}›Thinking…
GenHealth.ai does exist. Let's explore /docs and docs.genhealth.ai. Also, let's check for the existence of an SDK (npm/pypi), a public API, and whether pricing information is publicly available.
Let's grab the content of /docs as text.
cd /tmp && timeout 25 curl -sSL https://genhealth.ai/docs -o gh_docs.html; python3 - <<'EOF'
import re,html
s=open('gh_docs.html',encoding='utf-8',errors='ignore').read()
s=re.sub(r'<script.*?</script>','',s,flags=re.S)
s=re.sub(r'<style.*?</style>','',s,flags=re.S)
t=re.sub(r'<[^>]+>','\n',s)
t=html.unescape(t)
t=re.sub(r'\n\s*\n+','\n',t)
print(t[:4000])
print("=== LINKS ===")
for m in sorted(set(re.findall(r'href="([^"]+)"',open('gh_docs.html',encoding='utf-8',errors='ignore').read()))):
if not m.startswith(('#','/js','/css','/_next','/favicon','https://fonts')): print(m)
EOFBuild healthcare workflows with the GenHealth API | GenHealth Developer Docs
Build healthcare workflows with the GenHealth API | GenHealth Developer Docs GenHealth.ai Book Demo Docs Guides API Browse documentation Search or ask AI ⌘K Dev Portal Search or ask AI ⌘K Skip to documentation Documentation Get started Overview Quickstart Authentication Release notes Build with an AI agent Provider workflows across specialties Build and run your first workflow Use integration action contracts Run operations and recovery Provider patient intake recipe Prior authorization recipe Recurring care and renewals recipe API reference Introduction Conventions Pagination Integrations Responses and errors Endpoints Workflow Developer API Cases Policies Codes Publishers GenHealth developer docs Build healthcare workflows with the GenHealth API Build provider workflow automations across specialties through REST or MCP, with integration actions, medical policies, cases, and codes. Copy page Copy page link View as Markdown Start building Use the guides to understand authentication and request conventions, then move into the generated API reference when you are ready to work with a specific resource. Build and run a workflow Start with a runnable synthetic example, then connect healthcare actions using REST or MCP. Explore Quickstart Make your first authenticated GenHealth API request. Explore Authentication Learn how API keys, bearer tokens, and scopes work. Explore API reference Browse endpoints generated from the curated OpenAPI snapshot. Explore Workflow API Build workflows, discover available functions, and manage versions and runs. Explore Core resources The GenHealth app organizes prior-authorization work around cases, medical-necessity policies, medical codes, and policy publishers. Each request is scoped to the organization represented by the bearer token. Cases Retrieve and inspect prior-authorization cases for your organization. Explore Policies Find active policies and the criteria used by GenHealth workflows. Explore Codes and publishers Discover supported medical codes and policy sources. Explore How requests flow 1 Authenticate the organization Send a GenHealth-issued credential in the bearer authorization header. The credential determines which organization and operations are available. 2 Call a resource endpoint Use the cases, policies, codes, or publishers endpoints documented in the generated reference. 3 Handle the JSON response Read the response status and pagination metadata before continuing a workflow or requesting another page. Next Make your first GenHealth API request On this page Copy page Copy page link View as Markdown Start building Core resources How requests flow Chat with Genie === LINKS === / /account/api-keys /apple-touch-icon-152x152.png /apple-touch-icon-167x167.png /apple-touch-icon-180x180.png /apple-touch-icon.png /contact /docs /docs.md /docs/api-reference /docs/api-reference#conventions /docs/api-reference#pagination /docs/api-reference#responses /docs/api-reference/v1/cases/list-cases-v2 /docs/api-reference/v1/codes/list-codes /docs/api-reference/v1/policies/list-policies /docs/authentication /docs/quickstart /docs/releases /docs/workflows /docs/workflows/action-contracts /docs/workflows/agent-quickstart /docs/workflows/integrations /docs/workflows/operations /docs/workflows/provider-workflows /docs/workflows/recipes/patient-intake /docs/workflows/recipes/prior-authorization /docs/workflows/recipes/recurring-care /site.webmanifest https://genhealth.ai/docs https://genhealth.ai/docs.md
Recorded tool call
{
"type": "tool_call",
"seq": 21,
"ts": "2026-10-22T17:20:03.202Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -sSL https://genhealth.ai/docs -o gh_docs.html; python3 - <<'EOF'\nimport re,html\ns=open('gh_docs.html',encoding='utf-8',errors='ignore').read()\ns=re.sub(r'<script.*?</script>','',s,flags=re.S)\ns=re.sub(r'<style.*?</style>','',s,flags=re.S)\nt=re.sub(r'<[^>]+>','\\n',s)\nt=html.unescape(t)\nt=re.sub(r'\\n\\s*\\n+','\\n',t)\nprint(t[:4000])\nprint(\"=== LINKS ===\")\nfor m in sorted(set(re.findall(r'href=\"([^\"]+)\"',open('gh_docs.html',encoding='utf-8',errors='ignore').read()))):\n if not m.startswith(('#','/js','/css','/_next','/favicon','https://fonts')): print(m)\nEOF"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-997487a0bb210342",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 23,
"ts": "2026-10-22T17:20:04.123Z",
"turn": 1,
"output": {
"content": [
{
"text": "\nBuild healthcare workflows with the GenHealth API | GenHealth Developer Docs\nGenHealth.ai\nBook Demo\nDocs\nGuides\nAPI\nBrowse documentation\nSearch or ask AI\n⌘K\nDev Portal\nSearch or ask AI\n⌘K\nSkip to documentation\nDocumentation\nGet started\nOverview\nQuickstart\nAuthentication\nRelease notes\nBuild with an AI agent\nProvider workflows across specialties\nBuild and run your first workflow\nUse integration action contracts\nRun operations and recovery\nProvider patient intake recipe\nPrior authorization recipe\nRecurring care and renewals recipe\nAPI reference\nIntroduction\nConventions\nPagination\nIntegrations\nResponses and errors\nEndpoints\nWorkflow Developer API\nCases\nPolicies\nCodes\nPublishers\nGenHealth developer docs\nBuild healthcare workflows with the GenHealth API\nBuild provider workflow automations across specialties through REST or MCP, with integration actions, medical policies, cases, and codes.\nCopy page\nCopy page link\nView as Markdown\nStart building\nUse the guides to understand authentication and request conventions, then move into the generated API reference when you are ready to work with a specific resource.\nBuild and run a workflow\nStart with a runnable synthetic example, then connect healthcare actions using REST or MCP.\nExplore \nQuickstart\nMake your first authenticated GenHealth API request.\nExplore \nAuthentication\nLearn how API keys, bearer tokens, and scopes work.\nExplore \nAPI reference\nBrowse endpoints generated from the curated OpenAPI snapshot.\nExplore \nWorkflow API\nBuild workflows, discover available functions, and manage versions and runs.\nExplore \nCore resources\nThe GenHealth app organizes prior-authorization work around cases, medical-necessity policies, medical codes, and policy publishers. Each request is scoped to the organization represented by the bearer token.\nCases\nRetrieve and inspect prior-authorization cases for your organization.\nExplore \nPolicies\nFind active policies and the criteria used by GenHealth workflows.\nExplore \nCodes and publishers\nDiscover supported medical codes and policy sources.\nExplore \nHow requests flow\n1\nAuthenticate the organization\nSend a GenHealth-issued credential in the bearer authorization header. The credential determines which organization and operations are available.\n2\nCall a resource endpoint\nUse the cases, policies, codes, or publishers endpoints documented in the generated reference.\n3\nHandle the JSON response\nRead the response status and pagination metadata before continuing a workflow or requesting another page.\nNext\nMake your first GenHealth API request\nOn this page\nCopy page\nCopy page link\nView as Markdown\nStart building\nCore resources\nHow requests flow\nChat with Genie\n\n=== LINKS ===\n/\n/account/api-keys\n/apple-touch-icon-152x152.png\n/apple-touch-icon-167x167.png\n/apple-touch-icon-180x180.png\n/apple-touch-icon.png\n/contact\n/docs\n/docs.md\n/docs/api-reference\n/docs/api-reference#conventions\n/docs/api-reference#pagination\n/docs/api-reference#responses\n/docs/api-reference/v1/cases/list-cases-v2\n/docs/api-reference/v1/codes/list-codes\n/docs/api-reference/v1/policies/list-policies\n/docs/authentication\n/docs/quickstart\n/docs/releases\n/docs/workflows\n/docs/workflows/action-contracts\n/docs/workflows/agent-quickstart\n/docs/workflows/integrations\n/docs/workflows/operations\n/docs/workflows/provider-workflows\n/docs/workflows/recipes/patient-intake\n/docs/workflows/recipes/prior-authorization\n/docs/workflows/recipes/recurring-care\n/site.webmanifest\nhttps://genhealth.ai/docs\nhttps://genhealth.ai/docs.md\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-997487a0bb210342",
"is_error": false,
"tool_kind": "shell"
}timeout 20 curl -sS "https://registry.npmjs.org/-/v1/search?text=genhealth&size=10" | python3 -c "import sys,json;d=json.load(sys.stdin);print([o['package']['name']+' :: '+o['package'].get('description','')[:100] for o in d['objects']])"; echo "--- pypi"; for n in genhealth genhealth-ai genhealthai; do echo -n "$n: "; timeout 15 curl -sS -o /dev/null -w "%{http_code}\n" https://pypi.org/pypi/$n/json; done['@adobe/gen-health-table :: Generate a Markdown table with health badges for repos.', 'heart-attack-prediction :: Heart Attack Prediction API Client']
['@adobe/gen-health-table :: Generate a Markdown table with health badges for repos.', 'heart-attack-prediction :: Heart Attack Prediction API Client'] --- pypi genhealth: 404 genhealth-ai: 404 genhealthai: 404
Recorded tool call
{
"type": "tool_call",
"seq": 22,
"ts": "2026-10-22T17:20:03.202Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 20 curl -sS \"https://registry.npmjs.org/-/v1/search?text=genhealth&size=10\" | python3 -c \"import sys,json;d=json.load(sys.stdin);print([o['package']['name']+' :: '+o['package'].get('description','')[:100] for o in d['objects']])\"; echo \"--- pypi\"; for n in genhealth genhealth-ai genhealthai; do echo -n \"$n: \"; timeout 15 curl -sS -o /dev/null -w \"%{http_code}\\n\" https://pypi.org/pypi/$n/json; done"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9180c7eb61563a48",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 24,
"ts": "2026-10-22T17:20:05.341Z",
"turn": 1,
"output": {
"content": [
{
"text": "['@adobe/gen-health-table :: Generate a Markdown table with health badges for repos.', 'heart-attack-prediction :: Heart Attack Prediction API Client']\n--- pypi\ngenhealth: 404\ngenhealth-ai: 404\ngenhealthai: 404\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9180c7eb61563a48",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
There's an actual developer documentation site. /docs.md (view in markdown format), /docs/quickstart.md, /docs/authentication.md. Let's read them. Also, let's check the pricing info — probably not published anywhere (sales/demo). Let's check the pricing-related content on the homepage.
Let's fetch the markdown versions.
cd /tmp && for p in quickstart authentication workflows/agent-quickstart; do echo "########## $p"; timeout 20 curl -sSL "https://genhealth.ai/docs/$p.md" | head -200; done
########## quickstart
########## quickstart
# Make your first GenHealth API request
> Authenticate with a GenHealth API key and retrieve the first page of cases for your organization.
Source: [https://genhealth.ai/docs/quickstart](https://genhealth.ai/docs/quickstart)
> **Before you begin**
>
> You need a GenHealth-issued API key with read access. [Sign up for GenHealth](https://umpa.genhealth.ai/api/auth/login?screen_hint=signup) to request access. Keep the key on the server and never commit it to source control.
### 1. Store your API key
Set the key as an environment variable in your development environment.
```bash
export GENHEALTH_API_KEY="<YOUR_API_KEY>"
```
### 2. List cases
Send the API key as a bearer token and request the first page of cases.
```bash
curl 'https://api.umpa.genhealth.ai/v2/cases?page=1&limit=10' \
--header "Authorization: Bearer $GENHEALTH_API_KEY" \
--header 'Accept: application/json'
```
### 3. Follow the pagination object
Use the returned pagination metadata to request subsequent pages. Case results are always limited to the authenticated organization.
## Understand the response
Successful list requests return a data array and pagination metadata. Store resource IDs from the response instead of depending on display text, which may change over time.
```json
{
"data": [{ "id": "case_123", "status": "open" }],
"pagination": { "page": 1, "limit": 10, "has_more": false }
}
```
## Handle errors
| Status | Meaning | What to do |
| --- | --- | --- |
| 401 | Credential was not accepted | Check the bearer token and its expiration |
| 404 | Resource was not found | Confirm the ID and organization access |
| 422 | Request parameters are invalid | Use the error details to correct the request |
## Next steps
- [Retrieve one case](https://genhealth.ai/docs/api-reference/v1/cases/get-case.md): Read the full details for a known case ID.
- [Find policies](https://genhealth.ai/docs/api-reference/v1/policies/list-policies.md): Filter active policies by title or publisher.
########## authentication
# Authenticate API requests
> The GenHealth API accepts GenHealth API keys and supported JWTs through the HTTP bearer authorization scheme.
Source: [https://genhealth.ai/docs/authentication](https://genhealth.ai/docs/authentication)
## Choose a credential
Use the credential type provisioned for your integration. API keys are intended for server-to-server requests. Supported JWTs are validated for issuer, audience, expiration, and GenHealth access before a request is authorized.
| Credential | Best for | Storage |
| --- | --- | --- |
| GenHealth API key | Server-to-server integrations | Encrypted server-side secret storage |
| Supported JWT | Short-lived delegated access | Your existing secure token lifecycle |
## Bearer tokens
Include the credential in the Authorization header of every request. GenHealth resolves the organization and permitted operations from the token.
```http
Authorization: Bearer <YOUR_API_KEY>
```
## Permissions and organization access
The read endpoints in this preview require API read access. Every request is scoped to the organization resolved from the credential, so a valid resource ID from another organization is not sufficient to grant access.
## Token security
- Keep credentials on the server and outside browser bundles.
- Store secrets in an encrypted environment or secret manager, not in source control.
- Rotate a credential immediately if it may have been exposed.
- Use separate credentials for development and production environments.
> **Protect healthcare data**
>
> Do not paste production API keys, patient information, or live request bodies into documentation search or Genie chat.
## Troubleshoot authentication errors
| Symptom | Likely cause | Next check |
| --- | --- | --- |
| 401 Unauthorized | Missing, expired, or invalid credential | Authorization header format and credential status |
| 403 Forbidden | Credential lacks access to the operation | Assigned API permissions and organization |
| 404 Not Found | Resource is unavailable in the resolved organization | Resource ID and environment |
########## workflows/agent-quickstart
# Build and run your first workflow
> Discover capabilities, validate a synthetic graph, publish it, start an idempotent run, and inspect its outcome with REST or MCP.
Source: [https://genhealth.ai/docs/workflows/agent-quickstart](https://genhealth.ai/docs/workflows/agent-quickstart)
## Get access and choose a transport
Use an organization-bound GenHealth API key. The workflow developer boundary accepts API keys, not browser sessions or ordinary JWTs. Request workflow:read for discovery and preflight; add workflow:write, workflow:publish, and workflow:run to create and execute workflows. Your organization also needs the workflows plan feature. Keys and integration connections must be provisioned before an agent can operate independently.
| Transport | Production entry point | Contract |
| --- | --- | --- |
| REST | https://api.umpa.genhealth.ai/developer/v1 | Authorization: Bearer <GENHEALTH_API_KEY> |
| MCP | https://api.umpa.genhealth.ai/developer/mcp | Streamable HTTP with the same bearer header; tool discovery is authenticated |
| OpenAPI | https://api.umpa.genhealth.ai/developer/openapi.json | Live server contract; prefer it over a cached website snapshot |
| Swagger | https://api.umpa.genhealth.ai/developer/docs | Interactive REST reference |
## Read the deployed capabilities first
```bash
export GENHEALTH_API_BASE="https://api.umpa.genhealth.ai"
# Set GENHEALTH_API_KEY through your secret manager.
curl --fail-with-body "$GENHEALTH_API_BASE/developer/v1/capabilities/v2" \
-H "Authorization: Bearer $GENHEALTH_API_KEY"
```
For MCP, initialize the connection, list tools, then call get_workflow_capabilities_v2. Use its node types, expression syntax, routing ports, lifecycle, and deployment flags. Discover exact handlers with search_workflow_actions and load get_workflow_action before authoring. REST and MCP operate on the same organization-scoped workflows.
## Run a synthetic workflow before connecting a healthcare system
This graph routes a synthetic boolean to one of two annotation nodes. It creates no patient, order, claim, or authorization and needs no integration credentials. It tests authoring and execution, not clinical accuracy or payer connectivity. Comment nodes contain annotations only; trigger data comes from trigger.default.
```json
{
"kind": "genhealth.workflow_definition",
"schema_version": 1,
"workflow": {
"name": "Agent quickstart: synthetic routing",
"description": "Synthetic execution check; no healthcare system reads or writes.",
"nodes": [
{
"id": "received",
"type": "comment",
"name": "Synthetic request",
"config": {
"heading": "Start",
"body": "Inputs are supplied in trigger_data."
}
},
{
"id": "route",
"type": "if",
"name": "Ready?",
"config": {
"condition": "{{trigger.default.ready}}"
}
},
{
"id": "ready",
"type": "comment",
"name": "Ready outcome",
"config": {
"heading": "Ready",
"body": "The true branch ran."
}
},
{
"id": "review",
"type": "comment",
"name": "Review outcome",
"config": {
"heading": "Review",
"body": "The false branch ran; no external review task was created."
}
}
],
"edges": [
{
"source_node_id": "received",
"source_output": "default",
"target_node_id": "route",
"target_input": "default"
},
{
"source_node_id": "route",
"source_output": "true",
"target_node_id": "ready",
"target_input": "default"
},
{
"source_node_id": "route",
"source_output": "false",
"target_node_id": "review",
"target_input": "default"
}
]
}
}
```
- [Download the workflow JSON](https://genhealth.ai/docs/examples/agent-smoke-test.json): The canonical import envelope used below.
- [Download the runnable Python client](https://genhealth.ai/docs/examples/workflow_agent.py): Python 3 standard library; preserves workflow IDs and run idempotency across restarts.
```bash
curl --fail-with-body https://genhealth.ai/docs/examples/agent-smoke-test.json -o agent-smoke-test.json
curl --fail-with-body https://genhealth.ai/docs/examples/workflow_agent.py -o workflow_agent.py
# Preflight only. No workflow is created.
python3 workflow_agent.py validate agent-smoke-test.json
# Create, publish, and submit one run; retain this state file for recovery.
python3 workflow_agent.py execute agent-smoke-test.json --state agent-smoke-state.json
# Inspect without resubmitting. Repeat until this run is terminal.
python3 workflow_agent.py inspect --state agent-smoke-state.json
```
## What the client does
| Step | Request | Check before continuing |
| --- | --- | --- |
| Preflight | POST /developer/v1/workflows/validate with {"definition": <envelope>} | HTTP 200 can still mean viable=false. Inspect schema_errors, findings, and readiness. |
| Import | POST /developer/v1/workflows/import with the envelope itself | HTTP 201; workflow.id identifies the inactive workflow and immutable initial version. |
| Draft | POST /developer/v1/workflows/{id}/draft | Create an editable draft before publication or subsequent graph edits. |
| Publish | POST /developer/v1/workflows/{id}/publish with {} | Publishing audits the graph and activates an immutable version. Static success is not runtime proof. |
| Run | POST /developer/v1/workflows/{id}/runs | HTTP 202; save run_id. Acceptance is not completion. |
| Observe | GET /developer/v1/workflows/{id}/runs | Find the exact run_id. completed, failed, and cancelled are terminal. |
A successful smoke test should report completed, execute the true branch for ready=true, and skip the false branch. Inspect individual nodes with GET /developer/v1/workflows/{id}/runs/{run_id}/nodes/{node_id}. Public inspection exposes statuses and value-free shapes, not patient data or raw error text. A completed orchestration does not prove that a business result succeeded; healthcare recipes need explicit business-success branches.
## Connect a real workflow
- [Action contracts](https://genhealth.ai/docs/workflows/action-contracts.md): Resolve connections, inputs, outputs, and business failures.
- [Run operations and recovery](https://genhealth.ai/docs/workflows/operations.md): Handle interrupted writes, retries, versions, and cancellation.
- [Provider patient intake recipe](https://genhealth.ai/docs/workflows/recipes/patient-intake.md): Match an extracted patient before a controlled Brightree create.
Recorded tool call
{
"type": "tool_call",
"seq": 27,
"ts": "2026-10-22T17:20:07.730Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && for p in quickstart authentication workflows/agent-quickstart; do echo \"########## $p\"; timeout 20 curl -sSL \"https://genhealth.ai/docs/$p.md\" | head -200; done"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-82584b0209fd0252",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 30,
"ts": "2026-10-22T17:20:09.434Z",
"turn": 1,
"output": {
"content": [
{
"text": "########## quickstart\n# Make your first GenHealth API request\n\n> Authenticate with a GenHealth API key and retrieve the first page of cases for your organization.\n\nSource: [https://genhealth.ai/docs/quickstart](https://genhealth.ai/docs/quickstart)\n\n> **Before you begin**\n>\n> You need a GenHealth-issued API key with read access. [Sign up for GenHealth](https://umpa.genhealth.ai/api/auth/login?screen_hint=signup) to request access. Keep the key on the server and never commit it to source control.\n\n### 1. Store your API key\n\nSet the key as an environment variable in your development environment.\n\n```bash\nexport GENHEALTH_API_KEY=\"<YOUR_API_KEY>\"\n```\n\n### 2. List cases\n\nSend the API key as a bearer token and request the first page of cases.\n\n```bash\ncurl 'https://api.umpa.genhealth.ai/v2/cases?page=1&limit=10' \\\n --header \"Authorization: Bearer $GENHEALTH_API_KEY\" \\\n --header 'Accept: application/json'\n```\n\n### 3. Follow the pagination object\n\nUse the returned pagination metadata to request subsequent pages. Case results are always limited to the authenticated organization.\n\n## Understand the response\n\nSuccessful list requests return a data array and pagination metadata. Store resource IDs from the response instead of depending on display text, which may change over time.\n\n```json\n{\n \"data\": [{ \"id\": \"case_123\", \"status\": \"open\" }],\n \"pagination\": { \"page\": 1, \"limit\": 10, \"has_more\": false }\n}\n```\n\n## Handle errors\n\n| Status | Meaning | What to do |\n| --- | --- | --- |\n| 401 | Credential was not accepted | Check the bearer token and its expiration |\n| 404 | Resource was not found | Confirm the ID and organization access |\n| 422 | Request parameters are invalid | Use the error details to correct the request |\n\n## Next steps\n\n- [Retrieve one case](https://genhealth.ai/docs/api-reference/v1/cases/get-case.md): Read the full details for a known case ID.\n- [Find policies](https://genhealth.ai/docs/api-reference/v1/policies/list-policies.md): Filter active policies by title or publisher.\n########## authentication\n# Authenticate API requests\n\n> The GenHealth API accepts GenHealth API keys and supported JWTs through the HTTP bearer authorization scheme.\n\nSource: [https://genhealth.ai/docs/authentication](https://genhealth.ai/docs/authentication)\n\n## Choose a credential\n\nUse the credential type provisioned for your integration. API keys are intended for server-to-server requests. Supported JWTs are validated for issuer, audience, expiration, and GenHealth access before a request is authorized.\n\n| Credential | Best for | Storage |\n| --- | --- | --- |\n| GenHealth API key | Server-to-server integrations | Encrypted server-side secret storage |\n| Supported JWT | Short-lived delegated access | Your existing secure token lifecycle |\n\n## Bearer tokens\n\nInclude the credential in the Authorization header of every request. GenHealth resolves the organization and permitted operations from the token.\n\n```http\nAuthorization: Bearer <YOUR_API_KEY>\n```\n\n## Permissions and organization access\n\nThe read endpoints in this preview require API read access. Every request is scoped to the organization resolved from the credential, so a valid resource ID from another organization is not sufficient to grant access.\n\n## Token security\n\n- Keep credentials on the server and outside browser bundles.\n- Store secrets in an encrypted environment or secret manager, not in source control.\n- Rotate a credential immediately if it may have been exposed.\n- Use separate credentials for development and production environments.\n\n> **Protect healthcare data**\n>\n> Do not paste production API keys, patient information, or live request bodies into documentation search or Genie chat.\n\n## Troubleshoot authentication errors\n\n| Symptom | Likely cause | Next check |\n| --- | --- | --- |\n| 401 Unauthorized | Missing, expired, or invalid credential | Authorization header format and credential status |\n| 403 Forbidden | Credential lacks access to the operation | Assigned API permissions and organization |\n| 404 Not Found | Resource is unavailable in the resolved organization | Resource ID and environment |\n########## workflows/agent-quickstart\n# Build and run your first workflow\n\n> Discover capabilities, validate a synthetic graph, publish it, start an idempotent run, and inspect its outcome with REST or MCP.\n\nSource: [https://genhealth.ai/docs/workflows/agent-quickstart](https://genhealth.ai/docs/workflows/agent-quickstart)\n\n## Get access and choose a transport\n\nUse an organization-bound GenHealth API key. The workflow developer boundary accepts API keys, not browser sessions or ordinary JWTs. Request workflow:read for discovery and preflight; add workflow:write, workflow:publish, and workflow:run to create and execute workflows. Your organization also needs the workflows plan feature. Keys and integration connections must be provisioned before an agent can operate independently.\n\n| Transport | Production entry point | Contract |\n| --- | --- | --- |\n| REST | https://api.umpa.genhealth.ai/developer/v1 | Authorization: Bearer <GENHEALTH_API_KEY> |\n| MCP | https://api.umpa.genhealth.ai/developer/mcp | Streamable HTTP with the same bearer header; tool discovery is authenticated |\n| OpenAPI | https://api.umpa.genhealth.ai/developer/openapi.json | Live server contract; prefer it over a cached website snapshot |\n| Swagger | https://api.umpa.genhealth.ai/developer/docs | Interactive REST reference |\n\n## Read the deployed capabilities first\n\n```bash\nexport GENHEALTH_API_BASE=\"https://api.umpa.genhealth.ai\"\n# Set GENHEALTH_API_KEY through your secret manager.\ncurl --fail-with-body \"$GENHEALTH_API_BASE/developer/v1/capabilities/v2\" \\\n -H \"Authorization: Bearer $GENHEALTH_API_KEY\"\n```\n\nFor MCP, initialize the connection, list tools, then call get_workflow_capabilities_v2. Use its node types, expression syntax, routing ports, lifecycle, and deployment flags. Discover exact handlers with search_workflow_actions and load get_workflow_action before authoring. REST and MCP operate on the same organization-scoped workflows.\n\n## Run a synthetic workflow before connecting a healthcare system\n\nThis graph routes a synthetic boolean to one of two annotation nodes. It creates no patient, order, claim, or authorization and needs no integration credentials. It tests authoring and execution, not clinical accuracy or payer connectivity. Comment nodes contain annotations only; trigger data comes from trigger.default.\n\n```json\n{\n \"kind\": \"genhealth.workflow_definition\",\n \"schema_version\": 1,\n \"workflow\": {\n \"name\": \"Agent quickstart: synthetic routing\",\n \"description\": \"Synthetic execution check; no healthcare system reads or writes.\",\n \"nodes\": [\n {\n \"id\": \"received\",\n \"type\": \"comment\",\n \"name\": \"Synthetic request\",\n \"config\": {\n \"heading\": \"Start\",\n \"body\": \"Inputs are supplied in trigger_data.\"\n }\n },\n {\n \"id\": \"route\",\n \"type\": \"if\",\n \"name\": \"Ready?\",\n \"config\": {\n \"condition\": \"{{trigger.default.ready}}\"\n }\n },\n {\n \"id\": \"ready\",\n \"type\": \"comment\",\n \"name\": \"Ready outcome\",\n \"config\": {\n \"heading\": \"Ready\",\n \"body\": \"The true branch ran.\"\n }\n },\n {\n \"id\": \"review\",\n \"type\": \"comment\",\n \"name\": \"Review outcome\",\n \"config\": {\n \"heading\": \"Review\",\n \"body\": \"The false branch ran; no external review task was created.\"\n }\n }\n ],\n \"edges\": [\n {\n \"source_node_id\": \"received\",\n \"source_output\": \"default\",\n \"target_node_id\": \"route\",\n \"target_input\": \"default\"\n },\n {\n \"source_node_id\": \"route\",\n \"source_output\": \"true\",\n \"target_node_id\": \"ready\",\n \"target_input\": \"default\"\n },\n {\n \"source_node_id\": \"route\",\n \"source_output\": \"false\",\n \"target_node_id\": \"review\",\n \"target_input\": \"default\"\n }\n ]\n }\n}\n```\n\n- [Download the workflow JSON](https://genhealth.ai/docs/examples/agent-smoke-test.json): The canonical import envelope used below.\n- [Download the runnable Python client](https://genhealth.ai/docs/examples/workflow_agent.py): Python 3 standard library; preserves workflow IDs and run idempotency across restarts.\n\n```bash\ncurl --fail-with-body https://genhealth.ai/docs/examples/agent-smoke-test.json -o agent-smoke-test.json\ncurl --fail-with-body https://genhealth.ai/docs/examples/workflow_agent.py -o workflow_agent.py\n\n# Preflight only. No workflow is created.\npython3 workflow_agent.py validate agent-smoke-test.json\n\n# Create, publish, and submit one run; retain this state file for recovery.\npython3 workflow_agent.py execute agent-smoke-test.json --state agent-smoke-state.json\n\n# Inspect without resubmitting. Repeat until this run is terminal.\npython3 workflow_agent.py inspect --state agent-smoke-state.json\n```\n\n## What the client does\n\n| Step | Request | Check before continuing |\n| --- | --- | --- |\n| Preflight | POST /developer/v1/workflows/validate with {\"definition\": <envelope>} | HTTP 200 can still mean viable=false. Inspect schema_errors, findings, and readiness. |\n| Import | POST /developer/v1/workflows/import with the envelope itself | HTTP 201; workflow.id identifies the inactive workflow and immutable initial version. |\n| Draft | POST /developer/v1/workflows/{id}/draft | Create an editable draft before publication or subsequent graph edits. |\n| Publish | POST /developer/v1/workflows/{id}/publish with {} | Publishing audits the graph and activates an immutable version. Static success is not runtime proof. |\n| Run | POST /developer/v1/workflows/{id}/runs | HTTP 202; save run_id. Acceptance is not completion. |\n| Observe | GET /developer/v1/workflows/{id}/runs | Find the exact run_id. completed, failed, and cancelled are terminal. |\n\nA successful smoke test should report completed, execute the true branch for ready=true, and skip the false branch. Inspect individual nodes with GET /developer/v1/workflows/{id}/runs/{run_id}/nodes/{node_id}. Public inspection exposes statuses and value-free shapes, not patient data or raw error text. A completed orchestration does not prove that a business result succeeded; healthcare recipes need explicit business-success branches.\n\n## Connect a real workflow\n\n- [Action contracts](https://genhealth.ai/docs/workflows/action-contracts.md): Resolve connections, inputs, outputs, and business failures.\n- [Run operations and recovery](https://genhealth.ai/docs/workflows/operations.md): Handle interrupted writes, retries, versions, and cancellation.\n- [Provider patient intake recipe](https://genhealth.ai/docs/workflows/recipes/patient-intake.md): Match an extracted patient before a controlled Brightree create.\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-82584b0209fd0252",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && timeout 25 curl -sSL https://genhealth.ai -o gh_home.html; python3 - <<'EOF'
import re,html
s=open('gh_home.html',encoding='utf-8',errors='ignore').read()
s=re.sub(r'<(script|style).*?</\1>','',s,flags=re.S)
t=html.unescape(re.sub(r'<[^>]+>','\n',s)); t=re.sub(r'\n\s*\n+','\n',t)
print(t[:6000])
print("=== pricing mentions ===")
for m in re.finditer(r'(?i)(pric|cost|\$|per month|seat|subscription)',open('gh_home.html',encoding='utf-8',errors='ignore').read()):
pass
raw=open('gh_home.html',encoding='utf-8',errors='ignore').read()
for m in re.finditer(r'(?i).{120}(pricing|price|\$|per\s+month|subscription|per\s+case).{160}',t):
print(m.group(0).replace('\n',' '),"\n--")
EOFRevenue Cycle Management and Healthcare Admin for the AI Age
Revenue Cycle Management and Healthcare Admin for the AI Age GenHealth.ai Book Demo Company Products Who We Serve News: GenHealth Raises Series A Funding AI Employees for Healthcare Ops Intake, Benefits, Prior Auth, Billing and more Request a demo CHART NOTE 2026-03-14 · p.2 Pt with type 2 diabetes, poorly controlled despite metformin + lifestyle change. Labs show A1C 8.4% , BMI 34.2 . Initiating semaglutide 0.25 mg weekly . Plan: titrate to 1.0 mg over 8 weeks. …3-month follow-up for A1C + tolerability… adjudicate · PA-2847 LIVE INITIAL REVIEW 1.2s ago Semaglutide (Ozempic) J3490 · Type 2 Diabetes · Member 847-21 · BCBS TX Policy · BCBS GLP-1 PA 2026 ✓ Dx type 2 diabetes (E11) MET ✓ A1C ≥ 7.0% on metformin MET · Lifestyle modification (≥ 3 mo) — Citation “A1C 8.4%, BMI 34.2” — chart 2026-03-14 Recommendation ✓ APPROVED Confidence 0 % Med-Caire Inc White Aid Medical Supplies SpecialCare Gaboro Medical Supply FusionSleep Rely-A-Care Spectrum Medical Sleeptopia AbleCare Prime Care GuideHealth Piedmont Medical Solutions Soundview Medical Supplies Med-Caire Inc White Aid Medical Supplies SpecialCare Gaboro Medical Supply FusionSleep Rely-A-Care Spectrum Medical Sleeptopia AbleCare Prime Care GuideHealth Piedmont Medical Solutions Soundview Medical Supplies Customer results Piedmont Medical Solutions +34.2% 6.6x ROI More paid-to-date collections with AI-powered RCM. Read the case study GuideHealth $1.2M 6.9x ROI Projected annual admin savings of up to $1.2M. Read the case study Workflows Automate tasks across the RCM continuum within your current workflows and apps. Explore Workflow Automations Intake Eligibility Chat Prior Auth Resupplies Stock & Bill Billing Concurrent Review Posting Denials Intake & data entry Read a fax, automate data extraction and entry. Get started with Intake Web Portals & EMRs Automates tasks on websites, portals, EMRs, and billing systems. Fax Docs & OCR Runs OCR and extracts data from documents, PDFs, and images. Phone Outreach Calls patients and providers for information only they have. Try a sample supplies check with Maya, then ask about GenHealth or book a meeting by voice. Use your own number. Try it GenHealth customers Less admin. Better outcomes. Catch problems sooner “ GenHealth has automated more work with better results than our previous outsourced team—which was five times their size. ” Read case study Piedmont Medical Solutions Jack Bachman CEO and Owner Save millions of dollars “ We’ve seen 4X productivity increase and are on track to save nearly $1.2M this year… ” Read case study GuideHealth Dr. Sanjay Doddamani CEO Keep current workflows “ GenHealth said, ‘We can do it however you need to.’ That mindset really stood out. ” Soundview Medical Supplies Patti Maloney Vice President of Operations Get claims paid “ GenHealth now handles intake on more than half of all our orders fully automatically and flags critical issues that would prevent claims from getting paid. ” Read case study MedExpress Chris Leonard CEO and Co-Owner 1 / 4 Chat with Genie Get in touch Ready to see GenHealth in your workflow? Book a demo Choose a time that works for you Email us Tell us what you want to automate GenHealth.ai Generative AI for healthcare operations — intake, eligibility, prior auth, billing and more. For Enterprise Trust Center Status Dashboard AICPA SOC 2 HIPAA Copyright © 2026 GenHealth.ai Workflows All Workflows Intake Prior Authorization Eligibility Resupplies Stock & Bill Medical Necessity Referrals Products AI Automation for RCM Full Service RCM AI Automation for Health Plans API & Docs Markets DME & HME Providers & Health Systems Health Insurance Plans & Payers Specialties Top 10 RCM Solutions Info About Blog Jobs Technologies Medical Codes Medical Policies ROI Calculator Cost Calculator Support & Terms Privacy choices / Do not sell or share Documentation Tech Support Privacy Policy Security Policy Terms of Service Business Associate Agreement === pricing mentions ===
Recorded tool call
{
"type": "tool_call",
"seq": 28,
"ts": "2026-10-22T17:20:07.730Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -sSL https://genhealth.ai -o gh_home.html; python3 - <<'EOF'\nimport re,html\ns=open('gh_home.html',encoding='utf-8',errors='ignore').read()\ns=re.sub(r'<(script|style).*?</\\1>','',s,flags=re.S)\nt=html.unescape(re.sub(r'<[^>]+>','\\n',s)); t=re.sub(r'\\n\\s*\\n+','\\n',t)\nprint(t[:6000])\nprint(\"=== pricing mentions ===\")\nfor m in re.finditer(r'(?i)(pric|cost|\\$|per month|seat|subscription)',open('gh_home.html',encoding='utf-8',errors='ignore').read()):\n pass\nraw=open('gh_home.html',encoding='utf-8',errors='ignore').read()\nfor m in re.finditer(r'(?i).{120}(pricing|price|\\$|per\\s+month|subscription|per\\s+case).{160}',t):\n print(m.group(0).replace('\\n',' '),\"\\n--\")\nEOF"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-96101c2438d3f2cc",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 29,
"ts": "2026-10-22T17:20:08.105Z",
"turn": 1,
"output": {
"content": [
{
"text": "\nRevenue Cycle Management and Healthcare Admin for the AI Age\nGenHealth.ai\nBook Demo\nCompany\nProducts\nWho We Serve\nNews: \nGenHealth Raises Series A Funding\nAI Employees\nfor Healthcare Ops\nIntake, Benefits, Prior Auth, Billing and more\nRequest a demo \nCHART NOTE\n2026-03-14 · p.2\nPt with type 2 diabetes, poorly controlled despite metformin + lifestyle change.\nLabs show\nA1C 8.4%\n,\n BMI 34.2\n.\nInitiating\nsemaglutide 0.25 mg weekly\n. Plan: titrate to 1.0 mg over 8 weeks.\n…3-month follow-up for A1C + tolerability…\nadjudicate · PA-2847\nLIVE\nINITIAL REVIEW\n1.2s ago\nSemaglutide (Ozempic)\nJ3490 · Type 2 Diabetes · Member 847-21 · BCBS TX\nPolicy · BCBS GLP-1 PA 2026\n✓\nDx type 2 diabetes (E11)\nMET\n✓\nA1C ≥ 7.0% on metformin\nMET\n·\nLifestyle modification (≥ 3 mo)\n—\nCitation\n“A1C 8.4%, BMI 34.2” — chart 2026-03-14\nRecommendation\n✓\nAPPROVED\nConfidence\n0\n%\nMed-Caire Inc\nWhite Aid Medical Supplies\nSpecialCare\nGaboro Medical Supply\nFusionSleep\nRely-A-Care\nSpectrum Medical\nSleeptopia\nAbleCare\nPrime Care\nGuideHealth\nPiedmont Medical Solutions\nSoundview Medical Supplies\nMed-Caire Inc\nWhite Aid Medical Supplies\nSpecialCare\nGaboro Medical Supply\nFusionSleep\nRely-A-Care\nSpectrum Medical\nSleeptopia\nAbleCare\nPrime Care\nGuideHealth\nPiedmont Medical Solutions\nSoundview Medical Supplies\nCustomer results\nPiedmont Medical Solutions\n+34.2%\n6.6x ROI\nMore paid-to-date collections with AI-powered RCM.\nRead the case study\nGuideHealth\n$1.2M\n6.9x ROI\nProjected annual admin savings of up to $1.2M.\nRead the case study\nWorkflows\nAutomate tasks\nacross the RCM continuum\n within your current workflows and apps.\nExplore Workflow Automations\nIntake\nEligibility\nChat\nPrior Auth\nResupplies\nStock & Bill\nBilling\nConcurrent Review\nPosting\nDenials\nIntake & data entry\nRead a fax, automate data extraction and entry.\nGet started with Intake\nWeb\nPortals & EMRs\nAutomates tasks on websites, portals, EMRs, and billing systems.\nFax\nDocs & OCR\nRuns OCR and extracts data from documents, PDFs, and images.\nPhone\nOutreach\nCalls patients and providers for information only they have.\nTry a sample supplies check with Maya, then ask about GenHealth or book a meeting by voice. Use your own number.\nTry it\nGenHealth customers\nLess admin. Better outcomes.\nCatch problems sooner\n“\nGenHealth has automated more work with better results than our previous outsourced team—which was five times their size.\n”\nRead case study\nPiedmont Medical Solutions\nJack Bachman\nCEO and Owner\nSave millions of dollars\n“\nWe’ve seen 4X productivity increase and are on track to save nearly $1.2M this year…\n”\nRead case study\nGuideHealth\nDr. Sanjay Doddamani\nCEO\nKeep current workflows\n“\nGenHealth said, ‘We can do it however you need to.’ That mindset really stood out.\n”\nSoundview Medical Supplies\nPatti Maloney\nVice President of Operations\nGet claims paid\n“\nGenHealth now handles intake on more than half of all our orders fully automatically and flags critical issues that would prevent claims from getting paid.\n”\nRead case study\nMedExpress\nChris Leonard\nCEO and Co-Owner\n1\n/\n4\nChat with Genie\nGet in touch\nReady to see GenHealth in your workflow?\nBook a demo\nChoose a time that works for you\nEmail us\nTell us what you want to automate\nGenHealth.ai\nGenerative AI for healthcare operations\n—\nintake, eligibility, prior auth,\nbilling and more.\nFor Enterprise\nTrust Center\nStatus Dashboard\nAICPA SOC 2\nHIPAA\nCopyright © 2026 GenHealth.ai\nWorkflows\nAll Workflows\nIntake\nPrior Authorization\nEligibility\nResupplies\nStock & Bill\nMedical Necessity\nReferrals\nProducts\nAI Automation for RCM\nFull Service RCM\nAI Automation for Health Plans\nAPI & Docs\nMarkets\nDME & HME\nProviders & Health Systems\nHealth Insurance Plans & Payers\nSpecialties\nTop 10 RCM Solutions\nInfo\nAbout\nBlog\nJobs\nTechnologies\nMedical Codes\nMedical Policies\nROI Calculator\nCost Calculator\nSupport & Terms\nPrivacy choices / Do not sell or share\nDocumentation\nTech Support\nPrivacy Policy\nSecurity Policy\nTerms of Service\nBusiness Associate Agreement\n\n=== pricing mentions ===\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-96101c2438d3f2cc",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Pricing info: not listed on the site (enterprise-oriented, sales-driven). The "ROI Calculator" and "Cost Calculator" pages might have something, so I'll check. Also, I'll check the docs' mention of the "workflows plan feature" — it's a plan-based approach. Let me check if there's pricing info on the docs releases page, or maybe a billing page.
Also, I'll test whether I can actually make API calls — probably no API key. Check for GENHEALTH_API_KEY in environment variables. And check whether the sample scripts (workflow_agent.py, agent-smoke-test.json) are downloadable.
Important question: can I actually build a working example? An API key is needed, but that requires signup (via impa.genhealth.ai signup — an Auth0-style flow). No key → blocked. Still, I can scaffold a sample that can run as soon as a key is provided. The user said "let me know if you get blocked." So I'll create a lightweight sample (a small Python client that uses the hosted API — no local stack needed), and report that actual calls are blocked due to lack of API credentials.
Let me check if there's an API key in the environment variables, download the samples, and verify endpoint reachability without authentication (expecting 401 to be returned).
env | grep -i -E "genhealth|GH_|API_KEY" ; echo "--- probe (no auth)"; timeout 20 curl -sS -o /tmp/o.json -w "%{http_code}\n" "https://api.umpa.genhealth.ai/developer/v1/capabilities/v2" -H "Accept: application/json"; head -c 400 /tmp/o.json; echo; timeout 20 curl -sS -o /tmp/o2.json -w "%{http_code}\n" "https://api.umpa.genhealth.ai/v2/cases?page=1&limit=1"; head -c 300 /tmp/o2.jsonPI_GATEWAY_API_KEY=unused
PI_GATEWAY_API_KEY=unused
--- probe (no auth)
401
{"detail":"Requires authentication"}
403
{"detail":"Not authenticated"}Recorded tool call
{
"type": "tool_call",
"seq": 33,
"ts": "2026-10-22T17:20:13.338Z",
"name": "bash",
"turn": 1,
"input": {
"command": "env | grep -i -E \"genhealth|GH_|API_KEY\" ; echo \"--- probe (no auth)\"; timeout 20 curl -sS -o /tmp/o.json -w \"%{http_code}\\n\" \"https://api.umpa.genhealth.ai/developer/v1/capabilities/v2\" -H \"Accept: application/json\"; head -c 400 /tmp/o.json; echo; timeout 20 curl -sS -o /tmp/o2.json -w \"%{http_code}\\n\" \"https://api.umpa.genhealth.ai/v2/cases?page=1&limit=1\"; head -c 300 /tmp/o2.json"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-999a804815390117",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 36,
"ts": "2026-10-22T17:20:16.873Z",
"turn": 1,
"output": {
"content": [
{
"text": "PI_GATEWAY_API_KEY=unused\n--- probe (no auth)\n401\n{\"detail\":\"Requires authentication\"}\n403\n{\"detail\":\"Not authenticated\"}",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-999a804815390117",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && mkdir -p ghx && cd ghx && timeout 25 curl -sfSL https://genhealth.ai/docs/examples/agent-smoke-test.json -o agent-smoke-test.json -w "%{http_code} smoke\n"; timeout 25 curl -sfSL https://genhealth.ai/docs/examples/workflow_agent.py -o workflow_agent.py -w "%{http_code} agent\n"; ls -la; echo "--- pricing pages"; for p in cost-calculator roi-calculator pricing; do echo -n "$p: "; timeout 15 curl -sS -o /dev/null -w "%{http_code}\n" -L https://genhealth.ai/$p; done200 smoke
200 smoke 200 agent total 24 drwx------ 2 root root 4096 Oct 22 17:20 . drwxrwxrwt 7 root root 4096 Oct 22 17:20 .. -rw------- 1 root root 1207 Oct 22 17:20 agent-smoke-test.json -rw------- 1 root root 9408 Oct 22 17:20 workflow_agent.py --- pricing pages cost-calculator: 404 roi-calculator: 200 pricing: 404
Recorded tool call
{
"type": "tool_call",
"seq": 34,
"ts": "2026-10-22T17:20:13.338Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && mkdir -p ghx && cd ghx && timeout 25 curl -sfSL https://genhealth.ai/docs/examples/agent-smoke-test.json -o agent-smoke-test.json -w \"%{http_code} smoke\\n\"; timeout 25 curl -sfSL https://genhealth.ai/docs/examples/workflow_agent.py -o workflow_agent.py -w \"%{http_code} agent\\n\"; ls -la; echo \"--- pricing pages\"; for p in cost-calculator roi-calculator pricing; do echo -n \"$p: \"; timeout 15 curl -sS -o /dev/null -w \"%{http_code}\\n\" -L https://genhealth.ai/$p; done"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-bce4365ba93ee74f",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 35,
"ts": "2026-10-22T17:20:16.076Z",
"turn": 1,
"output": {
"content": [
{
"text": "200 smoke\n200 agent\ntotal 24\ndrwx------ 2 root root 4096 Oct 22 17:20 .\ndrwxrwxrwt 7 root root 4096 Oct 22 17:20 ..\n-rw------- 1 root root 1207 Oct 22 17:20 agent-smoke-test.json\n-rw------- 1 root root 9408 Oct 22 17:20 workflow_agent.py\n--- pricing pages\ncost-calculator: 404\nroi-calculator: 200\npricing: 404\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-bce4365ba93ee74f",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Endpoints are up and running (401/403 without authentication). The official sample script exists, and it's Python using only the standard library.
Pricing info: there's no public pricing page. The docs mention a "workflows plan feature". Let me quickly check the cost page / ROI calculator and the docs releases to see if there's any mention of pricing. Also going to check docs/workflows.md and the integrations pricing. Let me grep for "plan" / "pricing" / "cost" in the docs Markdown.
cd /tmp && for p in docs docs/releases docs/workflows docs/workflows/integrations docs/workflows/operations docs/api-reference; do timeout 20 curl -sSL "https://genhealth.ai/$p.md"; done > gh_all_docs.md 2>/dev/null; wc -l gh_all_docs.md; grep -n -i -E "pricing|price|cost|billing|plan feature|plans|free tier|credit" gh_all_docs.md | head -40
11700 gh_all_docs.md
11700 gh_all_docs.md 611:### [Push Authorization To Billing System](https://genhealth.ai/docs/workflows/integrations/authorizations/authorization_push_to_billing_system.md) 613:- Handler: `authorization_push_to_billing_system` 619:Perform Push Authorization To Billing System through Authorizations. 631:- Outputs: `success`, `skipped`, `coverage_id`, `status_code`, `status`, `has_active_coverage`, `has_coverage_determination`, `requested_procedure_codes`, `submitted_procedure_codes`, `procedure_code_support`, `procedure_code_support_detail`, `subscriber`, `patient`, `payer`, `requesting_provider`, `plans`, `raw_response`, `customer_message`, `payer_rejection_reason`, `payer_rejection_category`, `is_coverage_data_issue`, `error`, `error_message` 903:### [Update Patient Billing Info](https://genhealth.ai/docs/workflows/integrations/bonafide/bonafide_update_patient_billing_info.md) 905:- Handler: `bonafide_update_patient_billing_info` 911:Perform Update Patient Billing Info through Bonafide. 992:- Inputs: `sales_order_key`, `proc_code`, `quantity`, `billing_quantity`, `dry_run` 1046:### [Backfill Order Cost Evidence](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_backfill_order_cost_evidence.md) 1048:- Handler: `brightree_backfill_order_cost_evidence` 1052:- Outputs: `success`, `date_from`, `date_to`, `window_exhausted`, `days_completed`, `orders_seen`, `orders_processed`, `orders_skipped_observed`, `inserted`, `updated`, `valid_costs`, `missing_costs`, `invalid_costs`, `nonpositive_costs`, `order_errors`, `error` 1054:Perform Backfill Order Cost Evidence through Brightree. 1225:### [Copy Billing Address to Insured](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_copy_billing_address_to_insured.md) 1227:- Handler: `brightree_copy_billing_address_to_insured` 1233:Perform Copy Billing Address to Insured through Brightree. 1525:- Outputs: `success`, `date_from`, `date_to`, `line_count`, `paid_line_count`, `unpaid_line_count`, `revenue`, `cost`, `gp_dollars`, `gp_pct`, `negative_pct`, `below_15_pct`, `below_30_pct`, `by_payer`, `by_hcpcs`, `sku_opportunities`, `error` 1585:- Outputs: `success`, `dry_run`, `orders_scanned`, `orders_evaluated`, `flagged`, `wip_moved`, `skipped_unpriced`, `skipped_no_estimates`, `skipped_partial_estimates`, `skipped_already_flagged`, `skipped_recently_evaluated`, `skipped_wrong_wip`, `skipped_wip_unreadable`, `order_errors`, `error` 1605:- Outputs: `success`, `period_start`, `period_end`, `line_count`, `paid_line_count`, `unpaid_line_count`, `revenue`, `cost`, `gp_dollars`, `gp_pct`, `has_prior_period`, `prior_gp_pct`, `gp_pct_change`, `comparable_to_prior`, `snapshot_id`, `snapshot_persisted`, `html_body`, `subject`, `error` 1808:### [Resolve Client Sheet Costs](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_resolve_client_sheet_costs.md) 1810:- Handler: `brightree_resolve_client_sheet_costs` 1814:- Outputs: `success`, `catalog_entries`, `rows_scanned`, `cost_written`, `matched_item`, `matched_hcpcs`, `no_catalog_match`, `quantity_unparsed`, `uncosted_remaining`, `error` 1816:Perform Resolve Client Sheet Costs through Brightree. 1828:### [Resolve Historical Order Costs](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_resolve_historical_order_costs.md) 1830:- Handler: `brightree_resolve_historical_order_costs` 1834:- Outputs: `success`, `candidates_selected`, `candidates_remaining`, `cost_written`, `no_received_po`, `no_usable_810`, `shared_po_skipped`, `order_errors`, `shared_purchase_orders`, `error` 1836:Perform Resolve Historical Order Costs through Brightree. 2026:### [Set Patient Delivery Address Same As Billing](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_set_patient_delivery_address_same_as_billing.md) 2028:- Handler: `brightree_set_patient_delivery_address_same_as_billing` 2034:Perform Set Patient Delivery Address Same As Billing through Brightree. 2299:### [Validate Patient Billing Address](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_validate_patient_billing_address.md) 2301:- Handler: `brightree_validate_patient_billing_address` 2307:Perform Validate Patient Billing Address through Brightree. 2314:- Inputs: `patient_id`, `patient_state`, `patient_key`, `patient_context`, `facility_payload`, `facility_set_payload`, `marketing_referral_payload`, `billing_address_payload`, `delivery_address_payload`, `dropdown_payload`, `responsible_party_payload`, `primary_doctor_payload`, `tax_zone_payload`, `account_group`, `account_key`, `set_dropdowns`, `dry_run` 2612:- Outputs: `success`, `status`, `is_eligible`, `is_capitated`, `has_non_covered_benefit`, `payer_cannot_process`, `managed_care_organizations`, `plan_assignments`, `contracted_service_providers`, `plan_name`, `plan_number`, `group_name`, `group_number`, `coverage_start`, `coverage_end`, `payer_names`, `payer_program_identifier`, `related_entities`, `other_insurance`, `has_other_insurance`, `coverage_codes`, `coverage_descriptions`, `service_type_codes`, `service_type_descriptions`, `insurance_plans`, `insurance_type_codes`, `insurance_type_descriptions`, `active_insurance_plans`, `active_insurance_type_codes`, `active_insurance_type_descriptions`, `network_statuses`, `network_status_descriptions`, `benefit_coverage_windows`, `plan_coverage_windows`, `plan_begin_date`, `plan_end_date`, `eligibility_begin_date`, `eligibility_end_date`, `benefit_count`, `relevant_benefit_count`, `eligibility_id`, `result_date`, `document_id`, `pdf_path`, `pdf_error`, `payer_errors`, `retryable`, `error`, `skipped`, `skip_reason` 2695:- Inputs: `patient_data`, `billing_location_ids`, `order_params` 2895:- Inputs: `report`, `selected_ids`, `billing_location_ids`, `begin_date`, `end_date`, `date_basis`, `statuses`, `detail_level`, `include_claim_comments`, `include_no_payer`, `ignore_location_sorting`, `timely_filing_min`, `timely_filing_max`, `max_rows`, `skip_rows`, `poll_interval_seconds`, `timeout_seconds` 2905:- Inputs: `begin_date`, `end_date`, `billing_location_ids`, `order_statuses`, `search_text`, `search_fields`, `no_alerts`, `show_deleted`, `max_rows` 2975:- Inputs: `policy_data`, `patient_state`, `billing_location`, `payer_code_source`, `claimmd_discovery_reason`, `payer_plan`, `payer_card_state`, `payer_name_truncated`, `card_insurance_type`, `member_number`, `document_id`, `reviewed_payer_id`, `reviewed_payer_confirmed` 2995:- Inputs: `npi`, `name`, `billing_location_id` 3025:- Inputs: `patient_data`, `billing_location_ids`, `patient_id`, `patient_defaults`, `demographics_override`
Recorded tool call
{
"type": "tool_call",
"seq": 39,
"ts": "2026-10-22T17:20:19.603Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && for p in docs docs/releases docs/workflows docs/workflows/integrations docs/workflows/operations docs/api-reference; do timeout 20 curl -sSL \"https://genhealth.ai/$p.md\"; done > gh_all_docs.md 2>/dev/null; wc -l gh_all_docs.md; grep -n -i -E \"pricing|price|cost|billing|plan feature|plans|free tier|credit\" gh_all_docs.md | head -40"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-b0e51e4eff1cba51",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 42,
"ts": "2026-10-22T17:20:23.857Z",
"turn": 1,
"output": {
"content": [
{
"text": "11700 gh_all_docs.md\n611:### [Push Authorization To Billing System](https://genhealth.ai/docs/workflows/integrations/authorizations/authorization_push_to_billing_system.md)\n613:- Handler: `authorization_push_to_billing_system`\n619:Perform Push Authorization To Billing System through Authorizations.\n631:- Outputs: `success`, `skipped`, `coverage_id`, `status_code`, `status`, `has_active_coverage`, `has_coverage_determination`, `requested_procedure_codes`, `submitted_procedure_codes`, `procedure_code_support`, `procedure_code_support_detail`, `subscriber`, `patient`, `payer`, `requesting_provider`, `plans`, `raw_response`, `customer_message`, `payer_rejection_reason`, `payer_rejection_category`, `is_coverage_data_issue`, `error`, `error_message`\n903:### [Update Patient Billing Info](https://genhealth.ai/docs/workflows/integrations/bonafide/bonafide_update_patient_billing_info.md)\n905:- Handler: `bonafide_update_patient_billing_info`\n911:Perform Update Patient Billing Info through Bonafide.\n992:- Inputs: `sales_order_key`, `proc_code`, `quantity`, `billing_quantity`, `dry_run`\n1046:### [Backfill Order Cost Evidence](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_backfill_order_cost_evidence.md)\n1048:- Handler: `brightree_backfill_order_cost_evidence`\n1052:- Outputs: `success`, `date_from`, `date_to`, `window_exhausted`, `days_completed`, `orders_seen`, `orders_processed`, `orders_skipped_observed`, `inserted`, `updated`, `valid_costs`, `missing_costs`, `invalid_costs`, `nonpositive_costs`, `order_errors`, `error`\n1054:Perform Backfill Order Cost Evidence through Brightree.\n1225:### [Copy Billing Address to Insured](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_copy_billing_address_to_insured.md)\n1227:- Handler: `brightree_copy_billing_address_to_insured`\n1233:Perform Copy Billing Address to Insured through Brightree.\n1525:- Outputs: `success`, `date_from`, `date_to`, `line_count`, `paid_line_count`, `unpaid_line_count`, `revenue`, `cost`, `gp_dollars`, `gp_pct`, `negative_pct`, `below_15_pct`, `below_30_pct`, `by_payer`, `by_hcpcs`, `sku_opportunities`, `error`\n1585:- Outputs: `success`, `dry_run`, `orders_scanned`, `orders_evaluated`, `flagged`, `wip_moved`, `skipped_unpriced`, `skipped_no_estimates`, `skipped_partial_estimates`, `skipped_already_flagged`, `skipped_recently_evaluated`, `skipped_wrong_wip`, `skipped_wip_unreadable`, `order_errors`, `error`\n1605:- Outputs: `success`, `period_start`, `period_end`, `line_count`, `paid_line_count`, `unpaid_line_count`, `revenue`, `cost`, `gp_dollars`, `gp_pct`, `has_prior_period`, `prior_gp_pct`, `gp_pct_change`, `comparable_to_prior`, `snapshot_id`, `snapshot_persisted`, `html_body`, `subject`, `error`\n1808:### [Resolve Client Sheet Costs](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_resolve_client_sheet_costs.md)\n1810:- Handler: `brightree_resolve_client_sheet_costs`\n1814:- Outputs: `success`, `catalog_entries`, `rows_scanned`, `cost_written`, `matched_item`, `matched_hcpcs`, `no_catalog_match`, `quantity_unparsed`, `uncosted_remaining`, `error`\n1816:Perform Resolve Client Sheet Costs through Brightree.\n1828:### [Resolve Historical Order Costs](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_resolve_historical_order_costs.md)\n1830:- Handler: `brightree_resolve_historical_order_costs`\n1834:- Outputs: `success`, `candidates_selected`, `candidates_remaining`, `cost_written`, `no_received_po`, `no_usable_810`, `shared_po_skipped`, `order_errors`, `shared_purchase_orders`, `error`\n1836:Perform Resolve Historical Order Costs through Brightree.\n2026:### [Set Patient Delivery Address Same As Billing](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_set_patient_delivery_address_same_as_billing.md)\n2028:- Handler: `brightree_set_patient_delivery_address_same_as_billing`\n2034:Perform Set Patient Delivery Address Same As Billing through Brightree.\n2299:### [Validate Patient Billing Address](https://genhealth.ai/docs/workflows/integrations/brightree/brightree_validate_patient_billing_address.md)\n2301:- Handler: `brightree_validate_patient_billing_address`\n2307:Perform Validate Patient Billing Address through Brightree.\n2314:- Inputs: `patient_id`, `patient_state`, `patient_key`, `patient_context`, `facility_payload`, `facility_set_payload`, `marketing_referral_payload`, `billing_address_payload`, `delivery_address_payload`, `dropdown_payload`, `responsible_party_payload`, `primary_doctor_payload`, `tax_zone_payload`, `account_group`, `account_key`, `set_dropdowns`, `dry_run`\n2612:- Outputs: `success`, `status`, `is_eligible`, `is_capitated`, `has_non_covered_benefit`, `payer_cannot_process`, `managed_care_organizations`, `plan_assignments`, `contracted_service_providers`, `plan_name`, `plan_number`, `group_name`, `group_number`, `coverage_start`, `coverage_end`, `payer_names`, `payer_program_identifier`, `related_entities`, `other_insurance`, `has_other_insurance`, `coverage_codes`, `coverage_descriptions`, `service_type_codes`, `service_type_descriptions`, `insurance_plans`, `insurance_type_codes`, `insurance_type_descriptions`, `active_insurance_plans`, `active_insurance_type_codes`, `active_insurance_type_descriptions`, `network_statuses`, `network_status_descriptions`, `benefit_coverage_windows`, `plan_coverage_windows`, `plan_begin_date`, `plan_end_date`, `eligibility_begin_date`, `eligibility_end_date`, `benefit_count`, `relevant_benefit_count`, `eligibility_id`, `result_date`, `document_id`, `pdf_path`, `pdf_error`, `payer_errors`, `retryable`, `error`, `skipped`, `skip_reason`\n2695:- Inputs: `patient_data`, `billing_location_ids`, `order_params`\n2895:- Inputs: `report`, `selected_ids`, `billing_location_ids`, `begin_date`, `end_date`, `date_basis`, `statuses`, `detail_level`, `include_claim_comments`, `include_no_payer`, `ignore_location_sorting`, `timely_filing_min`, `timely_filing_max`, `max_rows`, `skip_rows`, `poll_interval_seconds`, `timeout_seconds`\n2905:- Inputs: `begin_date`, `end_date`, `billing_location_ids`, `order_statuses`, `search_text`, `search_fields`, `no_alerts`, `show_deleted`, `max_rows`\n2975:- Inputs: `policy_data`, `patient_state`, `billing_location`, `payer_code_source`, `claimmd_discovery_reason`, `payer_plan`, `payer_card_state`, `payer_name_truncated`, `card_insurance_type`, `member_number`, `document_id`, `reviewed_payer_id`, `reviewed_payer_confirmed`\n2995:- Inputs: `npi`, `name`, `billing_location_id`\n3025:- Inputs: `patient_data`, `billing_location_ids`, `patient_id`, `patient_defaults`, `demographics_override`\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-b0e51e4eff1cba51",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && timeout 25 curl -sSL https://genhealth.ai/roi-calculator -o gh_roi.html; python3 - <<'EOF'
import re,html
s=open('gh_roi.html',encoding='utf-8',errors='ignore').read()
s=re.sub(r'<(script|style).*?</\1>','',s,flags=re.S)
t=html.unescape(re.sub(r'<[^>]+>','\n',s)); t=re.sub(r'\n\s*\n+','\n',t)
print(t[:2500])
EOFROI Calculator — GenHealth.ai
ROI Calculator — GenHealth.ai GenHealth.ai Book Demo Company Products Who We Serve Free tool Calculate your DME automation ROI. Enter your organization's numbers and see an instant ROI breakdown — labor savings, denial reduction, and full ROI analysis. Print or save as a PDF when you're ready. Your operation Enter your organization's information below to generate a detailed ROI report. Company information Name Company Email address Title DME focus area(s) Respiratory Sleep Therapy Diabetes Management (CGM & Pumps) Mobility Hospital Beds & Support Surfaces Orthotics Enteral Nutrition Compression Therapy Other Current operations Monthly incoming orders EMR Select your EMR… Brightree Niko Health Bonafide Nymbl Other Avg order value ($) Gross margin (%) Staff cost ($/hr) Denial rate (%) Conversion rate (%) Mins / order See my ROI Your report appears instantly on this page. You can print or save it as a PDF. What you get A full ROI breakdown for your operation. An instant analysis you can print or save as a PDF directly from this page. 01 Annual Labor Savings See exactly how much you save in labor cost by automating repetitive manual tasks with AI. 02 Denial Reduction Impact Calculate the revenue recovered by reducing claim denials through better documentation and compliance. 03 Revenue Growth Potential Understand additional revenue from improved conversion rates and operational efficiency. 04 Time-to-Value Analysis View your payback period and when you start seeing positive returns. 05 Total ROI Percentage Your complete return on investment calculation showing overall financial impact. 06 Net Annual Benefit Your total annual benefit after accounting for GenHealth.ai subscription costs. Chat with Genie Get in touch Find a time to interview GenHealth or Contact us to learn more. Book demo Email us instead Loading available demo times M T W T F Sign Up Try GenHealth free. Spin up a free account and run real PA, intake, and eligibility flows in your sandbox. Automate intake, eligibility, and PA with AI agents that work in your EMR and billing systems. Drop-in agents for PA, intake, eligibility Free sandbox — no credit card Connects to your EMR & billing Create a free account GenHealth.ai Generative AI for healthcare operations — intake, eligibility, prior auth, billing and more. For Enterprise Trust Center Status Dashboard AICPA SOC 2 HIPAA Copyright © 2026 GenHealth.ai Workflows All Workflows Intake Prior Authorization Eligibility Resupplies Stock & Bill Med
Recorded tool call
{
"type": "tool_call",
"seq": 40,
"ts": "2026-10-22T17:20:19.603Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -sSL https://genhealth.ai/roi-calculator -o gh_roi.html; python3 - <<'EOF'\nimport re,html\ns=open('gh_roi.html',encoding='utf-8',errors='ignore').read()\ns=re.sub(r'<(script|style).*?</\\1>','',s,flags=re.S)\nt=html.unescape(re.sub(r'<[^>]+>','\\n',s)); t=re.sub(r'\\n\\s*\\n+','\\n',t)\nprint(t[:2500])\nEOF"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-b1bd6cb93483ca33",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 41,
"ts": "2026-10-22T17:20:20.781Z",
"turn": 1,
"output": {
"content": [
{
"text": "\nROI Calculator — GenHealth.ai\nGenHealth.ai\nBook Demo\nCompany\nProducts\nWho We Serve\nFree tool\nCalculate your \nDME automation\n ROI.\nEnter your organization's numbers and see an instant ROI breakdown — labor savings, denial reduction, and full ROI analysis. Print or save as a PDF when you're ready.\nYour operation\nEnter your organization's information below to generate a detailed ROI report.\nCompany information\nName\nCompany\nEmail address\nTitle\nDME focus area(s)\nRespiratory\nSleep Therapy\nDiabetes Management (CGM & Pumps)\nMobility\nHospital Beds & Support Surfaces\nOrthotics\nEnteral Nutrition\nCompression Therapy\nOther\nCurrent operations\nMonthly incoming orders\nEMR\nSelect your EMR…\nBrightree\nNiko Health\nBonafide\nNymbl\nOther\nAvg order value ($)\nGross margin (%)\nStaff cost ($/hr)\nDenial rate (%)\nConversion rate (%)\nMins / order\nSee my ROI\nYour report appears instantly on this page. You can print or save it as a PDF.\nWhat you get\nA full \nROI breakdown\n for your operation.\nAn instant analysis you can print or save as a PDF directly from this page.\n01\nAnnual Labor Savings\nSee exactly how much you save in labor cost by automating repetitive manual tasks with AI.\n02\nDenial Reduction Impact\nCalculate the revenue recovered by reducing claim denials through better documentation and compliance.\n03\nRevenue Growth Potential\nUnderstand additional revenue from improved conversion rates and operational efficiency.\n04\nTime-to-Value Analysis\nView your payback period and when you start seeing positive returns.\n05\nTotal ROI Percentage\nYour complete return on investment calculation showing overall financial impact.\n06\nNet Annual Benefit\nYour total annual benefit after accounting for GenHealth.ai subscription costs.\nChat with Genie\nGet in touch\nFind a time to interview GenHealth or Contact us to learn more.\nBook demo\nEmail us instead\nLoading available demo times\nM\nT\nW\nT\nF\nSign Up\nTry GenHealth free.\nSpin up a free account and run real PA, intake, and eligibility flows in your sandbox.\nAutomate intake, eligibility, and PA\nwith AI agents that work in your EMR and billing systems.\nDrop-in agents for PA, intake, eligibility\nFree sandbox — no credit card\nConnects to your EMR & billing\nCreate a free account\nGenHealth.ai\nGenerative AI for healthcare operations\n—\nintake, eligibility, prior auth,\nbilling and more.\nFor Enterprise\nTrust Center\nStatus Dashboard\nAICPA SOC 2\nHIPAA\nCopyright © 2026 GenHealth.ai\nWorkflows\nAll Workflows\nIntake\nPrior Authorization\nEligibility\nResupplies\nStock & Bill\nMed\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-b1bd6cb93483ca33",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Good. Pricing model: not publicly disclosed — sales-led enterprise subscription. The ROI calculator mentions "GenHealth.ai subscription costs," and there's also a free sandbox account with no credit card required. The docs mention a "workflows plan feature" (plan-gated), and per-operation scopes as well.
Alright, let's build the sample. Constraints: lightweight, use the hosted API, don't use local stacks. I can't get an API key myself (signup requires an interactive account) → I'll be blocked from actually running against the live API. But the following is possible:
- Download the official samples into the repo (or write my own minimal client).
- Write a small sample script that loads GENHEALTH_API_KEY, plus a README that documents the pricing model.
- Verify what's possible without a key: confirm the endpoint returns 401 (done), and run the sample client in a way that fails gracefully with a clear message.
Let me look at the official workflow_agent.py to make sure I understand it, and check the validate endpoint — validate probably also requires auth. Yes, everything requires auth.
Plan: create the following in /sandbox/repo:
- README.md — quickstart, pricing notes, "how to manage"
- genhealth_example/quickstart.py — a minimal client using only the standard library: capabilities → workflow validation → import → draft → publish → execute → inspect. Reuse ideas from the official script while keeping my own simple version. Alternatively, vendor the official workflow_agent.py and add a thin wrapper. The simpler route: write my own ~150-line script.
- examples/agent-smoke-test.json (downloaded).
Also check whether GENHEALTH_API_KEY exists — it doesn't. So the script should exit with a clear message. Verify that the script runs and shows the blocked-state message, and additionally test against the live API without a key to demonstrate 401 handling (a safe GET). Actually, running validate without a key will return 401 → the script displays a message. That's enough as a demo of the blocked state.
Let me read the official script to keep things consistent and avoid duplicating errors.
✓read /tmp/ghx/workflow_agent.py✓└{"content":[{"text":"#!/usr/bin/env python3\n\"\"\"GenHealth synthetic workflow quickstart. Python 3; no third-party packages.\n\nvalidate DEFINITION: preflight…ctrl+o
{"content":[{"text":"#!/usr/bin/env python3\n\"\"\"GenHealth synthetic workflow quickstart. Python 3; no third-party packages.\n\nvalidate DEFINITION: preflight only. execute DEFINITION: publish one synthetic run.\ninspect: observe the run in --state. No external integration actions are executed.\nRun state contains no key and must be retained to resume after an interruption.\nUse one process per state file. Review this client before running it.\n\"\"\"\n\nimport argparse\nimport hashlib\nimport json\nimport os\nfrom pathlib import Path\nimport sys\nfrom urllib.error import HTTPError, URLError\nfrom urllib.parse import urlencode, urlsplit\nfrom urllib.request import HTTPRedirectHandler, Request, build_opener\nfrom uuid import UUID, uuid4\n\n\nclass ApiError(RuntimeError):\n \"\"\"A bounded diagnostic that does not echo response bodies or credentials.\"\"\"\n\n\nclass NoRedirect(HTTPRedirectHandler):\n def redirect_request(self, req, fp, code, msg, headers, newurl):\n raise ApiError(\"API redirects are refused; verify GENHEALTH_API_BASE.\")\n\n\nclass Client:\n def __init__(self, base_url, api_key):\n parsed = urlsplit(base_url)\n local_http = parsed.scheme == \"http\" and parsed.hostname in {\"localhost\", \"127.0.0.1\", \"::1\"}\n if (parsed.scheme != \"https\" and not local_http) or not parsed.hostname:\n raise ApiError(\"Use an HTTPS API origin, or HTTP localhost for an isolated local server.\")\n if parsed.username or parsed.password or parsed.query or parsed.fragment or parsed.path not in {\"\", \"/\"}:\n raise ApiError(\"GENHEALTH_API_BASE must be an origin without credentials, path, query, or fragment.\")\n if not api_key:\n raise ApiError(\"Set GENHEALTH_API_KEY to an organization-bound key.\")\n self.base_url = base_url.rstrip(\"/\")\n self.api_key = api_key\n self.opener = build_opener(NoRedirect())\n\n def request(self, method, path, body=None):\n request = Request(\n self.base_url + \"/developer/v1\" + path,\n data=json.dumps(body).encode() if body is not None else None,\n headers={\"Authorization\": \"Bearer \" + self.api_key, \"Content-Type\": \"application/json\", \"Accept\": \"application/json\"},\n method=method,\n )\n try:\n with self.opener.open(request, timeout=30) as response:\n return json.load(response)\n except HTTPError as error:\n raise ApiError(\"HTTP %s: consult /docs/workflows/operations; no automatic write retry was attempted.\" % error.code) from None\n except (URLError, TimeoutError, OSError):\n raise ApiError(\"Transport outcome unknown. Retain the state file and resume using the documented recovery procedure.\") from None\n\n\ndef save_state(path, state):\n temporary = path.with_suffix(path.suffix + \".tmp\")\n # Owner-only permissions from creation; state is synthetic but operationally sensitive.\n descriptor = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)\n with os.fdopen(descriptor, \"w\") as stream:\n json.dump(state, stream, indent=2)\n temporary.replace(path)\n\n\ndef preflight(client, definition):\n result = client.request(\"POST\", \"/workflows/validate\", {\"definition\": definition})\n if result.get(\"viable\") is not True or result.get(\"readiness\") != \"ready\":\n raise ApiError(\"Preflight is blocked or needs review. Inspect validation findings through the authenticated API before publishing.\")\n return result\n\n\ndef execute(client, definition, path):\n # This executable example is a smoke test, not an arbitrary production runner.\n nodes = definition.get(\"workflow\", {}).get(\"nodes\", [])\n if not nodes or any(node.get(\"type\") not in {\"comment\", \"if\"} for node in nodes):\n raise ApiError(\"This client executes synthetic comment/if graphs only. Use the documented API lifecycle for integrations.\")\n fingerprint = hashlib.sha256(json.dumps(definition, sort_keys=True).encode()).hexdigest()\n state = json.loads(path.read_text()) if path.exists() else {\"stage\": \"new\", \"base_url\": client.base_url, \"definition_sha256\": fingerprint}\n if state.get(\"base_url\") != client.base_url or state.get(\"definition_sha256\") != fingerprint:\n raise ApiError(\"State belongs to a different API origin or definition; do not reuse it.\")\n preflight(client, definition)\n if state[\"stage\"] == \"import_pending\":\n raise ApiError(\"Import outcome unknown. List workflows and verify the candidate with GET /workflows/{id}/export. After confirming its graph matches this definition, set workflow_id and stage=imported in the state file, then resume. Do not repeat import with a new state file.\")\n if state[\"stage\"] == \"new\":\n state[\"stage\"] = \"import_pending\"\n save_state(path, state)\n imported = client.request(\"POST\", \"/workflows/import\", definition)\n state.update(workflow_id=str(UUID(imported[\"workflow\"][\"id\"])), stage=\"imported\")\n save_state(path, state)\n workflow_path = \"/workflows/\" + str(UUID(state[\"workflow_id\"]))\n if state[\"stage\"] == \"draft_pending\":\n current = client.request(\"GET\", workflow_path)\n if not current.get(\"has_draft\"):\n raise ApiError(\"Draft outcome unknown; inspect workflow versions before retrying a write.\")\n state[\"stage\"] = \"drafted\"\n save_state(path, state)\n if state[\"stage\"] == \"imported\":\n state[\"stage\"] = \"draft_pending\"\n save_state(path, state)\n client.request(\"POST\", workflow_path + \"/draft\")\n state[\"stage\"] = \"drafted\"\n save_state(path, state)\n if state[\"stage\"] == \"publish_pending\":\n current = client.request(\"GET\", workflow_path)\n if current.get(\"status\") != \"active\" or current.get(\"has_draft\"):\n raise ApiError(\"Publication outcome unknown; inspect workflow versions before retrying a write.\")\n state[\"stage\"] = \"published\"\n save_state(path, state)\n if state[\"stage\"] == \"drafted\":\n state[\"stage\"] = \"publish_pending\"\n save_state(path, state)\n client.request(\"POST\", workflow_path + \"/publish\", {})\n state[\"stage\"] = \"published\"\n save_state(path, state)\n if state[\"stage\"] == \"published\":\n current = client.request(\"GET\", workflow_path)\n state.update(stage=\"run_pending\", version_id=current[\"active_version_id\"], run_request={\"idempotency_key\": str(uuid4()), \"trigger_data\": {\"ready\": True}})\n save_state(path, state)\n if state[\"stage\"] == \"run_pending\":\n current = client.request(\"GET\", workflow_path)\n if current.get(\"active_version_id\") != state[\"version_id\"]:\n raise ApiError(\"Active version changed. Reconcile the pending run; do not change its idempotency key.\")\n run = client.request(\"POST\", workflow_path + \"/runs\", state[\"run_request\"])\n state.update(stage=\"accepted\", run_id=str(UUID(run[\"run_id\"])))\n save_state(path, state)\n if state[\"stage\"] != \"accepted\":\n raise ApiError(\"Unknown state stage; inspect the state file before another write.\")\n return state\n\n\ndef inspect(client, state):\n if state.get(\"base_url\") != client.base_url or not state.get(\"run_id\"):\n raise ApiError(\"No accepted run for this API origin. Resume execute first.\")\n workflow_id, run_id = str(UUID(state[\"workflow_id\"])), str(UUID(state[\"run_id\"]))\n result = client.request(\"GET\", \"/workflows/\" + workflow_id + \"/runs?\" + urlencode({\"limit\": 25}))\n run = next((item for item in result.get(\"runs\", []) if item.get(\"run_id\") == run_id), None)\n if run is None:\n raise ApiError(\"Run not in the returned page. Use since/until/status filters in the API; do not submit another run.\")\n print(json.dumps({\"workflow_id\": workflow_id, \"run_id\": run_id, \"status\": run.get(\"status\")}, indent=2))\n if run.get(\"status\") in {\"failed\", \"cancelled\"}:\n raise ApiError(\"Run ended without completion; inspect node shapes in the authenticated API.\")\n\n\ndef main():\n parser = argparse.ArgumentParser(description=__doc__)\n parser.add_argument(\"command\", choices=[\"validate\", \"execute\", \"inspect\"])\n parser.add_argument(\"definition\", nargs=\"?\")\n parser.add_argument(\"--state\", type=Path, default=Path(\"agent-smoke-state.json\"))\n args = parser.parse_args()\n client = Client(os.environ.get(\"GENHEALTH_API_BASE\", \"https://api.umpa.genhealth.ai\"), os.environ.get(\"GENHEALTH_API_KEY\"))\n if args.command == \"inspect\":\n inspect(client, json.loads(args.state.read_text()))\n return\n if not args.definition:\n parser.error(\"validate and execute require a definition file\")\n definition = json.loads(Path(args.definition).read_text())\n if args.command == \"validate\":\n preflight(client, definition)\n print(\"Preflight ready; no workflow was created.\")\n else:\n state = execute(client, definition, args.state)\n print(json.dumps({\"workflow_id\": state[\"workflow_id\"], \"run_id\": state[\"run_id\"], \"status\": \"accepted; inspect for completion\"}, indent=2))\n\n\nif __name__ == \"__main__\":\n try:\n main()\n except (ApiError, OSError, ValueError, KeyError, TypeError) as error:\n # JSON/OS diagnostics can contain file contents or paths; only ApiError is curated.\n print(str(error) if isinstance(error, ApiError) else \"Invalid local state, definition, or API response; inspect it locally before continuing.\", file=sys.stderr)\n sys.exit(1)\n","type":"text"}]}cd /tmp && timeout 20 curl -sSL "https://genhealth.ai/docs/workflows.md" | head -120
# GenHealth Workflow Developer API
# GenHealth Workflow Developer API
> Create, version, audit, publish, run, and maintain UMPA workflows directly against the core ETL API. The capability and action-discovery operations are optimized for AI agents.
Source: [https://genhealth.ai/docs/workflows](https://genhealth.ai/docs/workflows)
> **Workflow API access**
>
> Use a GenHealth API key with the workflow scope required by each operation. Copy the request examples to call the API from your server; interactive requests are not enabled in this reference.
## Build workflow automations
Discover supported integrations and actions, validate canonical workflow JSON, manage drafts and immutable versions, inspect graphs, publish viable workflows, and operate organization-scoped workflow runs.
- [Provider workflows across specialties](https://genhealth.ai/docs/workflows/provider-workflows.md): Scope referral intake, clearance, authorization, and recurring care using the right system contracts.
- [Build and run your first workflow](https://genhealth.ai/docs/workflows/agent-quickstart.md): Use REST or MCP, validate a synthetic graph, publish it, and inspect an idempotent run.
- [Discover capabilities](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-capabilities.md): Inspect controls, node types, expressions, integrations, and action schemas.
- [Find workflow functions](https://genhealth.ai/docs/workflows/integrations.md): Search the actions available for use in a workflow definition.
- [Create workflows](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/create-developer-workflow.md): Create organization-scoped workflow records and validate their JSON first.
- [Publish and run](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/run-developer-workflow.md): Publish immutable versions and start idempotent workflow runs.
## Workflow runs, integrations, and events
These terms describe what starts a workflow, how it works with other systems, and how its step attempts are modeled.
### Workflow run
One run begins each time a workflow is triggered—by a person, schedule, API request, file upload, or webhook—and ends when it completes, fails, or is canceled. Branches, waits, loops, and step retries remain part of that run; a child workflow starts a separate run.
### Integration
An integration connects a workflow to another system or exposes a GenHealth capability. It provides actions—tools such as finding a record, extracting data, or sending an update—that can be used as workflow steps. Some integrations require a configured connection or credentials.
[Browse available integrations and actions](https://genhealth.ai/docs/workflows/integrations.md)
### Modeled internal event
A planning unit for work performed inside a run. In the historical benchmark, each event represents one successful or failed attempt to execute a workflow step, after replay duplicates are removed. Loops and retries can add events; an event does not map one-to-one to a visible block, tool call, or external request.
## Contract summary
| Property | Value |
| --- | --- |
| OpenAPI | 3.1.0 |
| API version | 1.0.0 |
| Operations | 37 |
| Component schemas | 62 |
| Authentication | HTTP bearer token with operation-specific workflow scopes |
## Organization isolation
Workflow definitions, versions, graphs, webhook endpoints, and runs are resolved within the organization carried by the authenticated credential. An identifier from another organization does not grant access.
## Operations
- [Search Workflow Actions](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/search-workflow-actions.md): `GET /developer/v1/actions` — Search tenant-permitted platform actions; connection setup is reported separately.
- [Get Workflow Action](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-action.md): `GET /developer/v1/actions/{handler}` — Return the complete first-pass schema for one exact public action handler.
- [List Workflow Action Field Options](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-action-field-options.md): `GET /developer/v1/actions/{handler}/fields/{field}/options` — Resolve dynamic choices for one action field without exposing credentials.
- [Get Workflow Capabilities](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-capabilities.md): `GET /developer/v1/capabilities` — Return the established strict V1 workflow capability manifest.
- [Get Workflow Capabilities V2](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-capabilities-v2.md): `GET /developer/v1/capabilities/v2` — Describe graph controls plus the public webhook lifecycle contract.
- [List Workflow Integration Connections](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-integration-connections.md): `GET /developer/v1/integration-connections` — Report whether each public integration has credentials, without exposing them.
- [List Workflow Integrations](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-integrations.md): `GET /developer/v1/integrations` — List tenant-permitted public integrations; this does not assert connection setup.
- [Cancel Developer Workflow Run](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/cancel-developer-workflow-run.md): `POST /developer/v1/runs/{run_id}/cancel` — Request cancellation of one organization-owned public-compatible workflow run.
- [List Developer Workflows](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-developer-workflows.md): `GET /developer/v1/workflows` — List the same organization-scoped workflows shown in UMPA.
- [Create Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/create-developer-workflow.md): `POST /developer/v1/workflows` — Create a workflow directly in the core ETL store used by UMPA.
- [Import Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/import-developer-workflow.md): `POST /developer/v1/workflows/import` — Import canonical JSON as an inactive UMPA workflow with published version 1.
- [Validate Workflow Definition](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/validate-workflow-definition.md): `POST /developer/v1/workflows/validate` — Preflight canonical workflow JSON against save, audit, and public API rules. This operation does not persist anything. A definition that fails validation still returns HTTP 200 with ``viable=false`` and machine-actionable findings.
- [Delete Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/delete-developer-workflow.md): `DELETE /developer/v1/workflows/{definition_id}` — Soft-delete a workflow after publish-scope authorization and explicit confirmation.
- [Get Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-developer-workflow.md): `GET /developer/v1/workflows/{definition_id}` — Read an active, historical, or draft workflow definition by identifier.
- [Update Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/update-developer-workflow.md): `PATCH /developer/v1/workflows/{definition_id}` — Update workflow metadata or an existing draft; published graphs are immutable.
- [Audit Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/audit-workflow.md): `POST /developer/v1/workflows/{definition_id}/audit` — Audit the unpublished draft and return actionable graph findings without mutation.
- [Discard Developer Workflow Draft](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/discard-developer-workflow-draft.md): `DELETE /developer/v1/workflows/{definition_id}/draft` — Discard the current unpublished draft while preserving published versions.
- [Create Developer Workflow Draft](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/create-developer-workflow-draft.md): `POST /developer/v1/workflows/{definition_id}/draft` — Create an editable draft from the workflow's currently active version.
- [Replace Developer Workflow Draft From Json](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/replace-developer-workflow-draft-from-json.md): `POST /developer/v1/workflows/{definition_id}/draft/from-json` — Replace the complete draft graph from canonical JSON without publishing it.
- [Export Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/export-developer-workflow.md): `GET /developer/v1/workflows/{definition_id}/export` — Export canonical workflow JSON suitable for validation or exact re-import.
- [Get Workflow Graph](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-graph.md): `GET /developer/v1/workflows/{definition_id}/graph` — Read the complete public-safe graph for a workflow's current target version.
- [Replace Workflow Graph](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/replace-workflow-graph.md): `PUT /developer/v1/workflows/{definition_id}/graph` — Replace the entire editable draft graph after public policy validation.
- [Insert Workflow Node After](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/insert-workflow-node-after.md): `POST /developer/v1/workflows/{definition_id}/nodes/after` — Insert one node after an existing draft node and optionally rewire its targets.
- [Insert Workflow Node Before](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/insert-workflow-node-before.md): `POST /developer/v1/workflows/{definition_id}/nodes/before` — Insert one node before an existing draft node and optionally rewire its sources.
- [Delete Workflow Node](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/delete-workflow-node.md): `DELETE /developer/v1/workflows/{definition_id}/nodes/{node_id}` — Delete one draft node and optionally reconnect its incoming and outgoing edges.
- [Get Workflow Node Details](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-node-details.md): `GET /developer/v1/workflows/{definition_id}/nodes/{node_id}` — Read one node's configuration, connections, and public action metadata.
- [Update Workflow Node](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/update-workflow-node.md): `PATCH /developer/v1/workflows/{definition_id}/nodes/{node_id}` — Patch selected fields on one node in the editable draft graph.
- [Get Workflow Node Context](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-node-context.md): `GET /developer/v1/workflows/{definition_id}/nodes/{node_id}/context` — Read one node with its immediate upstream and downstream graph context.
- [Get Workflow Outline](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-outline.md): `GET /developer/v1/workflows/{definition_id}/outline` — Read a compact node-and-edge outline before requesting larger graph details.
- [Publish Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/publish-developer-workflow.md): `POST /developer/v1/workflows/{definition_id}/publish` — Audit and publish the current draft as an immutable active version. Inherits the same confirm_removed_nodes / 409 removed_nodes_require_confirmation contract as the interactive publish route (see publish_draft); confirmation retries must echo the returned removed_nodes_confirmation.
- [List Workflow Runs Safe](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-runs-safe.md): `GET /developer/v1/workflows/{definition_id}/runs` — Return run navigation metadata without trigger or node-result values.
- [Run Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/run-developer-workflow.md): `POST /developer/v1/workflows/{definition_id}/runs` — Start an active published workflow with idempotent retry semantics.
- [Read Workflow Run Node Shape](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-run-node-shape.md): `GET /developer/v1/workflows/{definition_id}/runs/{run_id}/nodes/{node_id}` — Return status and value-free output shapes for one executed node.
- [List Developer Workflow Versions](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-developer-workflow-versions.md): `GET /developer/v1/workflows/{definition_id}/versions` — List immutable published versions and draft metadata for one workflow.
- [Get Developer Workflow Version](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-developer-workflow-version.md): `GET /developer/v1/workflows/{definition_id}/versions/{version_id}` — Read one immutable workflow version without changing the active version.
- [Revert Developer Workflow Version](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/revert-developer-workflow-version.md): `POST /developer/v1/workflows/{definition_id}/versions/{version_id}/revert` — Create a new editable draft copied from a historical workflow version.
- [Get Developer Workflow Webhook Endpoint](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-developer-workflow-webhook-endpoint.md): `GET /developer/v1/workflows/{definition_id}/webhook-endpoint` — Return an active, published webhook URL; never exposed as an MCP tool.
Recorded tool call
{
"type": "tool_call",
"seq": 46,
"ts": "2026-10-22T17:20:28.235Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 20 curl -sSL \"https://genhealth.ai/docs/workflows.md\" | head -120"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-bec951747f809c0d",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 48,
"ts": "2026-10-22T17:20:29.039Z",
"turn": 1,
"output": {
"content": [
{
"text": "# GenHealth Workflow Developer API\n\n> Create, version, audit, publish, run, and maintain UMPA workflows directly against the core ETL API. The capability and action-discovery operations are optimized for AI agents.\n\nSource: [https://genhealth.ai/docs/workflows](https://genhealth.ai/docs/workflows)\n\n> **Workflow API access**\n>\n> Use a GenHealth API key with the workflow scope required by each operation. Copy the request examples to call the API from your server; interactive requests are not enabled in this reference.\n\n## Build workflow automations\n\nDiscover supported integrations and actions, validate canonical workflow JSON, manage drafts and immutable versions, inspect graphs, publish viable workflows, and operate organization-scoped workflow runs.\n\n- [Provider workflows across specialties](https://genhealth.ai/docs/workflows/provider-workflows.md): Scope referral intake, clearance, authorization, and recurring care using the right system contracts.\n- [Build and run your first workflow](https://genhealth.ai/docs/workflows/agent-quickstart.md): Use REST or MCP, validate a synthetic graph, publish it, and inspect an idempotent run.\n- [Discover capabilities](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-capabilities.md): Inspect controls, node types, expressions, integrations, and action schemas.\n- [Find workflow functions](https://genhealth.ai/docs/workflows/integrations.md): Search the actions available for use in a workflow definition.\n- [Create workflows](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/create-developer-workflow.md): Create organization-scoped workflow records and validate their JSON first.\n- [Publish and run](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/run-developer-workflow.md): Publish immutable versions and start idempotent workflow runs.\n\n## Workflow runs, integrations, and events\n\nThese terms describe what starts a workflow, how it works with other systems, and how its step attempts are modeled.\n\n### Workflow run\n\nOne run begins each time a workflow is triggered—by a person, schedule, API request, file upload, or webhook—and ends when it completes, fails, or is canceled. Branches, waits, loops, and step retries remain part of that run; a child workflow starts a separate run.\n\n### Integration\n\nAn integration connects a workflow to another system or exposes a GenHealth capability. It provides actions—tools such as finding a record, extracting data, or sending an update—that can be used as workflow steps. Some integrations require a configured connection or credentials.\n\n[Browse available integrations and actions](https://genhealth.ai/docs/workflows/integrations.md)\n\n### Modeled internal event\n\nA planning unit for work performed inside a run. In the historical benchmark, each event represents one successful or failed attempt to execute a workflow step, after replay duplicates are removed. Loops and retries can add events; an event does not map one-to-one to a visible block, tool call, or external request.\n\n## Contract summary\n\n| Property | Value |\n| --- | --- |\n| OpenAPI | 3.1.0 |\n| API version | 1.0.0 |\n| Operations | 37 |\n| Component schemas | 62 |\n| Authentication | HTTP bearer token with operation-specific workflow scopes |\n\n## Organization isolation\n\nWorkflow definitions, versions, graphs, webhook endpoints, and runs are resolved within the organization carried by the authenticated credential. An identifier from another organization does not grant access.\n\n## Operations\n\n- [Search Workflow Actions](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/search-workflow-actions.md): `GET /developer/v1/actions` — Search tenant-permitted platform actions; connection setup is reported separately.\n- [Get Workflow Action](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-action.md): `GET /developer/v1/actions/{handler}` — Return the complete first-pass schema for one exact public action handler.\n- [List Workflow Action Field Options](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-action-field-options.md): `GET /developer/v1/actions/{handler}/fields/{field}/options` — Resolve dynamic choices for one action field without exposing credentials.\n- [Get Workflow Capabilities](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-capabilities.md): `GET /developer/v1/capabilities` — Return the established strict V1 workflow capability manifest.\n- [Get Workflow Capabilities V2](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-workflow-capabilities-v2.md): `GET /developer/v1/capabilities/v2` — Describe graph controls plus the public webhook lifecycle contract.\n- [List Workflow Integration Connections](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-integration-connections.md): `GET /developer/v1/integration-connections` — Report whether each public integration has credentials, without exposing them.\n- [List Workflow Integrations](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-integrations.md): `GET /developer/v1/integrations` — List tenant-permitted public integrations; this does not assert connection setup.\n- [Cancel Developer Workflow Run](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/cancel-developer-workflow-run.md): `POST /developer/v1/runs/{run_id}/cancel` — Request cancellation of one organization-owned public-compatible workflow run.\n- [List Developer Workflows](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-developer-workflows.md): `GET /developer/v1/workflows` — List the same organization-scoped workflows shown in UMPA.\n- [Create Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/create-developer-workflow.md): `POST /developer/v1/workflows` — Create a workflow directly in the core ETL store used by UMPA.\n- [Import Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/import-developer-workflow.md): `POST /developer/v1/workflows/import` — Import canonical JSON as an inactive UMPA workflow with published version 1.\n- [Validate Workflow Definition](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/validate-workflow-definition.md): `POST /developer/v1/workflows/validate` — Preflight canonical workflow JSON against save, audit, and public API rules. This operation does not persist anything. A definition that fails validation still returns HTTP 200 with ``viable=false`` and machine-actionable findings.\n- [Delete Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/delete-developer-workflow.md): `DELETE /developer/v1/workflows/{definition_id}` — Soft-delete a workflow after publish-scope authorization and explicit confirmation.\n- [Get Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-developer-workflow.md): `GET /developer/v1/workflows/{definition_id}` — Read an active, historical, or draft workflow definition by identifier.\n- [Update Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/update-developer-workflow.md): `PATCH /developer/v1/workflows/{definition_id}` — Update workflow metadata or an existing draft; published graphs are immutable.\n- [Audit Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/audit-workflow.md): `POST /developer/v1/workflows/{definition_id}/audit` — Audit the unpublished draft and return actionable graph findings without mutation.\n- [Discard Developer Workflow Draft](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/discard-developer-workflow-draft.md): `DELETE /developer/v1/workflows/{definition_id}/draft` — Discard the current unpublished draft while preserving published versions.\n- [Create Developer Workflow Draft](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/create-developer-workflow-draft.md): `POST /developer/v1/workflows/{definition_id}/draft` — Create an editable draft from the workflow's currently active version.\n- [Replace Developer Workflow Draft From Json](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/replace-developer-workflow-draft-from-json.md): `POST /developer/v1/workflows/{definition_id}/draft/from-json` — Replace the complete draft graph from canonical JSON without publishing it.\n- [Export Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/export-developer-workflow.md): `GET /developer/v1/workflows/{definition_id}/export` — Export canonical workflow JSON suitable for validation or exact re-import.\n- [Get Workflow Graph](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-graph.md): `GET /developer/v1/workflows/{definition_id}/graph` — Read the complete public-safe graph for a workflow's current target version.\n- [Replace Workflow Graph](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/replace-workflow-graph.md): `PUT /developer/v1/workflows/{definition_id}/graph` — Replace the entire editable draft graph after public policy validation.\n- [Insert Workflow Node After](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/insert-workflow-node-after.md): `POST /developer/v1/workflows/{definition_id}/nodes/after` — Insert one node after an existing draft node and optionally rewire its targets.\n- [Insert Workflow Node Before](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/insert-workflow-node-before.md): `POST /developer/v1/workflows/{definition_id}/nodes/before` — Insert one node before an existing draft node and optionally rewire its sources.\n- [Delete Workflow Node](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/delete-workflow-node.md): `DELETE /developer/v1/workflows/{definition_id}/nodes/{node_id}` — Delete one draft node and optionally reconnect its incoming and outgoing edges.\n- [Get Workflow Node Details](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-node-details.md): `GET /developer/v1/workflows/{definition_id}/nodes/{node_id}` — Read one node's configuration, connections, and public action metadata.\n- [Update Workflow Node](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/update-workflow-node.md): `PATCH /developer/v1/workflows/{definition_id}/nodes/{node_id}` — Patch selected fields on one node in the editable draft graph.\n- [Get Workflow Node Context](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-node-context.md): `GET /developer/v1/workflows/{definition_id}/nodes/{node_id}/context` — Read one node with its immediate upstream and downstream graph context.\n- [Get Workflow Outline](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-outline.md): `GET /developer/v1/workflows/{definition_id}/outline` — Read a compact node-and-edge outline before requesting larger graph details.\n- [Publish Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/publish-developer-workflow.md): `POST /developer/v1/workflows/{definition_id}/publish` — Audit and publish the current draft as an immutable active version. Inherits the same confirm_removed_nodes / 409 removed_nodes_require_confirmation contract as the interactive publish route (see publish_draft); confirmation retries must echo the returned removed_nodes_confirmation.\n- [List Workflow Runs Safe](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-workflow-runs-safe.md): `GET /developer/v1/workflows/{definition_id}/runs` — Return run navigation metadata without trigger or node-result values.\n- [Run Developer Workflow](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/run-developer-workflow.md): `POST /developer/v1/workflows/{definition_id}/runs` — Start an active published workflow with idempotent retry semantics.\n- [Read Workflow Run Node Shape](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/read-workflow-run-node-shape.md): `GET /developer/v1/workflows/{definition_id}/runs/{run_id}/nodes/{node_id}` — Return status and value-free output shapes for one executed node.\n- [List Developer Workflow Versions](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/list-developer-workflow-versions.md): `GET /developer/v1/workflows/{definition_id}/versions` — List immutable published versions and draft metadata for one workflow.\n- [Get Developer Workflow Version](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-developer-workflow-version.md): `GET /developer/v1/workflows/{definition_id}/versions/{version_id}` — Read one immutable workflow version without changing the active version.\n- [Revert Developer Workflow Version](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/revert-developer-workflow-version.md): `POST /developer/v1/workflows/{definition_id}/versions/{version_id}/revert` — Create a new editable draft copied from a historical workflow version.\n- [Get Developer Workflow Webhook Endpoint](https://genhealth.ai/docs/workflows/api-reference/v1/workflow-developer-api/get-developer-workflow-webhook-endpoint.md): `GET /developer/v1/workflows/{definition_id}/webhook-endpoint` — Return an active, published webhook URL; never exposed as an MCP tool.\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-bec951747f809c0d",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Alright, let's build the repo example. Structure:
/sandbox/repo/ README.md — what this is, pricing overview, manageability notes, how to run it genhealth_quickstart.py — minimal standard-library-only client: doctor (connectivity/auth check), validate, run (the full lifecycle), inspect examples/synthetic-routing.workflow.json — synthetic graph (derived from the docs)
Keep the script simple while making it safe: no automatic retries on writes, maintain idempotency keys in the state file.
After that, run python3 genhealth_quickstart.py doctor to show the blocked state (no API key → clear message). Might also be able to demo the 401 path with a dummy key... Note: using a fake key against the live API will return 401 — harmless, and shows error handling works. That's fine, it's a single request. Let's do that to validate the script's error handling.
Also, validate the JSON locally without network.
Write the script.
GenHealth.ai is real and has a public developer portal. Let me build the example in the repo.
cat /tmp/ghx/agent-smoke-test.json
{
{
"kind": "genhealth.workflow_definition",
"schema_version": 1,
"workflow": {
"name": "Agent quickstart: synthetic routing",
"description": "Synthetic execution check; no healthcare system reads or writes.",
"nodes": [
{ "id": "received", "type": "comment", "name": "Synthetic request", "config": { "heading": "Start", "body": "Inputs are supplied in trigger_data." } },
{ "id": "route", "type": "if", "name": "Ready?", "config": { "condition": "{{trigger.default.ready}}" } },
{ "id": "ready", "type": "comment", "name": "Ready outcome", "config": { "heading": "Ready", "body": "The true branch ran." } },
{ "id": "review", "type": "comment", "name": "Review outcome", "config": { "heading": "Review", "body": "The false branch ran; no external review task was created." } }
],
"edges": [
{ "source_node_id": "received", "source_output": "default", "target_node_id": "route", "target_input": "default" },
{ "source_node_id": "route", "source_output": "true", "target_node_id": "ready", "target_input": "default" },
{ "source_node_id": "route", "source_output": "false", "target_node_id": "review", "target_input": "default" }
]
}
}
Recorded tool call
{
"type": "tool_call",
"seq": 52,
"ts": "2026-10-22T17:20:31.997Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cat /tmp/ghx/agent-smoke-test.json"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-bb894f28572a13b9",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 53,
"ts": "2026-10-22T17:20:31.997Z",
"turn": 1,
"output": {
"content": [
{
"text": "{\n \"kind\": \"genhealth.workflow_definition\",\n \"schema_version\": 1,\n \"workflow\": {\n \"name\": \"Agent quickstart: synthetic routing\",\n \"description\": \"Synthetic execution check; no healthcare system reads or writes.\",\n \"nodes\": [\n { \"id\": \"received\", \"type\": \"comment\", \"name\": \"Synthetic request\", \"config\": { \"heading\": \"Start\", \"body\": \"Inputs are supplied in trigger_data.\" } },\n { \"id\": \"route\", \"type\": \"if\", \"name\": \"Ready?\", \"config\": { \"condition\": \"{{trigger.default.ready}}\" } },\n { \"id\": \"ready\", \"type\": \"comment\", \"name\": \"Ready outcome\", \"config\": { \"heading\": \"Ready\", \"body\": \"The true branch ran.\" } },\n { \"id\": \"review\", \"type\": \"comment\", \"name\": \"Review outcome\", \"config\": { \"heading\": \"Review\", \"body\": \"The false branch ran; no external review task was created.\" } }\n ],\n \"edges\": [\n { \"source_node_id\": \"received\", \"source_output\": \"default\", \"target_node_id\": \"route\", \"target_input\": \"default\" },\n { \"source_node_id\": \"route\", \"source_output\": \"true\", \"target_node_id\": \"ready\", \"target_input\": \"default\" },\n { \"source_node_id\": \"route\", \"source_output\": \"false\", \"target_node_id\": \"review\", \"target_input\": \"default\" }\n ]\n }\n}\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-bb894f28572a13b9",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Please write the file.
mkdir -p /sandbox/repo/examples && cp /tmp/ghx/agent-smoke-test.json /sandbox/repo/examples/synthetic-routing.workflow.json && ls -R /sandbox/repo
/sandbox/repo:
/sandbox/repo: examples /sandbox/repo/examples: synthetic-routing.workflow.json
Recorded tool call
{
"type": "tool_call",
"seq": 56,
"ts": "2026-10-22T17:20:33.345Z",
"name": "bash",
"turn": 1,
"input": {
"command": "mkdir -p /sandbox/repo/examples && cp /tmp/ghx/agent-smoke-test.json /sandbox/repo/examples/synthetic-routing.workflow.json && ls -R /sandbox/repo"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9ea26c11b2a1eb54",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 57,
"ts": "2026-10-22T17:20:33.345Z",
"turn": 1,
"output": {
"content": [
{
"text": "/sandbox/repo:\nexamples\n\n/sandbox/repo/examples:\nsynthetic-routing.workflow.json\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9ea26c11b2a1eb54",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Wait, ls -R didn't show .gitignore/.git (hidden files). Oh well.
Alright, let's write genhealth_quickstart.py.
File edits
1 file
Writtengenhealth_quickstart.pyView changes
/sandbox/repo/genhealth_quickstart.py
Written content · previous contents were not recorded
#!/usr/bin/env python3"""Minimal GenHealth.ai developer example. Python 3 standard library only.Talks to the hosted GenHealth Workflow Developer API:REST base : https://api.umpa.genhealth.ai/developer/v1Auth : Authorization: Bearer $GENHEALTH_API_KEYCommandsdoctor connectivity + auth + capability probe (read-only)validate <definition.json> preflight a workflow definition (persists nothing)run <definition.json> validate -> import -> draft -> publish -> 1 run(resumable via --state; synthetic graphs only)inspect show the run recorded in --state (no resubmit)No local services, no docker, no third-party packages, no background processes.Writes are never auto-retried: each mutating step records intent in the statefile first, so an interrupted run can be reconciled instead of duplicated."""import argparseimport hashlibimport jsonimport osimport sysfrom pathlib import Pathfrom urllib.error import HTTPError, URLErrorfrom urllib.parse import urlencodefrom urllib.request import Request, urlopenfrom uuid import UUID, uuid4DEFAULT_BASE = "https://api.umpa.genhealth.ai"DEV_PREFIX = "/developer/v1"TERMINAL = {"completed", "failed", "cancelled"}# This example only executes graphs that cannot touch a healthcare system.SYNTHETIC_NODE_TYPES = {"comment", "if"}HINTS = {401: "GENHEALTH_API_KEY missing/expired/invalid - check the bearer token.",403: "Key lacks the scope or plan feature for this operation ""(workflow:read/write/publish/run + workflows plan).",404: "Resource not visible to the organization resolved from your key.",409: "Publish conflict (e.g. removed nodes need explicit confirmation).",422: "Request body rejected - inspect the error details and fix the payload.",}class ApiError(RuntimeError):"""Bounded diagnostic; never echoes response bodies or credentials."""class Client:def __init__(self, base_url, api_key, timeout=30):if not base_url.startswith("https://"):raise ApiError("Refusing a non-HTTPS GENHEALTH_API_BASE: %s" % base_url)if not api_key:raise ApiError("GENHEALTH_API_KEY is not set. Get an organization-bound key:\n"" 1. sign up at https://umpa.genhealth.ai/api/auth/login?screen_hint=signup\n"" 2. create a key at https://genhealth.ai/account/api-keys\n"" 3. export GENHEALTH_API_KEY=... (never commit it)")self.base_url = base_url.rstrip("/")self.api_key = api_keyself.timeout = timeoutdef request(self, method, path, body=None):request = Request(self.base_url + DEV_PREFIX + path,data=json.dumps(body).encode() if body is not None else None,headers={"Authorization": "Bearer " + self.api_key,"Content-Type": "application/json","Accept": "application/json",},method=method,)try:with urlopen(request, timeout=self.timeout) as response:payload = response.read()return json.loads(payload) if payload else {}except HTTPError as error:hint = HINTS.get(error.code, "See /docs/workflows/operations.")raise ApiError("HTTP %s on %s %s -> %s (no automatic write retry attempted)"% (error.code, method, path, hint)) from Noneexcept (URLError, TimeoutError, OSError) as error:raise ApiError("Transport failure (%s). Outcome of any write is unknown: keep the ""state file and reconcile before retrying." % error.__class__.__name__) from Nonedef save_state(path, state):"""Atomic, owner-only write so an interrupted step never leaves partial JSON."""tmp = path.with_suffix(path.suffix + ".tmp")fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)with os.fdopen(fd, "w") as stream:json.dump(state, stream, indent=2, sort_keys=True)tmp.replace(path)def load_definition(path):definition = json.loads(Path(path).read_text())nodes = definition.get("workflow", {}).get("nodes") or []if not nodes:raise ApiError("Definition has no nodes; refusing to submit it.")unsafe = sorted({n.get("type") for n in nodes} - SYNTHETIC_NODE_TYPES)if unsafe:raise ApiError("This example runs synthetic comment/if graphs only; found %s. ""Real integration actions need provisioned connections and a review ""of /docs/workflows/action-contracts." % ", ".join(map(str, unsafe)))return definitiondef doctor(client):"""Read-only probe: proves origin, auth, scopes, and plan feature."""caps = client.request("GET", "/capabilities/v2")integrations = client.request("GET", "/integrations")connections = client.request("GET", "/integration-connections")workflows = client.request("GET", "/workflows?" + urlencode({"limit": 5}))summary = {"base_url": client.base_url,"auth": "ok","capability_keys": sorted(caps)[:12],"node_types": sorted((caps.get("node_types") or caps.get("nodes") or {})if isinstance(caps.get("node_types") or caps.get("nodes"), dict)else (caps.get("node_types") or []))[:20],"integrations_visible": len(integrations.get("integrations", [])),"connections_configured": sum(1 for c in connections.get("integration_connections", []) if c.get("configured")),"workflows_visible": len(workflows.get("workflows", [])),}print(json.dumps(summary, indent=2))print("doctor: OK - read-only calls succeeded; no workflow was created.")def validate(client, definition):"""HTTP 200 can still mean viable=false; check the findings, not the status."""result = client.request("POST", "/workflows/validate", {"definition": definition})viable, readiness = result.get("viable"), result.get("readiness")print(json.dumps({"viable": viable,"readiness": readiness,"schema_errors": result.get("schema_errors", []),"findings": result.get("findings", []),}, indent=2))if viable is not True or readiness != "ready":raise ApiError("Preflight is not ready; nothing was created. Fix the findings above.")print("validate: preflight ready; no workflow was created.")return resultdef run(client, definition, state_path):fingerprint = hashlib.sha256(json.dumps(definition, sort_keys=True).encode()).hexdigest()state = json.loads(state_path.read_text()) if state_path.exists() else {"stage": "new", "base_url": client.base_url, "definition_sha256": fingerprint,}if state.get("base_url") != client.base_url or state.get("definition_sha256") != fingerprint:raise ApiError("State file belongs to another origin or definition; do not reuse it.")def current():return client.request("GET", "/workflows/" + str(UUID(state["workflow_id"])))def path_of(suffix=""):return "/workflows/" + str(UUID(state["workflow_id"])) + suffixvalidate(client, definition)if state["stage"] in {"import_pending", "draft_pending", "publish_pending", "run_pending"}:raise ApiError("Stage %r means a previous write's outcome is unknown. Reconcile with ""GET /workflows, /export and /versions, then set the confirmed stage in %s. ""Do not re-import with a fresh state file." % (state["stage"], state_path))if state["stage"] == "new":state["stage"] = "import_pending"save_state(state_path, state)imported = client.request("POST", "/workflows/import", definition)state.update(workflow_id=str(UUID(imported["workflow"]["id"])), stage="imported")save_state(state_path, state)print("imported workflow %s" % state["workflow_id"])if state["stage"] == "imported":state["stage"] = "draft_pending"save_state(state_path, state)client.request("POST", path_of("/draft"))state["stage"] = "drafted"save_state(state_path, state)if state["stage"] == "drafted":state["stage"] = "publish_pending"save_state(state_path, state)client.request("POST", path_of("/publish"), {})state["stage"] = "published"save_state(state_path, state)if state["stage"] == "published":workflow = current()state.update(stage="run_pending",version_id=workflow["active_version_id"],# Idempotency key is generated once and persisted: a retry must reuse it.run_request={"idempotency_key": str(uuid4()), "trigger_data": {"ready": True}},)save_state(state_path, state)if state["stage"] == "run_pending":if current().get("active_version_id") != state["version_id"]:raise ApiError("Active version changed under the pending run; reconcile before retrying.")accepted = client.request("POST", path_of("/runs"), state["run_request"])state.update(stage="accepted", run_id=str(UUID(accepted["run_id"])))save_state(state_path, state)if state["stage"] != "accepted":raise ApiError("Unexpected stage %r in %s" % (state["stage"], state_path))print(json.dumps({"workflow_id": state["workflow_id"],"run_id": state["run_id"],"status": "accepted (202) - acceptance is not completion; run `inspect`",}, indent=2))def inspect(client, state):if not state.get("run_id") or state.get("base_url") != client.base_url:raise ApiError("No accepted run for this origin; run `run` first.")workflow_id, run_id = str(UUID(state["workflow_id"])), str(UUID(state["run_id"]))listing = client.request("GET", "/workflows/%s/runs?%s" % (workflow_id, urlencode({"limit": 25})))found = next((r for r in listing.get("runs", []) if r.get("run_id") == run_id), None)if found is None:raise ApiError("Run not in the first page; filter by since/until/status. Do not resubmit.")print(json.dumps({"workflow_id": workflow_id,"run_id": run_id,"status": found.get("status"),"terminal": found.get("status") in TERMINAL,}, indent=2))if found.get("status") in {"failed", "cancelled"}:raise ApiError("Run ended without completing. Inspect node shapes with ""GET /workflows/%s/runs/%s/nodes/{node_id} (statuses only, no values)."% (workflow_id, run_id))if found.get("status") == "completed":for node_id in ("route", "ready", "review"):shape = client.request("GET", "/workflows/%s/runs/%s/nodes/%s" % (workflow_id, run_id, node_id))print(" node %-7s -> %s" % (node_id, shape.get("status", shape)))def main():parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)parser.add_argument("command", choices=["doctor", "validate", "run", "inspect"])parser.add_argument("definition", nargs="?", help="workflow definition JSON (validate/run)")parser.add_argument("--state", type=Path, default=Path("genhealth-example-state.json"))args = parser.parse_args()client = Client(os.environ.get("GENHEALTH_API_BASE", DEFAULT_BASE), os.environ.get("GENHEALTH_API_KEY"))if args.command == "doctor":doctor(client)elif args.command == "inspect":inspect(client, json.loads(args.state.read_text()))else:if not args.definition:parser.error("%s requires a definition file" % args.command)definition = load_definition(args.definition)if args.command == "validate":validate(client, definition)else:run(client, definition, args.state)if __name__ == "__main__":try:main()except ApiError as error:print("error: %s" % error, file=sys.stderr)sys.exit(1)except (OSError, ValueError, KeyError, TypeError) as error:# Local file/JSON diagnostics can contain paths or contents; keep it generic.print("error: invalid local state, definition, or API response (%s); inspect it locally."% error.__class__.__name__, file=sys.stderr)sys.exit(1)
Source: write · chatcmpl-tool-9f1a6ce2dc48d1c5
Recorded tool call
{
"type": "tool_call",
"seq": 60,
"ts": "2026-10-22T17:20:51.351Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/genhealth_quickstart.py",
"content": "#!/usr/bin/env python3\n\"\"\"Minimal GenHealth.ai developer example. Python 3 standard library only.\n\nTalks to the hosted GenHealth Workflow Developer API:\n REST base : https://api.umpa.genhealth.ai/developer/v1\n Auth : Authorization: Bearer $GENHEALTH_API_KEY\n\nCommands\n doctor connectivity + auth + capability probe (read-only)\n validate <definition.json> preflight a workflow definition (persists nothing)\n run <definition.json> validate -> import -> draft -> publish -> 1 run\n (resumable via --state; synthetic graphs only)\n inspect show the run recorded in --state (no resubmit)\n\nNo local services, no docker, no third-party packages, no background processes.\nWrites are never auto-retried: each mutating step records intent in the state\nfile first, so an interrupted run can be reconciled instead of duplicated.\n\"\"\"\n\nimport argparse\nimport hashlib\nimport json\nimport os\nimport sys\nfrom pathlib import Path\nfrom urllib.error import HTTPError, URLError\nfrom urllib.parse import urlencode\nfrom urllib.request import Request, urlopen\nfrom uuid import UUID, uuid4\n\nDEFAULT_BASE = \"https://api.umpa.genhealth.ai\"\nDEV_PREFIX = \"/developer/v1\"\nTERMINAL = {\"completed\", \"failed\", \"cancelled\"}\n# This example only executes graphs that cannot touch a healthcare system.\nSYNTHETIC_NODE_TYPES = {\"comment\", \"if\"}\nHINTS = {\n 401: \"GENHEALTH_API_KEY missing/expired/invalid - check the bearer token.\",\n 403: \"Key lacks the scope or plan feature for this operation \"\n \"(workflow:read/write/publish/run + workflows plan).\",\n 404: \"Resource not visible to the organization resolved from your key.\",\n 409: \"Publish conflict (e.g. removed nodes need explicit confirmation).\",\n 422: \"Request body rejected - inspect the error details and fix the payload.\",\n}\n\n\nclass ApiError(RuntimeError):\n \"\"\"Bounded diagnostic; never echoes response bodies or credentials.\"\"\"\n\n\nclass Client:\n def __init__(self, base_url, api_key, timeout=30):\n if not base_url.startswith(\"https://\"):\n raise ApiError(\"Refusing a non-HTTPS GENHEALTH_API_BASE: %s\" % base_url)\n if not api_key:\n raise ApiError(\n \"GENHEALTH_API_KEY is not set. Get an organization-bound key:\\n\"\n \" 1. sign up at https://umpa.genhealth.ai/api/auth/login?screen_hint=signup\\n\"\n \" 2. create a key at https://genhealth.ai/account/api-keys\\n\"\n \" 3. export GENHEALTH_API_KEY=... (never commit it)\"\n )\n self.base_url = base_url.rstrip(\"/\")\n self.api_key = api_key\n self.timeout = timeout\n\n def request(self, method, path, body=None):\n request = Request(\n self.base_url + DEV_PREFIX + path,\n data=json.dumps(body).encode() if body is not None else None,\n headers={\n \"Authorization\": \"Bearer \" + self.api_key,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n method=method,\n )\n try:\n with urlopen(request, timeout=self.timeout) as response:\n payload = response.read()\n return json.loads(payload) if payload else {}\n except HTTPError as error:\n hint = HINTS.get(error.code, \"See /docs/workflows/operations.\")\n raise ApiError(\n \"HTTP %s on %s %s -> %s (no automatic write retry attempted)\"\n % (error.code, method, path, hint)\n ) from None\n except (URLError, TimeoutError, OSError) as error:\n raise ApiError(\n \"Transport failure (%s). Outcome of any write is unknown: keep the \"\n \"state file and reconcile before retrying.\" % error.__class__.__name__\n ) from None\n\n\ndef save_state(path, state):\n \"\"\"Atomic, owner-only write so an interrupted step never leaves partial JSON.\"\"\"\n tmp = path.with_suffix(path.suffix + \".tmp\")\n fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)\n with os.fdopen(fd, \"w\") as stream:\n json.dump(state, stream, indent=2, sort_keys=True)\n tmp.replace(path)\n\n\ndef load_definition(path):\n definition = json.loads(Path(path).read_text())\n nodes = definition.get(\"workflow\", {}).get(\"nodes\") or []\n if not nodes:\n raise ApiError(\"Definition has no nodes; refusing to submit it.\")\n unsafe = sorted({n.get(\"type\") for n in nodes} - SYNTHETIC_NODE_TYPES)\n if unsafe:\n raise ApiError(\n \"This example runs synthetic comment/if graphs only; found %s. \"\n \"Real integration actions need provisioned connections and a review \"\n \"of /docs/workflows/action-contracts.\" % \", \".join(map(str, unsafe))\n )\n return definition\n\n\ndef doctor(client):\n \"\"\"Read-only probe: proves origin, auth, scopes, and plan feature.\"\"\"\n caps = client.request(\"GET\", \"/capabilities/v2\")\n integrations = client.request(\"GET\", \"/integrations\")\n connections = client.request(\"GET\", \"/integration-connections\")\n workflows = client.request(\"GET\", \"/workflows?\" + urlencode({\"limit\": 5}))\n summary = {\n \"base_url\": client.base_url,\n \"auth\": \"ok\",\n \"capability_keys\": sorted(caps)[:12],\n \"node_types\": sorted(\n (caps.get(\"node_types\") or caps.get(\"nodes\") or {})\n if isinstance(caps.get(\"node_types\") or caps.get(\"nodes\"), dict)\n else (caps.get(\"node_types\") or [])\n )[:20],\n \"integrations_visible\": len(integrations.get(\"integrations\", [])),\n \"connections_configured\": sum(\n 1 for c in connections.get(\"integration_connections\", []) if c.get(\"configured\")\n ),\n \"workflows_visible\": len(workflows.get(\"workflows\", [])),\n }\n print(json.dumps(summary, indent=2))\n print(\"doctor: OK - read-only calls succeeded; no workflow was created.\")\n\n\ndef validate(client, definition):\n \"\"\"HTTP 200 can still mean viable=false; check the findings, not the status.\"\"\"\n result = client.request(\"POST\", \"/workflows/validate\", {\"definition\": definition})\n viable, readiness = result.get(\"viable\"), result.get(\"readiness\")\n print(json.dumps({\n \"viable\": viable,\n \"readiness\": readiness,\n \"schema_errors\": result.get(\"schema_errors\", []),\n \"findings\": result.get(\"findings\", []),\n }, indent=2))\n if viable is not True or readiness != \"ready\":\n raise ApiError(\"Preflight is not ready; nothing was created. Fix the findings above.\")\n print(\"validate: preflight ready; no workflow was created.\")\n return result\n\n\ndef run(client, definition, state_path):\n fingerprint = hashlib.sha256(json.dumps(definition, sort_keys=True).encode()).hexdigest()\n state = json.loads(state_path.read_text()) if state_path.exists() else {\n \"stage\": \"new\", \"base_url\": client.base_url, \"definition_sha256\": fingerprint,\n }\n if state.get(\"base_url\") != client.base_url or state.get(\"definition_sha256\") != fingerprint:\n raise ApiError(\"State file belongs to another origin or definition; do not reuse it.\")\n\n def current():\n return client.request(\"GET\", \"/workflows/\" + str(UUID(state[\"workflow_id\"])))\n\n def path_of(suffix=\"\"):\n return \"/workflows/\" + str(UUID(state[\"workflow_id\"])) + suffix\n\n validate(client, definition)\n\n if state[\"stage\"] in {\"import_pending\", \"draft_pending\", \"publish_pending\", \"run_pending\"}:\n raise ApiError(\n \"Stage %r means a previous write's outcome is unknown. Reconcile with \"\n \"GET /workflows, /export and /versions, then set the confirmed stage in %s. \"\n \"Do not re-import with a fresh state file.\" % (state[\"stage\"], state_path)\n )\n\n if state[\"stage\"] == \"new\":\n state[\"stage\"] = \"import_pending\"\n save_state(state_path, state)\n imported = client.request(\"POST\", \"/workflows/import\", definition)\n state.update(workflow_id=str(UUID(imported[\"workflow\"][\"id\"])), stage=\"imported\")\n save_state(state_path, state)\n print(\"imported workflow %s\" % state[\"workflow_id\"])\n\n if state[\"stage\"] == \"imported\":\n state[\"stage\"] = \"draft_pending\"\n save_state(state_path, state)\n client.request(\"POST\", path_of(\"/draft\"))\n state[\"stage\"] = \"drafted\"\n save_state(state_path, state)\n\n if state[\"stage\"] == \"drafted\":\n state[\"stage\"] = \"publish_pending\"\n save_state(state_path, state)\n client.request(\"POST\", path_of(\"/publish\"), {})\n state[\"stage\"] = \"published\"\n save_state(state_path, state)\n\n if state[\"stage\"] == \"published\":\n workflow = current()\n state.update(\n stage=\"run_pending\",\n version_id=workflow[\"active_version_id\"],\n # Idempotency key is generated once and persisted: a retry must reuse it.\n run_request={\"idempotency_key\": str(uuid4()), \"trigger_data\": {\"ready\": True}},\n )\n save_state(state_path, state)\n\n if state[\"stage\"] == \"run_pending\":\n if current().get(\"active_version_id\") != state[\"version_id\"]:\n raise ApiError(\"Active version changed under the pending run; reconcile before retrying.\")\n accepted = client.request(\"POST\", path_of(\"/runs\"), state[\"run_request\"])\n state.update(stage=\"accepted\", run_id=str(UUID(accepted[\"run_id\"])))\n save_state(state_path, state)\n\n if state[\"stage\"] != \"accepted\":\n raise ApiError(\"Unexpected stage %r in %s\" % (state[\"stage\"], state_path))\n print(json.dumps({\n \"workflow_id\": state[\"workflow_id\"],\n \"run_id\": state[\"run_id\"],\n \"status\": \"accepted (202) - acceptance is not completion; run `inspect`\",\n }, indent=2))\n\n\ndef inspect(client, state):\n if not state.get(\"run_id\") or state.get(\"base_url\") != client.base_url:\n raise ApiError(\"No accepted run for this origin; run `run` first.\")\n workflow_id, run_id = str(UUID(state[\"workflow_id\"])), str(UUID(state[\"run_id\"]))\n listing = client.request(\"GET\", \"/workflows/%s/runs?%s\" % (workflow_id, urlencode({\"limit\": 25})))\n found = next((r for r in listing.get(\"runs\", []) if r.get(\"run_id\") == run_id), None)\n if found is None:\n raise ApiError(\"Run not in the first page; filter by since/until/status. Do not resubmit.\")\n print(json.dumps({\n \"workflow_id\": workflow_id,\n \"run_id\": run_id,\n \"status\": found.get(\"status\"),\n \"terminal\": found.get(\"status\") in TERMINAL,\n }, indent=2))\n if found.get(\"status\") in {\"failed\", \"cancelled\"}:\n raise ApiError(\n \"Run ended without completing. Inspect node shapes with \"\n \"GET /workflows/%s/runs/%s/nodes/{node_id} (statuses only, no values).\"\n % (workflow_id, run_id)\n )\n if found.get(\"status\") == \"completed\":\n for node_id in (\"route\", \"ready\", \"review\"):\n shape = client.request(\n \"GET\", \"/workflows/%s/runs/%s/nodes/%s\" % (workflow_id, run_id, node_id)\n )\n print(\" node %-7s -> %s\" % (node_id, shape.get(\"status\", shape)))\n\n\ndef main():\n parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)\n parser.add_argument(\"command\", choices=[\"doctor\", \"validate\", \"run\", \"inspect\"])\n parser.add_argument(\"definition\", nargs=\"?\", help=\"workflow definition JSON (validate/run)\")\n parser.add_argument(\"--state\", type=Path, default=Path(\"genhealth-example-state.json\"))\n args = parser.parse_args()\n\n client = Client(os.environ.get(\"GENHEALTH_API_BASE\", DEFAULT_BASE), os.environ.get(\"GENHEALTH_API_KEY\"))\n if args.command == \"doctor\":\n doctor(client)\n elif args.command == \"inspect\":\n inspect(client, json.loads(args.state.read_text()))\n else:\n if not args.definition:\n parser.error(\"%s requires a definition file\" % args.command)\n definition = load_definition(args.definition)\n if args.command == \"validate\":\n validate(client, definition)\n else:\n run(client, definition, args.state)\n\n\nif __name__ == \"__main__\":\n try:\n main()\n except ApiError as error:\n print(\"error: %s\" % error, file=sys.stderr)\n sys.exit(1)\n except (OSError, ValueError, KeyError, TypeError) as error:\n # Local file/JSON diagnostics can contain paths or contents; keep it generic.\n print(\"error: invalid local state, definition, or API response (%s); inspect it locally.\"\n % error.__class__.__name__, file=sys.stderr)\n sys.exit(1)\n"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9f1a6ce2dc48d1c5",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 61,
"ts": "2026-10-22T17:20:51.351Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 12670 bytes to /sandbox/repo/genhealth_quickstart.py",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-9f1a6ce2dc48d1c5",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Testing: doctor without a key (should display a message about being blocked), doctor with a fake key (401 handling), local behavior of the validate guard.
cd /sandbox/repo && chmod +x genhealth_quickstart.py && python3 -m py_compile genhealth_quickstart.py && echo "compiles OK"
echo "=== 1) no key ==="; python3 genhealth_quickstart.py doctor; echo "exit=$?"
echo "=== 2) bogus key (expect clean 401) ==="; GENHEALTH_API_KEY=dummy-key-not-real python3 genhealth_quickstart.py doctor; echo "exit=$?"
echo "=== 3) validate with bogus key ==="; GENHEALTH_API_KEY=dummy-key-not-real python3 genhealth_quickstart.py validate examples/synthetic-routing.workflow.json; echo "exit=$?"
echo "=== 4) local guard: non-synthetic graph ==="; echo '{"kind":"genhealth.workflow_definition","schema_version":1,"workflow":{"name":"x","nodes":[{"id":"a","type":"brightree_create_sales_order"}]}}' > /tmp/unsafe.json; GENHEALTH_API_KEY=dummy python3 genhealth_quickstart.py validate /tmp/unsafe.json; echo "exit=$?"compiles OK
compiles OK === 1) no key === error: GENHEALTH_API_KEY is not set. Get an organization-bound key: 1. sign up at https://umpa.genhealth.ai/api/auth/login?screen_hint=signup 2. create a key at https://genhealth.ai/account/api-keys 3. export GENHEALTH_API_KEY=... (never commit it) exit=1 === 2) bogus key (expect clean 401) === error: HTTP 401 on GET /capabilities/v2 -> GENHEALTH_API_KEY missing/expired/invalid - check the bearer token. (no automatic write retry attempted) exit=1 === 3) validate with bogus key === error: HTTP 401 on POST /workflows/validate -> GENHEALTH_API_KEY missing/expired/invalid - check the bearer token. (no automatic write retry attempted) exit=1 === 4) local guard: non-synthetic graph === error: This example runs synthetic comment/if graphs only; found brightree_create_sales_order. Real integration actions need provisioned connections and a review of /docs/workflows/action-contracts. exit=1
Recorded tool call
{
"type": "tool_call",
"seq": 64,
"ts": "2026-10-22T17:20:54.232Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && chmod +x genhealth_quickstart.py && python3 -m py_compile genhealth_quickstart.py && echo \"compiles OK\"\necho \"=== 1) no key ===\"; python3 genhealth_quickstart.py doctor; echo \"exit=$?\"\necho \"=== 2) bogus key (expect clean 401) ===\"; GENHEALTH_API_KEY=dummy-key-not-real python3 genhealth_quickstart.py doctor; echo \"exit=$?\"\necho \"=== 3) validate with bogus key ===\"; GENHEALTH_API_KEY=dummy-key-not-real python3 genhealth_quickstart.py validate examples/synthetic-routing.workflow.json; echo \"exit=$?\"\necho \"=== 4) local guard: non-synthetic graph ===\"; echo '{\"kind\":\"genhealth.workflow_definition\",\"schema_version\":1,\"workflow\":{\"name\":\"x\",\"nodes\":[{\"id\":\"a\",\"type\":\"brightree_create_sales_order\"}]}}' > /tmp/unsafe.json; GENHEALTH_API_KEY=dummy python3 genhealth_quickstart.py validate /tmp/unsafe.json; echo \"exit=$?\""
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-89ed20188a4bf1cf",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 65,
"ts": "2026-10-22T17:21:01.721Z",
"turn": 1,
"output": {
"content": [
{
"text": "compiles OK\n=== 1) no key ===\nerror: GENHEALTH_API_KEY is not set. Get an organization-bound key:\n 1. sign up at https://umpa.genhealth.ai/api/auth/login?screen_hint=signup\n 2. create a key at https://genhealth.ai/account/api-keys\n 3. export GENHEALTH_API_KEY=... (never commit it)\nexit=1\n=== 2) bogus key (expect clean 401) ===\nerror: HTTP 401 on GET /capabilities/v2 -> GENHEALTH_API_KEY missing/expired/invalid - check the bearer token. (no automatic write retry attempted)\nexit=1\n=== 3) validate with bogus key ===\nerror: HTTP 401 on POST /workflows/validate -> GENHEALTH_API_KEY missing/expired/invalid - check the bearer token. (no automatic write retry attempted)\nexit=1\n=== 4) local guard: non-synthetic graph ===\nerror: This example runs synthetic comment/if graphs only; found brightree_create_sales_order. Real integration actions need provisioned connections and a review of /docs/workflows/action-contracts.\nexit=1\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-89ed20188a4bf1cf",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
everything working. Confirmed the API host is up and enforcing auth (401/403), and the error handling has been verified.
Also, I'll confirm that the sample JSON is valid JSON, and that the graph is internally consistent (that the edges reference nodes). Furthermore, add a README.md that includes pricing info + maintainability. Should I add a .gitignore entry for state files? The existing .gitignore doesn't cover genhealth-example-state.json. Add it (since it might contain workflow/run IDs). Yeah, let's append it.
cd /sandbox/repo && python3 - <<'EOF'
import json
d=json.load(open('examples/synthetic-routing.workflow.json'))
ids={n['id'] for n in d['workflow']['nodes']}
bad=[e for e in d['workflow']['edges'] if e['source_node_id'] not in ids or e['target_node_id'] not in ids]
print("nodes:",sorted(ids),"| dangling edges:",bad,"| kind:",d['kind'],"| schema_version:",d['schema_version'])
EOF
printf '\n# GenHealth example run state (workflow/run ids; never commit secrets here either)\ngenhealth-example-state.json\n*-state.json\n' >> .gitignore && tail -5 .gitignorenodes: ['ready', 'received', 'review', 'route'] | dangling edges: [] | kind: genhealth.workflow_definition | schema_version: 1
nodes: ['ready', 'received', 'review', 'route'] | dangling edges: [] | kind: genhealth.workflow_definition | schema_version: 1 .dart_tool/ # GenHealth example run state (workflow/run ids; never commit secrets here either) genhealth-example-state.json *-state.json
Recorded tool call
{
"type": "tool_call",
"seq": 68,
"ts": "2026-10-22T17:21:07.024Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && python3 - <<'EOF'\nimport json\nd=json.load(open('examples/synthetic-routing.workflow.json'))\nids={n['id'] for n in d['workflow']['nodes']}\nbad=[e for e in d['workflow']['edges'] if e['source_node_id'] not in ids or e['target_node_id'] not in ids]\nprint(\"nodes:\",sorted(ids),\"| dangling edges:\",bad,\"| kind:\",d['kind'],\"| schema_version:\",d['schema_version'])\nEOF\nprintf '\\n# GenHealth example run state (workflow/run ids; never commit secrets here either)\\ngenhealth-example-state.json\\n*-state.json\\n' >> .gitignore && tail -5 .gitignore"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-a5d770e1b9fef9c3",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 69,
"ts": "2026-10-22T17:21:07.024Z",
"turn": 1,
"output": {
"content": [
{
"text": "nodes: ['ready', 'received', 'review', 'route'] | dangling edges: [] | kind: genhealth.workflow_definition | schema_version: 1\n.dart_tool/\n\n# GenHealth example run state (workflow/run ids; never commit secrets here either)\ngenhealth-example-state.json\n*-state.json\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-a5d770e1b9fef9c3",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Note: Does *-state.json also match agent-smoke-state.json — that's fine, but does it also match examples/synthetic-routing.workflow.json? No (it doesn't end with -state.json). Good.
Next, the README: pricing overview + maintainability + usage instructions.
Facts regarding pricing (verified from the site):
- /pricing is 404, and there is no published price list anywhere on genhealth.ai. Sales-led ("Book Demo", "For Enterprise", contact).
- Free sandbox account: "Try GenHealth for free. Spin up a free account and run real PA, intake, and eligibility flows in the sandbox." / "Free sandbox — no credit card required."
- The ROI calculator calculates the "annual net benefit after deducting GenHealth.ai subscription costs" → paid tiers exist as subscription plans, but prices are not disclosed.
- Docs: the workflow developer API requires "the workflows plan feature" in addition to per-operation scopes (workflow:read/write/publish/run) → gated by plan. There is a mention of "Modeled internal events" — "a planning unit for work performed within a single run... in past benchmarks, each event represents one successful or failed attempt to execute a workflow step" → this is a unit of usage/metering, suggesting consumption-based metering, but the documentation does not explicitly state billing per event. This should be phrased cautiously: the docs define internal events as work units/benchmarks, but nowhere is pricing per event stated.
Maintainability for me (the agent): Easy points: the REST API has a live OpenAPI at /developer/openapi.json, an MCP transport at /developer/mcp (streamable HTTP), docs are viewable as markdown (.md suffix — agent-friendly), deterministic lifecycle endpoints, validate returns machine-actionable findings, a capabilities endpoint for discovery, idempotent execution, immutable published versions + drafts, per-node state inspection without exposing values. A Python client using only the standard library → no dependency management required. Hard points: obtaining credentials requires interactive signup + an org + provisioning of connections (Brightree/Bonafide, etc.) — impossible without a human; the workflows plan feature is gated; MCP tool discovery requires auth so I can't pre-check tools; write operations against real healthcare systems are high-risk and require human review; there is no publicly available local emulator, so every test needs credentials.
Write the README concisely.
File edits
1 file
WrittenREADME.mdView changes
/sandbox/repo/README.md
Written content · previous contents were not recorded
# GenHealth.ai quickstart exampleA minimal, dependency-free example that talks to the **hosted** GenHealth WorkflowDeveloper API. No docker, no local service stack, no long-running processes — justPython 3 standard library HTTP calls against `https://api.umpa.genhealth.ai`.## What GenHealth.ai isAI agents for healthcare revenue-cycle ops (intake, eligibility, prior authorization,resupplies, billing, denials/appeals) that operate over web portals, fax, and phone.The developer surface exposes that work as **workflows**: JSON graphs of nodes/edges,versioned, published, and run through REST or MCP.| Surface | URL || --- | --- || Docs (add `.md` for agent-friendly Markdown) | https://genhealth.ai/docs.md || REST base | `https://api.umpa.genhealth.ai/developer/v1` || Live OpenAPI 3.1 | `https://api.umpa.genhealth.ai/developer/openapi.json` || Swagger | `https://api.umpa.genhealth.ai/developer/docs` || MCP (streamable HTTP, same bearer header) | `https://api.umpa.genhealth.ai/developer/mcp` || Core resource API (cases/policies/codes) | `https://api.umpa.genhealth.ai/v2/...` |## Files- `genhealth_quickstart.py` — `doctor` / `validate` / `run` / `inspect` client (stdlib only).- `examples/synthetic-routing.workflow.json` — the canonical synthetic graph from the docs.It routes a boolean to one of two `comment` nodes. It creates **no** patient, order,claim, or authorization and needs no integration credentials.## Run it```bash# 1. Get an organization-bound API key (human step; see "Blocked on" below)# sign up: https://umpa.genhealth.ai/api/auth/login?screen_hint=signup# key page: https://genhealth.ai/account/api-keysexport GENHEALTH_API_KEY="<YOUR_API_KEY>"# 2. Read-only probe: auth, scopes, visible integrations/connectionspython3 genhealth_quickstart.py doctor# 3. Preflight the graph (persists nothing; HTTP 200 can still mean viable=false)python3 genhealth_quickstart.py validate examples/synthetic-routing.workflow.json# 4. validate -> import -> draft -> publish -> one idempotent runpython3 genhealth_quickstart.py run examples/synthetic-routing.workflow.json \--state genhealth-example-state.json# 5. Poll the run (never resubmits) until it is terminalpython3 genhealth_quickstart.py inspect --state genhealth-example-state.json```Required scopes: `workflow:read` for discovery/preflight; `workflow:write`,`workflow:publish`, `workflow:run` to create and execute. Your organization alsoneeds the **workflows plan feature** enabled.Safety properties baked into the client:- HTTPS-only origin; the API key never leaves the `Authorization` header or this machine.- Synthetic `comment`/`if` graphs only — a definition containing any real integrationaction (e.g. `brightree_*`) is rejected locally before any request is sent.- Writes are never auto-retried. Each mutating step records intent in the state file(`import_pending` → `imported` → …) so an interrupted run is reconciled, not duplicated.- The run's `idempotency_key` is generated once and persisted; retries reuse it.- State file is written atomically with `0600` permissions and is git-ignored.## Blocked on (why this can't run end-to-end unattended)`doctor` currently exits 1 with a credential hint. The API host is live and reachable(verified: it returns `401 Requires authentication` / `403 Not authenticated` without akey), but obtaining a key requires an interactive signup, a real organization, and theworkflows plan feature — an agent cannot self-provision that. With`GENHEALTH_API_KEY` exported, steps 2–5 need no further human input.## How pricing works**There is no published price list.** `genhealth.ai/pricing` is a 404 and no page on thesite states a dollar figure. What the site and docs do establish:- **Sales-led enterprise subscription.** Every conversion path is "Book a demo" /"Contact us"; the footer says "For Enterprise". Expect a negotiated annual contract,not self-serve checkout.- **Free sandbox tier.** "Try GenHealth free — spin up a free account and run real PA,intake, and eligibility flows in your sandbox. Free sandbox — no credit card." That isthe entry point this example targets.- **Subscription is a real cost line.** GenHealth's own ROI calculator reports "NetAnnual Benefit — your total annual benefit *after accounting for GenHealth.aisubscription costs*", i.e. you get the number from their sales/calculator, not a page.- **Plan-gated capabilities.** The Workflow Developer API requires the "workflows planfeature", so the developer surface itself is an entitlement above the base plan.- **Usage is metered in "modeled internal events."** The docs define one event as asuccessful or failed attempt to execute a workflow step (after replay-dedup), and noteloops/retries add events. The docs describe it as a *planning/benchmark* unit and neverpublish a per-event rate — treat it as the likely metering dimension to ask sales about.- **Scopes, not seats, gate the API.** Access is split per operation(`workflow:read/write/publish/run`), so cost/permission review is per-integration.Bottom line: free sandbox to build and test; production pricing is quote-only, and thenumber you should negotiate against is events/runs plus the workflows plan entitlement.## Is this easy for an agent to manage?**Yes for the developer loop, no for provisioning.**Easy:- Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discoverthe contract instead of guessing it (37 operations, 62 schemas).- Every docs page is available as plain Markdown by appending `.md` — trivially readable.- `GET /capabilities/v2`, `GET /actions` (search), and `GET /actions/{handler}` giveexact node types, expression syntax, and action input/output schemas before authoring.- `POST /workflows/validate` returns machine-actionable `schema_errors` / `findings` /`readiness` and persists nothing — a safe, cheap preflight loop.- Immutable published versions + explicit drafts + revert, idempotent runs, per-nodevalue-free status inspection, and org-scoped isolation make state reasoning tractable.- Zero dependencies (stdlib `urllib`) means no lockfiles, builds, or version drift.Hard / human-required:- Credentials, the organization, the workflows plan feature, and integration connections(Brightree, Bonafide, payer portals…) must be provisioned by a person.- Real healthcare actions write to EMR/billing/payer systems; a completed orchestrationdoes not prove a business result, so recipes need explicit business-success branchesand human review before production.- MCP tool discovery is itself authenticated, so I cannot pre-verify tool availabilitywithout a key.- No public local emulator: every integration-level test consumes sandbox entitlement.
Source: write · chatcmpl-tool-941a42ca26385068
Recorded tool call
{
"type": "tool_call",
"seq": 72,
"ts": "2026-10-22T17:21:20.846Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/README.md",
"content": "# GenHealth.ai quickstart example\n\nA minimal, dependency-free example that talks to the **hosted** GenHealth Workflow\nDeveloper API. No docker, no local service stack, no long-running processes — just\nPython 3 standard library HTTP calls against `https://api.umpa.genhealth.ai`.\n\n## What GenHealth.ai is\n\nAI agents for healthcare revenue-cycle ops (intake, eligibility, prior authorization,\nresupplies, billing, denials/appeals) that operate over web portals, fax, and phone.\nThe developer surface exposes that work as **workflows**: JSON graphs of nodes/edges,\nversioned, published, and run through REST or MCP.\n\n| Surface | URL |\n| --- | --- |\n| Docs (add `.md` for agent-friendly Markdown) | https://genhealth.ai/docs.md |\n| REST base | `https://api.umpa.genhealth.ai/developer/v1` |\n| Live OpenAPI 3.1 | `https://api.umpa.genhealth.ai/developer/openapi.json` |\n| Swagger | `https://api.umpa.genhealth.ai/developer/docs` |\n| MCP (streamable HTTP, same bearer header) | `https://api.umpa.genhealth.ai/developer/mcp` |\n| Core resource API (cases/policies/codes) | `https://api.umpa.genhealth.ai/v2/...` |\n\n## Files\n\n- `genhealth_quickstart.py` — `doctor` / `validate` / `run` / `inspect` client (stdlib only).\n- `examples/synthetic-routing.workflow.json` — the canonical synthetic graph from the docs.\n It routes a boolean to one of two `comment` nodes. It creates **no** patient, order,\n claim, or authorization and needs no integration credentials.\n\n## Run it\n\n```bash\n# 1. Get an organization-bound API key (human step; see \"Blocked on\" below)\n# sign up: https://umpa.genhealth.ai/api/auth/login?screen_hint=signup\n# key page: https://genhealth.ai/account/api-keys\nexport GENHEALTH_API_KEY=\"<YOUR_API_KEY>\"\n\n# 2. Read-only probe: auth, scopes, visible integrations/connections\npython3 genhealth_quickstart.py doctor\n\n# 3. Preflight the graph (persists nothing; HTTP 200 can still mean viable=false)\npython3 genhealth_quickstart.py validate examples/synthetic-routing.workflow.json\n\n# 4. validate -> import -> draft -> publish -> one idempotent run\npython3 genhealth_quickstart.py run examples/synthetic-routing.workflow.json \\\n --state genhealth-example-state.json\n\n# 5. Poll the run (never resubmits) until it is terminal\npython3 genhealth_quickstart.py inspect --state genhealth-example-state.json\n```\n\nRequired scopes: `workflow:read` for discovery/preflight; `workflow:write`,\n`workflow:publish`, `workflow:run` to create and execute. Your organization also\nneeds the **workflows plan feature** enabled.\n\nSafety properties baked into the client:\n\n- HTTPS-only origin; the API key never leaves the `Authorization` header or this machine.\n- Synthetic `comment`/`if` graphs only — a definition containing any real integration\n action (e.g. `brightree_*`) is rejected locally before any request is sent.\n- Writes are never auto-retried. Each mutating step records intent in the state file\n (`import_pending` → `imported` → …) so an interrupted run is reconciled, not duplicated.\n- The run's `idempotency_key` is generated once and persisted; retries reuse it.\n- State file is written atomically with `0600` permissions and is git-ignored.\n\n## Blocked on (why this can't run end-to-end unattended)\n\n`doctor` currently exits 1 with a credential hint. The API host is live and reachable\n(verified: it returns `401 Requires authentication` / `403 Not authenticated` without a\nkey), but obtaining a key requires an interactive signup, a real organization, and the\nworkflows plan feature — an agent cannot self-provision that. With\n`GENHEALTH_API_KEY` exported, steps 2–5 need no further human input.\n\n## How pricing works\n\n**There is no published price list.** `genhealth.ai/pricing` is a 404 and no page on the\nsite states a dollar figure. What the site and docs do establish:\n\n- **Sales-led enterprise subscription.** Every conversion path is \"Book a demo\" /\n \"Contact us\"; the footer says \"For Enterprise\". Expect a negotiated annual contract,\n not self-serve checkout.\n- **Free sandbox tier.** \"Try GenHealth free — spin up a free account and run real PA,\n intake, and eligibility flows in your sandbox. Free sandbox — no credit card.\" That is\n the entry point this example targets.\n- **Subscription is a real cost line.** GenHealth's own ROI calculator reports \"Net\n Annual Benefit — your total annual benefit *after accounting for GenHealth.ai\n subscription costs*\", i.e. you get the number from their sales/calculator, not a page.\n- **Plan-gated capabilities.** The Workflow Developer API requires the \"workflows plan\n feature\", so the developer surface itself is an entitlement above the base plan.\n- **Usage is metered in \"modeled internal events.\"** The docs define one event as a\n successful or failed attempt to execute a workflow step (after replay-dedup), and note\n loops/retries add events. The docs describe it as a *planning/benchmark* unit and never\n publish a per-event rate — treat it as the likely metering dimension to ask sales about.\n- **Scopes, not seats, gate the API.** Access is split per operation\n (`workflow:read/write/publish/run`), so cost/permission review is per-integration.\n\nBottom line: free sandbox to build and test; production pricing is quote-only, and the\nnumber you should negotiate against is events/runs plus the workflows plan entitlement.\n\n## Is this easy for an agent to manage?\n\n**Yes for the developer loop, no for provisioning.**\n\nEasy:\n- Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discover\n the contract instead of guessing it (37 operations, 62 schemas).\n- Every docs page is available as plain Markdown by appending `.md` — trivially readable.\n- `GET /capabilities/v2`, `GET /actions` (search), and `GET /actions/{handler}` give\n exact node types, expression syntax, and action input/output schemas before authoring.\n- `POST /workflows/validate` returns machine-actionable `schema_errors` / `findings` /\n `readiness` and persists nothing — a safe, cheap preflight loop.\n- Immutable published versions + explicit drafts + revert, idempotent runs, per-node\n value-free status inspection, and org-scoped isolation make state reasoning tractable.\n- Zero dependencies (stdlib `urllib`) means no lockfiles, builds, or version drift.\n\nHard / human-required:\n- Credentials, the organization, the workflows plan feature, and integration connections\n (Brightree, Bonafide, payer portals…) must be provisioned by a person.\n- Real healthcare actions write to EMR/billing/payer systems; a completed orchestration\n does not prove a business result, so recipes need explicit business-success branches\n and human review before production.\n- MCP tool discovery is itself authenticated, so I cannot pre-verify tool availability\n without a key.\n- No public local emulator: every integration-level test consumes sandbox entitlement.\n"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-941a42ca26385068",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 73,
"ts": "2026-10-22T17:21:20.846Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 6839 bytes to /sandbox/repo/README.md",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-941a42ca26385068",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Verify the README's descriptions: 37 operations, 62 schemas — from the contract summary in workflows.md. Yes. Also "37 operations" is correct.
Run the final check: doctor once more with no key, ls the repository. Also verify the openapi.json endpoint mentioned in the docs — check whether it's reachable (it probably returns 401). Quick check to avoid incorrect descriptions.
for p in /developer/openapi.json /developer/docs /developer/mcp; do echo -n "$p -> "; timeout 15 curl -sS -o /dev/null -w "%{http_code}\n" "https://api.umpa.genhealth.ai$p"; done; echo; cd /sandbox/repo && ls -la && git status --short/developer/openapi.json -> 200
/developer/openapi.json -> 200 /developer/docs -> 200 /developer/mcp -> 405 total 48 drwxr-xr-x 5 root root 4096 Oct 22 17:21 . drwxr-xr-x 7 root root 4096 Oct 22 17:19 .. drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git -rw-r--r-- 1 root root 534 Oct 22 17:21 .gitignore -rw------- 1 root root 6871 Oct 22 17:21 README.md drwx------ 2 root root 4096 Oct 22 17:20 __pycache__ drwx------ 2 root root 4096 Oct 22 17:20 examples -rwx------ 1 root root 12670 Oct 22 17:20 genhealth_quickstart.py M .gitignore ?? README.md ?? examples/ ?? genhealth_quickstart.py
Recorded tool call
{
"type": "tool_call",
"seq": 76,
"ts": "2026-10-22T17:21:23.477Z",
"name": "bash",
"turn": 1,
"input": {
"command": "for p in /developer/openapi.json /developer/docs /developer/mcp; do echo -n \"$p -> \"; timeout 15 curl -sS -o /dev/null -w \"%{http_code}\\n\" \"https://api.umpa.genhealth.ai$p\"; done; echo; cd /sandbox/repo && ls -la && git status --short"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-a05423469934b630",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 77,
"ts": "2026-10-22T17:21:24.769Z",
"turn": 1,
"output": {
"content": [
{
"text": "/developer/openapi.json -> 200\n/developer/docs -> 200\n/developer/mcp -> 405\n\ntotal 48\ndrwxr-xr-x 5 root root 4096 Oct 22 17:21 .\ndrwxr-xr-x 7 root root 4096 Oct 22 17:19 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root 534 Oct 22 17:21 .gitignore\n-rw------- 1 root root 6871 Oct 22 17:21 README.md\ndrwx------ 2 root root 4096 Oct 22 17:20 __pycache__\ndrwx------ 2 root root 4096 Oct 22 17:20 examples\n-rwx------ 1 root root 12670 Oct 22 17:20 genhealth_quickstart.py\n M .gitignore\n?? README.md\n?? examples/\n?? genhealth_quickstart.py\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-a05423469934b630",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
pycache is generated by py_compile — ignored via .gitignore. Fix the permissions of README/examples (600/700 is weird but fine). Let me normalize with chmod and check whether openapi.json is publicly readable (200 — good, no auth needed!). Let me peek inside to confirm it's the real contract. This also backs up the claim that "the contract can be discovered without keys."
cd /sandbox/repo && chmod 644 README.md genhealth_quickstart.py examples/*.json && chmod 755 examples && rm -rf __pycache__
timeout 20 curl -sSL https://api.umpa.genhealth.ai/developer/openapi.json -o /tmp/gh_openapi.json -w "%{http_code}\n"; python3 - <<'EOF'
import json
d=json.load(open('/tmp/gh_openapi.json'))
print("openapi:",d.get("openapi"),"| version:",d.get("info",{}).get("version"))
print("paths:",len(d.get("paths",{})),"| schemas:",len(d.get("components",{}).get("schemas",{})))
print("sample:",list(d.get("paths",{}))[:6])
print("security:",d.get("components",{}).get("securitySchemes"))
EOF
git status --short200
200
openapi: 3.1.0 | version: 1.0.0
paths: 29 | schemas: 62
sample: ['/developer/v1/capabilities', '/developer/v1/capabilities/v2', '/developer/v1/actions', '/developer/v1/integrations', '/developer/v1/integration-connections', '/developer/v1/actions/{handler}']
security: {'HTTPBearer': {'type': 'http', 'scheme': 'bearer'}}
M .gitignore
?? README.md
?? examples/
?? genhealth_quickstart.py
Recorded tool call
{
"type": "tool_call",
"seq": 80,
"ts": "2026-10-22T17:21:27.328Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && chmod 644 README.md genhealth_quickstart.py examples/*.json && chmod 755 examples && rm -rf __pycache__\ntimeout 20 curl -sSL https://api.umpa.genhealth.ai/developer/openapi.json -o /tmp/gh_openapi.json -w \"%{http_code}\\n\"; python3 - <<'EOF'\nimport json\nd=json.load(open('/tmp/gh_openapi.json'))\nprint(\"openapi:\",d.get(\"openapi\"),\"| version:\",d.get(\"info\",{}).get(\"version\"))\nprint(\"paths:\",len(d.get(\"paths\",{})),\"| schemas:\",len(d.get(\"components\",{}).get(\"schemas\",{})))\nprint(\"sample:\",list(d.get(\"paths\",{}))[:6])\nprint(\"security:\",d.get(\"components\",{}).get(\"securitySchemes\"))\nEOF\ngit status --short"
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-928eba50a160d92e",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 81,
"ts": "2026-10-22T17:21:28.110Z",
"turn": 1,
"output": {
"content": [
{
"text": "200\nopenapi: 3.1.0 | version: 1.0.0\npaths: 29 | schemas: 62\nsample: ['/developer/v1/capabilities', '/developer/v1/capabilities/v2', '/developer/v1/actions', '/developer/v1/integrations', '/developer/v1/integration-connections', '/developer/v1/actions/{handler}']\nsecurity: {'HTTPBearer': {'type': 'http', 'scheme': 'bearer'}}\n M .gitignore\n?? README.md\n?? examples/\n?? genhealth_quickstart.py\n",
"type": "text"
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-928eba50a160d92e",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
openapi.json is publicly readable (no auth needed) — 29 paths / 62 schemas (the docs say 37 operations — 29 paths can contain multiple operations per path; 37 operations is reasonable). My README states "37 operations, 62 schemas" citing the docs — accurate as a citation. Also, I could note that openapi.json can be fetched without authentication. Minor update to the README: state that OpenAPI is publicly fetchable (verified) — this strengthens the claim that it's "easy to manage." Make a small edit.
After that, do a final run of doctor to confirm the behavior, and report back.
File edits
1 file
ModifiedREADME.md+2−1View changes
/sandbox/repo/README.md
Replacement excerpt
- Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discover- the contract instead of guessing it (37 operations, 62 schemas).+ the contract instead of guessing it (docs: 37 operations, 62 schemas; the OpenAPI file+ itself is publicly fetchable — verified: OpenAPI 3.1.0, 29 paths, 62 schemas, bearer auth).
Source: edit · chatcmpl-tool-88148475a4d914ac
Recorded tool call
{
"type": "tool_call",
"seq": 84,
"ts": "2026-10-22T17:21:30.982Z",
"name": "edit",
"turn": 1,
"input": {
"path": "/sandbox/repo/README.md",
"edits": [
{
"newText": "- Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discover\n the contract instead of guessing it (docs: 37 operations, 62 schemas; the OpenAPI file\n itself is publicly fetchable — verified: OpenAPI 3.1.0, 29 paths, 62 schemas, bearer auth).",
"oldText": "- Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discover\n the contract instead of guessing it (37 operations, 62 schemas)."
}
]
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-88148475a4d914ac",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 85,
"ts": "2026-10-22T17:21:30.982Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully replaced 1 block(s) in /sandbox/repo/README.md.",
"type": "text"
}
],
"details": {
"diff": " ...\n 102 **Yes for the developer loop, no for provisioning.**\n 103 \n 104 Easy:\n 105 - Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discover\n-106 the contract instead of guessing it (37 operations, 62 schemas).\n+106 the contract instead of guessing it (docs: 37 operations, 62 schemas; the OpenAPI file\n+107 itself is publicly fetchable — verified: OpenAPI 3.1.0, 29 paths, 62 schemas, bearer auth).\n 107 - Every docs page is available as plain Markdown by appending `.md` — trivially readable.\n 108 - `GET /capabilities/v2`, `GET /actions` (search), and `GET /actions/{handler}` give\n 109 exact node types, expression syntax, and action input/output schemas before authoring.\n 110 - `POST /workflows/validate` returns machine-actionable `schema_errors` / `findings` /\n ...",
"patch": "--- /sandbox/repo/README.md\n+++ /sandbox/repo/README.md\n@@ -102,9 +102,10 @@\n **Yes for the developer loop, no for provisioning.**\n \n Easy:\n - Live `openapi.json` + Swagger + an authenticated **MCP** transport mean I can discover\n- the contract instead of guessing it (37 operations, 62 schemas).\n+ the contract instead of guessing it (docs: 37 operations, 62 schemas; the OpenAPI file\n+ itself is publicly fetchable — verified: OpenAPI 3.1.0, 29 paths, 62 schemas, bearer auth).\n - Every docs page is available as plain Markdown by appending `.md` — trivially readable.\n - `GET /capabilities/v2`, `GET /actions` (search), and `GET /actions/{handler}` give\n exact node types, expression syntax, and action input/output schemas before authoring.\n - `POST /workflows/validate` returns machine-actionable `schema_errors` / `findings` /\n",
"firstChangedLine": 106
}
},
"run_id": "cmvjt3bdh011s0jusn4ty4cox",
"tool_id": "chatcmpl-tool-88148475a4d914ac",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Done. Final report. Keep it concise, and cover the following: what was built, the pricing mechanism, ease of management, the blocking issue (no API key), and a note that the developer workflow does indeed exist so I haven't stopped.
GenHealth.ai does have a real developer workflow (public docs portal, REST + MCP + live OpenAPI), so I built the example rather than stopping.
What I built (/sandbox/repo)
| File | Purpose |
|---|---|
genhealth_quickstart.py | Stdlib-only client for the hosted API: doctor (read-only auth/capability probe), validate (preflight, persists nothing), run (validate → import → draft → publish → one idempotent run), inspect (poll run, never resubmits) |
examples/synthetic-routing.workflow.json | The canonical synthetic graph from their docs — routes a boolean to one of two comment nodes; creates no patient/order/claim, needs no integration creds |
README.md | Quickstart, pricing summary, manageability notes |
.gitignore | Now excludes *-state.json run state |
Safety built in: HTTPS-only origin, key never leaves the Authorization header, synthetic comment/if graphs only (any real action like brightree_* is rejected locally before a request is sent), no automatic write retries (intent recorded in state file first so interrupted writes get reconciled, not duplicated), persisted idempotency key, atomic 0600 state writes.
Verified locally: compiles, graph edges resolve, and all four error paths behave — missing key prints setup steps, a bogus key yields a clean HTTP 401 diagnostic, unsafe graphs are refused offline. The live host is up: /developer/v1/capabilities/v2 → 401 Requires authentication, /v2/cases → 403, /developer/openapi.json → 200 (publicly readable: OpenAPI 3.1.0, 29 paths, 62 schemas).
How pricing works
No published price list — genhealth.ai/pricing is a 404 and no page states a dollar figure. What's verifiable:
- Sales-led enterprise subscription — every path is "Book a demo"/"Contact us"; footer says "For Enterprise".
- Free sandbox tier — "spin up a free account and run real PA, intake, and eligibility flows in your sandbox… no credit card." That's the entry point this example targets.
- Subscription is a real cost line — their ROI calculator reports net benefit "after accounting for GenHealth.ai subscription costs".
- Plan-gated dev surface — the Workflow Developer API requires the "workflows plan feature" entitlement.
- Metering dimension — docs define a "modeled internal event" as one successful/failed workflow-step attempt (loops/retries add events), described as a planning/benchmark unit with no published rate. Ask sales for $/event plus the workflows entitlement.
- Access is split by scopes (
workflow:read/write/publish/run), not seats.
Will this be easy for me to manage?
Yes for the dev loop, no for provisioning. Easy: publicly fetchable OpenAPI + Swagger + MCP transport, every docs page readable as Markdown by appending .md, discovery endpoints (/capabilities/v2, /actions, /actions/{handler}) for exact node types and action schemas, a non-persisting validate that returns machine-actionable findings, immutable versions/drafts/revert, idempotent runs, zero dependencies. Hard: credentials, organization, plan feature, and integration connections (Brightree/Bonafide/payer portals) must be provisioned by a human; real healthcare actions write to live systems and need explicit business-success branches plus review; MCP tool discovery is itself authenticated; no local emulator exists.
Where I'm blocked
doctor exits 1: no GENHEALTH_API_KEY, and self-provisioning one requires interactive signup + a real org + the workflows plan feature — I can't do that. Export a key and steps 2–5 run unattended:
export GENHEALTH_API_KEY="<YOUR_API_KEY>"
python3 genhealth_quickstart.py doctor
No local stacks started, no long-running commands waited on.
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents