ax-check.com
by Gauge
R
RevenueHero
revenuehero.io
ax-check.com
Checked 28 September 2026
B
81/100
Agents need your login
Docs and pricing are clear, but no API or SDK path exists yet
14 of 23 checks passed: setup steps and pricing are stated plainly, but API, MCP, CLI and SDK details are unassessed with no evidence found.
2 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no revenuehero.io account. Recorded 28 September 2026 on Pi.
3 recorded · 3m 30s
3m 30s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
The user asks about "RevenueHero". I don't know this product. Let me check the sandbox environment first — maybe there's something in the repo. Let me look.
✓$ pwd; ls -la; echo "---"; ls /sandbox✓└{"content":[{"text":"/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 28 22:50 ..\ndrwxr-xr-x 8 root root 40…ctrl+o
{"content":[{"text":"/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 28 22:50 ..\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---\nrepo\n","type":"text"}]}✓$ cat /etc/os-release 2>/dev/null | head -3; echo "---"; ls /usr/local/lib/node_modules/@earendil-works/pi-coding-agent 2>/dev/null | head✓└{"content":[{"text":"PRETTY_NAME=\"Ubuntu 24.04.4 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\n---\nCHANGELOG.md\nREADME.md\ndist\ndocs\nexamples\nnode_modules…ctrl+o
{"content":[{"text":"PRETTY_NAME=\"Ubuntu 24.04.4 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\n---\nCHANGELOG.md\nREADME.md\ndist\ndocs\nexamples\nnode_modules\nnpm-shrinkwrap.json\npackage.json\n","type":"text"}]}›Thinking…
The repo is empty except .git. Let me check git log and .gitignore.
Now, "RevenueHero" — I need to determine whether this product exists. Let me check network access and search npm/PyPI for a RevenueHero SDK.
✓$ cat .gitignore; echo "--- git log ---"; git log --oneline -5 2>&1 | head✓└{"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/…ctrl+o
{"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/\n--- git log ---\n9ebf5fb Initial workspace\n","type":"text"}]}✓$ timeout 15 npm search revenuehero --json 2>&1 | head -40; echo "=== registry ==="; timeout 15 curl -s -o /dev/null -w "%{http_code}\n" https://registry.npmjs.org/revenuehero 2>&1✓└{"content":[{"text":"[\n\n{\"name\":\"@revenuehero/sdk-react\",\"keywords\":[\"revenuehero\",\"scheduling\"],\"version\":\"2.0.0\",\"description\":\"RevenueHero…ctrl+o
{"content":[{"text":"[\n\n{\"name\":\"@revenuehero/sdk-react\",\"keywords\":[\"revenuehero\",\"scheduling\"],\"version\":\"2.0.0\",\"description\":\"RevenueHero React SDK\",\"sanitized_name\":\"@revenuehero/sdk-react\",\"publisher\":{\"email\":\"dev@revenuehero.io\",\"username\":\"dev-revenuehero\"},\"maintainers\":[{\"email\":\"dev@revenuehero.io\",\"username\":\"dev-revenuehero\"}],\"license\":\"AGPL-3.0\",\"date\":\"2025-08-01T04:20:35.828Z\",\"links\":{\"homepage\":\"https://github.com/revenuehero/sdk#readme\",\"repository\":\"git+https://github.com/revenuehero/sdk.git\",\"bugs\":\"https://github.com/revenuehero/sdk/issues\",\"npm\":\"https://www.npmjs.com/package/@revenuehero/sdk-react\"}}\n\n,\n\n{\"name\":\"@revenuehero/sdk-qwik\",\"keywords\":[\"revenuehero\",\"scheduling\",\"qwik\"],\"version\":\"2.1.0\",\"description\":\"RevenueHero Qwik SDK\",\"sanitized_name\":\"@revenuehero/sdk-qwik\",\"publisher\":{\"email\":\"dev@revenuehero.io\",\"username\":\"dev-revenuehero\"},\"maintainers\":[{\"email\":\"dev@revenuehero.io\",\"username\":\"dev-revenuehero\"}],\"license\":\"AGPL-3.0\",\"date\":\"2025-06-11T19:34:53.581Z\",\"links\":{\"homepage\":\"https://github.com/revenuehero/sdk#readme\",\"repository\":\"git+https://github.com/revenuehero/sdk.git\",\"bugs\":\"https://github.com/revenuehero/sdk/issues\",\"npm\":\"https://www.npmjs.com/package/@revenuehero/sdk-qwik\"}}\n\n,\n\n{\"name\":\"@surface-labs/forms-sdk\",\"keywords\":[\"surface\",\"forms\",\"sdk\",\"lead-capture\",\"scheduler\"],\"version\":\"0.1.1\",\"description\":\"Thin-client Surface Forms SDK: bind your own HTML to a Surface form record — headless engine, DOM binding, React adapter, embedded schedulers, tracking.\",\"sanitized_name\":\"@surface-labs/forms-sdk\",\"publisher\":{\"email\":\"parag.more@withsurface.com\",\"username\":\"parag.more.withsurface.com\"},\"maintainers\":[{\"email\":\"parag.more@withsurface.com\",\"username\":\"parag.more.withsurface.com\"},{\"email\":\"arjun@withsurface.com\",\"username\":\"arjunsahai\"}],\"license\":\"MIT\",\"date\":\"2026-09-04T12:32:44.477Z\",\"links\":{\"homepage\":\"https://docs.withsurface.com/docs/forms-sdk/overview\",\"npm\":\"https://www.npmjs.com/package/@surface-labs/forms-sdk\"}}\n\n,\n\n{\"name\":\"aw-wizard-forms\",\"keywords\":[\"form\",\"wizard\",\"multi-step\",\"typeform\",\"hubspot\",\"webflow\",\"web-component\",\"custom-element\",\"lit\",\"lightweight\"],\"version\":\"4.13.0\",\"description\":\"A lightweight, Typeform-style multi-step form web component for Webflow + HubSpot integration\",\"sanitized_name\":\"aw-wizard-forms\",\"publisher\":{\"email\":\"parsu@atomicwork.com\",\"username\":\"parsuram-atomicwork\"},\"maintainers\":[{\"email\":\"parsu@atomicwork.com\",\"username\":\"parsuram-atomicwork\"}],\"license\":\"MIT\",\"date\":\"2026-03-02T13:36:33.149Z\",\"links\":{\"homepage\":\"https://github.com/atomicworkhq/aw-wizard-forms#readme\",\"repository\":\"git+https://github.com/atomicworkhq/aw-wizard-forms.git\",\"bugs\":\"https://github.com/atomicworkhq/aw-wizard-forms/issues\",\"npm\":\"https://www.npmjs.com/package/aw-wizard-forms\"}}\n\n,\n\n{\"name\":\"@akash-aw/aw-wizard-forms\",\"keywords\":[\"form\",\"wizard\",\"multi-step\",\"typeform\",\"hubspot\",\"webflow\",\"web-component\",\"custom-element\",\"lit\",\"lightweight\"],\"version\":\"4.14.0\",\"description\":\"A lightweight, Typeform-style multi-step form web component for Webflow + HubSpot integration\",\"sanitized_name\":\"@akash-aw/aw-wizard-forms\",\"publisher\":{\"email\":\"akash.choudhary@atomicwork.com\",\"username\":\"akash-aw\"},\"maintainers\":[{\"email\":\"akash.choudhary@atomicwork.com\",\"username\":\"akash-aw\"}],\"license\":\"MIT\",\"date\":\"2026-04-10T16:57:43.800Z\",\"links\":{\"homepage\":\"https://github.com/atomicworkhq/aw-wizard-forms#readme\",\"repository\":\"git+https://github.com/atomicworkhq/aw-wizard-forms.git\",\"bugs\":\"https://github.com/atomicworkhq/aw-wizard-forms/issues\",\"npm\":\"https://www.npmjs.com/package/@akash-aw/aw-wizard-forms\"}}\n\n,\n\n{\"name\":\"@vicistack/speed-to-lead-response-time\",\"keywords\":[\"vicidial\",\"asterisk\",\"call-center\",\"voip\",\"predictive-dialer\",\"speed\",\"lead\",\"response\",\"time\"],\"version\":\"1.0.0\",\"description\":\"Speed to Lead Response Time Optimization — ViciStack call center engineering guide\",\"sanitized_name\":\"@vicistack/speed-to-lead-response-time\",\"publisher\":{\"email\":\"jason@ccdocs.com\",\"username\":\"vicistack\"},\"maintainers\":[{\"email\":\"jason@ccdocs.com\",\"username\":\"vicistack\"}],\"license\":\"MIT\",\"date\":\"2026-03-27T16:50:10.310Z\",\"links\":{\"homepage\":\"https://vicistack.com/blog/speed-to-lead-response-time/\",\"repository\":\"git+https://github.com/vicistack/speed-to-lead-response-time.git\",\"bugs\":\"https://github.com/vicistack/speed-to-lead-response-time/issues\",\"npm\":\"https://www.npmjs.com/package/@vicistack/speed-to-lead-response-time\"}}\n]\n\n=== registry ===\n404\n","type":"text"}]}›Thinking…
RevenueHero exists — real product at tryrevenuehero.com, a scheduling/booking platform ("RevenueHero" by RevenueHero.io). npm packages @revenuehero/sdk-react etc. Let's check what packages exist and their docs.
Let me fetch the README of @revenuehero/sdk-react and check other packages like @revenuehero/sdk-core or @revenuehero/sdk-vue.
✓$ for p in @revenuehero/sdk-react @revenuehero/sdk-core @revenuehero/sdk-vue @revenuehero/sdk-angular @revenuehero/sdk-svelte @revenuehero/sdk-js @revenuehero/sdk; do echo "== $p"; timeout 15 curl -s "h…✓└{"content":[{"text":"== @revenuehero/sdk-react\n2.0.0 RevenueHero React SDK ./dist/index.js [] https://github.com/revenuehero/sdk#readme\n== @revenuehero/sdk-co…ctrl+o
for p in @revenuehero/sdk-react @revenuehero/sdk-core @revenuehero/sdk-vue @revenuehero/sdk-angular @revenuehero/sdk-svelte @revenuehero/sdk-js @revenuehero/sdk; do echo "== $p"; timeout 15 curl -s "https://registry.npmjs.org/$(echo $p | sed 's|/|%2F|')/latest" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('version'), d.get('description'), d.get('main'), list(d.get('dependencies',{}).keys()), d.get('homepage'))" 2>&1 | head -3; done
{"content":[{"text":"== @revenuehero/sdk-react\n2.0.0 RevenueHero React SDK ./dist/index.js [] https://github.com/revenuehero/sdk#readme\n== @revenuehero/sdk-core\nTraceback (most recent call last):\n File \"<string>\", line 1, in <module>\nAttributeError: 'str' object has no attribute 'get'\n== @revenuehero/sdk-vue\nTraceback (most recent call last):\n File \"<string>\", line 1, in <module>\nAttributeError: 'str' object has no attribute 'get'\n== @revenuehero/sdk-angular\nTraceback (most recent call last):\n File \"<string>\", line 1, in <module>\nAttributeError: 'str' object has no attribute 'get'\n== @revenuehero/sdk-svelte\nTraceback (most recent call last):\n File \"<string>\", line 1, in <module>\nAttributeError: 'str' object has no attribute 'get'\n== @revenuehero/sdk-js\nTraceback (most recent call last):\n File \"<string>\", line 1, in <module>\nAttributeError: 'str' object has no attribute 'get'\n== @revenuehero/sdk\nTraceback (most recent call last):\n File \"<string>\", line 1, in <module>\nAttributeError: 'str' object has no attribute 'get'\n","type":"text"}]}✓$ timeout 20 curl -s "https://registry.npmjs.org/@revenuehero%2Fsdk-react/latest" | python3 -c "✓└{"content":[{"text":"NO README\n","type":"text"}]}ctrl+o
timeout 20 curl -s "https://registry.npmjs.org/@revenuehero%2Fsdk-react/latest" | python3 -c "
import sys,json;d=json.load(sys.stdin);print(d.get('readme','NO README')[:6000])"
›Thinking…
Only @revenuehero/sdk-react, sdk-qwik exist. Let me search npm for all revenuehero packages.
Also check the GitHub repo github.com/revenuehero/sdk and docs. And whether general network access works (curl to tryrevenuehero.com / docs).
✓$ timeout 20 curl -s "https://registry.npmjs.org/-/v1/search?text=revenuehero&size=25" | python3 -c "✓└{"content":[{"text":"@revenuehero/sdk-react 2.0.0 2025-08-01 | RevenueHero React SDK\n@revenuehero/sdk-qwik 2.1.0 2025-06-11 | RevenueHero Qwik SDK\n@surface-la…ctrl+o
timeout 20 curl -s "https://registry.npmjs.org/-/v1/search?text=revenuehero&size=25" | python3 -c "
import sys,json
for o in json.load(sys.stdin)['objects']:
p=o['package']; print(p['name'], p['version'], p.get('date','')[:10], '|', p.get('description'))
"
{"content":[{"text":"@revenuehero/sdk-react 2.0.0 2025-08-01 | RevenueHero React SDK\n@revenuehero/sdk-qwik 2.1.0 2025-06-11 | RevenueHero Qwik SDK\n@surface-labs/forms-sdk 0.1.1 2026-09-04 | Thin-client Surface Forms SDK: bind your own HTML to a Surface form record — headless engine, DOM binding, React adapter, embedded schedulers, tracking.\naw-wizard-forms 4.13.0 2026-03-02 | A lightweight, Typeform-style multi-step form web component for Webflow + HubSpot integration\n@akash-aw/aw-wizard-forms 4.14.0 2026-04-10 | A lightweight, Typeform-style multi-step form web component for Webflow + HubSpot integration\n@vicistack/speed-to-lead-response-time 1.0.0 2026-03-27 | Speed to Lead Response Time Optimization — ViciStack call center engineering guide\n","type":"text"}]}✓$ for u in https://github.com/revenuehero/sdk https://raw.githubusercontent.com/revenuehero/sdk/main/README.md https://tryrevenuehero.com https://revenuehero.io; do echo "== $u"; timeout 15 curl -s -o /…✓└{"content":[{"text":"== https://github.com/revenuehero/sdk\n200\n== https://raw.githubusercontent.com/revenuehero/sdk/main/README.md\n404\n== https://tryrevenue…ctrl+o
for u in https://github.com/revenuehero/sdk https://raw.githubusercontent.com/revenuehero/sdk/main/README.md https://tryrevenuehero.com https://revenuehero.io; do echo "== $u"; timeout 15 curl -s -o /dev/null -w "%{http_code}\n" -L "$u"; done
{"content":[{"text":"== https://github.com/revenuehero/sdk\n200\n== https://raw.githubusercontent.com/revenuehero/sdk/main/README.md\n404\n== https://tryrevenuehero.com\n200\n== https://revenuehero.io\n200\n","type":"text"}]}›Thinking…
Good, network works. Let's inspect the GitHub repo (default branch) and the site for docs/pricing.
✓$ timeout 20 curl -s https://api.github.com/repos/revenuehero/sdk | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('full_name'),d.get('default_branch'),d.get('description'),d.get('starga…✓└{"content":[{"text":"revenuehero/sdk main None 0 {'key': 'agpl-3.0', 'name': 'GNU Affero General Public License v3.0', 'spdx_id': 'AGPL-3.0', 'url': 'https://ap…ctrl+o
timeout 20 curl -s https://api.github.com/repos/revenuehero/sdk | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('full_name'),d.get('default_branch'),d.get('description'),d.get('stargazers_count'),d.get('license'),d.get('pushed_at'),d.get('archived'))"
{"content":[{"text":"revenuehero/sdk main None 0 {'key': 'agpl-3.0', 'name': 'GNU Affero General Public License v3.0', 'spdx_id': 'AGPL-3.0', 'url': 'https://api.github.com/licenses/agpl-3.0', 'node_id': 'MDc6TGljZW5zZTE='} 2026-04-07T14:11:40Z False\n","type":"text"}]}✓$ timeout 20 curl -sL https://tryrevenuehero.com -o /tmp/rh.html -w "%{http_code} %{url_effective}\n"; python3 - <<'EOF'✓└{"content":[{"text":"200 https://www.revenuehero.io/\n117734\n RevenueHero | Lead routing and scheduling you can explain 🚀 Introducing the Attio native integra…ctrl+o
timeout 20 curl -sL https://tryrevenuehero.com -o /tmp/rh.html -w "%{http_code} %{url_effective}\n"; python3 - <<'EOF'
import re
h=open('/tmp/rh.html',encoding='utf-8',errors='ignore').read()
print(len(h))
t=re.sub(r'<script.*?</script>','',h,flags=re.S)
t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>',' ',t)
t=re.sub(r'\s+',' ',t)
print(t[:3000])
EOF
{"content":[{"text":"200 https://www.revenuehero.io/\n117734\n RevenueHero | Lead routing and scheduling you can explain 🚀 Introducing the Attio native integration : Match, qualify, and route leads to the right rep in under 3 seconds. Every booking and account owner syncs back to the Attio automatically Learn more → Product Features Routing Match leads to their owner, rotate the rest, and log every decision Scheduling Qualify buyers and open the right rep's calendar, inbound, outbound, or at events Analytics See conversion by week, distribution by rep, and the record behind every meeting Automation Log meetings in the CRM, credit back no-shows, and trigger your downstream workflows Resources Integrations Connect the CRM, forms, sequencers, and enrichment tools you already run Changelog Updates on everything new and improved in the product Moving to RevenueHero Switching from another tool? What changes, who you need on the calls, and how long it took teams that moved off Chili Piper, HubSpot Meetings, or Calendly. See how migrations go Solutions People Demand Gen leaders Generate more pipeline with the same traffic RevOps leaders Centralise your stack for meeting automation and conversion data Sales leaders Skip an entire lifecycle stage in all your deals Industries Healthcare Simplify health-tech sales and hospital scheduling Fintech Keep consumers off your reps' calendars, book only real leads Cybersecurity Qualify on enriched data so you never miss a serious buyer Platforms HubSpot Book off your forms, route to the owner, sync every outcome Salesforce More pipeline booked, CRM stays clean Attio Every meeting booked, routed, and written back to Attio Moving to RevenueHero Switching from another tool? What changes, who you need on the calls, and how long it took teams that moved off Chili Piper, HubSpot Meetings, or Calendly. See how migrations go Customers Success Stories View all case studies → See how Freshworks drove 57% more bookings See why Seamless switched to RevenueHero to automate meeting scheduling How matter 3x'd demos and boosted calls by 35% Wall of love View all customer reviews → Why Northbeam chose RevenueHero over Chili Piper, Calendly, and HubSpot With RevenueHero, all the logic happens at the point of signup, which means that there are no problems for my sales team. They just look at their calendars and are ready to go Bryan Bumgardner Director of Growth Marketing Read full case study Resources Resources Blog Get insights into marketing, sales, and growth Podcast RevOps leaders on the record about how they operate Playbook Proven B2B plays for more qualified meetings and pipeline Benchmarks & Reports Inbound conversion rates by industry, funnel stage and company size Pipeline Velocity Calculator Work out how fast deals move through your pipeline Help Everything you need to know about how to use RevenueHero Moving to RevenueHero Switching from another tool? What changes, who you need on the calls, and how long it took teams that moved off Chili Piper, HubSpot Meetings, \n","type":"text"}]}›Thinking…
Real product. Now: developer workflow — the SDK repo. Let me look at the repo README and packages. Also docs site (help center / developer docs, e.g., docs.revenuehero.io or developers.revenuehero.io). And pricing page.
Note: RevenueHero SDK is likely a small JS lib for embedding scheduler. Requires an account + a scheduler ID (hosted product). The developer workflow: embed <script> or use SDK with your account credentials.
Let me check repo contents and docs subdomains.
✓$ timeout 20 curl -s "https://api.github.com/repos/revenuehero/sdk/git/trees/main?recursive=1" | python3 -c "✓└{"content":[{"text":".changeset\n.changeset/README.md\n.changeset/config.json\n.github\n.github/PULL_REQUEST_TEMPLATE.md\n.github/workflows\n.github/workflows/r…ctrl+o
timeout 20 curl -s "https://api.github.com/repos/revenuehero/sdk/git/trees/main?recursive=1" | python3 -c "
import sys,json
d=json.load(sys.stdin)
for t in d.get('tree',[])[:200]: print(t['path'])
"
{"content":[{"text":".changeset\n.changeset/README.md\n.changeset/config.json\n.github\n.github/PULL_REQUEST_TEMPLATE.md\n.github/workflows\n.github/workflows/release.yaml\n.gitignore\n.nvmrc\nLICENSE\npackage.json\npackages\npackages/qwik\npackages/qwik/CHANGELOG.md\npackages/qwik/README.md\npackages/qwik/lib-types\npackages/qwik/lib-types/index.d.ts\npackages/qwik/lib\npackages/qwik/lib/index.qwik.cjs\npackages/qwik/lib/index.qwik.mjs\npackages/qwik/package.json\npackages/qwik/src\npackages/qwik/src/index.tsx\npackages/qwik/tsconfig.json\npackages/qwik/vite.config.ts\npackages/react\npackages/react/CHANGELOG.md\npackages/react/package.json\npackages/react/src\npackages/react/src/index.tsx\npackages/react/tsconfig.json\npnpm-lock.yaml\npnpm-workspace.yaml\n","type":"text"}]}✓$ for u in https://docs.revenuehero.io https://developers.revenuehero.io https://www.revenuehero.io/pricing https://www.revenuehero.io/help; do echo "== $u"; timeout 15 curl -s -o /dev/null -w "%{http_c…✓└{"content":[{"text":"== https://docs.revenuehero.io\n200 -> https://app.revenuehero.io/login\n== https://developers.revenuehero.io\n200 -> https://app.revenuehe…ctrl+o
for u in https://docs.revenuehero.io https://developers.revenuehero.io https://www.revenuehero.io/pricing https://www.revenuehero.io/help; do echo "== $u"; timeout 15 curl -s -o /dev/null -w "%{http_code} -> %{url_effective}\n" -L "$u"; done
{"content":[{"text":"== https://docs.revenuehero.io\n200 -> https://app.revenuehero.io/login\n== https://developers.revenuehero.io\n200 -> https://app.revenuehero.io/login\n== https://www.revenuehero.io/pricing\n200 -> https://www.revenuehero.io/pricing\n== https://www.revenuehero.io/help\n404 -> https://www.revenuehero.io/help\n","type":"text"}]}›Thinking…
docs.revenuehero.io redirects to app login — so developer docs are gated behind login. Let me read the SDK source (react/src/index.tsx, qwik README) from GitHub raw, and the pricing page.
✓$ for f in packages/react/src/index.tsx packages/qwik/README.md packages/qwik/src/index.tsx package.json; do echo "===== $f"; timeout 15 curl -sL "https://raw.githubusercontent.com/revenuehero/sdk/main/…✓└{"content":[{"text":"===== packages/react/src/index.tsx\nimport { memo, useEffect } from \"react\";\n\nexport type TCustomFormTypes = \"pardot\" | \"jotForm\";\…ctrl+o
for f in packages/react/src/index.tsx packages/qwik/README.md packages/qwik/src/index.tsx package.json; do echo "===== $f"; timeout 15 curl -sL "https://raw.githubusercontent.com/revenuehero/sdk/main/$f"; done
{"content":[{"text":"===== packages/react/src/index.tsx\nimport { memo, useEffect } from \"react\";\n\nexport type TCustomFormTypes = \"pardot\" | \"jotForm\";\n\nexport interface IRevenueHeroParams {\n /**\n * Inbound router ID.\n */\n routerId: string;\n\n /**\n * Form type.\n */\n formType?: TCustomFormTypes;\n\n /**\n * Localized text for the greeting message.\n */\n greetingText?: string;\n\n /**\n * Locale for the RevenueHero Scheduler.\n */\n locale?: string;\n\n /**\n * Determines whether to show loader when the scheduler is loading.\n */\n showLoader?: boolean;\n}\n\n/**\n * Props for the RevenueHero component.\n */\nexport interface IRevenueHeroProps extends IRevenueHeroParams {\n /**\n * Whether or not to enable the RevenueHero component.\n * Once enabled, the script will be loaded and the onLoad callback will be called.\n * It cannot be disabled after enabling.\n */\n enabled?: boolean;\n\n /**\n * The target element ID where the scheduler will be embedded.\n */\n embedTarget?: string;\n\n /**\n * The ID of the form.\n * auto schedules when form selector is provided\n */\n formId?: string;\n\n /**\n * Callback function called when the RevenueHero component is loaded.\n */\n onLoad?: () => void;\n}\n\n/**\n * Represents a RevenueHero instance.\n */\ninterface RevenueHeroClient {\n prototype: RevenueHeroClient;\n new (params: IRevenueHeroParams): RevenueHeroClient;\n\n /**\n * Schedule a form.\n * @param formId - The ID of the form to schedule.\n * @param embedTarget - The ID of the element to embed the scheduler into.\n */\n schedule: (formId: string, embedTarget?: string) => void;\n}\n\ndeclare global {\n interface Window {\n RevenueHero: RevenueHeroClient;\n }\n}\n\nconst RH_GLOBAL_STORAGE_KEYS = [\n \"RH_EMBED_TARGET\",\n \"RH_DATA_SOURCE\",\n \"RH_SESSION_ID\",\n \"RH_ROUTER_ID\",\n \"RH_FORM_SUBMITTED\",\n];\n\nconst isBrowser =\n typeof window !== \"undefined\" && typeof document !== \"undefined\";\n\nfunction loadScript(): Promise<void> {\n const el = document.createElement(\"script\");\n\n const promise = new Promise<void>((resolve, reject) => {\n el.addEventListener(\"load\", () => {\n resolve();\n });\n\n el.addEventListener(\"error\", (e) => {\n reject(e);\n });\n });\n\n el.src = \"https://assets.revenuehero.io/scheduler.min.js\";\n\n document.body.appendChild(el);\n\n return promise;\n}\n\n/**\n * ! Why this promise is hoisted ?\n * - when multiple RevenueHero components are mounted at the same time, the script is loaded only once.\n * - the promise is hoisted to wait till script is loaded and then call the init function.\n */\nlet loadPromise: Promise<void> | null = null;\n\nexport const RevenueHero = memo(\n ({\n enabled,\n embedTarget,\n formId,\n onLoad,\n ...props\n }: IRevenueHeroProps): JSX.Element | null => {\n useEffect(() => {\n const init = () => {\n const RevenueHero = window.RevenueHero;\n\n if (!RevenueHero) {\n throw new Error(\"RevenueHero is not available\");\n }\n\n if (formId) {\n const instance = new RevenueHero(props);\n\n instance.schedule(formId, embedTarget);\n }\n\n onLoad?.();\n };\n\n if (!isBrowser || !enabled) return;\n\n if (loadPromise === null) {\n loadPromise = loadScript();\n }\n\n loadPromise.then(init);\n\n // reset global state when parent component unmounts\n return () => {\n if (window.RevenueHero === undefined) return;\n\n // @ts-expect-error formsConnected is static property on RevenueHero constructor\n window.RevenueHero.formsConnected = [];\n\n RH_GLOBAL_STORAGE_KEYS.forEach((key) => {\n localStorage.removeItem(key);\n });\n };\n }, [embedTarget, enabled, formId, onLoad, props]);\n\n return null;\n }\n);\n===== packages/qwik/README.md\n# RevenueHero Qwik SDK\n\nThe official RevenueHero SDK for Qwik applications.\n\n## Installation\n\n```bash\nnpm install @revenuehero/sdk-qwik\n```\n\n```bash\nyarn add @revenuehero/sdk-qwik\n```\n\n```bash\npnpm add @revenuehero/sdk-qwik\n```\n\n## Usage\n\nThe SDK provides three approaches for integrating RevenueHero with your Qwik forms:\n\n### Method 1: Traditional Forms (Auto-attach)\n\nFor traditional HTML forms without Qwik's reactive form handling:\n\n```tsx\nimport { component$ } from '@builder.io/qwik';\nimport { RevenueHero } from '@revenuehero/sdk-qwik';\n\nexport default component$(() => {\n return (\n <div>\n <form id=\"contact-form\">\n <input type=\"email\" name=\"email\" required />\n <input type=\"text\" name=\"firstName\" required />\n <button type=\"submit\">Submit</button>\n </form>\n\n <RevenueHero\n enabled={true}\n routerId=\"your-router-id\"\n formId=\"#contact-form\"\n showLoader={true}\n />\n </div>\n );\n});\n```\n\n### Method 2: Qwik Reactive Forms (Manual)\n\nFor Qwik forms with `preventdefault:submit` or reactive form libraries:\n\n```tsx\nimport { component$, $ } from '@builder.io/qwik';\nimport { useRevenueHero } from '@revenuehero/sdk-qwik';\n\nexport default component$(() => {\n const submitToRevenueHero = useRevenueHero({ \n routerId: 'your-router-id',\n showLoader: true \n });\n\n const handleSubmit = $((event: SubmitEvent, form: HTMLFormElement) => {\n // Get form data\n const formData = new FormData(form);\n const data = Object.fromEntries(formData.entries());\n \n // Your custom form logic here\n console.log('Form submitted:', data);\n \n // Submit to RevenueHero\n submitToRevenueHero(data)\n .then((response) => {\n console.log('RevenueHero response:', response);\n // Dialog opens automatically\n })\n .catch((error) => {\n console.error('RevenueHero error:', error);\n });\n });\n\n return (\n <form \n id=\"qwik-form\" \n preventdefault:submit\n onSubmit$={handleSubmit}\n >\n <input type=\"email\" name=\"email\" required />\n <input type=\"text\" name=\"firstName\" required />\n <button type=\"submit\">Submit</button>\n </form>\n );\n});\n```\n\n### Method 3: With Modular Forms\n\nFor [@modular-forms/qwik](https://modularforms.dev/) integration:\n\n```tsx\nimport { component$ } from '@builder.io/qwik';\nimport { useForm, type SubmitHandler } from '@modular-forms/qwik';\nimport { useRevenueHero } from '@revenuehero/sdk-qwik';\n\ntype ContactForm = {\n email: string;\n firstName: string;\n};\n\nexport default component$(() => {\n const [contactForm, { Form, Field }] = useForm<ContactForm>({\n loader: useFormLoader(),\n });\n\n const submitToRevenueHero = useRevenueHero({ \n routerId: 'your-router-id' \n });\n\n const handleSubmit: SubmitHandler<ContactForm> = $((values) => {\n // Process with Modular Forms\n console.log('Form values:', values);\n \n // Submit to RevenueHero\n submitToRevenueHero(values);\n });\n\n return (\n <Form onSubmit$={handleSubmit}>\n <Field name=\"email\">\n {(field, props) => (\n <input {...props} type=\"email\" placeholder=\"Email\" />\n )}\n </Field>\n \n <Field name=\"firstName\">\n {(field, props) => (\n <input {...props} type=\"text\" placeholder=\"First Name\" />\n )}\n </Field>\n \n <button type=\"submit\">Submit</button>\n </Form>\n );\n});\n```\n\n## API Reference\n\n### RevenueHero Component\n\nThe main component for traditional form integration.\n\n#### Props\n\n| Prop | Type | Required | Default | Description |\n|------|------|----------|---------|-------------|\n| `enabled` | `boolean` | No | `false` | Whether to enable RevenueHero |\n| `routerId` | `string` | Yes | - | Your RevenueHero router ID |\n| `formId` | `string` | No | - | CSS selector for the form to attach to |\n| `embedTarget` | `string` | No | - | CSS selector for where to embed the scheduler |\n| `formType` | `'pardot' \\| 'jotForm'` | No | - | Specific form type for custom handling |\n| `greetingText` | `string` | No | - | Custom greeting text |\n| `locale` | `string` | No | - | Locale for the scheduler |\n| `showLoader` | `boolean` | No | `true` | Whether to show loading indicator |\n| `onLoad` | `() => void` | No | - | Callback when SDK is loaded |\n\n### useRevenueHero Hook\n\nHook for manual form submission integration.\n\n#### Parameters\n\n```tsx\nconst submitToRevenueHero = useRevenueHero({\n routerId: string; // Required: Your router ID\n formType?: 'pardot' | 'jotForm';\n greetingText?: string;\n locale?: string;\n showLoader?: boolean; // Default: true\n});\n```\n\n#### Returns\n\nA function that submits form data to RevenueHero:\n\n```tsx\n(formData: Record<string, any>) => Promise<any>\n```\n\n## Why Three Methods?\n\n**Method 1 (Traditional)** works great for standard HTML forms where RevenueHero can attach event listeners directly.\n\n**Method 2 (Manual)** is needed for Qwik's reactive forms because:\n\n- Qwik uses `preventdefault:submit` which prevents traditional form submission\n- RevenueHero's event listeners can't intercept the form data\n- Manual submission gives you full control over when and how RevenueHero is triggered\n\n**Method 3 (Modular Forms)** is the same as Method 2 but shows the specific integration pattern for the popular Modular Forms library.\n\n## Error Handling\n\n```tsx\nconst handleSubmit = $((event: SubmitEvent, form: HTMLFormElement) => {\n const formData = new FormData(form);\n const data = Object.fromEntries(formData.entries());\n \n submitToRevenueHero(data)\n .then((response) => {\n // Success - dialog opens automatically\n console.log('Success:', response);\n })\n .catch((error) => {\n // Handle errors\n if (error.message === 'RevenueHero not loaded') {\n console.error('SDK failed to load');\n } else {\n console.error('Submission failed:', error);\n }\n });\n});\n```\n\n## TypeScript Support\n\nThe SDK is written in TypeScript and provides full type safety:\n\n```tsx\nimport type { IRevenueHeroParams, IRevenueHeroProps } from '@revenuehero/sdk-qwik';\n```\n\n## Examples\n\nCheck out our [demo application](https://github.com/revenuehero/sdk/tree/main/packages/qwik-demo-app) for complete working examples.\n\n## Support\n\n- [Documentation](https://docs.revenuehero.io)\n- [GitHub Issues](https://github.com/revenuehero/sdk/issues)\n- [Contact Support](mailto:support@revenuehero.io)\n\n## License\n\nMIT License - see [LICENSE](../../LICENSE) for details.===== packages/qwik/src/index.tsx\nimport { component$, useVisibleTask$, useSignal, $ } from '@builder.io/qwik';\n\nexport type TCustomFormTypes = \"pardot\" | \"jotForm\";\n\nexport interface IRevenueHeroParams {\n /**\n * Inbound router ID.\n */\n routerId: string;\n\n /**\n * Form type.\n */\n formType?: TCustomFormTypes;\n\n /**\n * Localized text for the greeting message.\n */\n greetingText?: string;\n\n /**\n * Locale for the RevenueHero Scheduler.\n */\n locale?: string;\n\n /**\n * Determines whether to show loader when the scheduler is loading.\n */\n showLoader?: boolean;\n}\n\n/**\n * Props for the RevenueHero component.\n */\nexport interface IRevenueHeroProps extends IRevenueHeroParams {\n /**\n * Whether or not to enable the RevenueHero component.\n * Once enabled, the script will be loaded and the onLoad callback will be called.\n * It cannot be disabled after enabling.\n */\n enabled?: boolean;\n\n /**\n * The target element ID where the scheduler will be embedded.\n */\n embedTarget?: string;\n\n /**\n * The ID of the form.\n * auto schedules when form selector is provided\n */\n formId?: string;\n\n /**\n * Callback function called when the RevenueHero component is loaded.\n */\n onLoad?: () => void;\n}\n\n/**\n * Represents a RevenueHero instance.\n */\ninterface RevenueHeroInstance {\n /**\n * Schedule a form.\n * @param formId - The ID of the form to schedule.\n * @param embedTarget - The ID of the element to embed the scheduler into.\n */\n schedule: (formId: string, embedTarget?: string) => void;\n \n /**\n * Submit form data directly to RevenueHero\n */\n submit: (data: Record<string, any>) => Promise<any>;\n \n /**\n * Dialog instance for opening the scheduler\n */\n dialog: {\n open: (response: any) => void;\n };\n}\n\n/**\n * Represents the RevenueHero constructor/class.\n */\ninterface RevenueHeroClient {\n prototype: RevenueHeroInstance;\n new (params: IRevenueHeroParams): RevenueHeroInstance;\n\n /**\n * Static property to track connected forms\n */\n formsConnected: string[];\n}\n\ndeclare global {\n interface Window {\n RevenueHero: RevenueHeroClient;\n }\n}\n\nconst RH_GLOBAL_STORAGE_KEYS = [\n \"RH_EMBED_TARGET\",\n \"RH_DATA_SOURCE\",\n \"RH_SESSION_ID\",\n \"RH_ROUTER_ID\",\n \"RH_FORM_SUBMITTED\",\n];\n\nconst isBrowser =\n typeof window !== \"undefined\" && typeof document !== \"undefined\";\n\nfunction loadScript(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const existingScript = document.querySelector('script[src=\"https://assets.revenuehero.io/scheduler.min.js\"]');\n if (existingScript) {\n resolve();\n return;\n }\n\n const el = document.createElement(\"script\");\n \n el.addEventListener(\"load\", () => {\n resolve();\n });\n\n el.addEventListener(\"error\", (e) => {\n reject(e);\n });\n\n el.type = \"text/javascript\";\n el.async = true;\n el.src = \"https://assets.revenuehero.io/scheduler.min.js\";\n document.body.appendChild(el);\n });\n}\n\n/**\n * ! Why this promise is hoisted ?\n * - when multiple RevenueHero components are mounted at the same time, the script is loaded only once.\n * - the promise is hoisted to wait till script is loaded and then call the init function.\n */\nconst scriptLoader = {\n loadPromise: null as Promise<void> | null\n};\n\n// Main RevenueHero component export\nexport const RevenueHero = component$<IRevenueHeroProps>((props) => {\n const { enabled, embedTarget, formId, onLoad, ...params } = props;\n\n const init = $(() => {\n const RevenueHero = window.RevenueHero;\n\n if (!RevenueHero) {\n throw new Error(\"RevenueHero is not available\");\n }\n\n if (formId) {\n const instance = new RevenueHero(params);\n instance.schedule(formId, embedTarget);\n }\n\n onLoad?.();\n });\n\n useVisibleTask$(({ track, cleanup }) => {\n track(() => enabled);\n\n if (!enabled) return;\n\n if (scriptLoader.loadPromise === null) {\n scriptLoader.loadPromise = loadScript();\n }\n\n scriptLoader.loadPromise\n .then(() => {\n if (typeof window.RevenueHero === 'undefined') {\n return;\n }\n init();\n })\n .catch(() => {\n // Failed to load script\n });\n\n cleanup(() => {\n if (window.RevenueHero === undefined) return;\n\n if (window.RevenueHero.formsConnected) {\n window.RevenueHero.formsConnected.length = 0;\n }\n\n RH_GLOBAL_STORAGE_KEYS.forEach((key) => {\n localStorage.removeItem(key);\n });\n });\n });\n\n return null;\n});\n\n/**\n * Hook for manual RevenueHero submission in Qwik forms\n * \n * @example\n * ```tsx\n * export default component$(() => {\n * const submitToRH = useRevenueHero({ routerId: 'your-router-id' });\n * \n * const handleSubmit = $((event: SubmitEvent, form: HTMLFormElement) => {\n * // Your form logic here\n * const formData = new FormData(form);\n * const data = Object.fromEntries(formData.entries());\n * \n * // Submit to RevenueHero\n * submitToRH(data);\n * });\n * \n * return (\n * <form preventdefault:submit onSubmit$={handleSubmit}>\n * <input name=\"email\" type=\"email\" />\n * <button type=\"submit\">Submit</button>\n * </form>\n * );\n * });\n * ```\n */\nexport const useRevenueHero = (params: IRevenueHeroParams) => {\n const isLoaded = useSignal(false);\n\n // Ensure script is loaded when hook is used\n useVisibleTask$(() => {\n if (scriptLoader.loadPromise === null) {\n scriptLoader.loadPromise = loadScript();\n }\n\n scriptLoader.loadPromise\n .then(() => {\n isLoaded.value = true;\n })\n .catch(() => {\n console.error('[RevenueHero] Failed to load script');\n });\n });\n\n return $((formData: Record<string, any>) => {\n if (!isLoaded.value || typeof window.RevenueHero === 'undefined') {\n console.error('[RevenueHero] Script not loaded yet');\n return Promise.reject(new Error('RevenueHero not loaded'));\n }\n\n const instance = new window.RevenueHero(params);\n \n return instance.submit(formData).then((response: any) => {\n if (response) {\n instance.dialog.open(response);\n }\n return response;\n });\n });\n};===== package.json\n{\n \"name\": \"sdk\",\n \"version\": \"1.0.0\",\n \"description\": \"RevenueHero Client SDK\",\n \"private\": \"true\",\n \"scripts\": {\n \"react:build:prod\": \"pnpm run --filter @revenuehero/sdk-react build:prod\",\n \"qwik:build:prod\": \"pnpm run --filter @revenuehero/sdk-qwik build:prod\",\n \"ci:publish\": \"pnpm run build && pnpm publish -r --access public\",\n \"ci:version\": \"pnpm changeset version\",\n \"build\": \"pnpm --filter @revenuehero/* -r build:prod\"\n },\n \"license\": \"AGPL-3.0\",\n \"engines\": {\n \"node\": \">= 18.12.1\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.1\"\n }\n}\n","type":"text"}]}✓$ timeout 20 curl -sL https://www.revenuehero.io/pricing -o /tmp/pricing.html; python3 - <<'EOF'✓└{"content":[{"text":"\nPricing Plans That Let You Scale | RevenueHero\n🚀 Introducing the Attio native integration : \nMatch, qualify, and route leads to the ri…ctrl+o
timeout 20 curl -sL https://www.revenuehero.io/pricing -o /tmp/pricing.html; python3 - <<'EOF'
import re
h=open('/tmp/pricing.html',encoding='utf-8',errors='ignore').read()
t=re.sub(r'<script.*?</script>','',h,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>','\n',t); t=re.sub(r'[ \t]+',' ',t); t=re.sub(r'\n\s*\n+','\n',t)
print(t[:6000])
EOF
{"content":[{"text":"\nPricing Plans That Let You Scale | RevenueHero\n🚀 Introducing the Attio native integration : \nMatch, qualify, and route leads to the right rep in under 3 seconds. Every booking and account owner syncs back to the Attio automatically \nLearn more →\nProduct\nFeatures\nRouting\nMatch leads to their owner, rotate the rest, and log every decision\nScheduling\nQualify buyers and open the right rep's calendar, inbound, outbound, or at events\nAnalytics\nSee conversion by week, distribution by rep, and the record behind every meeting\nAutomation\nLog meetings in the CRM, credit back no-shows, and trigger your downstream workflows\nResources\nIntegrations\nConnect the CRM, forms, sequencers, and enrichment tools you already run\nChangelog\nUpdates on everything new and improved in the product\nMoving to RevenueHero\nSwitching from another tool?\nWhat changes, who you need on the calls, and how long it took teams that moved off Chili Piper, HubSpot Meetings, or Calendly.\nSee how migrations go\nSolutions\nPeople\nDemand Gen leaders\nGenerate more pipeline with the same traffic\nRevOps leaders\nCentralise your stack for meeting automation and conversion data\nSales leaders\nSkip an entire lifecycle stage in all your deals\nIndustries\nHealthcare\nSimplify health-tech sales and hospital scheduling\nFintech \nKeep consumers off your reps' calendars, book only real leads\nCybersecurity\nQualify on enriched data so you never miss a serious buyer\nPlatforms\nHubSpot\nBook off your forms, route to the owner, sync every outcome\nSalesforce\nMore pipeline booked, CRM stays clean\nAttio\nEvery meeting booked, routed, and written back to Attio\nMoving to RevenueHero\nSwitching from another tool?\nWhat changes, who you need on the calls, and how long it took teams that moved off Chili Piper, HubSpot Meetings, or Calendly.\nSee how migrations go\nCustomers\nSuccess Stories\nView all case studies \n→\nSee how Freshworks drove 57% more bookings\nSee why Seamless switched to RevenueHero to automate meeting scheduling\nHow matter 3x'd demos and boosted calls by 35%\nWall of love\nView all customer reviews \n→\nWhy Northbeam chose RevenueHero over Chili Piper, Calendly, and HubSpot\nWith RevenueHero, all the logic happens at the point of signup, which means that there are no problems for my sales team. They just look at their calendars and are ready to go\nBryan Bumgardner\nDirector of Growth Marketing\nRead full case study\nResources\nResources\nBlog\nGet insights into marketing, sales, and growth\nPodcast\nRevOps leaders on the record about how they operate\nPlaybook\nProven B2B plays for more qualified meetings and pipeline\nBenchmarks & Reports\nInbound conversion rates by industry, funnel stage and company size\nPipeline Velocity Calculator\nWork out how fast deals move through your pipeline\nHelp\nEverything you need to know about how to use RevenueHero\nMoving to RevenueHero\nSwitching from another tool?\nWhat changes, who you need on the calls, and how long it took teams that moved off Chili Piper, HubSpot Meetings, or Calendly.\nSee how migrations go\nPricing\nSign In\nRequest a Demo\nSign In\nBook a Demo\nDouble your pipeline, not your budget.\nInstantly qualify, schedule, route leads to any sales rep, ensure a smooth handover to reps, and personalize meetings.\nInbound\nOutbound\nLite\nEnterprise add-ons\nEssentials\nBook more meetings from all your channels\nYearly\nMonthly\nFixed platform fee: $79/mo\n$25\n/mo/user\nFixed platform fee: $99/mo\n$35\n/mo/user\nRequest a demo \nWhat’s included\nInstant scheduling\nScheduling on web forms\nIn‑app scheduling\nBooking pages for every user\nRouting and distribution\nQualification on form and enriched values\nRound‑robin or any custom logic to route leads\nDomain‑based matching\nConversion lifts\nEmbeddable content in booking pages\nMagic links for email campaigns\nMultiple reminders and automated follow‑ups\nIntegration\nNative integrations with HubSpot, Salesforce, Zoho, Slack, Attio and more\nMeeting Ops automation\nWorkflows across meeting lifecycle\nScale\nUnlimited form submissions.\nNo admin licenses.\nOnboarding and support\nGuided onboarding and implementation\n24‑hour support via Slack Connect\nEnterprise\nScale inbound conversions across channels\nYearly\nMonthly\nFixed platform fee: $79/mo\n$35\n/mo/user\nFixed platform fee: $99/mo\n$45\n/mo/user\nRequest a demo \nWhat’s included\nEverything in essentials plus:\nSmart matching and routing\nFuzzy matching\nMatching based on any custom property\nLookup field based matching\nCollective round robin\nFallback redistribution\nCustom lists in routing\nBalanced round robin\nOwnership automation\nCustom owner updates\nContact/Lead creation\nDynamic scheduling\nDynamic meeting type assignment\nDynamic guest addition\nGroup meeting links\nAdvanced scheduling windows\nExtensibility\nWebhooks\nCustom code in booking pages\nBrand control\nComplete white-labeling\nCustom domain for booking pages\nCustom domain in notifications\nSecurity and Security\nOkta SSO\nEssentials\nAutomate meeting handoffs and all the CRM admin work that comes with it\nWhat’s included\nHandoff and book meetings on behalf of reps\nMagic links for 1-click booking experiences in email sequences\nEmbed meeting slots in email for more conversions\nCustom domain to stay on brand\nMultiple reminders & automated follow ups\nCustom lead to account matching for ABM & named account marketing\nCompensate when no-shows happen or when reps are on a vacation\nGuided onboarding & implementation \nNative integration with Slack\n24 hours support on Slack connect\nDKIM to stay on brand and better email deliverability\nAuto-populate form fills for more conversions and accurate routing\nFuzzy matching to route meetings to right rep\nYearly\nMonthly\n$25\n/mo/user\n$20\n/mo/user\nUnlimited meetings & form submissions. No admin license fee.\nRequest a demo \nEssentials\nAutomate all the admin tasks in booking meetings. No more email back and forth.\nWhat’s included\nPersonalised page with multiple meeting links\nBooking pages with embeddable content\nEmbedded slots in emails for faster conversions\nAutomated remin\n","type":"text"}]}›Thinking…
Great — pricing is public. Now, is there a developer workflow I can act on? Yes: the client SDK. It requires a routerId from a RevenueHero account (hosted product). Without an account/routerId, the example can't fully run end-to-end, but I can build the example code and verify the SDK builds/type-checks locally.
Also check whether there's a public API/webhooks docs (docs are login-gated). Also check assets.revenuehero.io/scheduler.min.js availability.
Plan: build a minimal static example (plain HTML + vanilla JS, no build step) plus optionally a React example using the SDK. But npm install requires network — fine, but no long-running dev servers. I could install the react SDK and typecheck a component. Keep it light.
Let me check: is there a public REST API? Look for docs in help center. Let's try revenuehero.io/help... 404. Maybe help.revenuehero.io or a public knowledge base. Let me quickly check a few.
Also check whether the scheduler script is publicly fetchable (so the example can at least load).
Let me do a couple of quick checks, then write files.
I'll build:
- example/index.html — vanilla JS embed with routerId from env/placeholder
- example/react/App.tsx — using @revenuehero/sdk-react
- README.md — how it works, pricing summary, manageability notes
Verify: npm install @revenuehero/sdk-react + react in a scratch dir, run tsc typecheck on the React example. That's quick-ish. Let's try.
Also test scheduler.min.js returns 200.
✓$ timeout 15 curl -s -o /tmp/sched.js -w "%{http_code} size=%{size_download}\n" https://assets.revenuehero.io/scheduler.min.js; head -c 300 /tmp/sched.js; echo; grep -o "RH_[A-Z_]*" /tmp/sched.js | sort…✓└{"content":[{"text":"200 size=32349\nthis.RevenueHero=(()=>{function m(e,{defaultLocale:t}){switch(t??e){case\"ar\":case\"ar-AE\":case\"ar-BH\":case\"ar-DZ\":ca…ctrl+o
timeout 15 curl -s -o /tmp/sched.js -w "%{http_code} size=%{size_download}\n" https://assets.revenuehero.io/scheduler.min.js; head -c 300 /tmp/sched.js; echo; grep -o "RH_[A-Z_]*" /tmp/sched.js | sort -u | head -20
{"content":[{"text":"200 size=32349\nthis.RevenueHero=(()=>{function m(e,{defaultLocale:t}){switch(t??e){case\"ar\":case\"ar-AE\":case\"ar-BH\":case\"ar-DZ\":case\"ar-EG\":case\"ar-IQ\":case\"ar-JO\":case\"ar-KW\":case\"ar-LB\":case\"ar-LY\":case\"ar-MA\":case\"ar-OM\":case\"ar-QA\":case\"ar-SA\":case\"ar-SD\":case\"ar-SY\":case\"ar-TN\":case\"ar-YE\":return\"ar\";case\"cs\"\nRH_DATA_SOURCE\nRH_EMBED_TARGET\nRH_FORM_ID\nRH_FORM_SUBMITTED\nRH_HIDE_LOADER\nRH_PARENT_FOCUSED\nRH_ROUTER_ID\nRH_SESSION_ID\nRH_SHOW_LOADER\nRH_SUBMITTING_SESSION\n","type":"text"}]}✓$ for u in https://help.revenuehero.io https://www.revenuehero.io/help/ https://www.revenuehero.io/integrations https://api.revenuehero.io/v1; do echo -n "$u -> "; timeout 12 curl -s -o /dev/null -w "%{…✓└{"content":[{"text":"https://help.revenuehero.io -> 200 https://help.revenuehero.io/home/get-started\nhttps://www.revenuehero.io/help/ -> 404 https://www.revenu…ctrl+o
for u in https://help.revenuehero.io https://www.revenuehero.io/help/ https://www.revenuehero.io/integrations https://api.revenuehero.io/v1; do echo -n "$u -> "; timeout 12 curl -s -o /dev/null -w "%{http_code} %{url_effective}\n" -L "$u"; done
{"content":[{"text":"https://help.revenuehero.io -> 200 https://help.revenuehero.io/home/get-started\nhttps://www.revenuehero.io/help/ -> 404 https://www.revenuehero.io/help\nhttps://www.revenuehero.io/integrations -> 200 https://www.revenuehero.io/integrations\nhttps://api.revenuehero.io/v1 -> 401 https://api.revenuehero.io/v1\n","type":"text"}]}›Thinking…
help.revenuehero.io is public. Let me search it for developer/SDK/API/webhooks docs.
✓$ timeout 20 curl -sL "https://help.revenuehero.io/home/get-started" -o /tmp/help.html -w "%{http_code}\n"; python3 - <<'EOF'✓└{"content":[{"text":"200\n/crm/prevent-duplicate-logging\n/enrichment/enrichment-crm\n/enrichment/enrichment-overview\n/enrichment/zerobounce\n/faqs-and-quick-f…ctrl+o
timeout 20 curl -sL "https://help.revenuehero.io/home/get-started" -o /tmp/help.html -w "%{http_code}\n"; python3 - <<'EOF'
import re
h=open('/tmp/help.html',encoding='utf-8',errors='ignore').read()
links=sorted(set(re.findall(r'href="(/[^"#]*)"',h)))
for l in links[:80]: print(l)
print("LEN",len(h))
EOF
{"content":[{"text":"200\n/crm/prevent-duplicate-logging\n/enrichment/enrichment-crm\n/enrichment/enrichment-overview\n/enrichment/zerobounce\n/faqs-and-quick-fixes/crm-sync\n/faqs-and-quick-fixes/flagged-user-inboxes\n/home/get-started\n/home/get-started-user\n/home/get-started.md\n/integrations/appcues\n/integrations/chrome-extension\n/integrations/gong\n/integrations/javascript-events\n/integrations/slack\n/integrations/twilio\n/llms.txt\n/meeting-categories/meeting-categories\n/meeting-categories/prospect-limits\n/meeting-links/group-links\n/meeting-links/link-settings\n/meeting-links/meetings-profile\n/meeting-links/personal-meeting-links\n/meetings/meeting-actions\n/meetings/overview\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon-dark/android-chrome-192x192.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon-dark/favicon-16x16.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon-dark/favicon-32x32.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon-dark/favicon.ico\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon/android-chrome-192x192.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon/apple-touch-icon.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon/favicon-16x16.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon/favicon-32x32.png\n/mintlify-assets/_mintlify/favicons/revenuehero/wUwuvaEj8UaHiTec/_generated/favicon/favicon.ico\n/mintlify-assets/_next/static/chunks/2119d8c4cd150ffe.js?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/462bacc63bed9960.css?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/47232d04bffc0a26.js?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/55a309039aea88c1.js?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/6d55b684068fd47e.js?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/7dac459a5be0fbd2.js?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/84b99a46231ef6be.js?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/chunks/aaa51283d61f795b.css?dpl=dpl_Ho9ervNewT2mACrUoYbN7qri7kim\n/mintlify-assets/_next/static/media/83afe278b6a6bb3c.p.3a6ba036.woff2\n/mintlify-assets/_next/static/media/PaperMono_Variable.p.aa32f7a0.woff2\n/mintlify-assets/_next/static/media/f67ad414ed34149c.p.84166d94.woff2\n/reports/overview\n/resource-filters\n/routers/overview\n/scheduler-blocked-by-optimization-plugins\n/settings/settings-overview\n/sitemap.xml\n/teams/add-members\n/teams/create-teams\n/teams/remove-members\n/type/create-meeting-type\n/web-forms/overview\n/workflows/create-workflows\n/workflows/overview\n/workflows/webhook-payloads\nLEN 409225\n","type":"text"}]}›Thinking…
There's /llms.txt — great, a Mintlify docs site. Fetch llms.txt for developer-relevant docs: web-forms/overview, integrations/javascript-events, routers/overview, workflows/webhook-payloads.
✓$ timeout 20 curl -sL https://help.revenuehero.io/llms.txt | head -80✓└{"content":[{"text":"# RevenueHero Docs\n\n- [Getting Started with RevenueHero](https://help.revenuehero.io/home/get-started.md): New to RevenueHero? Welcome on…ctrl+o
{"content":[{"text":"# RevenueHero Docs\n\n- [Getting Started with RevenueHero](https://help.revenuehero.io/home/get-started.md): New to RevenueHero? Welcome onboard! 👋\n- [Overview of Routers in RevenueHero](https://help.revenuehero.io/routers/overview.md): Routers in RevenueHero determine the experience that your contacts have when they submit a form on your website.\n- [How to create an Inbound Router?](https://help.revenuehero.io/routers/inbound/create-inbound-router.md): An Inbound Router listens to your lead capture form, qualifies each submission, and instantly books the right meeting with the right rep. This document walks you through creating one from start to finish.\n- [How to map your web form in RevenueHero?](https://help.revenuehero.io/routers/inbound/mapping-your-form.md): Mapping your web form allows RevenueHero to use each field in your form as routing conditions.\n- [How to support multiple languages on your scheduler?](https://help.revenuehero.io/routers/inbound/multi-language-support.md): Allow your prospects to read the scheduler through multiple languages.\n- [How to install the RevenueHero script?](https://help.revenuehero.io/Inbound-router-installation.md): All the ways you can invoke the RevenueHero scheduler on your website, from standard form listeners to programmatic triggers like hero.submit() and hero.dialog.open().\n- [How to create a Campaign Router?](https://help.revenuehero.io/routers/campaign/create-campaign-router.md): Creating a Campaign Router is simple and easy. It's just a few easy steps, and this article walks you through each step in detail.\n- [How to create Relays?](https://help.revenuehero.io/routers/relays/create-relays.md): Creating a Relay is simple and easy. It's just six steps, and this article walks you through each step in detail.\n- [How to book a Relay meeting with a prospect from within your CRM?](https://help.revenuehero.io/routers/relays/book-relay-meetings/within-crm.md): You can handoff meetings to the right rep in 2 clicks under 5 seconds. This article covers how you can do that.\n- [How to book a Relay meeting with a prospect from within your Inbox?](https://help.revenuehero.io/routers/relays/book-relay-meetings/within-inbox.md): You can handoff meetings to the right rep in 2 clicks under 5 seconds. This article covers how you can do that.\n- [How to book a Relay meeting with a prospect from within any sales tool?](https://help.revenuehero.io/routers/relays/book-relay-meetings/within-any-tool.md): You can handoff meetings to the right rep in 2 clicks under 5 seconds. This article covers how you can do that.\n- [How to create a form in RevenueHero?](https://help.revenuehero.io/routers/forms/custom-forms.md): Creating a form is simple and easy. This article walks you through each step in detail.\n- [How to create a post-booking form?](https://help.revenuehero.io/routers/forms/post-booking-forms.md): Collect the context your reps need after a prospect books, without adding fields that hurt your conversion rate.\n- [Overview of Reports in RevenueHero](https://help.revenuehero.io/reports/overview.md): Reports in RevenueHero offer an at-a-glance view of your funnel health and movement of meetings across different stages.\n- [Routing Logs](https://help.revenuehero.io/reports/inbound/routing-logs.md): A routing log is the full trace of a single form submission, from the form all the way to your CRM.\n- [Analyse your inbound funnel health](https://help.revenuehero.io/reports/inbound/conversion-reports.md): Conversion reports give you an at-a-glance analysis of your overall inbound conversions with trends and funnel visualisations.\n- [Track meeting distribution and outcomes](https://help.revenuehero.io/reports/inbound/distribution-reports.md): Distribution reports give you an at-a-glance view of how meetings are distributed amongst your sales team, along with the meeting outcomes associated to each sales rep.\n- [Trace every single campaign CTA interaction](https://help.revenuehero.io/reports/campaign/routing-logs.md): Routing logs for your campaign links give you ground up visibility of meetings getting booked through campaigns\n- [Analyse your campaign performance](https://help.revenuehero.io/reports/campaign/conversion-reports.md): Conversion reports give you an at-a-glance analysis of your overall campaign performance and a funnel visualisation for your campaigns\n- [Stay on top of meeting distribution through campaigns](https://help.revenuehero.io/reports/campaign/distribution-reports.md): Distribution reports give you an at-a-glance view of how meetings are distributed amongst your sales team, along with the meeting outcomes associated to each sales rep.\n- [What are Matching Rules? ](https://help.revenuehero.io/what-are-matching-rules.md)\n- [How to create a Matching Rule?](https://help.revenuehero.io/rules/matching/create-matching-rule.md): Route meetings to your existing CRM owner for lead or contact with Matching rules\n- [How to create a new Distribution Rule?](https://help.revenuehero.io/rules/distribution/create-distribution-rule.md): Route meetings to new owners for lead or contact via Round Robin with Distribution rules\n- [How to create a Group Round Robin?](https://help.revenuehero.io/rules/distribution/group-round-robin.md): Route meetings to multiple folks via Group Round Robin with Distribution rules.\n- [Round Robin History](https://help.revenuehero.io/rules/distribution/round-robin-history.md): See what has transpired via Round Robin in your rule and calibrate if necessary\n- [How does Balanced Round Robin work?](https://help.revenuehero.io/rules/distribution/balanced-round-robin.md): Route the next meeting to the rep carrying the lightest current workload, so no one gets buried while others sit idle, instead of cycling reps in a fixed order.\n- [Strict, Flexible, or Balanced Round Robin: which should you use?](https://help.revenuehero.io/rules/distribution/round-robin-methods.md): The three Round Robin methods assign meetings on different inputs. Pick the one that matches whether you optimize for booking speed or even distribution.\n- [How to update CRM owner fields when a distribution rule matches?](https://help.revenuehero.io/rules/distribution/update-owner.md): Write the assigned rep back as the owner on lead, contact, and account records when a distribution rule matches.\n- [Meetings in RevenueHero](https://help.revenuehero.io/meetings/overview.md): Meetings are core to RevenueHero. Learn all about them here.\n- [Meetings in RevenueHero](https://help.revenuehero.io/meetings/meeting-actions.md): Easily manage any scheduled meeting right from within your workspace — reschedule, reassign, cancel, or mark no-shows in seconds.\n- [How to create a Meeting Type?](https://help.revenuehero.io/type/create-meeting-type.md): Customize your meeting configuration like duration, buffers and invite texts for your meetings in a few simple steps\n- [How to create a meeting type with default availability?](https://help.revenuehero.io/type/default-availability-meeting-type.md): Customize your meeting configuration like duration, buffers and invite texts for your meetings in a few simple steps\n- [How to create a meeting type for events?](https://help.revenuehero.io/type/events-meeting-type.md): Customize your meeting configuration like duration, buffers and invite texts for your meetings in a few simple steps\n- [How to create a meeting type with custom availability?](https://help.revenuehero.io/type/custom-availability-meeting-type.md): Customize your meeting configuration like duration, buffers and invite texts for your meetings in a few simple steps\n- [Setting Up Meeting Type Sync Between RevenueHero and HubSpot ](https://help.revenuehero.io/type/hub-spo.md): Link your RevenueHero meeting types to HubSpot so every booked meeting is categorized automatically.\n- [Meeting Categories in RevenueHero](https://help.revenuehero.io/meeting-categories/meeting-categories.md): Categorize relevant meetings and limit the number of meetings your reps are assigned.\n- [How to limit how often a prospect or company can book?](https://help.revenuehero.io/meeting-categories/prospect-limits.md): Cap how many meetings a single prospect or a whole company can book.\n- [How to set up Personal Meeting Links?](https://help.revenuehero.io/meeting-links/personal-meeting-links.md): Learn how to set up your own customized 1-1 meeting links\n- [How to set up Group Meeting Links?](https://help.revenuehero.io/meeting-links/group-links.md): Learn how to set up meeting links with combined availability of you and your colleagues.\n- [How to set up your Meetings Profile?](https://help.revenuehero.io/meeting-links/meetings-profile.md): Learn how to set up your meetings profile.\n- [Meeting Link Settings](https://help.revenuehero.io/meeting-links/link-settings.md): Meeting Link Settings allow admins to control CRM sync behaviour, configure base link assets, and create themes for all users. These settings apply to personal and group meeting links created within your organization.\n- [Overview of Workflows in RevenueHero](https://help.revenuehero.io/workflows/overview.md): Workflows in RevenueHero help configure notifications when certain events occur\n- [How to create a Workflow?](https://help.revenuehero.io/workflows/create-workflows.md): Creating a Workflow is simple and easy. It's just 4 steps, and this article walks you through each step in detail.\n- [Webhook Payload](https://help.revenuehero.io/workflows/webhook-payloads.md): Samples of different webhook payloads received for different source\n- [Slack notification for Meeting completion](https://help.revenuehero.io/workflows/examples/meeting-completed-slack-notification.md): Learn how to set up a workflow to receive Slack messages when a RevenueHero meeting ends\n- [How to create a team?](https://help.revenuehero.io/teams/create-teams.md): Group your sales reps into teams so distribution rules can round-robin meetings between them, assign to selected members, or route to a single rep based on conditions.\n- [How to add members to a team?](https://help.revenuehero.io/teams/add-members.md): Add existing users or invite new reps to a team so they can start receiving meetings through round-robin distribution.\n- [How to remove members from a Team?](https://help.revenuehero.io/teams/remove-members.md)\n- [RevenueHero Settings](https://help.revenuehero.io/settings/settings-overview.md)\n- [How to set up user profile?](https://help.revenuehero.io/settings/personal/profile.md): Let's talk about how you can customize your profile to show off your swag.\n- [How to change Password?](https://help.revenuehero.io/settings/personal/password.md): Need to change your password? This article walks you through the steps.\n- [How to change my Availability?](https://help.revenuehero.io/settings/personal/my-availability.md): Need to change your availability? Let's look at how you can edit this.\n- [Integrating Calendar and Conferencing Tool](https://help.revenuehero.io/settings/personal/my-integrations.md): Learn how to integrate RevenueHero user with Google/Outlook Calendar, Zoom, Google Meet, or MS Teams.\n- [Setting Your Booking Preferences](https://help.revenuehero.io/settings/personal/my-preferences.md): Set up your default preferences for Relays.\n- [Adding Form Entries to Meeting Invites in RevenueHero ](https://help.revenuehero.io/settings/organization/add-form-entries-in-the-invite.md): Push the form answers your AE actually needs into the calendar invite, and leave the routing-only fields out.\n- [How to change Organization details?](https://help.revenuehero.io/settings/organization/details.md)\n- [How to invite users to RevenueHero?](https://help.revenuehero.io/settings/organization/all-users.md)\n- [Nominees](https://help.revenuehero.io/settings/organization/nominees.md)\n- [Organization Integrations](https://help.revenuehero.io/settings/organization/integrations.md): Learn how to integrate RevenueHero with Slack, HubSpot, Salesforce, Zoho, or Attio CRM tools.\n- [How to create lists in RevenueHero?](https://help.revenuehero.io/settings/organization/lists.md)\n- [How to customize your Widget?](https://help.revenuehero.io/settings/organization/branding.md): Customize how your scheduler loads, looks and feels. Let the Picasso in you run wild.\n- [How to set up custom domain?](https://help.revenuehero.io/settings/organization/scheduler-domain.md): Give your links your brand's touch by adding a custom domain.\n- [How to customize email domain?](https://help.revenuehero.io/settings/organization/email-domain.md): Give your reminder emails your brand's touch by adding a custom domain.\n- [How to change Round Robin settings?](https://help.revenuehero.io/settings/organization/distribution/distribution.md)\n- [Using Subgroups for Complex Qualification Logic](https://help.revenuehero.io/settings/organization/distribution/subgroups.md): Nest conditions logically to match how your qualification rules actually work. Eliminate endless AND/OR chains.\n- [How to set up company holidays?](https://help.revenuehero.io/settings/organization/holidays.md): Create account-level holidays to automatically block your team's availability. No more relying on everyone to manually block their own calendars. Without holidays in RevenueHero, your team has to manually block their calendars for every company holiday. If one person forgets, meetings get booked on…\n- [UTM Parameters tracking in RevenueHero ](https://help.revenuehero.io/settings/organization/utm-tracking.md): Capture UTM parameters when prospects book meeting through RevenueHero\n- [Adding Form Entries to Meeting Invites in RevenueHero ](https://help.revenuehero.io/settings/organization/add-form-entries-in-the-invite.md): Push the form answers your AE actually needs into the calendar invite, and leave the routing-only fields out.\n- [Customizing Layouts in RevenueHero](https://help.revenuehero.io/settings/organization/layouts.md): With custom Layouts, design scheduling experiences that feel like an extension of your brand.\n- [How to manage availability exceptions?](https://help.revenuehero.io/settings/organization/exceptions.md): Create one-off blocks and overrides so your team's availability reflects reality, not just their default working hours.\n- [How to set up Meeting Locations](https://help.revenuehero.io/settings/organization/meeting-locations.md): Build a reusable catalog of how meetings happen (video, phone, or in-person) and attach them to your meeting types so prospects can pick how they connect.\n- [Custom Email Blocklist](https://help.revenuehero.io/settings/organization/custom-email-blocklist.md)\n- [Security settings overview](https://help.revenuehero.io/security-overview.md): Control who can sign into your RevenueHero account, which login methods they use, and which websites are allowed to embed your scheduler.\n- [How to integrate HubSpot CRM?](https://help.revenuehero.io/crm/hubspot/overview.md): Integrate your HubSpot CRM with RevenueHero in 3 simple steps\n- [What data is pushed by RevenueHero to HubSpot?](https://help.revenuehero.io/crm/hubspot/crm-fields.md): RevenueHero keeps your HubSpot CRM up-to-date with Prospect, Meeting, and Activity information\n- [How to integrate Salesforce CRM?](https://help.revenuehero.io/crm/salesforce/overview.md): Integrate your Salesforce CRM with RevenueHero in 4 simple steps\n- [What data is pushed by RevenueHero to Salesforce?](https://help.revenuehero.io/crm/salesforce/crm-fields.md): RevenueHero keeps your Salesforce CRM up-to-date with Prospect and Meeting information\n- [How to make RevenueHero fields in Salesforce visible?](https://help.revenuehero.io/crm/salesforce/toggle-field-visibility.md): This guide helps you make RevenueHero fields visible in Salesforce\n","type":"text"}]}✓$ timeout 20 curl -sL https://help.revenuehero.io/web-forms/overview.md | head -120✓└{"content":[{"text":"> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover al…ctrl+o
{"content":[{"text":"> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# How to map your web form in RevenueHero?\n\n> Mapping your web form allows RevenueHero to use each field in your form as routing conditions.\n\nMapping your lead intake form is the first step in setting up your distribution workflows in RevenueHero. The mapping allows RevenueHero to use each one of your form input fields (visible and hidden) as conditions in routing rules.\n\n<Note>\n **NOTE**\n\n RevenueHero only listens to the form submission to trigger the scheduling widget. It does not interfere with any of your existing data or current form functions.\n</Note>\n\nTo map your form:\n\n1. In the navigation panel, click on **Inbound → Forms**.\n2. Click on Add new form\n\n<Frame>\n <img src=\"https://mintcdn.com/revenuehero/p8JUmtDoedAH86s1/images/form_mapping_new_1.png?fit=max&auto=format&n=p8JUmtDoedAH86s1&q=85&s=025a271f34dcc0d08ef28a252301b7d0\" alt=\"\" width=\"1920\" height=\"993\" data-path=\"images/form_mapping_new_1.png\" />\n</Frame>\n\n3. Name your form mapping to ensure that you’re able to recollect which form was mapped\n4. In the form selector field add the selector ID of your form. (This can be found by inspecting your form on the page and looking up the form id associated with it). This is required for RevenueHero to know which form submission to listen to, before triggering the scheduling widget.\n\nFor specific instructions for your webform, here are some form providers that we work with:\n\n<CardGroup cols={3}>\n <Card title=\"Pardot\" icon=\"https://logo.clearbit.com/salesforce.com\" iconType=\"duotone\" href=\"/web-forms/pardot\" />\n\n <Card title=\"Marketo\" icon=\"https://logo.clearbit.com/marketo.com\" iconType=\"duotone\" href=\"/web-forms/marketo\" />\n\n <Card title=\"Gravity forms\" icon=\"https://logo.clearbit.com/gravityforms.com\" iconType=\"duotone\" href=\"/web-forms/gravity\" />\n\n <Card title=\"Webflow\" icon=\"https://logo.clearbit.com/webflow.com\" iconType=\"duotone\" href=\"/web-forms/webflow\" />\n\n <Card title=\"Gatsby\" icon=\"https://logo.clearbit.com/gatsbyjs.com\" iconType=\"duotone\" href=\"/web-forms/gatsby\" />\n\n <Card title=\"Jotform\" icon=\"pager\" iconType=\"duotone\" href=\"/web-forms/jotform\" />\n\n <Card title=\"Typeform\" icon=\"https://logo.clearbit.com/typeform.com\" iconType=\"duotone\" href=\"/web-forms/typeform\" />\n\n <Card title=\"Unbounce\" icon=\"https://logo.clearbit.com/unbounce.com\" iconType=\"duotone\" href=\"/web-forms/unbounce\" />\n\n <Card title=\"Intercom\" icon=\"https://logo.clearbit.com/intercom.com\" iconType=\"duotone\" href=\"/web-forms/intercom\" />\n</CardGroup>\n\n<Note>\n Contact us at [support@revenuehero.io](mailto:support@revenuehero.io) if you don't find your form provider on this list.\n\n RevenueHero is form agnostic and can work with any form - we'll be quick to add help documentation for your provider.\n</Note>\n\n<Card title=\"Custom web form\" icon=\"circle-nodes\" iconType=\"duotone\" href=\"/web-forms/custom\">\n Click here to understand how to work with a custom form.\n</Card>\n","type":"text"}]}›Thinking…
Excellent — docs are public and even LLM-friendly (.md). Let me fetch the key installation doc: /Inbound-router-installation.md and javascript-events, and webhook payloads.
✓$ timeout 20 curl -sL https://help.revenuehero.io/Inbound-router-installation.md | sed 's/<img[^>]*>//' | head -200✓└{"content":[{"text":"> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover al…ctrl+o
{"content":[{"text":"> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# How to install the RevenueHero script?\n\n> All the ways you can invoke the RevenueHero scheduler on your website, from standard form listeners to programmatic triggers like hero.submit() and hero.dialog.open().\n\nThe standard way to invoke RevenueHero is `hero.schedule('#form-id')`, which listens for your form's submit event and opens the scheduler automatically. But that doesn't always fit. Maybe you're running server-side validation before showing the calendar. Maybe your form lives inside an iframe. Maybe you're building in React and there's no traditional form submit event to listen to.\n\nThis article covers every way to invoke the RevenueHero scheduler on your website. For the step-by-step router setup that generates your script snippet, see [Create Inbound Router](/routers/inbound/create-inbound-router#install-the-script).\n\n<Note>\n **BEFORE YOU BEGIN**\n\n 1. [Create an Inbound Router](/routers/inbound/create-inbound-router) and note your **Router ID**\n 2. Add the RevenueHero source script to the `<head>` of your page:\n\n ```html theme={null}\n <script type=\"text/javascript\" src=\"https://assets.revenuehero.io/scheduler.min.js\"></script>\n ```\n</Note>\n\n## Methods\n\nThe RevenueHero script exposes three methods. The first, `hero.schedule()`, is the standard method documented in every [web forms integration guide](/web-forms/custom). The other two, `hero.submit()` and `hero.dialog.open()`, give you programmatic control over the entire flow.\n\n### hero.schedule(formSelector)\n\nBinds to a form's native submit event. When the form is submitted, RevenueHero intercepts the data, runs routing rules, and opens the scheduler automatically.\n\n```javascript theme={null}\nconst hero = new RevenueHero({ routerId: 'xxx' });\nhero.schedule('#demo-form'); // CSS selector for your form element\n```\n\n**When to use:** Your form uses a standard HTML submit and you don't need to intercept the submission before the scheduler appears.\n\n**Limitation:** If you call `e.preventDefault()` on the form's submit event before RevenueHero can listen to it, `hero.schedule()` will never fire. Use `hero.submit()` instead.\n\n### hero.submit(formData)\n\nSends form field data directly to RevenueHero for routing and qualification. Returns a Promise that resolves with session data you can use to open the scheduler.\n\n```javascript theme={null}\nconst hero = new RevenueHero({ routerId: 'xxx' });\n\nhero.submit({\n email: 'jane@acme.com',\n firstname: 'Jane',\n lastname: 'Doe',\n company: 'Acme Inc'\n}).then(function(sessionData) {\n hero.dialog.open(sessionData);\n});\n```\n\n**When to use:** You need to control what happens between form submission and the scheduler appearing. Custom validation, async API calls, multi-step forms, SPA frameworks, or any flow where `hero.schedule()` doesn't work.\n\n<Warning>\n **Pass a plain object, not a FormData instance.** If you're collecting data from a form element, convert it first:\n\n ```javascript theme={null}\n const formElement = document.getElementById('demo-form');\n const formData = Object.fromEntries(new FormData(formElement).entries());\n hero.submit(formData); // plain object like { email: '...', name: '...' }\n ```\n\n Passing a raw `FormData` object will silently fail.\n</Warning>\n\n### hero.dialog.open(sessionData)\n\nOpens the scheduler popup programmatically. Takes the session data returned from `hero.submit()`.\n\n```javascript theme={null}\nhero.submit(formData).then(function(sessionData) {\n hero.dialog.open(sessionData);\n});\n```\n\n**When to use:** Always used together with `hero.submit()`. This is what actually makes the calendar visible to your prospect.\n\n## Constructor options\n\nThe `RevenueHero` constructor accepts a configuration object:\n\n| Parameter | Type | Required | Description |\n| - | - | - | - |\n| `routerId` | string | Yes | Your Router ID from the Inbound Router setup |\n| `formType` | string | No | Set to `'pardot'` or `'jotform'` for those form providers |\n| `showLoader` | boolean | No | Shows a loading spinner while routing rules are evaluated |\n\n```javascript theme={null}\nconst hero = new RevenueHero({\n routerId: 'xxx',\n showLoader: true\n});\n```\n\nYour Router ID is displayed in the **Widget Installation** step when you [create or edit an Inbound Router](/routers/inbound/create-inbound-router#install-the-script).\n\n## Custom validation before scheduling\n\nThe most common reason to use `hero.submit()` is when you need to validate form data before showing the scheduler. Run your validation, and only trigger RevenueHero if it passes.\n\n```html theme={null}\n<form id=\"bookademoform\">\n <input name=\"email\" type=\"email\" required />\n <input name=\"firstName\" type=\"text\" required />\n <input name=\"company\" type=\"text\" />\n <button type=\"submit\">Request Demo</button>\n</form>\n\n<script type=\"text/javascript\" src=\"https://assets.revenuehero.io/scheduler.min.js\"></script>\n<script type=\"text/javascript\">\n const form = document.getElementById('bookademoform');\n\n form.addEventListener('submit', async function(e) {\n e.preventDefault();\n\n const data = Object.fromEntries(new FormData(form).entries());\n\n // Your custom validation (API call, domain check, etc.)\n const response = await fetch('https://your-api.com/validate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: data.email })\n });\n const result = await response.json();\n\n if (result.status === 'valid') {\n // Only show the scheduler for valid leads\n const hero = new RevenueHero({ routerId: 'xxx', showLoader: true });\n hero.submit(data).then(function(sessionData) {\n hero.dialog.open(sessionData);\n });\n } else {\n // Show an error message\n document.getElementById('error').textContent = 'Please use a work email.';\n }\n });\n</script>\n```\n\n<Tip>\n This pattern is useful for running checks like email validation services, domain blocklists, or CRM lookups before consuming a RevenueHero routing. If the check fails, the prospect never sees the scheduler and no routing log entry is created.\n</Tip>\n\n## Webflow forms (AJAX intercept)\n\nWebflow forms submit via AJAX by default. If the standard `hero.schedule()` doesn't trigger the scheduler on your Webflow site, use this jQuery-based intercept pattern:\n\n```html theme={null}\n<script type=\"text/javascript\" src=\"https://assets.revenuehero.io/scheduler.min.js\"></script>\n<script type=\"text/javascript\">\n jQuery(document).ajaxComplete(function(event, xhr, settings) {\n if (settings.url.includes('https://webflow.com/api/v1/form/')) {\n var formElement = document.querySelector('#wf-form-Email-Form');\n var isSuccessful = xhr.status === 200;\n var isTargetForm = settings.data.includes(formElement.dataset['wfElementId']);\n\n if (isTargetForm && isSuccessful) {\n var submitData = Object.fromEntries(new FormData(formElement).entries());\n var hero = new RevenueHero({ routerId: 'xxx' });\n hero.submit(submitData).then(function(sessionData) {\n hero.dialog.open(sessionData);\n });\n }\n }\n });\n</script>\n```\n\nReplace `#wf-form-Email-Form` with your Webflow form's CSS ID and `'xxx'` with your Router ID.\n\n<Warning>\n This script must be placed in the **Before `</body>` tag** section in Webflow, not the `<head>`. The form element needs to exist in the DOM before the script runs.\n</Warning>\n\nFor the standard Webflow installation that works without this intercept, see [Webflow Forms](/web-forms/webflow).\n\n## React and Next.js\n\nIn single-page applications, the RevenueHero script needs to load dynamically since there's no traditional page load.\n\n### React\n\n```jsx theme={null}\nimport { useEffect, useRef } from 'react';\n\nfunction DemoForm() {\n const formRef = useRef(null);\n\n useEffect(() => {\n const script = document.createElement('script');\n script.src = 'https://assets.revenuehero.io/scheduler.min.js';\n script.onload = () => {\n // Script loaded, RevenueHero is now available on window.RevenueHero\n };\n","type":"text"}]}✓$ timeout 20 curl -sL https://help.revenuehero.io/integrations/javascript-events.md | sed 's/<img[^>]*>//' | head -150; echo "===== SECURITY"; timeout 20 curl -sL https://help.revenuehero.io/security-ov…✓└{"content":[{"text":"> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover al…ctrl+o
timeout 20 curl -sL https://help.revenuehero.io/integrations/javascript-events.md | sed 's/<img[^>]*>//' | head -150; echo "===== SECURITY"; timeout 20 curl -sL https://help.revenuehero.io/security-overview.md | sed 's/<img[^>]*>//' | head -60
{"content":[{"text":"> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# RevenueHero JavaScript Events\n\n> RevenueHero JavaScript events are sent from the scheduler at different stages. Learn about those events that can be used to trigger downstream activities.\n\nThe **RevenueHero JavaScript** tracks and emits the following JavaScript events through the lifecycle of the meeting booking experience which can be captured using a sample message listener like the following to be used for actions like sending event to Google Analytics, Pixel, etc.\n\n```javascript Example theme={null}\nwindow.addEventListener('message', (ev) => {\n if(ev.data.type == 'MEETING_BOOKED') {\n // Send to Google Analytics\n dataLayer.push({ event: 'meeting_booked' });\n\n // Send to pixel\n fbq('track', 'RevenueHero', { event: 'meeting_booked' });\n }\n})\n```\n\n#### MEETING\\_BOOKED\n\nThe event is sent when a meeting is booked successfully with the meeting payload\n\n```javascript Payload theme={null}\n{\n \"type\": \"MEETING_BOOKED\",\n \"meeting\": {\n \"id\": \"1234\",\n \"type\": \"meeting\",\n \"attributes\": {\n \"team_id\": 123,\n \"form_routing_rule_id\": 123,\n \"form_matching_rule_id\": null,\n \"name\": \"Road Runner and Coyote | Acme Inc.\",\n \"slug\": \"b60364750e05f1e74e623733c3c3c6476b496323\",\n \"status\": \"upcoming\",\n \"booker_name\": \"Road Runner\",\n \"booker_email\": \"road.runner@acme.inc\",\n \"meeting_time\": \"2023-11-24T05:30:00.000Z\",\n \"created_at\": \"2023-11-24T05:30:00.000Z\",\n \"cancellation_reason\": null,\n \"reschedule_count\": 0,\n \"last_rescheduled_at\": null,\n \"booking_guests\": [],\n \"calendar_notification_title\": null,\n \"calendar_notification_body\": null,\n \"reminder_notification_title\": null,\n \"reminder_notification_body\": null,\n \"conference_link\": null,\n \"parsed_name\": \"Road Runner and Coyote | Acme Inc.\",\n \"booking_participants\": [{\n \"name\": \"Road Runner\",\n \"email\": \"road.runner@acme.inc\",\n \"organizer\": true,\n \"rsvp_status\": \"accepted\",\n \"primary_guest\": false\n },\n {\n \"name\": \"Wile E. Coyote\",\n \"email\": \"wilee.coyote@acme.inc\",\n \"organizer\": false,\n \"rsvp_status\": \"accepted\",\n \"primary_guest\": true\n }\n ],\n \"duration\": 30,\n \"previous_meeting_time\": null,\n \"reminder_due\": \"2023-11-24T05:30:00.000Z\",\n \"time_zone\": \"America/Los_Angeles\",\n \"subdomain\": \"acme.inc\",\n \"in_progress\": false\n }\n }\n}\n```\n\n#### MEETING\\_RESCHEDULED\n\nThe event is sent when a meeting is rescheduled from the booking widget successfully with the meeting payload\n\n```javascript Payload theme={null}\n{\n \"type\": \"MEETING_RESCHEDULED\",\n \"meeting\": {\n \"id\": \"1234\",\n \"type\": \"meeting\",\n \"attributes\": {\n \"team_id\": 123,\n \"form_routing_rule_id\": 123,\n \"form_matching_rule_id\": null,\n \"name\": \"Road Runner and Coyote | Acme Inc.\",\n \"slug\": \"b60364750e05f1e74e623733c3c3c6476b496323\",\n \"status\": \"upcoming\",\n \"booker_name\": \"Road Runner\",\n \"booker_email\": \"road.runner@acme.inc\",\n \"meeting_time\": \"2023-11-24T15:30:00.000Z\",\n \"created_at\": \"2023-11-24T05:30:00.000Z\",\n \"cancellation_reason\": null,\n \"reschedule_count\": 1,\n \"last_rescheduled_at\": \"2023-11-24T05:30:00.000Z\",\n \"booking_guests\": [],\n \"calendar_notification_title\": null,\n \"calendar_notification_body\": null,\n \"reminder_notification_title\": null,\n \"reminder_notification_body\": null,\n \"conference_link\": null,\n \"parsed_name\": \"Road Runner and Coyote | Acme Inc.\",\n \"booking_participants\": [{\n \"name\": \"Road Runner\",\n \"email\": \"road.runner@acme.inc\",\n \"organizer\": true,\n \"rsvp_status\": \"accepted\",\n \"primary_guest\": false\n },\n {\n \"name\": \"Wile E. Coyote\",\n \"email\": \"wilee.coyote@acme.inc\",\n \"organizer\": false,\n \"rsvp_status\": \"accepted\",\n \"primary_guest\": true\n }\n ],\n \"duration\": 30,\n \"previous_meeting_time\": \"2023-11-24T05:30:00.000Z\",\n \"reminder_due\": \"2023-11-24T05:30:00.000Z\",\n \"time_zone\": \"America/Los_Angeles\",\n \"subdomain\": \"acme.inc\",\n \"in_progress\": false\n }\n }\n}\n```\n\n#### CLOSE\\_ADD\\_GUEST\n\nThe event is sent when a prospect exits from the guest addition textbox\n\n```javascript Payload theme={null}\n{\n\ttype: 'CLOSE_ADD_GUEST'\n}\n```\n\n#### ADDING\\_GUEST\n\nThe event is sent when a prospect clicks on the Invite Guest button and lands in the guest addition textbox\n\n===== SECURITY\n> ## Documentation Index\n> Fetch the complete documentation index at: https://help.revenuehero.io/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Security settings overview\n\n> Control who can sign into your RevenueHero account, which login methods they use, and which websites are allowed to embed your scheduler.\n\nTwo questions sit behind your RevenueHero security settings: who is allowed into your account, and where is your scheduler allowed to run. The Security page answers both from one place. It controls account access (who can sign up, how they log in) and embedding (which of your domains can host the booking widget). This page walks through each section so you know what every control does before you change it.\n\n<Note>\n **BEFORE YOU BEGIN**\n\n Security settings are account-wide and affect every member. Changes here can lock people out or block your live scheduler, so review each section before saving.\n</Note>\n\n## Open Security settings\n\nIn the left sidebar, click **Settings → Security**.\n\n<Frame>\n \n</Frame>\n\n## Who can sign up to your account\n\nControls whether anyone can create an account under your organization or only people you invite. Click **Edit** to choose between open signup and invite-only, and to set a domain allowlist so only addresses on your company domains can join.\n\nUse invite-only with a domain allowlist when you want tight control over who becomes a RevenueHero user.\n\n## Login methods\n\nSets how your members authenticate: password, Google SSO, Microsoft SSO, or Okta. Click **Edit** to turn methods on and off. At least one method must stay enabled.\n\nFor the full walkthrough, see [Login methods](/settings/security/login-methods). To provision through Okta, see [Set up Okta](/settings/security/okta).\n\n## Trusted Origins\n\nControls which websites are allowed to embed your scheduler. This works as an allowlist: click **Add trusted origins** and enter each site's full origin URL (for example `https://www.yourcompany.com`). Once you've added at least one origin, scheduling is allowed only from those origins, and a submission from any other domain is blocked.\n\nHere's the behavior to understand: when no trusted origins are specified, RevenueHero allows submissions from **any** domain. The moment you add your first origin, you switch from \"any domain\" to a strict allowlist of exactly the origins you listed.\n\n<Tip>\n Add every domain and subdomain your forms live on, including staging and landing-page subdomains. A scheduler that works on your main site but fails on a campaign subdomain is almost always a missing trusted origin.\n</Tip>\n\n<Warning>\n Leaving Trusted Origins empty means any website can embed your booking widget, since no allowlist is enforced. Add your real domains to lock embedding down to the sites you control, but make sure you've listed every domain your forms run on first, or you'll block your own live scheduler.\n</Warning>\n\n***\n\nThat is the Security page. Account access on the left, scheduler embedding on the right, all in one place. 🎉🎉🎉\n\n<CardGroup cols={2}>\n <Card title=\"Login methods\" icon=\"key\" iconType=\"solid\" href=\"/settings/security/login-methods\">\n Turn password, Google, and Microsoft sign-in on or off.\n </Card>\n\n <Card title=\"Set up Okta\" icon=\"shield-halved\" iconType=\"solid\" href=\"/settings/security/okta\">\n","type":"text"}]}›Thinking…
I have everything I need. Now build a light example:
example/index.html— static page with a demo form + RevenueHero script +hero.submit()flow + meeting-booked event listener. Router ID configurable via?routerId=query param or a constant.example/react/DemoForm.tsx— React version using@revenuehero/sdk-react.README.md— how pricing works, what I built, how to run (just open the file / any static file server — that's not a "local service stack", though the user said don't start local service stacks. I won't start anything; I'll just note it).
Verify: I should verify the React example typechecks. That needs npm install of react + the SDK. Let's try quickly with a timeout. That's an install, not a long-running service. Let's attempt in a scratch dir, with --no-audit --no-fund. If it's slow, skip and note.
Also note the SDK react package has no dependencies and no README; check its peer deps.
Let me create files and run a typecheck.
Also note: an important blocker — the example can't complete end-to-end without a Router ID from a RevenueHero account (sales-gated: "Request a demo" on all pricing tiers; no self-serve signup visible). Let me check whether there's a self-serve signup — app.revenuehero.io/signup? Let me check quickly. Also whether trusted origins would block localhost/file:// — important practical note: with no trusted origins set, any domain works, so localhost works out of the box.
Let me check signup availability and the react package's package.json peerDeps.
✓$ for u in https://app.revenuehero.io/signup https://app.revenuehero.io/register https://app.revenuehero.io/login; do echo -n "$u -> "; timeout 12 curl -s -o /dev/null -w "%{http_code} %{url_effective}\…✓└{"content":[{"text":"https://app.revenuehero.io/signup -> 404 https://app.revenuehero.io/404\nhttps://app.revenuehero.io/register -> 404 https://app.revenuehero…ctrl+o
for u in https://app.revenuehero.io/signup https://app.revenuehero.io/register https://app.revenuehero.io/login; do echo -n "$u -> "; timeout 12 curl -s -o /dev/null -w "%{http_code} %{url_effective}\n" -L "$u"; done; echo "=== react pkg json"; timeout 15 curl -s https://registry.npmjs.org/@revenuehero%2Fsdk-react/latest | python3 -c "import sys,json;d=json.load(sys.stdin);print(json.dumps({k:d.get(k) for k in ['version','peerDependencies','dependencies','main','module','types','license']},indent=1))"
{"content":[{"text":"https://app.revenuehero.io/signup -> 404 https://app.revenuehero.io/404\nhttps://app.revenuehero.io/register -> 404 https://app.revenuehero.io/register\nhttps://app.revenuehero.io/login -> 200 https://app.revenuehero.io/login\n=== react pkg json\n{\n \"version\": \"2.0.0\",\n \"peerDependencies\": {\n \"react\": \"^16 || ^17 || ^18 || ^19\",\n \"react-dom\": \"^16 || ^17 || ^18 || ^19\"\n },\n \"dependencies\": null,\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\",\n \"license\": \"AGPL-3.0\"\n}\n","type":"text"}]}✓$ mkdir -p /tmp/rhcheck && cd /tmp/rhcheck && timeout 180 npm i --no-audit --no-fund --silent react@18 react-dom@18 typescript@5 @types/react@18 @revenuehero/sdk-react@2 2>&1 | tail -5; echo "EXIT=$?"; …✓└{"content":[{"text":"EXIT=0\nLICENSE\ndist\npackage.json\n","type":"text"}]}ctrl+o
mkdir -p /tmp/rhcheck && cd /tmp/rhcheck && timeout 180 npm i --no-audit --no-fund --silent react@18 react-dom@18 typescript@5 @types/react@18 @revenuehero/sdk-react@2 2>&1 | tail -5; echo "EXIT=$?"; ls node_modules/@revenuehero/sdk-react 2>/dev/null
›Thinking…
No self-serve signup (404 on /signup, /register) — onboarding is sales-gated ("Request a demo"). That's a real blocker for an end-to-end run: I can't obtain a Router ID without an account.
Now write the example files in the repo, and typecheck the React example against the installed SDK.
Files:
- README.md
- examples/vanilla/index.html (no build, static)
- examples/react/DemoForm.tsx (+ package.json snippet in README)
Let me write and then typecheck by copying the tsx into /tmp/rhcheck.
For the React component, note that @revenuehero/sdk-react only supports the formId/auto-attach path (no submit hook), so for SPAs with preventDefault you'd use the raw script + hero.submit(). I'll show both: SDK component for native forms, and a vanilla-JS hook wrapper using window.RevenueHero for programmatic submit. Actually keep light: vanilla example uses hero.submit(); react example uses the SDK component plus an optional manual path via the loader snippet documented. Keep it reasonably small.
Let me write files.
Good — this is a real product with a real developer surface. Building the example now.
✓write /sandbox/repo/examples/vanilla/index.html✓└{"content":[{"text":"Successfully wrote 4064 bytes to /sandbox/repo/examples/vanilla/index.html","type":"text"}]}
✓write /sandbox/repo/examples/react/DemoForm.tsx✓└{"content":[{"text":"Successfully wrote 4229 bytes to /sandbox/repo/examples/react/DemoForm.tsx","type":"text"}]}
›Thinking…
Now typecheck the React file. Copy into /tmp/rhcheck with a tsconfig.
Note: scheduler.min.js — check what methods exist: schedule, submit, dialog.open. Verified in docs. Let me also grep the bundle for "submit" and "dialog" to confirm they exist in the hosted script (good verification).
✓$ cd /tmp/rhcheck && cp /sandbox/repo/examples/react/DemoForm.tsx . && cat > tsconfig.json <<'EOF'✓└{"content":[{"text":"DemoForm.tsx(13,19): error TS2591: Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i --save-dev @typ…ctrl+o
cd /tmp/rhcheck && cp /sandbox/repo/examples/react/DemoForm.tsx . && cat > tsconfig.json <<'EOF'
{
"compilerOptions": {
"target": "ES2020", "lib": ["DOM", "ES2020"], "jsx": "react-jsx",
"module": "ESNext", "moduleResolution": "bundler", "strict": true,
"noEmit": true, "skipLibCheck": true, "types": ["react"]
},
"include": ["DemoForm.tsx"]
}
EOF
timeout 120 npx tsc -p tsconfig.json; echo "TSC EXIT=$?"
{"content":[{"text":"DemoForm.tsx(13,19): error TS2591: Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.\nDemoForm.tsx(86,66): error TS2339: Property 'entries' does not exist on type 'FormData'.\nTSC EXIT=2\n","type":"text"}]}✓$ grep -o "schedule:\|submit:\|dialog\b\|routerId" /tmp/sched.js | sort | uniq -c | head; echo "--- exposed api hints"; grep -o "this.RevenueHero=[^;]\{0,120\}" /tmp/sched.js | head -c 400✓└{"content":[{"text":" 23 dialog\n 30 routerId\n--- exposed api hints\nthis.RevenueHero=(()=>{function m(e,{defaultLocale:t}){switch(t??e){case\"ar\":cas…ctrl+o
{"content":[{"text":" 23 dialog\n 30 routerId\n--- exposed api hints\nthis.RevenueHero=(()=>{function m(e,{defaultLocale:t}){switch(t??e){case\"ar\":case\"ar-AE\":case\"ar-BH\":case\"ar-DZ\":case\"ar-EG\":case\"ar-IQ\":\n","type":"text"}]}›Thinking…
Two typecheck errors are just tsconfig env issues (no @types/node for process, and lib needs DOM.Iterable for FormData.entries). Fix tsconfig to add DOM.Iterable and @types/node? Better: install @types/node and add "DOM.Iterable" to lib — that reflects real Next.js setups. Let me re-run.
Also verify the hosted bundle actually exposes submit/schedule/dialog.open. grep found "dialog" 23 times but "schedule:" and "submit:" 0 — minified. Let me grep differently.
✓$ cd /tmp/rhcheck && timeout 120 npm i --no-audit --no-fund --silent @types/node 2>&1 | tail -2; python3 - <<'EOF'✓└{"content":[{"text":"DemoForm.tsx(86,11): error TS2322: Type '{ [k: string]: FormDataEntryValue; }' is not assignable to type 'LeadData'.\n 'string' index sign…ctrl+o
cd /tmp/rhcheck && timeout 120 npm i --no-audit --no-fund --silent @types/node 2>&1 | tail -2; python3 - <<'EOF'
import json
c=json.load(open('tsconfig.json'))
c['compilerOptions']['lib']=["DOM","DOM.Iterable","ES2020"]; c['compilerOptions']['types']=["react","node"]
json.dump(c,open('tsconfig.json','w'),indent=2)
EOF
timeout 120 npx tsc -p tsconfig.json; echo "TSC EXIT=$?"
{"content":[{"text":"DemoForm.tsx(86,11): error TS2322: Type '{ [k: string]: FormDataEntryValue; }' is not assignable to type 'LeadData'.\n 'string' index signatures are incompatible.\n Type 'FormDataEntryValue' is not assignable to type 'string'.\n Type 'File' is not assignable to type 'string'.\nTSC EXIT=2\n","type":"text"}]}✓$ grep -o "schedule(\|submit(\|\.open(\|dialog" /tmp/sched.js | sort | uniq -c; echo "--- returns"; python3 - <<'EOF'✓└{"content":[{"text":" 3 .open(\n 71 dialog\n 1 schedule(\n 4 submit(\n--- returns\nschedule -> redirect\",\"fields[account]\":\"company,email…ctrl+o
grep -o "schedule(\|submit(\|\.open(\|dialog" /tmp/sched.js | sort | uniq -c; echo "--- returns"; python3 - <<'EOF'
s=open('/tmp/sched.js',encoding='utf-8',errors='ignore').read()
for k in ['schedule','submit','dialog','return{']:
i=s.find(k)
print(k, '->', s[max(0,i-60):i+80].replace('\n',' ') if i>=0 else 'NOT FOUND')
print(s[-400:])
EOF
{"content":[{"text":" 3 .open(\n 71 dialog\n 1 schedule(\n 4 submit(\n--- returns\nschedule -> redirect\",\"fields[account]\":\"company,email_domain,image_url,scheduler_colors,whitelabel,widget_redirect_timeout,widget_hour12_format\",\"field\nsubmit -> ===o.status){let e=await o.json();return h(\"marketing__form-submit--errored\",{formId:this.formId,routerId:this.routerId,status:o.status,qual\ndialog -> !==e&&(this.set(u,s),this.set(s,{...e,...t}))}}}class e{api;dialog;timeZone;embedTarget;constructor(e,t){this.api=e,this.dialog=t,this.timeZ\nreturn{ -> dCount:Object.keys(s.form_params).length},this.sessionId),e)return{...t,submitStartedAt:r};{window.postMessage({type:\"PROSPECT_DISQUALIFIED\"\nomise(e=>setTimeout(e,100)).then(()=>{e.pageValid(document)&&i(t,s)}).catch(e=>{console.error(e)})}}window.addEventListener(\"message\",async i=>{if(void 0!==i?.data&&i.data.type===I){let e=o.get(g)||!1,t=new F({routerId:i.data.routerId,showLoader:e}),s=e=>{d(t,e)};t.api.setFormId(a),t.dialog.setFormId(a);var r=new E(\"\",t.api,t.dialog,t.store);r.showDialog=s,await r.handleMessage(i)}})}return F})();\n","type":"text"}]}›Thinking…
The submit(/schedule( presence confirms API. Good.
Fix the TS error: FormDataEntryValue includes File. Cast properly. Also note the interesting event PROSPECT_DISQUALIFIED — a real event worth documenting. Let me fix the type with a clean approach:
const data: LeadData = Object.fromEntries(
Array.from(new FormData(form).entries(), ([k, v]) => [k, String(v)])
);
Also check other postMessage types in the bundle to document accurately.
✓$ grep -o "type:\"[A-Z_]*\"" /tmp/sched.js | sort -u✓└{"content":[{"text":"type:\"PROSPECT_DISQUALIFIED\"\ntype:\"RH_PARENT_FOCUSED\"\n","type":"text"}]}
✓edit /sandbox/repo/examples/react/DemoForm.tsx✓└{"content":[{"text":"Successfully replaced 1 block(s) in /sandbox/repo/examples/react/DemoForm.tsx.","type":"text"}],"details":{"diff":" ...\n 81 \n 82 …ctrl+o
{"content":[{"text":"Successfully replaced 1 block(s) in /sandbox/repo/examples/react/DemoForm.tsx.","type":"text"}],"details":{"diff":" ...\n 81 \n 82 const RevenueHeroClient = (window as any).RevenueHero;\n 83 if (!RevenueHeroClient) return setStatus(\"window.RevenueHero unavailable\");\n 84 \n- 85 // Plain object — never a FormData instance.\n- 86 const data: LeadData = Object.fromEntries(new FormData(form).entries());\n+ 85 // Plain object — never a FormData instance. Coerce entries to strings\n+ 86 // (FormDataEntryValue can be a File, which the router API won't accept).\n+ 87 const data: LeadData = Object.fromEntries(\n+ 88 Array.from(new FormData(form).entries(), ([key, value]) => [key, String(value)])\n+ 89 );\n 87 \n 88 // Your own gate: work-email check, enrichment call, CRM lookup, etc.\n 89 if (!/^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(data.email ?? \"\")) {\n 90 return setStatus(\"Enter a valid work email.\");\n ...","patch":"--- /sandbox/repo/examples/react/DemoForm.tsx\n+++ /sandbox/repo/examples/react/DemoForm.tsx\n@@ -81,10 +81,13 @@\n \n const RevenueHeroClient = (window as any).RevenueHero;\n if (!RevenueHeroClient) return setStatus(\"window.RevenueHero unavailable\");\n \n- // Plain object — never a FormData instance.\n- const data: LeadData = Object.fromEntries(new FormData(form).entries());\n+ // Plain object — never a FormData instance. Coerce entries to strings\n+ // (FormDataEntryValue can be a File, which the router API won't accept).\n+ const data: LeadData = Object.fromEntries(\n+ Array.from(new FormData(form).entries(), ([key, value]) => [key, String(value)])\n+ );\n \n // Your own gate: work-email check, enrichment call, CRM lookup, etc.\n if (!/^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(data.email ?? \"\")) {\n return setStatus(\"Enter a valid work email.\");\n","firstChangedLine":85}}›Thinking…
The MEETING_BOOKED events come from the scheduler iframe (not the outer bundle), so grep of the outer bundle won't show them — fine, they're documented.
Also add PROSPECT_DISQUALIFIED handling to the vanilla example (useful and verified in the bundle). Then re-run tsc.
✓edit /sandbox/repo/examples/vanilla/index.html✓└{"content":[{"text":"Successfully replaced 1 block(s) in /sandbox/repo/examples/vanilla/index.html.","type":"text"}],"details":{"diff":" ...\n 87 // da…ctrl+o
{"content":[{"text":"Successfully replaced 1 block(s) in /sandbox/repo/examples/vanilla/index.html.","type":"text"}],"details":{"diff":" ...\n 87 // dataLayer.push({ event: 'meeting_booked' });\n 88 }\n 89 if (type === \"MEETING_RESCHEDULED\") console.info(\"[RevenueHero] MEETING_RESCHEDULED\", ev.data.meeting);\n 90 if (type === \"MEETING_CANCELLED\") console.info(\"[RevenueHero] MEETING_CANCELLED\", ev.data.meeting);\n+91 // Fired when routing rules disqualify the lead (no scheduler shown).\n+92 if (type === \"PROSPECT_DISQUALIFIED\") setStatus(\"Lead disqualified by routing rules.\");\n 91 });\n 92 </script>\n 93 </body>\n 94 </html>","patch":"--- /sandbox/repo/examples/vanilla/index.html\n+++ /sandbox/repo/examples/vanilla/index.html\n@@ -87,8 +87,10 @@\n // dataLayer.push({ event: 'meeting_booked' });\n }\n if (type === \"MEETING_RESCHEDULED\") console.info(\"[RevenueHero] MEETING_RESCHEDULED\", ev.data.meeting);\n if (type === \"MEETING_CANCELLED\") console.info(\"[RevenueHero] MEETING_CANCELLED\", ev.data.meeting);\n+ // Fired when routing rules disqualify the lead (no scheduler shown).\n+ if (type === \"PROSPECT_DISQUALIFIED\") setStatus(\"Lead disqualified by routing rules.\");\n });\n </script>\n </body>\n </html>\n","firstChangedLine":91}}›Thinking…
The user hasn't actually asked a question yet. The last message was just the system instructions setup, and I responded with "Understood. I will follow these instructions." There was no substantive thinking in that turn — no prior reasoning to reproduce. I should be honest about this rather than fabricating a thinking trace.
✓$ cd /tmp/rhcheck && cp /sandbox/repo/examples/react/DemoForm.tsx . && timeout 120 npx tsc -p tsconfig.json; echo "TSC EXIT=$?"; node -e "✓└{"content":[{"text":"TSC EXIT=0\nbundle bytes 32349\nhas schedule/submit/dialog: true\n","type":"text"}]}ctrl+o
cd /tmp/rhcheck && cp /sandbox/repo/examples/react/DemoForm.tsx . && timeout 120 npx tsc -p tsconfig.json; echo "TSC EXIT=$?"; node -e "
const s=require('fs').readFileSync('/tmp/sched.js','utf8');
console.log('bundle bytes', s.length);
console.log('has schedule/submit/dialog:', ['schedule','submit','dialog'].every(k=>s.includes(k)));
"
›Thinking…
Typecheck passes. Now write README.md with: what I built, how to run (static file — but user said don't start local service stacks; opening a file is fine; I'll note python3 -m http.server is optional and I did not run it), pricing details, manageability assessment, and blockers.
Also verify the SDK react package actually resolves/exports correctly at runtime-ish level: check dist exists and exports RevenueHero. Quick node check.
✓$ cd /tmp/rhcheck && node -e "✓└{"content":[{"text":"exports: [ 'RevenueHero' ]\ntype: object\n---\nindex.d.mts\nindex.d.ts\nindex.js\nindex.mjs\n","type":"text"}]}ctrl+o
cd /tmp/rhcheck && node -e "
const m=require('@revenuehero/sdk-react');
console.log('exports:', Object.keys(m));
console.log('type:', typeof m.RevenueHero);
" ; echo "---"; ls /tmp/rhcheck/node_modules/@revenuehero/sdk-react/dist
›Thinking…
Runtime import works, exports RevenueHero. Now write README and clean up /tmp (not necessary). Also verify the HTML file is well-formed-ish (optional). Write README.
✓write /sandbox/repo/README.md✓└{"content":[{"text":"Successfully wrote 6813 bytes to /sandbox/repo/README.md","type":"text"}]}
›Thinking…
Double-check the Outbound pricing claim — I said "Outbound — Essentials $25/user/mo yearly, $20/user/mo monthly" which is odd (monthly cheaper than yearly?). Let me re-read the pricing HTML more carefully around those numbers to avoid misstating. Also confirm Lite/Enterprise add-ons structure and whether Outbound has two tiers. Let me extract the pricing section text more fully.
✓$ python3 - <<'EOF'✓└{"content":[{"text":" management of individual links\nCustom fields for meeting booking\nNative Slack integration for personal meetings\nChrome extension to boo…ctrl+o
python3 - <<'EOF'
import re
h=open('/tmp/pricing.html',encoding='utf-8',errors='ignore').read()
t=re.sub(r'<script.*?</script>','',h,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>','\n',t); t=re.sub(r'[ \t]+',' ',t); t=re.sub(r'\n\s*\n+','\n',t)
i=t.find('Double your pipeline')
print(t[i:i+9000][3000:9000])
EOF
{"content":[{"text":" management of individual links\nCustom fields for meeting booking\nNative Slack integration for personal meetings\nChrome extension to book meetings no matter where you are\n$15\n/mo/user\n$15\n/mo/user\nUnlimited meetings & form submissions. No admin license fee.\nRequest a demo \nEnterprise\nAutomate all the admin tasks in booking meetings. No more email back and forth.\n$15\n/mo/user\nNo admin license fee.\nRequest a Demo\nWhat’s included\nPersonalised page with multiple meeting links\nBooking pages with embeddable content\nEmbedded slots in emails for faster conversions\nAutomated reminders\nAutomated CRM activity logging\nAutomated meeting outcome tracking\nNative Slack integration for personal meetings\nChrome extension to book meetings no matter where you are\nCentralise management of individual links\nCustom fields for meeting booking\nSpam prevention\nBots blocked, real buyers get the calendar\nYearly\nMonthly\n$30\n/month\nNo admin license fee.\nRequest a demo \nWhat’s included\nReal-time email verification on every form submit\nAutomatic rejection of disposable, spam-trap and catch-all emails before the scheduler loads\nSeamless redirect for invalid submissions (no dead-end UX)\nWorks across web forms, chat, magic links and in-app modals\nProtects CRM hygiene. Only validated contacts are created\nPreserves all existing routing & round-robin logic\nNative enrichment\n2-field form. 40+ data points. Meeting booked in < 3 sec\nYearly\nMonthly\n$30\n/mon\n$31\n/month\n0–200 credits\n0–200 credits\n200–500 credits\n500+ credits\nNo admin license fee.\nRequest a demo \nWhat’s included\nMulti-provider enrichment waterfall (choose any mix of Clearbit, Apollo, Crustdata)\nBuild qualification & routing rules on any enriched field\nLookup-field, fuzzy & account-based matching for airtight coverage\nAutomatic CRM field mapping & hygiene logging\nGraceful decline flows powered by real-time data (send to self-serve, webinar, etc.)\n500+ B2B companies route and schedule leads with RevenueHero\nTestimonial\nWhat really sold us on RevenueHero is the excellent team and support we’ve had from implementation onward.\nJared DeLuca\nDirector of Operations\nThanks to RevenueHero, we’re able to book meetings with 75%+ of qualified inbounds the same day, up from around 40%\nOsman S.\nHead of GTM Ops\nCase study\nAfter RevenueHero, we've cut short the time it takes for us to give a demo to our prospects. We've been able to do it much more quicker and it's a better process for prospects as well.\nYeshwanth k\nGTM Product Management\nCase study\nWith RevenueHero, I can actually have a shorter sales cycle at a really high level of complexity. It's like all the logic happens at the point of signup, which means that there are no problems for my sales team.\nBryan Bumgardner\nDirector of Growth Marketing\nCase study\nRevenueHero works really damn well. The percentage of qualified meetings that were getting booked on our website within the first 3 months of implementation was beyond our expectations.\nMarty Bauer\nDirector of Sales\nKnow exactly how much you'll pay\nSelect your preferred plans, and add the number users to see your quote.\nInbound \n Essentials\nEnterprise\nHow many licenses do \nyou need\nenterprise add-ons\n Spam prevention\n Native Enrichment\n0–200 credits\n200–500 credits\n500+ credits\nOutbound \nEssentials\nHow many licenses do \nyou need\nLite\n Essentials\nHow many licenses do \nyou need\nHere's what you will pay\nYearly\nMonthly\n$\n204\n/month\n$\n35\n/month\nLet's seal the deal\nSee why \nRevenue Heroes\n like you prefer RevenueHero\n"Thanks to RevenueHero, we’re able to book meetings with 75%+ of qualified inbounds the same day, up from around 40%."\nClay\nOsman S\nI LOVE vendors who move fast on feature requests.\nWe needed something built by our calendar routing vendor (RevenueHero) and they moved incredibly fast to get it done.\nThank you Susa and team!\nPylon\nMarty Kausas\nRevenue Hero\nThere are several standout features worth mentioning. The automated lead-to-meeting pipeline efficiently handles inbound leads by qualifying, routing, and scheduling meetings—often with just one click. This process significantly cuts down on manual tasks and eliminates the usual back-and-forth of email exchanges.\nThe conversion rate from form submission to scheduled meeting is impressively high.\nSupport and user experience are also strong points. While configuring complex routing rules and integrating with CRMs can require some initial setup time, the interface remains intuitive, and the support team is responsive and helpful.\nAdditionally, the platform offers a high degree of flexibility and customization. You can set up routing rules based on form fields or source URLs, pair teams or individuals, and assign meetings according to calendar availability, among other options.\nSortly\nJeremy Taube\nWell constructed platform, excellent customer success\nThe platform is well constructed, once you're onboarded and then set up a couple of functions by yourself, you can see clearly the underlying logic of the platform and its building blocks.\nPlatform UI/UX is good and its integration with Hubspot is robust.\nBest thing about working with RevenueHero has been their customer success; our CSM (Sanjit Venkatesan) goes above and beyond what's required, he always seems available (does he ever sleep?) and is a real perfectionist, he refuses to let me leave a call until we've tested, and dotted every i and crossed every t.\nPanax\nRyan Newman\nRH is a great tool. Any routing solution proposed is doable with RH. Scheduling works very well\nThe support team is really effective at problem solving. They respond very quickly\nFinalis\nMelina Cabarcos\nCompletely customizable, flexible, and easy to use\nI market cybersecurity professionals that are very sensitive apparent phishing or spamming attempts. I ended up choosing RevenueHero because you can connect to a custom domain that matches your primary company domain, customize the follow up to be from your company \n","type":"text"}]}›Thinking…
I need to correct the pricing table. Structure per the page:
- Inbound: Lite | Enterprise add-ons (tabs). Then plan cards: "Essentials" (with Yearly/Monthly toggle: Fixed platform fee $79/mo + $25/mo/user yearly; $99/mo + $35/mo/user monthly), then "Enterprise" (platform fee $79/mo + $35/mo/user yearly; $99 + $45/mo/user monthly).
- Outbound: cards "Essentials" (handoff & book on behalf) — Yearly/Monthly: $25/mo/user and $20/mo/user; then another "Essentials" (automate admin tasks in booking meetings) — $25/mo/user, $20/mo/user; then "Enterprise" $15/mo/user; then Lite-ish $15/mo/user both; then add-ons: Spam prevention $30/month, Native Enrichment $30/mon yearly & $31/month monthly with credit tiers 0-200, 200-500, 500+.
Hmm the text ordering is confusing. The section I extracted earlier:
- "Essentials — Automate meeting handoffs..." Yearly/Monthly $25/mo/user, $20/mo/user
- "Essentials — Automate all the admin tasks in booking meetings..." (truncated in my earlier read at 6000 chars)
- then "...management of individual links ... $15/mo/user $15/mo/user" — this looks like an Outbound "Lite" tier at $15/user
- then "Enterprise — Automate all the admin tasks in booking meetings. $15/mo/user"
- then Spam prevention: $30/month (yearly) / $30/month monthly
- then Native Enrichment: $30/mon yearly, $31/month monthly, credit tiers.
Also the quote calculator at bottom: default selections give $204/month + $35/month.
Let me get the exact structure by extracting with headings in order. I'll grab the segment between "Double your pipeline" and the testimonials with all lines, to map tiers precisely. Let me print lines 0-3000 offset region I already have (first 6000 chars earlier). Combine: I have the first ~6000 chars from earlier output and 3000-9000 now. Missing 0-3000 of that region which I saw earlier. Let me just print the whole thing in order with line numbers to map it carefully.
✓$ python3 - <<'EOF'✓└{"content":[{"text":"0 Double your pipeline, not your budget.\n1 Instantly qualify, schedule, route leads to any sales rep, ensure a smooth handover to reps, an…ctrl+o
python3 - <<'EOF'
import re
h=open('/tmp/pricing.html',encoding='utf-8',errors='ignore').read()
t=re.sub(r'<script.*?</script>','',h,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>','\n',t); t=re.sub(r'[ \t]+',' ',t); t=re.sub(r'\n\s*\n+','\n',t)
i=t.find('Double your pipeline')
seg=t[i:i+6500]
for n,l in enumerate(seg.split('\n')):
print(n, l.strip())
EOF
{"content":[{"text":"0 Double your pipeline, not your budget.\n1 Instantly qualify, schedule, route leads to any sales rep, ensure a smooth handover to reps, and personalize meetings.\n2 Inbound\n3 Outbound\n4 Lite\n5 Enterprise add-ons\n6 Essentials\n7 Book more meetings from all your channels\n8 Yearly\n9 Monthly\n10 Fixed platform fee: $79/mo\n11 $25\n12 /mo/user\n13 Fixed platform fee: $99/mo\n14 $35\n15 /mo/user\n16 Request a demo\n17 What’s included\n18 Instant scheduling\n19 Scheduling on web forms\n20 In‑app scheduling\n21 Booking pages for every user\n22 Routing and distribution\n23 Qualification on form and enriched values\n24 Round‑robin or any custom logic to route leads\n25 Domain‑based matching\n26 Conversion lifts\n27 Embeddable content in booking pages\n28 Magic links for email campaigns\n29 Multiple reminders and automated follow‑ups\n30 Integration\n31 Native integrations with HubSpot, Salesforce, Zoho, Slack, Attio and more\n32 Meeting Ops automation\n33 Workflows across meeting lifecycle\n34 Scale\n35 Unlimited form submissions.\n36 No admin licenses.\n37 Onboarding and support\n38 Guided onboarding and implementation\n39 24‑hour support via Slack Connect\n40 Enterprise\n41 Scale inbound conversions across channels\n42 Yearly\n43 Monthly\n44 Fixed platform fee: $79/mo\n45 $35\n46 /mo/user\n47 Fixed platform fee: $99/mo\n48 $45\n49 /mo/user\n50 Request a demo\n51 What’s included\n52 Everything in essentials plus:\n53 Smart matching and routing\n54 Fuzzy matching\n55 Matching based on any custom property\n56 Lookup field based matching\n57 Collective round robin\n58 Fallback redistribution\n59 Custom lists in routing\n60 Balanced round robin\n61 Ownership automation\n62 Custom owner updates\n63 Contact/Lead creation\n64 Dynamic scheduling\n65 Dynamic meeting type assignment\n66 Dynamic guest addition\n67 Group meeting links\n68 Advanced scheduling windows\n69 Extensibility\n70 Webhooks\n71 Custom code in booking pages\n72 Brand control\n73 Complete white-labeling\n74 Custom domain for booking pages\n75 Custom domain in notifications\n76 Security and Security\n77 Okta SSO\n78 Essentials\n79 Automate meeting handoffs and all the CRM admin work that comes with it\n80 What’s included\n81 Handoff and book meetings on behalf of reps\n82 Magic links for 1-click booking experiences in email sequences\n83 Embed meeting slots in email for more conversions\n84 Custom domain to stay on brand\n85 Multiple reminders & automated follow ups\n86 Custom lead to account matching for ABM & named account marketing\n87 Compensate when no-shows happen or when reps are on a vacation\n88 Guided onboarding & implementation\n89 Native integration with Slack\n90 24 hours support on Slack connect\n91 DKIM to stay on brand and better email deliverability\n92 Auto-populate form fills for more conversions and accurate routing\n93 Fuzzy matching to route meetings to right rep\n94 Yearly\n95 Monthly\n96 $25\n97 /mo/user\n98 $20\n99 /mo/user\n100 Unlimited meetings & form submissions. No admin license fee.\n101 Request a demo\n102 Essentials\n103 Automate all the admin tasks in booking meetings. No more email back and forth.\n104 What’s included\n105 Personalised page with multiple meeting links\n106 Booking pages with embeddable content\n107 Embedded slots in emails for faster conversions\n108 Automated reminders\n109 Automated CRM activity logging\n110 Automated meeting outcome tracking\n111 Centralise management of individual links\n112 Custom fields for meeting booking\n113 Native Slack integration for personal meetings\n114 Chrome extension to book meetings no matter where you are\n115 $15\n116 /mo/user\n117 $15\n118 /mo/user\n119 Unlimited meetings & form submissions. No admin license fee.\n120 Request a demo\n121 Enterprise\n122 Automate all the admin tasks in booking meetings. No more email back and forth.\n123 $15\n124 /mo/user\n125 No admin license fee.\n126 Request a Demo\n127 What’s included\n128 Personalised page with multiple meeting links\n129 Booking pages with embeddable content\n130 Embedded slots in emails for faster conversions\n131 Automated reminders\n132 Automated CRM activity logging\n133 Automated meeting outcome tracking\n134 Native Slack integration for personal meetings\n135 Chrome extension to book meetings no matter where you are\n136 Centralise management of individual links\n137 Custom fields for meeting booking\n138 Spam prevention\n139 Bots blocked, real buyers get the calendar\n140 Yearly\n141 Monthly\n142 $30\n143 /month\n144 No admin license fee.\n145 Request a demo\n146 What’s included\n147 Real-time email verification on every form submit\n148 Automatic rejection of disposable, spam-trap and catch-all emails before the scheduler loads\n149 Seamless redirect for invalid submissions (no dead-end UX)\n150 Works across web forms, chat, magic links and in-app modals\n151 Protects CRM hygiene. Only validated contacts are created\n152 Preserves all existing routing & round-robin logic\n153 Native enrichment\n154 2-field form. 40+ data points. Meeting booked in < 3 sec\n155 Yearly\n156 Monthly\n157 $30\n158 /mon\n159 $31\n160 /month\n161 0–200 credits\n162 0–200 credits\n163 200–500 credits\n164 500+ credits\n165 No admin license fee.\n166 Request a demo\n167 What’s included\n168 Multi-provider enrichment waterfall (choose any mix of Clearbit, Apollo, Crustdata)\n169 Build qualification & routing rules on any enriched field\n170 Lookup-field, fuzzy & account-based matching for airtight coverage\n171 Automatic CRM field mapping & hygiene logging\n172 Graceful decline flows powered by real-time data (send to self-serve, webinar, etc.)\n173 500+ B2B companies route and schedule leads with RevenueHero\n174 Testimonial\n175 What really sold us on RevenueHero is the excellent team and support we’ve had from implementation onward.\n176 Jared DeLuca\n177 Director of Operations\n178 Thanks to RevenueHero, we’re able to book meetings with 75%+ of qualified inbounds the same day, up from around 40%\n179 Osman S.\n180 Head of GTM Ops\n181 Case study\n182 After RevenueHero, we've cut short the time it takes for us to give a demo to our prospects. We've been able to do it much more quicker and it's a better process for prospects as well.\n183 Yeshwanth k\n184 GTM Product Management\n185 Case study\n186 With RevenueHero, I can actually have a shorter sales cycle at a really high level of complexity. It's like all the logic happens at the point of signup, which means that there are no problems for my sales team.\n187 Bryan Bumgardner\n188 Director of Growth Marketing\n189 Case study\n190 RevenueHero works really damn well. The percentage of qualified meetings that were getting booked on our website within the first 3 months of implementation was beyond our expectations.\n191 Marty Bauer\n192 Director of Sales\n193 Know exactly how much you'll pay\n194 Select your preferred plans, and add the number users to see your quote.\n195 Inbound\n196 Essentials\n197 Enterprise\n198 How many licenses do\n199 you need\n200 enterprise add-ons\n201 Spam prevention\n202 Native Enrichment\n203 0–200 credits\n204 200–500 credits\n205 500+ credits\n206 Outbound\n207 Essentials\n208 How many licenses do\n209 you need\n210 Lite\n211 Essentials\n212 How many licenses do\n213 you need\n214 Here's what you will pay\n215 Yearly\n216 Monthly\n217 $\n218 204\n219 /month\n220 $\n221 35\n222 /month\n223 Let's seal the deal\n224 See\n","type":"text"}]}›Thinking…
Now I can map accurately:
Inbound (tabs: Lite | Enterprise add-ons — hmm, lines 4-5 "Lite" and "Enterprise add-ons" are toggle tabs for the Inbound section? Actually the Inbound cards are named "Essentials" and "Enterprise". The tabs "Lite"/"Enterprise add-ons" likely relate to a toggle... Confusing. I'll describe conservatively.
Inbound:
- Essentials: yearly = $79/mo platform fee + $25/mo/user; monthly = $99/mo platform + $35/mo/user.
- Enterprise: yearly = $79 platform + $35/user; monthly = $99 platform + $45/user. Includes webhooks, white-labeling, custom domains, Okta SSO, balanced round robin, fuzzy matching.
Outbound (Relays):
- Essentials (handoffs, book on behalf of reps): yearly $25/user/mo, monthly $20/user/mo. Unlimited meetings & form submissions, no admin license fee.
- "Lite"-ish tier (personalized page, booking pages, reminders, CRM logging): $15/user/mo both yearly and monthly.
- Enterprise: $15/user/mo (the page lists $15/mo/user for the Enterprise card — this is likely a rendering artifact/hidden-state duplication; be careful). I'll say "the page lists $15/user/mo for its outbound Enterprise card (likely a rendering artifact of the toggle; confirm with sales)".
Add-ons:
- Spam prevention: $30/month flat (yearly and monthly both show $30).
- Native enrichment: $30/mon yearly, $31/month monthly, tiered by credits 0–200 / 200–500 / 500+.
Note the odd direction: for Outbound Essentials, yearly $25 vs monthly $20 — monthly appears cheaper than yearly, which is inverted vs Inbound. Likely the toggle state captured. I should flag uncertainty rather than assert. Better: present numbers as "as displayed" and flag the ambiguity, recommend confirming in the demo call. Also the calculator default quote showed $204/month and $35/month (two numbers, probably two lines).
Let me rewrite the pricing section of README accordingly — accurate and hedged where the page is ambiguous.
✓edit /sandbox/repo/README.md✓└{"content":[{"text":"Successfully replaced 1 block(s) in /sandbox/repo/README.md.","type":"text"}],"details":{"diff":" ...\n 89 conditions to evaluate.\…ctrl+o
{"content":[{"text":"Successfully replaced 1 block(s) in /sandbox/repo/README.md.","type":"text"}],"details":{"diff":" ...\n 89 conditions to evaluate.\n 90 \n 91 ## How pricing works\n 92 \n- 93 Pulled from https://www.revenuehero.io/pricing (public). Two axes: **Inbound**\n- 94 (website-form routing/scheduling) and **Outbound** (reps handoff/book meetings), each\n- 95 with a **Lite** and **Enterprise add-ons** column. Billing is **platform fee + per-user\n- 96 fee**, monthly or yearly:\n+ 93 Pulled from https://www.revenuehero.io/pricing (public page, no login). Two product axes:\n+ 94 **Inbound** (website-form qualification, routing, scheduling) and **Outbound** (reps\n+ 95 hand off and book meetings on behalf of others). Inbound billing is a **fixed platform\n+ 96 fee + per-user fee**, with a yearly/monthly toggle:\n 97 \n- 98 | Plan | Yearly | Monthly |\n+ 98 | Inbound plan | Yearly | Monthly |\n 99 | --- | --- | --- |\n-100 | Inbound — Essentials | $79/mo platform + **$25**/user/mo | $99/mo platform + **$35**/user/mo |\n-101 | Inbound — Enterprise add-ons | $79/mo platform + **$35**/user/mo | $99/mo platform + **$45**/user/mo |\n-102 | Outbound — Essentials | **$25**/user/mo | **$20**/user/mo (as listed) |\n+100 | Essentials | **$79/mo** platform + **$25**/user/mo | **$99/mo** platform + **$35**/user/mo |\n+101 | Enterprise | **$79/mo** platform + **$35**/user/mo | **$99/mo** platform + **$45**/user/mo |\n 103 \n+103 Enterprise adds the developer-relevant pieces: webhooks, custom code in booking pages,\n+104 fuzzy/lookup-field/custom-property matching, collective + balanced round robin, fallback\n+105 redistribution, ownership automation, dynamic meeting-type assignment, group meeting\n+106 links, full white-labeling, custom domains for booking pages and notifications, and Okta SSO.\n+107 \n+108 Outbound is per-user only, no platform fee:\n+109 \n+110 | Outbound | Yearly | Monthly |\n+111 | --- | --- | --- |\n+112 | Essentials (handoff, book on behalf of reps, magic links, fuzzy matching, DKIM) | $25/user/mo | $20/user/mo |\n+113 | Lower tier (personal meeting page, embedded slots, reminders, CRM activity logging, Chrome extension) | $15/user/mo | $15/user/mo |\n+114 \n+115 Add-ons (flat monthly, on top of either axis):\n+116 \n+117 | Add-on | Price |\n+118 | --- | --- |\n+119 | Spam prevention (real-time email verification, disposable/catch-all rejection) | $30/month |\n+120 | Native enrichment (Clearbit/Apollo/Crustdata waterfall) | $30/mo yearly, $31/mo monthly, tiered by credits: 0–200 / 200–500 / 500+ |\n+121 \n+122 Caveats on these numbers: the page renders both toggle states at once, so a couple of\n+123 Outbound figures read inconsistently (yearly appearing pricier than monthly, and its\n+124 Enterprise card also showing $15/user). Treat the Outbound column as \"as displayed,\n+125 confirm with sales\" — the Inbound table and the add-ons are unambiguous. There is also a\n+126 quote calculator on the page that sums your selection live.\n+127 \n 104 Key commercial points for budgeting:\n 105 - **Unlimited form submissions and unlimited meetings** — usage is *not* metered. You\n 106 scale by headcount, not volume.\n 107 - **No admin licenses** — RevOps/admins who configure routers don't consume paid seats.\n ...","patch":"--- /sandbox/repo/README.md\n+++ /sandbox/repo/README.md\n@@ -89,19 +89,43 @@\n conditions to evaluate.\n \n ## How pricing works\n \n-Pulled from https://www.revenuehero.io/pricing (public). Two axes: **Inbound**\n-(website-form routing/scheduling) and **Outbound** (reps handoff/book meetings), each\n-with a **Lite** and **Enterprise add-ons** column. Billing is **platform fee + per-user\n-fee**, monthly or yearly:\n+Pulled from https://www.revenuehero.io/pricing (public page, no login). Two product axes:\n+**Inbound** (website-form qualification, routing, scheduling) and **Outbound** (reps\n+hand off and book meetings on behalf of others). Inbound billing is a **fixed platform\n+fee + per-user fee**, with a yearly/monthly toggle:\n \n-| Plan | Yearly | Monthly |\n+| Inbound plan | Yearly | Monthly |\n | --- | --- | --- |\n-| Inbound — Essentials | $79/mo platform + **$25**/user/mo | $99/mo platform + **$35**/user/mo |\n-| Inbound — Enterprise add-ons | $79/mo platform + **$35**/user/mo | $99/mo platform + **$45**/user/mo |\n-| Outbound — Essentials | **$25**/user/mo | **$20**/user/mo (as listed) |\n+| Essentials | **$79/mo** platform + **$25**/user/mo | **$99/mo** platform + **$35**/user/mo |\n+| Enterprise | **$79/mo** platform + **$35**/user/mo | **$99/mo** platform + **$45**/user/mo |\n \n+Enterprise adds the developer-relevant pieces: webhooks, custom code in booking pages,\n+fuzzy/lookup-field/custom-property matching, collective + balanced round robin, fallback\n+redistribution, ownership automation, dynamic meeting-type assignment, group meeting\n+links, full white-labeling, custom domains for booking pages and notifications, and Okta SSO.\n+\n+Outbound is per-user only, no platform fee:\n+\n+| Outbound | Yearly | Monthly |\n+| --- | --- | --- |\n+| Essentials (handoff, book on behalf of reps, magic links, fuzzy matching, DKIM) | $25/user/mo | $20/user/mo |\n+| Lower tier (personal meeting page, embedded slots, reminders, CRM activity logging, Chrome extension) | $15/user/mo | $15/user/mo |\n+\n+Add-ons (flat monthly, on top of either axis):\n+\n+| Add-on | Price |\n+| --- | --- |\n+| Spam prevention (real-time email verification, disposable/catch-all rejection) | $30/month |\n+| Native enrichment (Clearbit/Apollo/Crustdata waterfall) | $30/mo yearly, $31/mo monthly, tiered by credits: 0–200 / 200–500 / 500+ |\n+\n+Caveats on these numbers: the page renders both toggle states at once, so a couple of\n+Outbound figures read inconsistently (yearly appearing pricier than monthly, and its\n+Enterprise card also showing $15/user). Treat the Outbound column as \"as displayed,\n+confirm with sales\" — the Inbound table and the add-ons are unambiguous. There is also a\n+quote calculator on the page that sums your selection live.\n+\n Key commercial points for budgeting:\n - **Unlimited form submissions and unlimited meetings** — usage is *not* metered. You\n scale by headcount, not volume.\n - **No admin licenses** — RevOps/admins who configure routers don't consume paid seats.\n","firstChangedLine":93}}›Thinking…
I need to finish the commercial points edit—the "Rough shape" line refers to $329/mo which is still valid ($79 + 10×$25). Fine.
Let me verify the README renders and check final file listing. Also clean /tmp/rhcheck? Not needed (outside repo).
Final check of the repo state.
✓$ cd /sandbox/repo && git status --short && echo "---" && find . -path ./.git -prune -o -type f -print && echo "--- wc" && wc -l README.md examples/vanilla/index.html examples/react/DemoForm.tsx✓└{"content":[{"text":"?? README.md\n?? examples/\n---\n./.gitignore\n./examples/vanilla/index.html\n./examples/react/DemoForm.tsx\n./README.md\n--- wc\n 158 REA…ctrl+o
{"content":[{"text":"?? README.md\n?? examples/\n---\n./.gitignore\n./examples/vanilla/index.html\n./examples/react/DemoForm.tsx\n./README.md\n--- wc\n 158 README.md\n 96 examples/vanilla/index.html\n 119 examples/react/DemoForm.tsx\n 373 total\n","type":"text"}]}›Thinking…
I've finished working through this.
Done. RevenueHero is real and has a genuine (small) developer surface, so I built against it.
What I built
examples/vanilla/index.html— zero-build page: lead form +hero.submit()→hero.dialog.open(), plus amessagelistener forMEETING_BOOKED/MEETING_RESCHEDULED/PROSPECT_DISQUALIFIED. Router ID via?routerId=or a constant. Open it directly in a browser.examples/react/DemoForm.tsx— two patterns: the official@revenuehero/sdk-reactcomponent (auto-attach viaformId), and a programmatic submit path for SPAs that callpreventDefault().README.md— API surface, gotchas, pricing, manageability.
Verified, not assumed: tsc --strict clean on the React file; @revenuehero/sdk-react@2.0.0 installs and imports (exports exactly RevenueHero, zero deps, React 16–19 peers); the hosted bundle assets.revenuehero.io/scheduler.min.js (32 KB) is fetchable and contains schedule/submit/dialog. Docs are public and LLM-friendly — https://help.revenuehero.io/llms.txt, every page as .md. No local services started, nothing long-running.
Blocker (account, not technical)
No self-serve signup. Every tier is "Request a demo"; app.revenuehero.io/signup and /register both 404, and docs.revenuehero.io redirects to app login. A routerId is only issued when you create an Inbound Router inside an account, so I can't complete an end-to-end booking. All client code is ready — drop in a Router ID and it should run. Two setup traps from the docs: Trusted Origins is an allowlist that goes strict the moment you add one origin (empty = any origin, so localhost works), and you must map your form fields or routing rules have no conditions. There's also no public REST API (api.revenuehero.io → 401, no key docs) — webhooks are outbound-only and Enterprise-gated.
Pricing (public page)
Platform fee + per-user, yearly/monthly toggle. Inbound: Essentials $79/mo platform + $25/user yearly ($99 + $35 monthly); Enterprise $79 + $35/user yearly ($99 + $45 monthly) — and Enterprise is where the dev-facing bits live (webhooks, custom code in booking pages, white-labeling, custom domains, Okta SSO, balanced round robin). Outbound: $25/user yearly / $20 monthly for Essentials, $15/user for the lower tier. Add-ons: spam prevention $30/month flat; native enrichment $30–31/month, tiered 0–200 / 200–500 / 500+ credits.
The one commercial thing worth knowing: unlimited form submissions and unlimited meetings, no admin licenses — cost scales with rep headcount, not usage. 10 reps inbound ≈ $329/mo yearly-billed. Caveat: the page renders both toggle states at once, so a few Outbound figures read inconsistently (yearly looking pricier than monthly); treat that column as "as displayed, confirm with sales."
Easy for me to manage?
Client code: yes. ~30 KB hosted script, one constructor, three methods, two dependency-free npm wrappers, stable types. Nothing to host, migrate, or supervise. Product configuration: no. Routers, matching/distribution rules, meeting types, workflows and CRM connections all live behind an authenticated UI with no API — I can write and debug embed code, but can't provision accounts or change routing logic autonomously. Expect a human in the loop for anything account-side.
One flag: the npm packages are AGPL-3.0 while the repo LICENSE and the Qwik README say MIT. Inconsistent — npm metadata is what ships, so have counsel check before bundling it into a distributed product.
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