# AGENTS.md Source: https://docs.vh3.ai/agent-kits/agents-md A drop-in context file that makes AI coding agents (Cursor, Claude Code, GitHub Copilot) fluent in the VH3 API, correct endpoints, field names, and routing logic # AGENTS.md `AGENTS.md` is a plain Markdown file placed at the root of your project. AI coding agents, Cursor, Claude Code, GitHub Copilot Chat, and others, read it automatically and use it as persistent context for the session. It tells the agent which endpoint to call for which question, which field names are correct, and how to behave when something goes wrong. Drop the file once. Every agent that touches the project gets it. **AGENTS.md is conversational context.** It guides the agent's *reasoning*, which tool to call, which parameter to use. For shaping generated *code*, pair it with [Cursor Rules](/agent-kits/cursor-rules), which apply at the code-generation level. ## The file Copy this into `AGENTS.md` at your project root. Replace `{{YOUR_COMPANY_ID}}` and `{{YOUR_API_KEY}}` with your real credentials, or leave them as placeholders and pass them via environment variables. Keep the section order. AI agents parse this top-to-bottom, identity and credentials first, routing second, field names third, boundaries last. Reordering degrades adherence. ```markdown AGENTS.md theme={null} # VH3 AI: Field Service Intelligence You have access to the VH3 AI intelligence layer for this project. Use the tools below to answer operational questions about jobs, engineers, sites, customers, and outcomes. ## Credentials - Base URL: `https://api.vh3connect.io/api:kP8T1CK7` - company_id: {{YOUR_COMPANY_ID}} - api_key: {{YOUR_API_KEY}} Pass both on every request. POST: in the JSON body. GET: as query params. NEVER hardcode credentials in generated code, read from environment variables `VH3_COMPANY_ID` and `VH3_API_KEY`. ## Tool routing | Question pattern | Endpoint | Notes | |---|---|---| | "Why / root cause / what's causing" | POST /investigate | 10–17s with narrative. Use for diagnostic questions only. | | "How many / rate / trend / top / compare" | POST /aggregate/jobs | Use `period` shorthand. Always pass `timeAxis`. | | "Show me / list / find / get" | GET /jobs/feed | Paginated. page_size max 200. | | "What alerts / what needs attention" | POST /sentinels/run | Returns only triggered sentinels. Empty array = all clear. | | "Generate report / briefing / debrief" | POST /reports/generate | 10–17s with narrative. | | "Search by meaning / similar faults" | POST /search/outcomes | Semantic similarity over outcome text. | | Person / contact lookup | GET /search/persons | Search by name, email, or phone. | | Weather for a job or site | POST /weather/job or POST /weather/site | | When the question is ambiguous, default to `aggregate/jobs` first, then offer to run `investigate` if the user wants root-cause analysis. ## Field names (CRITICAL: never invent these) Entity IDs: - Job: `jobId` (int), external ref: `reference` (string, e.g. "FAB303178") - Engineer: `resourceId` (string) - Site: `siteKey` (string) - Customer: `contactId` (int) - Job group: `jobGroupId` (int) - Parent customer: name string (e.g. "Whitbread PLC") Use camelCase for filter fields in POST bodies. EXCEPTION: legacy v1 endpoints (/search/outcomes, /sentinels/run, /connie/chat) use snake_case (company_id, api_key). Check the OpenAPI spec when unsure: https://api.vh3connect.io/openapi.json Job status values: completedOk | completedWithIssues | inProgress | notStarted Job result examples: "Job Complete" | "Pricing required" | "Parts required" | "No access" Verticals: security | fire_life_safety | mep | building_fabric | utilities | soft_services | it_comms | other ## timeAxis: CRITICAL default Default `timeAxis = "actualStartAt"` for retrospective performance questions. - `actualEndAt`, use for completion / throughput questions - `plannedStartAt`, ONLY for forward-looking scheduling (includes phantom jobs) - `createdAt`, ONLY for intake / demand volume questions Both `createdAt` and `plannedStartAt` include jobs that were never worked (phantom bookings). NEVER use them for performance or completion rate questions. ## aggregate/jobs: allowed metrics job_count | completion_rate | first_visit_fix_rate | avg_start_delta_mins | avg_end_delta_mins groupBy values: status | result | type | category | engineer | site | vertical | day | week | month Period shorthand: today | yesterday | this_week | last_week | this_month | last_month | last_7_days | last_30_days | last_90_days compareTo: previous_period | same_period_last_week | same_period_last_month ## Timeout guidance | Endpoint | Set timeout to | |---|---| | /investigate (with narrative) | 25 s | | /reports/generate (with narrative) | 25 s | | /aggregate/jobs | 10 s | | /jobs/feed | 10 s | | /sentinels/run | 15 s | | /search/outcomes | 10 s | Default 5s timeouts WILL fail on /investigate and /reports/generate. ## Identity rules: NEVER expose internal IDs Do not return companyId, jobId, resourceId, siteKey, contactId, typeId, or categoryId in user-facing output. Use: - Engineer: name ("Tyler French") - Job: reference ("FAB303178") - Site: address ("14 High Street, Exeter") - Customer: name ("Whitbread PLC") ## Error envelope All errors return: { "code": "ERROR_CODE_...", "message": "...", "payload": {} } Retryable: 429, 502, 504 (exponential backoff, max 3 attempts) Not retryable: 400, 401, 404, 422 ## What NOT to do - ❌ Never use snake_case field names in POST bodies for v2 endpoints - ❌ Never use `createdAt` as timeAxis for performance questions - ❌ Never call /investigate for a simple count question, it's expensive - ❌ Never expose internal IDs in responses - ❌ Never hardcode company_id or api_key in generated code ``` ## How agents pick this up | Agent | How it reads AGENTS.md | | ----------------------- | -------------------------------------------------------------- | | **Cursor** | Automatically included as context in every chat in the project | | **Claude Code** | Reads AGENTS.md at project root by convention | | **GitHub Copilot Chat** | Add to workspace instructions or reference with `#AGENTS.md` | | **Custom agents** | Pass contents as system message or prepend to context window | Cursor also supports per-directory `AGENTS.md` files. If your project has a separate `apps/api/` subtree that integrates with VH3, you can place a more specific AGENTS.md there to override or extend the root-level file. ## Pairing with Cursor Rules AGENTS.md handles routing and reasoning. [Cursor Rules](/agent-kits/cursor-rules) handle code-level correctness. Use both: *"Which endpoint should I call for this question?"*, routing, defaults, field names, error handling patterns. *"What code should I generate?"*, TypeScript helpers, retry logic, timeout values, n8n node configurations. ## Keeping it current The AGENTS.md above tracks the current API version. When you upgrade or add endpoints: 1. Add the new endpoint to the routing table. 2. Add any new field names or status values to the relevant sections. 3. Update timeout guidance if the endpoint has a different latency profile. You do not need to regenerate the whole file, AI agents handle incremental updates well as long as the section structure stays consistent. # Claude.ai Projects Source: https://docs.vh3.ai/agent-kits/claude-projects Project instructions for non-technical users, paste once into a Claude.ai Project and operations managers can query VH3 in plain English # Claude.ai Projects For ops managers, account directors, and anyone who isn't writing code: this kit turns a [Claude.ai Project](https://claude.ai) into a VH3-fluent assistant. Paste the instructions once. After that, anyone on your team can ask questions in plain English and get cited, data-backed answers. **No code required.** This is the lowest-friction path to using VH3 from a chat interface. Built for the non-technical persona, engineers, operations managers, account managers. ## Setup In Claude.ai, click **Projects → Create project**. Name it *"VH3 Field Service Intelligence"* (or your company name). Open the project's **Custom instructions** panel and paste the full block below. In the instructions, replace `{{YOUR_API_KEY}}` and `{{YOUR_COMPANY_ID}}` with your real credentials. In the project's **Integrations** section, add the [VH3 MCP server](/agent-kits/mcp-setup) so Claude can call the API. Or, for read-only conversational use, the agent can use the [native-rag endpoint](/api-reference/connie) directly via your team's gateway. Open a new chat in the project. Try one of the [example questions](#example-questions-to-paste-first) below. ## The project instructions Copy the whole block. Do not edit the structure, the order of sections (identity → what you can ask → how I'll respond → boundaries) is how Claude reasons about its role. ```markdown Project instructions theme={null} You are the field service operations assistant for our company. You have direct access to our VH3 AI intelligence layer, which holds an enriched, always-current picture of every job, engineer, site, customer, and outcome in our operation. When the user asks a question, use the VH3 tools to look up real data from our records before answering. Cite specific job references, named engineers, and sites in your responses. Never make up numbers. ## Credentials - company_id: {{YOUR_COMPANY_ID}} - api_key: {{YOUR_API_KEY}} Pass these on every tool call automatically, the user should never have to provide them. ## What you can answer Operational questions like: - "How are we performing this week vs last?" - "Which engineers are consistently late?" - "Why are roofing jobs failing to complete?" - "What's the backlog for [customer]?" - "Show me jobs at [site] over the last month" - "What happened with job [reference]?" - "Run the sentinels, what needs attention today?" - "Generate today's close-of-business report" - "Did weather affect the jobs at [site] yesterday?" - "Which sites have recurring faults?" - "Top 10 customers by callout volume this quarter" ## How to respond 1. **Lead with the headline.** One sentence answer at the top. 2. **Back it with data.** Cite specific job references (e.g. "FAB303178"), engineer names ("Tyler French"), and sites ("14 High Street, Exeter"). 3. **Use tables for lists.** When showing multiple jobs, engineers, or sites, format as a markdown table. 4. **For comparisons, lead with the delta.** "Completions are up 12% this week (218 vs 195 last week)." 5. **Flag partial periods.** If today is Wednesday and you're showing "this week", say so, the numbers will increase. 6. **End with a next step.** Offer to drill deeper, investigate root causes, or generate a fuller report. ## How NOT to respond - ❌ Never expose internal database IDs (companyId, jobId, resourceId, siteKey, contactId). Use names and references. - ❌ Never dump raw JSON. Synthesise into prose, tables, or bullets. - ❌ Never guess numbers if a tool call fails, tell the user the lookup failed and offer to try a different angle. - ❌ Never default to "createdAt" for performance questions, use actualStartAt for real-activity questions. ## Tool selection guide | Question pattern | Tool to call | |---|---| | "Why / root cause / what's causing" | investigate | | "How many / rate / trend / top / compare" | aggregate_jobs | | "Show me / list / get / find" | jobs_feed | | "What alerts / what needs attention" | sentinels_run | | "Generate report" | reports_generate | | "Weather for job / site" | weather_for_job / weather_for_site | | Ambiguous, could go either way | aggregate_jobs first, then offer investigate | ## Voice You are a calm, competent operations colleague. Not a chatbot. Plain English. No emoji. No "Great question!" preamble. Get to the answer. Use British English spellings. ``` ## Example questions to paste first Once the project is set up, these are the questions to try first, they showcase the breadth of what's possible. * *"Who are the top 5 engineers by first-visit fix rate this month?"* * *"Which engineers consistently finish late on HVAC jobs?"* * *"Compare departments on completion rate over the last 90 days."* * *"Why are drainage jobs taking longer than planned?"* * *"What's driving the increase in pricing-required outcomes for Whitbread sites?"* * *"We've had three callouts at site \[address] this quarter, what's going on?"* * *"Generate today's start-of-day briefing."* * *"Give me the close-of-business report for yesterday."* * *"Generate the monthly account report for our largest customer."* * *"Run the sentinels and summarise what needs attention today."* * *"Which sites have triggered repeat-failure alerts in the last week?"* * *"Are there any dormant customers worth re-engaging?"* * *"Completions this week vs last week, broken down by vertical."* * *"Job intake today compared to yesterday."* * *"First-visit fix rate this month vs last month by engineer."* ## What "good" looks like Here's the kind of response you should expect once the project is set up correctly: > **Roofing job delays are driven by three main factors: complex repairs requiring specialists, the need for structural surveys and pricing approvals, and adverse weather conditions.** > > Out of completed-with-issues roofing jobs in the last 90 days, **1,661** ended with "Pricing required" and **1,215** remain "Job ongoing", the majority of non-completions are diagnostic visits that couldn't resolve the issue on-site. > > **Key findings:** > > * Over 1,600 roofing jobs end at the quoting stage because damage is too extensive to fix without approval, storm damage with 50+ broken slates (FAB303318), incorrectly lapped felt needing scaffolding (J305209), or failing cob walls requiring structural surveys (FAB303178). > * Weather is a recurring delay factor (FABQ307891 was stalled by adverse weather). > * Multi-trade complexity adds procurement and scheduling delays. > > **Recommendations:** > > 1. Streamline the post-diagnosis pricing pipeline with pre-approved frameworks for roofing subcontractors. > 2. Build weather contingency into roofing schedules. > 3. Equip engineers for temporary waterproofing on first visits. > > *Confidence: high. Scope: completed-with-issues roofing jobs, last 90 days. Want me to drill into any of these patterns?* Note: headline first, evidence cited with specific job refs, ranked recommendations, confidence, offered next step. ## For wider team rollout Claude.ai Projects can be shared across your team. Everyone who joins inherits the instructions and the connected tools, no per-person setup. Instead of pasting the API key into instructions, use the [MCP server config](/agent-kits/mcp-setup) with credentials in environment variables. Then the project instructions reference the tool, not the secret. Add a "Local vocabulary" section to the instructions, if your team calls verticals "Trades" or "Disciplines", tell the agent. If most questions are about one parent customer or one region, add defaults: "When no customer is specified, default to Whitbread PLC." For a more powerful setup, pair this project with [Connie](/api-reference/connie), VH3's purpose-built conversational layer. Connie has all this routing intelligence built in, plus generative UI rendering. The Claude.ai project is for teams who prefer to stay in their existing AI chat tool. # Claude Skills Source: https://docs.vh3.ai/agent-kits/claude-skills Anthropic SKILL.md template for Claude Code and MCP clients, operational routing, tool selection, and response format for the VH3 intelligence layer # Claude Skills [Anthropic Skills](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/skills) are Markdown files with YAML frontmatter that Claude loads when a task matches the skill description. Use this kit when you want Claude Code, Claude Desktop with skills, or another Anthropic-compatible client to answer field service operations questions with the correct VH3 MCP tools and parameters. **Skills are triggered context.** Unlike [AGENTS.md](/agent-kits/agents-md) (always-on project context) or [Claude.ai Projects](/agent-kits/claude-projects) (paste-once project instructions), a skill activates when the user's question matches the `description` in the frontmatter. Pair with the [MCP Server](/agent-kits/mcp-setup) so the tools referenced below are available. ## Setup Follow [MCP Server setup](/agent-kits/mcp-setup) so tools like `vh3-ai-v2:investigate` and `vh3-ai-v2:aggregate_jobs` are available to the client. In your skills directory (e.g. `.claude/skills/vh3-ops-assistant/SKILL.md` for Claude Code), create a file named `SKILL.md`. Copy the full block below into `SKILL.md`. Replace `{{YOUR_COMPANY_ID}}` and `{{YOUR_API_KEY}}` with your real values from [Authentication](/authentication). Never commit live credentials to source control. ## The skill file Keep the frontmatter `description` broad enough to catch casual operational questions, that is what triggers the skill. Do not shorten the tool-selection tables; they prevent invalid parameter names at the API. ```markdown SKILL.md theme={null} --- name: vh3-ops-assistant description: > Field service operations assistant with direct access to the VH3 AI intelligence layer. Use this skill whenever the user asks ANY operational question about jobs, engineers, sites, customers, performance, reports, alerts, or field service data, including questions like "how are we doing this week", "which engineers are struggling", "what happened with job X", "run the sentinels", "generate a report", "why are jobs failing", "show me [customer]'s backlog", "did weather affect jobs at [site]", or any question that requires looking up real data from VH3. Trigger even for casual or loosely phrased operational questions, if it touches jobs, engineers, sites, customers, or performance, this skill applies. --- # VH3 Field Service Operations Assistant You are a calm, competent field service operations colleague. You have direct access to the VH3 AI intelligence layer, which holds an enriched, always-current picture of every job, engineer, site, customer, and outcome in the operation. Use the VH3 tools to look up real data before answering. Cite specific job references, named engineers, and sites. Never make up numbers. If a tool call fails, say so and offer a different angle, do not guess. --- ## Credentials Pass these on **every** vh3_* tool call: - `company_id`: `{{YOUR_COMPANY_ID}}` - `api_key`: `{{YOUR_API_KEY}}` --- ## Tool selection | Question pattern | Tool to call first | |---|---| | "Why / root cause / what's causing" | `vh3-ai-v2:investigate` | | "How many / rate / trend / top / compare" | `vh3-ai-v2:aggregate_jobs` | | "Show me / list / get / find" | `vh3-ai-v2:jobs_feed` | | "What alerts / what needs attention" | `vh3-ai-v2:run_sentinels` | | "Generate report" | `vh3-ai-v2:reports_generate` | | "Weather for job / site" | `vh3-ai-v2:weather_for_job` | | Broad context / open analysis | `vh3-ai-v2:investigate` with `vh3-ai-v2:jobs_feed` | | Ambiguous, could go either way | `aggregate_jobs` first, then offer `investigate` | ### Valid report_type values (vh3-ai-v2:reports_generate) | Value | Use case | Required params | |---|---|---| | `start_of_day` | Morning briefing | `date` (YYYY-MM-DD) | | `midday` | Lunchtime check-in | `date` | | `close_of_business` | End-of-day wrap-up | `date` | | `day_review` | Reflective daily review | `date` | | `start_of_week` | Weekly kickoff | `date` (any day in that week) | | `midweek` | Mid-week pulse | `date` | | `end_of_week` | Weekly summary | `date` | | `account_monthly` | Customer account report | `month` (YYYY-MM) + `contact_id` | Never use: `weekly_summary`, `monthly_summary`, `daily_summary`, `month_review`, `end_of_month`. Omit the `sections` parameter entirely to get all sections. Never pass `{}` or `[]`. ### Valid metric values (vh3-ai-v2:aggregate_jobs) `count` · `onTime` · `avgDuration` · `completionRate` Never use: `firstTimeFix`, `fvf_rate`, `ftf`, `first_time_fix`, `sla`, `breach`. If `aggregate_jobs` fails, fall back to `vh3-ai-v2:investigate` and parse outcomes manually. ### Valid preset values (vh3-ai-v2:investigate) | Preset | Use case | Required filters | |---|---|---| | `context` | Broad operational context for a date range | None mandatory | | `job_neighborhood` | Graph neighbourhood around a specific job | `jobId` | | `customer_subgraph` | All jobs, engineers, history for a customer | `contactId` | | `engineer_workload` | Workload for a specific engineer | `resourceId` (required) | | `site_history` | Full job history for a site | `siteKey` | Never use: `engineer_throughput`, `sla_breach_summary`, `site_recurring_issues`, `performance_summary`. Do not add pre-flight validation for presets, pass them directly and let the API validate. --- ## Recommended workflows ### Weekly performance analysis 1. `vh3-ai-v2:aggregate_jobs`, `metric=count`, `metric=onTime`, `metric=completionRate` 2. `vh3-ai-v2:investigate`, `preset=context`, `date_from`/`date_to` 3. Parse `HAS_RESULT` relationships on job nodes for outcome breakdown 4. Optionally: `vh3-ai-v2:reports_generate` with `report_type=end_of_week` ### Engineer performance 1. `vh3-ai-v2:search_autocomplete`, find engineer and `resourceId` 2. `vh3-ai-v2:investigate`, `preset=engineer_workload`, `resourceId`, date range 3. `vh3-ai-v2:jobs_feed`, `resourceId` + date range for raw job list 4. `vh3-ai-v2:aggregate_jobs`, `metric=count`, `group_by=engineer` for volume comparison ### Customer / account review 1. `vh3-ai-v2:search_autocomplete`, find `contactId` 2. `vh3-ai-v2:investigate`, `preset=customer_subgraph`, `contactId` 3. `vh3-ai-v2:reports_generate`, `report_type=account_monthly`, `contact_id`, `month` ### Specific job lookup 1. `vh3-ai-v2:get_job`, job reference 2. `vh3-ai-v2:weather_for_job`, if weather context is relevant --- ## Response format **1. Lead with the headline.** One sentence at the top. **2. Back it with data.** Cite specific job references (e.g. "FAB303178"), engineer names ("Tyler French"), and sites ("14 High Street, Exeter"). **3. Use tables for lists.** Multiple jobs, engineers, or sites → markdown table. **4. For comparisons, lead with the delta.** "Completions are up 12% this week (218 vs 195)." **5. Flag partial periods.** If today is Wednesday and showing "this week", say so. **6. End with a next step.** Offer to drill deeper, investigate root causes, or run a report. --- ## What NOT to do - Never expose internal IDs (companyId, jobId, resourceId, siteKey, contactId), use names and references instead. - Never dump raw JSON, synthesise into prose, tables, or bullets. - Never guess numbers if a tool call fails, say the lookup failed and offer another approach. - Never use "createdAt" for performance questions, use `actualStartAt` for real-activity data. - Never use Connie (`vh3-ai-v2:connie_chat`) for data analysis or performance questions. --- ## Voice Plain British English. No emoji. No "Great question!" preamble. Calm and direct. Get to the answer. ``` ## Skills vs other kits | Kit | When to use | | ------------------------------------------------- | ---------------------------------------------------------------------------------------- | | **Claude Skills** (this page) | Claude Code or any client that loads Anthropic-format `SKILL.md` files on matching tasks | | [AGENTS.md](/agent-kits/agents-md) | Always-on context for coding agents in a repo | | [Claude.ai Projects](/agent-kits/claude-projects) | Non-technical ops team in the Claude.ai web UI | | [MCP Server](/agent-kits/mcp-setup) | Required backend, exposes the `vh3-ai-v2:*` tools this skill calls | For production deployments, prefer MCP JWT auth from [MCP Server setup](/agent-kits/mcp-setup) over embedding API keys in the skill file. If your client supports environment-backed credentials, reference those instead of pasting secrets into `SKILL.md`. # Cursor Rules Source: https://docs.vh3.ai/agent-kits/cursor-rules Drop-in .cursor/rules/ files that make Cursor's code generation VH3-aware, correct field names, proper error handling, n8n workflow conventions # Cursor Rules Cursor reads `.cursor/rules/*.mdc` files automatically and applies them to chats based on the rule's scope. Unlike [AGENTS.md](/agent-kits/agents-md), which is conversational context, Cursor rules apply specifically to **code generation:** they shape what Cursor *writes*, not just what it *says*. Drop the three files below into `.cursor/rules/` and any code Cursor generates in that project will use the right parameter names, handle the right errors, and follow the VH3 API conventions. **Use rules + AGENTS.md together.** AGENTS.md tells the agent which endpoint to call for which question. Cursor rules ensure the code it writes around those calls is correct. ## File 1: `vh3-api-domain.mdc` (always apply) This rule gives Cursor persistent VH3 vocabulary. It applies to every chat in the project. ````markdown .cursor/rules/vh3-api-domain.mdc theme={null} --- description: VH3 AI API domain vocabulary, schemas, and field names. Always apply. alwaysApply: true --- # VH3 AI: Domain Model All code in this project integrates with the VH3 AI intelligence layer. Use these exact names and types when generating API calls, type definitions, or data models. ## Base URL & auth - Base URL: `https://api.vh3connect.io/api:kP8T1CK7` - Every request requires `company_id` (string) and `api_key` (string) - POST: pass in JSON body. GET: pass as query params. - NEVER hardcode credentials. Read from `VH3_COMPANY_ID` and `VH3_API_KEY` environment variables. ## Entities - `Job`, id: `jobId` (int), external ref: `reference` (string, e.g. "FAB303178") - `Engineer`, id: `resourceId` (string), display: `name` - `Site`, id: `siteKey` (string), display: `siteAddress` - `Customer`, id: `contactId` (int), display: `name` - `JobGroup`, id: `jobGroupId` (int), groups related visits - `ParentCustomer`, id: name string (e.g. "Whitbread PLC") ## Job key fields - `reference`, `jobId`, `companyId` - `status`, completedOk, completedWithIssues, inProgress, notStarted - `result`, "Job Complete", "Pricing required", "Parts required", "No access" - `vertical`, security | fire_life_safety | mep | building_fabric | utilities | soft_services | it_comms | other - Timing: `plannedStartAt`, `actualStartAt`, `startDeltaMins`, `endDeltaMins` - `processedOutcome`, long-form text, always truncate before display ## CRITICAL: never invent parameter names Use exactly these names (camelCase, NOT snake_case for filter fields): ✅ `companyId` (NOT company_id in JSON bodies of v2 endpoints) ✅ `resourceId` (NOT engineer_id, resource_id, engineerId) ✅ `siteKey` (NOT site_id, site_key, siteId) ✅ `contactId` (NOT customer_id, contact_id, customerId) ✅ `typeId` (NOT type_id, jobTypeId) ⚠️ EXCEPTION: legacy v1 endpoints (e.g. /search/outcomes, /sentinels/run, /connie/chat) use `company_id` and `api_key` (snake_case) in the body. Check the OpenAPI spec when unsure: https://api.vh3connect.io/openapi.json ## Aggregation metrics (whitelisted) POST /aggregate/jobs accepts only these metrics: - `job_count` - `completion_rate` - `first_visit_fix_rate` - `avg_start_delta_mins` - `avg_end_delta_mins` GroupBy: status, result, type, category, engineer, site, vertical, day, week, month. Period shorthand: today, yesterday, this_week, last_week, this_month, last_month, last_7_days, last_30_days, last_90_days. CompareTo: previous_period, same_period_last_week, same_period_last_month. ## timeAxis: CRITICAL default Default `timeAxis = "actualStartAt"` for any retrospective question. Other values: actualEndAt (completions), plannedStartAt (forward-looking only, includes phantom jobs), createdAt (intake only), scheduledAt (dispatching). ## Error envelope All errors: ``` { "code": "ERROR_CODE_...", "message": "...", "payload": {} } ``` Status codes: 400 validation, 401 unauthorised, 404 not found, 422 semantic validation, 429 rate limit, 500 server error. Retryable: 429, 502, 504. Not retryable: 400, 401, 404, 422. ## Identity in responses Never expose `companyId`, `jobId`, `resourceId`, `siteKey`, `contactId`, `typeId`, `categoryId` in user-facing output. Use names and references. ```` ## File 2: `vh3-api-calls.mdc` (TypeScript / JavaScript / Python) This rule applies when writing API integration code in `.ts`, `.js`, or `.py` files. ````markdown .cursor/rules/vh3-api-calls.mdc theme={null} --- description: VH3 API call patterns, auth, timeouts, retries, error handling globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.py"] alwaysApply: false --- # VH3 API: Code Patterns When writing code that calls the VH3 API, follow these patterns. ## Auth: always from env ```ts const VH3_BASE = "https://api.vh3connect.io/api:kP8T1CK7"; const VH3_COMPANY_ID = process.env.VH3_COMPANY_ID!; const VH3_API_KEY = process.env.VH3_API_KEY!; ``` Throw a clear error if either is missing at module load, do not let requests fail with 400 at runtime. ## Standard POST helper ```ts async function vh3Post(path: string, body: Record): Promise { const res = await fetch(`${VH3_BASE}${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ company_id: VH3_COMPANY_ID, api_key: VH3_API_KEY, ...body, }), }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Vh3Error(res.status, err.code, err.message); } return res.json() as Promise; } ``` ## Timeouts | Endpoint | Set timeout to | |---|---| | `/investigate` (with narrative) | 25s | | `/reports/generate` (with narrative) | 25s | | `/aggregate/jobs` | 10s | | `/jobs/feed` | 10s | | `/sentinels/run` | 15s | | `/search/outcomes` | 10s | The `/investigate` and `/reports/generate` endpoints with narrative have 10–17s expected latency. Do NOT set a 5s timeout. ## Retry policy Retry on 429, 502, 504 with exponential backoff (1s, 2s, 4s, max 3 attempts). Do NOT retry 400, 401, 404, 422, they will not succeed. ## Pagination `/jobs/feed` is paginated. Use `page_size` (default 20, max 200) and `page_number`. Stop when returned array length < page_size. ## Period helpers: never compute date ranges manually For `/aggregate/jobs`, use the `period` shorthand instead of computing startDate/endDate. The server handles ISO week boundaries, partial periods, and timezone correctness. ✅ `{ period: "this_week", compareTo: "previous_period" }` ❌ Manually computing `startDate = new Date(...)` then passing as filter ## TypeScript types When generating types for API responses, mark optional fields as such (many endpoints return optional engineer/customer/site data). Use the OpenAPI spec at `https://api.vh3connect.io/openapi.json` as the source of truth, do not infer types from one example response. ```` ## File 3: `vh3-n8n-workflows.mdc` (n8n workflows) For projects using [n8n-as-code](/n8n-node) to build VH3 workflows. ````markdown .cursor/rules/vh3-n8n-workflows.mdc theme={null} --- description: VH3 API patterns inside n8n workflow files globs: ["**/*.workflow.ts"] alwaysApply: false --- # VH3 API: n8n Workflow Patterns When generating n8n nodes that call the VH3 API, follow these patterns. ## Credentials, not hardcoded values Create an n8n credential called `vh3Api` with two fields: `companyId` and `apiKey`. Reference in nodes via `{{ $credentials.vh3Api.companyId }}` and `{{ $credentials.vh3Api.apiKey }}`. Never put these in node parameters. ## HTTP Request node: VH3 POST pattern ```ts @node({ name: 'Run Sentinels', type: 'n8n-nodes-base.httpRequest', version: 4.2, position: [400, 200], }) RunSentinels = { method: 'POST', url: 'https://api.vh3connect.io/api:kP8T1CK7/sentinels/run', sendBody: true, contentType: 'json', bodyParameters: { parameters: [ { name: 'company_id', value: '={{ $credentials.vh3Api.companyId }}' }, { name: 'api_key', value: '={{ $credentials.vh3Api.apiKey }}' }, ], }, options: { timeout: 15000 }, }; ``` ## Common patterns | Goal | Endpoint | Schedule trigger | |---|---|---| | Daily morning briefing | POST /reports/generate (start_of_day) | 07:00 weekdays | | End-of-day debrief | POST /reports/generate (close_of_business) | 18:00 weekdays | | Sentinel sweep + Slack alert | POST /sentinels/run → Slack node | hourly or daily | | New-job semantic context | POST /search/outcomes triggered by FMS webhook | webhook | | Weekly account report | POST /reports/generate (account_monthly) | Monday 09:00 | ## AI Agent node: use VH3 as a tool When wiring an AI Agent node, connect the **VH3 AI Tool** sub-node from the community node (`n8n-nodes-vh3ai`). Tool names, parameters, and routing hints live on the tool definitions; do not duplicate them in the system prompt. See [n8n Agent Prompts](/agent-kits/n8n-agents) for ready-to-paste system prompts. ## NEVER - ❌ Never hardcode `company_id` or `api_key` in workflow JSON - ❌ Never use the HTTP Request node's "raw body" mode, use parameters so credentials show as `={{ $credentials... }}` not plaintext - ❌ Never set HTTP timeout < 20000ms for /investigate or /reports/generate - ❌ Never commit a workflow with a populated credential, push will reject ```` ## Installing the rules ```bash theme={null} mkdir -p .cursor/rules ``` Copy each block above into the corresponding filename inside `.cursor/rules/`. Cursor reads `.mdc` files on project load. Reload the window or reopen the project to pick up changes. Ask Cursor: *"Write me a TypeScript function that calls the VH3 aggregate endpoint to get this week's completion rate by engineer."* The generated code should use `actualStartAt` as the timeAxis, read auth from env vars, and use the correct camelCase parameter names. ## How the rules interact `vh3-api-domain.mdc` applies to every chat. Cursor always knows the entity model and field names. `vh3-api-calls.mdc` applies only when editing implementation files. Shapes generated code. `vh3-n8n-workflows.mdc` applies inside n8n-as-code projects. Enforces credential and timeout conventions. AGENTS.md handles routing and reasoning. Cursor rules handle code-level correctness. Use both. The `globs` field uses the project-relative pattern. If your integration code lives in a subdirectory (e.g. `apps/api/src/`), the patterns still match, Cursor walks the whole tree. # MCP Server Source: https://docs.vh3.ai/agent-kits/mcp-setup Connect any MCP-compatible AI client, Claude Desktop, Cursor, custom agents, directly to the VH3 intelligence layer # MCP Server The VH3 AI MCP server exposes the full intelligence layer as [Model Context Protocol](https://modelcontextprotocol.io) tools. Any MCP-compatible client, Claude Desktop, Cursor, a custom agent, or your own toolchain, can connect directly without building middleware. Once connected, the client gets the same tools used by the Connie assistant: `investigate`, `aggregate_jobs`, `jobs_feed`, `run_sentinels`, `reports_generate`, `search_outcomes`, and more, with all credentials and routing handled server-side via JWT authentication. ## Server details | Property | Value | | -------------------- | --------------------------------------------------------------------------- | | **SSE endpoint** | `https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse` | | **Transport** | SSE (Server-Sent Events) via `mcp-remote` proxy | | **Auth** | Bearer JWT token in `Authorization` header (obtained from `auth/mcp-token`) | | **Protocol version** | MCP 2025-06-18 | ## Prerequisites Claude Desktop and Cursor connect to remote MCP servers via a lightweight proxy called [`mcp-remote`](https://www.npmjs.com/package/mcp-remote). It runs automatically through `npx`, which ships with Node.js. Download the **LTS** installer for your platform from [nodejs.org](https://nodejs.org/en/download): * **macOS:** Download the `.pkg` installer from [nodejs.org](https://nodejs.org/en/download), open it, and click through the wizard. No terminal required. * **Windows:** Download the `.msi` installer. Make sure **"Add to PATH"** is checked during installation (this is the default). After installing, verify by opening a terminal (macOS: Terminal.app, Windows: Command Prompt) and running: ```bash theme={null} node --version npx --version ``` Both should return a version number (e.g. `v22.x.x`). If `npx` is not recognised, Node.js is either not installed or not in your system PATH — see [Troubleshooting](#troubleshooting) below. The MCP proxy makes outbound HTTPS connections to `api.vh3connect.io` and `registry.npmjs.org` (to fetch `mcp-remote` on first use). If your organisation uses a firewall or proxy, ask your IT team to allowlist these domains. **Why Node.js?** Claude Desktop only supports local process (stdio) MCP servers in its config file. It cannot connect to remote HTTP/SSE endpoints directly. The `mcp-remote` proxy bridges the gap — Claude Desktop launches it as a local process, and it handles the network connection to VH3. This is [the standard pattern](https://modelcontextprotocol.io/quickstart/user) recommended by the MCP specification. ## Get your MCP token Before connecting any client, you need a long-lived MCP token (valid for 90 days). Call the login endpoint with your email and password to obtain a standard session token: ```bash theme={null} curl -X POST https://api.vh3connect.io/api:lBQnyyZL/auth/login \ -H "Content-Type: application/json" \ -d '{"email": "you@company.com", "password": "your-password"}' ``` Copy the `authToken` from the response. Call the `auth/mcp-token` endpoint using your session token: ```bash theme={null} curl -X POST https://api.vh3connect.io/api:lBQnyyZL/auth/mcp-token \ -H "Authorization: Bearer YOUR_SESSION_TOKEN" ``` The response contains `authToken` (your 90-day MCP token) and `expires_in: 7776000`. Save the MCP token in an environment variable. Never commit it to source control. ```bash theme={null} export VH3_MCP_TOKEN="eyJhbGci..." ``` ## Quick start: Claude Desktop Claude Desktop connects to the VH3 MCP server via SSE using the [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) proxy. Requires [Node.js 18+](#prerequisites). The config file location depends on your platform: | Platform | Path | | ----------- | ----------------------------------------------------------------- | | **macOS** | `~/Library/Application Support/Claude/claude_desktop_config.json` | | **Windows** | `%APPDATA%\Claude\claude_desktop_config.json` | You can also open it from Claude Desktop: **Settings → Developer → Edit Config**. Create the file if it does not exist. **macOS:** ```json claude_desktop_config.json theme={null} { "mcpServers": { "vh3-ai": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse", "--header", "Authorization:${VH3_MCP_TOKEN}" ], "env": { "VH3_MCP_TOKEN": "Bearer YOUR_MCP_TOKEN" } } } } ``` **Windows:** ```json claude_desktop_config.json theme={null} { "mcpServers": { "vh3-ai": { "command": "cmd", "args": [ "/c", "npx", "-y", "mcp-remote", "https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse", "--header", "Authorization:${VH3_MCP_TOKEN}" ], "env": { "VH3_MCP_TOKEN": "Bearer YOUR_MCP_TOKEN" } } } } ``` Replace `YOUR_MCP_TOKEN` with the token from [Get your MCP token](#get-your-mcp-token). Quit fully (**Cmd+Q** on macOS, **File → Quit** on Windows — closing the window is not enough) and reopen. You should see a hammer icon in the chat input. Click it to confirm the VH3 tools are listed. Try: *"How many jobs did we complete last week, broken down by engineer?"* Claude will call `aggregate_jobs` and return a cited answer. **Windows users:** You must use `"command": "cmd"` with `"/c"` as the first arg. Claude Desktop spawns the command directly without a shell, so `npx` alone will fail with `spawn npx ENOENT`. Wrapping it in `cmd /c` ensures Windows resolves `npx` via the system PATH. The auth token is placed in the `env` block rather than inline in `args`. This is the [recommended pattern](https://www.npmjs.com/package/mcp-remote) — `mcp-remote` can misparse header values containing spaces when they appear directly in the args array on Windows. ## Quick start: Cursor Go to **Cursor Settings → MCP** and add a new server, or edit `.cursor/mcp.json` in your project root. Requires [Node.js 18+](#prerequisites). **macOS:** ```json .cursor/mcp.json theme={null} { "mcpServers": { "vh3-ai": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse", "--header", "Authorization:${VH3_MCP_TOKEN}" ], "env": { "VH3_MCP_TOKEN": "Bearer YOUR_MCP_TOKEN" } } } } ``` **Windows:** ```json .cursor/mcp.json theme={null} { "mcpServers": { "vh3-ai": { "command": "cmd", "args": [ "/c", "npx", "-y", "mcp-remote", "https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse", "--header", "Authorization:${VH3_MCP_TOKEN}" ], "env": { "VH3_MCP_TOKEN": "Bearer YOUR_MCP_TOKEN" } } } } ``` Replace `YOUR_MCP_TOKEN` with your token. See [Get your MCP token](#get-your-mcp-token). Prefer environment variables over inline tokens. Set `VH3_MCP_TOKEN` in your shell profile and reference it from the config, or use [Cursor Rules](/agent-kits/cursor-rules) alongside the MCP connection to keep tokens out of config files. ## Available tools Once connected, these tools are available in any MCP-compatible client. No `company_id` or `api_key` inputs are needed, credentials are resolved automatically from your JWT. ### FSI Intelligence | Tool | Description | Typical latency | | --------------------- | --------------------------------------------------------------- | --------------- | | `connie_chat` | Conversational AI assistant trained on your company's data | 5–15 s | | `investigate` | Deep evidence-backed investigation using graph + vector search | 10–17 s | | `search_outcomes` | Semantic search over job outcome text | \< 2 s | | `search_autocomplete` | Fast typeahead across jobs, contacts, engineers, sites | \< 1 s | | `contacts_feed` | Paginated contact list with free-text search | \< 3 s | | `contact_detail` | Full contact detail with optional stored summary | \< 3 s | | `weather_for_job` | Weather conditions for a job's location and time | \< 2 s | | `company_snapshot` | Company profile and FSI platform health | \< 2 s | | `reports_generate` | Operational reports (start\_of\_day, close\_of\_business, etc.) | 10–17 s | | `run_sentinels` | Run sentinel alert rules on demand | 3–8 s | ### Jobs | Tool | Description | Typical latency | | ---------------- | -------------------------------------------------------------------- | --------------- | | `list_jobs` | Paginated job listing with filters (status, type, contact, resource) | \< 3 s | | `get_job` | Full FSI-enriched job detail with worksheets and graph context | \< 3 s | | `jobs_feed` | Paginated job feed (alias for list\_jobs) | \< 3 s | | `aggregate_jobs` | KPI metrics with period comparison and group-by dimensions | \< 3 s | | `get_fsi_job` | FSI-enriched job detail (alias for get\_job) | \< 3 s | ### Quotes & Invoices | Tool | Description | Typical latency | | --------------- | ------------------------------------------------------ | --------------- | | `list_quotes` | Paginated quote listing with filters | \< 3 s | | `get_quote` | Full quote detail with line items | \< 2 s | | `list_invoices` | Paginated invoice listing with filters | \< 3 s | | `get_invoice` | Full invoice detail with line items and payment status | \< 2 s | `investigate`, `reports_generate`, and `connie_chat` have 10–17s expected latency. Some MCP clients have aggressive timeouts. If you see tool call failures on these endpoints, check your client's timeout setting and increase it to at least 25 seconds. ## Authentication The MCP server uses JWT Bearer token authentication. Tokens are obtained via the `auth/mcp-token` endpoint (see [Get your MCP token](#get-your-mcp-token) above). | Property | Value | | ------------------ | -------------------------------------------------------------- | | **Header** | `Authorization: Bearer ` | | **Token lifetime** | 90 days | | **Scope** | Automatically resolves your user, company, and API credentials | The JWT encodes your user identity. All tool calls are automatically scoped to your company, no `company_id` or `api_key` parameters are needed. Cross-tenant access is impossible. Never commit your MCP token to source control. Use environment variables and reference them from your MCP client configuration. ## Troubleshooting ### `spawn npx ENOENT` (Windows) Claude Desktop cannot find `npx`. Two possible causes: 1. **Node.js is not installed.** Install it from [nodejs.org](https://nodejs.org/en/download) and restart Claude Desktop. 2. **Node.js is installed but not in Claude Desktop's PATH.** Use `"command": "cmd"` with `"/c"` as the first arg (see [Windows config above](#quick-start-claude-desktop)). Alternatively, use the full path to npx: `"command": "C:\\Program Files\\nodejs\\npx.cmd"`. ### `npx is not recognized` (Windows) Same root cause as above — Node.js is not on the system PATH. Install Node.js using the `.msi` installer (not the zip), which adds it to PATH automatically. After installing, **restart Claude Desktop** (or reboot) so it picks up the new PATH. ### "Not valid MCP server configuration" The config JSON is malformed. Common causes: * **Trailing comma** after the last entry in an object or array. * **Two separate JSON objects** instead of one (e.g. `mcpServers` and `preferences` in separate `{}` blocks — they must be siblings in a single root object). * **Using `"url"` or `"headers"` keys** — Claude Desktop does not support these. Use the `command` + `mcp-remote` pattern shown above. Paste your config into [jsonlint.com](https://jsonlint.com) to validate the JSON syntax. ### Tools don't appear after restart * Verify you fully quit Claude Desktop (**Cmd+Q** / **File → Quit**), not just closed the window. * Check logs: **Settings → Developer → Open Logs Folder** and look for `mcp-remote` stderr output. * Verify your token hasn't expired (90-day lifetime). Re-run the [token exchange](#get-your-mcp-token) if needed. * Confirm outbound HTTPS to `api.vh3connect.io` and `registry.npmjs.org` is not blocked by a firewall. ### Tool calls timeout `investigate`, `reports_generate`, and `connie_chat` can take 10–17 seconds. Some clients have aggressive timeouts. Increase your client's tool call timeout to at least 25 seconds. ### Further reading * [MCP Specification](https://modelcontextprotocol.io) — the protocol standard * [MCP Debugging Guide](https://modelcontextprotocol.io/docs/tools/debugging) — official troubleshooting * [`mcp-remote` on npm](https://www.npmjs.com/package/mcp-remote) — the SSE proxy package * [Claude Desktop MCP Quickstart](https://modelcontextprotocol.io/quickstart/user) — Anthropic's setup guide ## Using the MCP server from custom agents For agents built with the Anthropic SDK, OpenAI Agents SDK, or similar frameworks: ```python Python (Anthropic SDK) theme={null} import os import anthropic client = anthropic.Anthropic() response = client.beta.messages.create( model="claude-opus-4-5", max_tokens=4096, mcp_servers=[ { "type": "url", "url": "https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse", "name": "vh3-ai-v2", "authorization_token": os.environ["VH3_MCP_TOKEN"], } ], messages=[{"role": "user", "content": "What needs attention today?"}], ) ``` ```typescript TypeScript (SSE transport) theme={null} import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; const transport = new SSEClientTransport( new URL("https://api.vh3connect.io/x2/mcp/UZkEeuG7/mcp/sse"), { requestInit: { headers: { Authorization: `Bearer ${process.env.VH3_MCP_TOKEN!}`, }, }, } ); const client = new Client({ name: "my-agent", version: "1.0.0" }); await client.connect(transport); const tools = await client.listTools(); console.log(tools); // lists all 19 VH3 tools ``` ## Tool selection guide for agents When your agent receives a free-form question and needs to decide which tool to call: | Question pattern | Tool | | -------------------------------------------------------------- | ------------------------------------------------ | | "why / root cause / what's causing / investigate" | `investigate` | | "how many / rate / trend / top / compare / period over period" | `aggregate_jobs` | | "show me / list / find / get jobs" | `list_jobs` or `jobs_feed` | | "what needs attention / alerts / sentinels" | `run_sentinels` | | "generate report / briefing / debrief / weekly summary" | `reports_generate` | | "similar to / fault like / what else looks like" | `search_outcomes` | | "find customer / contact / site" | `contacts_feed` or `search_autocomplete` | | "quotes / pricing / quotations" | `list_quotes` or `get_quote` | | "invoices / billing / payments" | `list_invoices` or `get_invoice` | | Ambiguous / unclear | `aggregate_jobs` first, then offer `investigate` | For a full system prompt you can paste directly into your agent, see the [Claude.ai Projects](/agent-kits/claude-projects) and [n8n Agent Prompts](/agent-kits/n8n-agents) kits, both include routing logic optimised for agent use. ## Pairing with AGENTS.md If you're using the MCP server inside a Cursor or Claude Code session, pair it with the [AGENTS.md](/agent-kits/agents-md) file in your project root. The MCP server handles execution; AGENTS.md handles routing logic, field name correctness, and the rules around what IDs to expose to users. Handles *execution*, connects the client to the actual API, manages auth, returns real data. Handles *reasoning*, tells the agent which tool to call, which parameters to pass, and how to present results. # n8n Agent Prompts Source: https://docs.vh3.ai/agent-kits/n8n-agents System prompts for n8n AI Agent workflows using the VH3 AI community node # n8n Agent Prompts VH3 AI is built to be extended. The intelligence layer (enriched jobs, operational memory, discovery, sentinels, reports) sits underneath Connie, your API, and native integrations. **n8n** is where you wire that layer into the rest of your stack: Slack, email, CRM, spreadsheets, scheduling, and the thousand-plus apps your team already uses. The [verified VH3 AI community node](https://link.vh3.ai/n8n) puts field service operations and AI on the same canvas. Install it once, connect your credentials, and build deterministic workflows or LLM-powered agents without a proprietary workflow builder or a development queue. [Check the community node pack here](https://link.vh3.ai/n8n) for the full action list, install steps, and n8n's integration overview. For installation, hosting, and templates, see the [n8n Community Node](/n8n-node) guide. ## Why n8n is the obvious extension layer | What you get | Why it matters | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **Production automation** | Scheduling, branching, retries, and observability on a platform teams already run in anger | | **Visual + optional code** | Operations can build on the canvas; technical teams can version workflows when they need to | | **1,000+ connectors** | Route VH3 intelligence to Gmail, Outlook, Slack, Teams, HubSpot, Xero, Google Sheets, and the rest of your stack | | **VH3 node + AI Tool** | 150+ operations (jobs, contacts, sentinels, reports, Connie, cases, email triage) with descriptions the agent reads at runtime | | **Included on your plan** | Full n8n automation platform from VH3 API tier upward; community node free to install | | **Templates and managed hosting** | 100+ starter workflows, or `{your-company}.n8n.vh3.ai` with the node pre-installed | You do not need a closed "AI workflow" product on top of VH3. n8n is the open automation layer; the community node is the bridge. Native integrations handle sync inside the platform; n8n handles **your** routing, alerts, and custom logic. Use **deterministic** VH3 AI nodes (cron → sentinel → Slack) when the steps are fixed. Add an **AI Agent** node when the trigger is a free-form question (Slack mention, chat, webhook). Same substrate, different control surface. ## The community node in n8n Once installed, VH3 AI appears in the node panel with triggers, actions, and an AI Tool variant for agent workflows. n8n node details panel showing the installed VH3 AI community node with action categories such as Account Report, Briefing, and Case A typical automation chains Outlook or Slack with VH3 ingest, classification, and job operations, then branches on status before notifying your team. n8n workflow canvas connecting Microsoft Outlook trigger to VH3 AI ingest, status switch, and further VH3 job nodes ## When to use the node directly vs an AI Agent | Use VH3 AI nodes in the workflow when... | Add an AI Agent node when... | | ---------------------------------------------------------------------- | --------------------------------------------------------------------- | | Steps are fixed (daily report, sentinel digest, email triage pipeline) | The user asks in natural language (Slack mention, chat, webhook body) | | You want no LLM cost on every run | The model should choose which VH3 operation fits the question | | You are syncing data to CRM, sheets, or storage | You are building a conversational ops assistant | ## Architecture ``` Trigger (Slack mention / webhook / schedule / chat) ↓ AI Agent node ├── Language Model (OpenAI / Anthropic / Gemini, BYOK) ├── Memory (Buffer Window, optional) ├── System Prompt ← from this page └── VH3 AI Tool (community node) ↓ Reply or next workflow step (Slack, email, case, etc.) ``` Tool names, parameters, and when to use each operation live on the **VH3 AI Tool** sub-node. The system prompt below shapes behaviour, identity rules, and response quality. Do not duplicate parameter lists in the prompt. ## Quick setup Self-hosted: Settings → Community Nodes → `n8n-nodes-vh3ai`. n8n Cloud: search **VH3 AI**. Or use a [managed VH3 n8n instance](/n8n-node#hosting-options). See [Check the community node pack here](https://link.vh3.ai/n8n). API Key and Company ID from your VH3 account. See [Credentials](/n8n-node#credentials) on the n8n node page. Add a trigger, an **AI Agent** node, your language model, and connect the **VH3 AI Tool** generated from the community node. Copy the [system message](#the-system-prompt) into the agent's System Message field. Optionally append the [routing appendix](#optional-routing-appendix). Use Buffer Window memory with `sessionKey` set to channel or user id so follow-ups keep context. ## The system prompt Paste this into the **System Message** field of the AI Agent node. It contains no workflow expressions: credentials and tool wiring stay in n8n. Copy the whole block. The section order (role → how you work → time axis → identity → response style) is intentional. ```markdown System Message theme={null} You are the field service operations assistant for this organisation. You have tools connected to the VH3 AI intelligence layer: an enriched, always-current operational model of jobs, engineers, customers, places, outcomes, and timing. Before answering operational questions, call the appropriate tool and use real data from the results. Never invent numbers. If a tool fails, say the lookup failed and offer a different angle. ## How you work Discovery first when the question is lookup or precedent-shaped. Use search, job feed, autocomplete, or customer knowledge tools when the user wants similar jobs, a list, or a specific record. Synthesis when the question needs diagnosis or narrative. Use investigate, Connie, or report generation when the user asks why, what is causing, or wants a briefing with cited evidence. These calls take longer; set brief expectations if needed. Metrics and comparisons. Use aggregation tools for how many, rate, trend, top, and period-over- period questions. Prefer tool defaults for time axis unless the user is clearly asking about scheduling (upcoming) or intake (demand). ## Time axis (critical) For backward-looking performance and workload, prefer when field work actually started or finished, not when records were created or jobs were only planned. Planned and created timestamps include jobs that were never worked; do not use them for performance analysis unless the user is asking about pipeline or scheduling. For period comparisons (this week vs last week), use the tool comparison parameters rather than inventing date ranges. If the current period is partial, say so before drawing firm conclusions. ## Identity and scoping Everything is contact-centric: customers are contacts; places are addresses under a customer. Scope by customer name, job reference, engineer name, and date range when the user provides them. Never show internal identifiers in replies (database IDs, linkage keys). Use job references, engineer names, customer names, and site addresses. ## How to respond 1. Lead with the headline answer in one sentence. 2. Support with cited job references, names, and places from tool output. 3. Use tables for lists of jobs, engineers, or sites. 4. For comparisons, lead with direction and magnitude (up 12%, down 7%). 5. End with one offered next step (investigate further, run sentinels, etc.). 6. Plain English. British spellings. No filler preamble. If confidence is low or data is thin, say what would sharpen the answer. ``` ## Optional routing appendix Paste this **below** the main system message if you want a short reminder without repeating tool parameter docs. Tool descriptions on the VH3 AI Tool node remain the source of truth. ```markdown Routing appendix theme={null} ## Tool choice (summary) - Why / root cause / what is driving → investigate (or Connie for dialogue) - How many / rate / trend / top / compare → aggregate jobs - Show / list / find a job or account → job feed or search tools - What needs attention / alerts → run sentinels - Briefing / debrief / report → generate report - Similar past work / precedent → semantic search on outcomes or customer sections Follow each tool's description for parameters. Do not guess internal IDs. ``` ## Testing the agent Once wired up, try these in your trigger channel: | Message | Expected behaviour | | -------------------------------------------- | -------------------------------------------------------- | | *"How many jobs did we complete last week?"* | Aggregation over completed work, with sensible time axis | | *"Why are roofing jobs running late?"* | Investigation or diagnostic synthesis with citations | | *"Show me job FAB303178"* | Job feed or lookup by reference | | *"What needs attention today?"* | Sentinels | | *"Generate today's start-of-day briefing"* | Report generation | ## Performance notes Investigation and reports with narrative often need 20 to 25 seconds. Set the VH3 tool or workflow timeout accordingly; default short timeouts will fail on synthesis endpoints. Use Buffer Window memory with `contextWindowLength: 10` and `sessionKey` scoped to the channel or user. Without memory, follow-ups like "drill into roofing" lose context. Each tool call adds tokens. The VH3 AI Tool descriptions carry routing detail; keep the system prompt focused on behaviour and identity, not parameter enums. Prefer fast tools (search, feed, sentinels) for triggers and filters; reserve investigate and narrative reports for steps that need language. See [Operational discovery](/guides/operational-discovery). ## Related Install, credentials, hosting, and operation list. Verified integration page and full action catalogue. Citizen builders, substrate, and programmatic access. Same intelligence surface for Claude Desktop and Cursor. # n8n Node — Coding Agent Reference Source: https://docs.vh3.ai/agent-kits/n8n-node-reference Complete resource, operation, and pattern reference for AI assistants building VH3 AI n8n workflows # n8n Node — Coding Agent Reference Attach this document at the start of any AI session where you are building VH3 AI n8n workflows. It covers the node's resources, operations, routing decisions, patterns, and constraints, and works with Claude.ai, Claude Code, Cursor, or any chat session with the file attached. * Source: [github.com/VH3DIGITAL/n8n-nodes-vh3ai](https://github.com/VH3DIGITAL/n8n-nodes-vh3ai) * npm: [n8n-nodes-vh3ai](https://www.npmjs.com/package/n8n-nodes-vh3ai) * Agent prompts: [/agent-kits/n8n-agents](/agent-kits/n8n-agents) ## Connecting your AI assistant to n8n ### The recommended setup: official n8n connector + this document The **official n8n connector** (developed by n8n GmbH, available in the Claude connector directory) connects Claude to your live n8n instance. On instances running n8n **v2.18.4 or higher**, it exposes the full instance-level MCP — including workflow building, not just execution. **What it can do** (verified on VH3-managed instances): | Tool | Purpose | | --------------------------------------- | ----------------------------------------------------- | | `get_sdk_reference` | Load the n8n Workflow SDK before writing code | | `get_suggested_nodes` | Recommended node types for a workflow pattern | | `search_nodes` / `get_node_types` | Discover nodes and fetch exact parameter schemas | | `list_credentials` | Find available credentials by name (secrets redacted) | | `validate_workflow` | Pre-deploy validation of workflow code | | `create_workflow_from_code` | Compile SDK code and save to your instance | | `search_workflows` / `execute_workflow` | Find and run existing workflows | **Setup (Claude.ai) — step by step:** Switch to **Code** mode in Claude.ai. Your active connectors appear in the input bar at the bottom of the screen. Claude Code main screen showing the connector bar with an n8n connector active Click on the **Connectors** area, then click **Add → Browse connectors** to open the connector directory. Claude Code connectors panel with the Add dropdown open showing Browse connectors option In the Directory, select **Connectors** and search for **n8n**. The official n8n connector by n8n GmbH will appear. Claude.ai connector directory search showing the n8n connector result Switch to your n8n instance. Click **Settings** in the left sidebar and select **Instance-level MCP** from the menu. n8n settings sidebar with Instance-level MCP highlighted in the menu Toggle Instance-level MCP on, then copy the **Server URL** shown in the Connection details panel. This is the URL you'll paste back into Claude. n8n Instance-level MCP settings page showing the toggle enabled and Server URL https://n8n.vh3.ai/mcp-server/http **VH3-managed instances:** Your URL is `https://{your-company}.n8n.vh3.ai/mcp-server/http`. Contact VH3 support if Instance-level MCP is not yet enabled on your instance. Back in the Claude connector directory, click the n8n connector. When the **Install n8n** dialog appears, paste your Server URL into the field and click **Continue**. Claude will ask for permission to access your n8n instance. Click **Allow** — this grants Claude the ability to list, execute, create, and update workflows on your behalf. OAuth permission screen showing Claude wants access to your n8n instance with a list of permitted actions The n8n connector now appears in your directory and is active in the Claude Code input bar. You can now ask Claude to build, validate, and deploy workflows directly on your instance. Claude connector directory showing the n8n connector listed and active **Setup (Claude Code — CLI):** ```bash theme={null} claude mcp add --transport http n8n-mcp https:///mcp-server/http ``` Enable instance-level MCP in your n8n instance first: **Settings → Instance-level MCP**. Full tool reference: [n8n MCP tools reference](https://docs.n8n.io/advanced-ai/mcp/mcp_tools_reference/) **VH3-managed instances:** Your n8n URL is `https://{your-company}.n8n.vh3.ai`. The `n8n-nodes-vh3ai` community node and VH3 credentials are pre-installed. Contact VH3 support if you need your MCP access token or API key. ### This reference document — the VH3 AI layer The official n8n MCP knows n8n's built-in nodes and the Workflow SDK. It does **not** know the VH3 AI community node — its resources, operations, routing rules, or patterns. Without this document, an AI assistant will not know: * Which resource and operation to choose for a given question (section 5) * That `jobFeed` should be preferred over `jobs` for reads (section 3d) * The correct `timeAxis` for performance vs intake questions (section 4) * How `ingestEmail` status values route downstream (section 6.8) * That custom field IDs must be fetched from the job type first (section 10) * The exact node type name (`n8n-nodes-vh3ai.vh3Ai`) and credential type (`vh3AiApi`) Attach this document at the start of any session where you are building VH3 AI workflows. Combined with the n8n connector, this is the complete stack. ### Optional: czlonkowski/n8n-mcp (Cursor and offline authoring) [czlonkowski/n8n-mcp](https://github.com/czlonkowski/n8n-mcp) is a separate community MCP server. It is **not** what the official Claude n8n connector uses, and is **not** required for the build experience described above. Consider it if you are working in **Cursor** or another editor, want stricter pre-deploy validation, or need offline node schema lookup without a live n8n connection. It uses different tool names (`n8n_create_workflow`, `get_node`, etc.) and requires a one-time install via npx or Docker. Setup: [github.com/czlonkowski/n8n-mcp](https://github.com/czlonkowski/n8n-mcp) ### Summary | Layer | What it provides | Required? | | ------------------------------------------- | ----------------------------------------------------------- | -------------------------------------- | | Official n8n connector | Build, validate, deploy, and run workflows on your instance | Yes — core setup | | This document | VH3 AI node: resources, operations, routing, patterns | Yes — VH3 domain knowledge | | [n8n Agent Prompts](/agent-kits/n8n-agents) | System message for AI Agent node workflows | When building conversational AI agents | | `czlonkowski/n8n-mcp` | Offline node schema, strict validation, Cursor integration | Optional | *** ## 1. Identity | Property | Value | | ------------------ | ------------------------------------------------------------------------- | | NPM package | `n8n-nodes-vh3ai` | | Node type name | `vh3Ai` | | Display name | `VH3 AI` | | Credential type | `vh3AiApi` | | `usableAsTool` | `true` — can be dropped directly into an AI Agent node as a tool sub-node | | n8nNodesApiVersion | `1` | *** ## 2. Credential: `vh3AiApi` Four fields are stored in the credential. Two are fixed defaults and should not be changed unless VH3 support instructs otherwise. | Field | Internal name | Required | Default | Notes | | ------------ | ------------- | ------------- | ---------------------------------------- | ------------------------------------------------------------------------------------ | | API Key | `apiKey` | Yes | — | Sent as `X-API-KEY` header on every request | | Company ID | `companyId` | Conditionally | — | Required for single-record operations (e.g. Get Job). Omit for list/feed operations. | | Base URL | `baseUrl` | Yes | `https://api.vh3connect.io` | BigChange Web Services proxy base | | FSI Base URL | `fsiBaseUrl` | Yes | `https://api.vh3connect.io/api:kP8T1CK7` | VH3 AI intelligence layer base | When generating a VH3 AI node block in JSON, reference the credential as: ```json theme={null} "credentials": { "vh3AiApi": { "id": "", "name": "" } } ``` *** ## 3. Resource taxonomy The node exposes **30 resources** split across three internal API layers. This split is invisible in the UI but critical for understanding timeout, latency, and data freshness expectations. ### 3a. BigChange data resources (CRUD) These map directly to the BigChange field-service platform. Operations are typically fast (\<2 s). The resource values are used in `$parameter["resource"]`. | Display name | `resource` value | What it covers | | ------------------------------- | -------------------- | ------------------------------------------------------------------------ | | Job (BigChange) | `jobs` | CRUD, schedule, start, set result, cancel, manage stock constraints | | Contact (BigChange) | `contacts` | Companies and sites — create, read, update, delete | | Resource / Engineer (BigChange) | `resources` | Engineers/technicians and their groups | | Job Type (BigChange) | `jobTypes` | Job type templates (installation/repair/maintenance schemas) | | Vehicle (BigChange) | `vehicles` | Fleet vehicles — read/create/update records and groups | | Worksheet (BigChange) | `worksheets` | Mobile worksheet definitions, questions, and submitted answers | | Worksheet Group (BigChange) | `worksheetGroups` | Folders that organise worksheet definitions | | Invoice (BigChange) | `invoices` | Sales invoices and line items | | Note (BigChange) | `notes` | Notes/tasks/updates on jobs, contacts, and persons | | Person (BigChange) | `persons` | Individual people attached to a contact (site contacts, consent history) | | Job Group (BigChange) | `jobGroups` | Linked sets of jobs (multi-visit projects) | | Stock (BigChange) | `stock` | Product categories, stock details, items, movements, suppliers | | Reference Data (BigChange) | `referenceData` | Department codes, nominal (accounting) codes | | Quote (BigChange) | `quotes` | Sales quotes and line items | | Sales Opportunity (BigChange) | `salesOpportunities` | CRM pipeline — read, edit, line items, probabilities, stages | | Purchase Order (BigChange) | `purchaseOrders` | Purchase orders and line items | ### 3b. Web Services resources (BigChange driver API) Thin proxy over the BigChange Web Services layer. Responses use different envelope shapes (`result` array, not `data`). | Display name | `resource` value | What it covers | | ------------------------- | ---------------- | --------------------------------------------------- | | Attachment (Web Services) | `wsAttachments` | Retrieve/list attachments for BigChange entities | | Report (Web Services) | `wsReports` | Driver/vehicle performance and infringement reports | | Tracking (Web Services) | `wsTracking` | GPS journeys, live positions, odometer readings | ### 3c. VH3 AI intelligence resources These call the FSI intelligence layer. They are **slower** (2–25 s depending on operation) and consume LLM tokens for synthesis operations. | Display name | `resource` value | Latency tier | What it covers | | ----------------------- | ---------------- | --------------- | ------------------------------------------------------------------ | | Job Feed (VH3 AI) | `jobFeed` | Fast (\< 3 s) | Enriched, paginated job feed with aggregation and analytics | | Search (VH3 AI) | `search` | Fast (\< 3 s) | Semantic and outcome search, autocomplete, customer knowledge base | | Sentinel (VH3 AI) | `sentinel` | Medium (3–8 s) | Proactive monitoring checks | | Pulse (VH3 AI) | `pulse` | Fast | Cached business-health dashboard snapshot | | Email (VH3 AI) | `email` | Fast–Medium | Email triage: classify, ingest, batch classify, list rules | | Briefing (VH3 AI) | `briefing` | Medium (5–10 s) | Pre-visit intelligence briefing + call script for an engineer | | Case (VH3 AI) | `cases` | Fast | Case management: create, update, transition, comment, link items | | Connie (VH3 AI) | `connie` | Medium (5–15 s) | Conversational AI assistant: chat, sessions, history search | | Report (VH3 AI) | `reports` | Slow (10–25 s) | Operational reports (daily, weekly, monthly) with narrative | | Investigate (VH3 AI) | `investigate` | Slow (10–25 s) | Multi-step hybrid vector + graph investigation | | Account Report (VH3 AI) | `accountReport` | Slow (10–25 s) | Monthly account review across full parent-child hierarchy | | Intelligence (VH3 AI) | `intelligence` | Medium | Job type profiling — list, get, generate intelligence profiles | | Weather (VH3 AI) | `weather` | Fast | Weather for jobs, sites, forecasts, historical lookups | | User (VH3 AI) | `users` | Fast | User management — list, invite, update role, delete | ### 3d. FSI-first principle **When both a BigChange resource and a VH3 AI intelligence resource can answer the same question, prefer the intelligence layer.** The FSI layer ingests and enriches all job data continuously. For read operations — job feeds, aggregations, search, analysis, monitoring — it is faster (often cached), returns richer data, and avoids unnecessary load on the BigChange API. | Question | Prefer | Reason | | ------------------------ | ------------------------------------------ | -------------------------------------- | | List or search jobs | `jobFeed` (VH3 AI) over `jobs` (BigChange) | Enriched, cached, supports aggregation | | What needs attention? | `sentinel` (VH3 AI) | Pre-computed, no extra API calls | | Business health snapshot | `pulse` (VH3 AI) | Cached dashboard, single call | | Find a customer by name | `search → autocomplete` (VH3 AI) | Fuzzy match, no ID required | | Historical job analysis | `jobFeed → aggregateJobs` (VH3 AI) | Built-in metrics, period comparison | The intelligence layer does not write to BigChange. It is read-only for operational intelligence. To create or modify records — jobs, contacts, invoices, notes — use the BigChange CRUD resources (section 3a). *** ## 4. The time axis — critical for data quality Several Job Feed and Aggregate Jobs operations accept a `dateField` or `timeAxis` parameter. Choosing the wrong axis produces misleading results. ### Available timestamp fields | Value | What it represents | Use when... | | ---------------- | -------------------------------------------- | ------------------------------------------------------- | | `actualStartAt` | When the engineer physically began the job | Measuring real performance, throughput, productivity | | `actualEndAt` | When the engineer finished | Measuring duration, closure rates, end-of-day analysis | | `createdAt` | When the job record was created in BigChange | Measuring intake volume, demand pipeline analysis | | `plannedStartAt` | When the job was scheduled to start | Measuring scheduling accuracy, schedule adherence drift | | `plannedEndAt` | When the job was scheduled to finish | — | | `scheduledAt` | When the scheduling decision was made | — | ### Decision rules **Default to `actualStartAt`** for any performance or workload question. It reflects real field activity and excludes jobs that were planned but never worked. ``` Question type → Recommended time axis ─────────────────────────────────── ──────────────────────── How many jobs did we complete? actualStartAt / actualEndAt What's our first-visit fix rate? actualStartAt How many jobs came in this week? createdAt Are engineers on time? plannedStartAt → actualStartAt delta What's in the schedule for today? plannedStartAt How long do jobs take? actualStartAt → actualEndAt delta ``` `createdAt` includes jobs that were planned but never attended. Do not use it for performance analysis unless the user is explicitly asking about intake volume or pipeline. **Partial periods**: When the current period (e.g. `this_week`) is still in progress, say so before drawing conclusions. The `compareTo` parameter (`previous_period`, `same_period_last_week`, `same_period_last_month`) handles apples-to-apples comparison automatically — prefer it over inventing date ranges. *** ## 5. Routing guide — which resource and operation to use Use this table when the user's intent is expressed in natural language, to select the right VH3 AI node operation. | User intent | Resource | Operation | | ---------------------------------------------------- | --------------- | -------------------------------------------------------------- | | "How many jobs did we complete last week?" | `jobFeed` | `aggregateJobs` — metric: `job_count`, timeAxis: `actualEndAt` | | "What's our first-visit fix rate?" | `jobFeed` | `aggregateJobs` — metric: `first_visit_fix_rate` | | "Show me jobs for customer X" | `jobFeed` | `listJobFeed` — filter: `contactId` | | "Show me all jobs for an account including children" | `jobFeed` | `listAccountJobFeed` | | "Get the detail for job FAB303178" | `jobFeed` | `getEnrichedJob` | | "Find jobs like this one / similar past work" | `search` | `searchOutcomes` or `searchIntake` | | "What do we know about this customer?" | `search` | `getSummaryByContact` or `searchSummarySections` | | "Find a customer / engineer / site" | `search` | `autocomplete` | | "What needs attention today?" | `sentinel` | `runSentinels` (sentinelId: `all`) | | "Is there a pattern of problems at a site?" | `sentinel` | `runSentinels` — `new_problem_site` or `site_deterioration` | | "Why are roofing jobs running late?" | `investigate` | `runInvestigation` | | "What is causing repeat failures?" | `investigate` | `runInvestigation` | | "Generate today's start-of-day briefing" | `reports` | `generateReport` — reportType: `start_of_day` | | "End of week summary" | `reports` | `generateReport` — reportType: `end_of_week` | | "Monthly account review for client X" | `accountReport` | `generateAccountReport` | | "Brief the engineer before they visit" | `briefing` | `generateBriefing` | | "Classify this incoming email" | `email` | `classifyEmail` or `batchClassifyEmail` | | "Extract job data from this FM portal email" | `email` | `ingestEmail` | | "What's our current business health?" | `pulse` | `getPulse` | | "Ask Connie about..." | `connie` | `connieChat` | | "Create a case for this incident" | `cases` | `createCase` | | "Create / update a job" | `jobs` | `create` / `update` | | "Create / update a contact" | `contacts` | `create` / `update` | | "What's the weather for this job?" | `weather` | `getWeatherForJob` | | "Create jobs from FM portal emails" | `email` | `ingestEmail` — route downstream on returned `status` field | *** ## 6. Per-resource operation reference ### 6.1 Job Feed (`jobFeed`) | Operation | Key inputs | Notes | | -------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `listJobFeed` | `status` (multi), `dateField`, `dateFrom`, `dateTo`, `contactId`, `resourceId`, `typeId` | Default `dateField`: `createdAt`. Add `simplify: true` to strip nulls. | | `listAccountJobFeed` | `contactId` (required — any in hierarchy) | Traverses full parent-child account tree automatically | | `aggregateJobs` | `metric`, `period`, `timeAxis`, `groupBy`, `compareTo` | Use `compareTo` for period-over-period. `groupBy` options: `status`, `result`, `typeId`, `categoryId`, `resourceId`, `siteKey`, `vertical`, `day`, `week`, `month` | | `getEnrichedJob` | `jobId` (required), `includeWorksheets` | Returns AI enrichment: vertical, sentiment, key phrases | **Aggregate metrics**: `job_count`, `completion_rate`, `first_visit_fix_rate`, `avg_start_delta_mins`, `avg_end_delta_mins`. **Period presets**: `today`, `yesterday`, `this_week`, `last_week`, `this_month`, `last_month`, `last_7_days`, `last_30_days`, `last_90_days`. Override with `startDate`/`endDate` for custom ranges. ### 6.2 Search (`search`) | Operation | Key inputs | Notes | | ----------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `autocomplete` | `query`, `typeFilter` (multi: `customer`, `engineer`, `job`, `person`, `site`) | Fast fuzzy lookup across all entity types | | `searchOutcomes` | `queryText`, `contactId`, `resourceId`, `typeId`, `maxAgeMonths` | Semantic search on job diagnostic summaries | | `searchIntake` | `queryText`, `contactId`, `resourceId`, `typeId` | Semantic search with knowledge graph enrichment | | `searchIntakeBasic` | `queryText` | Same as above, without graph enrichment (faster) | | `searchSummarySections` | `query`, `contactId`, `sectionKey` | Search the CustomerSummary knowledge base. Section keys: `customer_overview`, `job_history_patterns`, `operational_performance`, `risk_opportunity`, `systems_equipment`, `communication_summary`, `key_analyses` | | `getSummaryByContact` | `contactId`, `fullReport` | Retrieves all stored CustomerSummary sections. Set `fullReport: true` for assembled markdown. | Date filtering on semantic search operations is applied **client-side** after the API responds. Set `maxAgeMonths` to limit result age. ### 6.3 Sentinel (`sentinel`) | Operation | Key inputs | Notes | | ---------------------- | ----------------------------- | ------------------------------------------------------------------ | | `runSentinels` | `sentinelId` (default: `all`) | Returns only triggered alerts. Use `all` for a full check. | | `getSentinelResults` | — | Returns cached results from the last run (fast, no re-computation) | | `listSentinelRegistry` | — | Lists all sentinel definitions with thresholds and schedules | **Available sentinels**: `carryover_accumulation`, `customer_noncomplete_anomaly`, `customer_risk_escalation`, `data_quality_alert`, `engineer_performance_slip`, `fvf_rate_drop`, `new_problem_site`, `repeat_failure_escalation`, `scheduling_accuracy_drift`, `site_deterioration`, `sla_breach_cluster`, `workload_imbalance`. For scheduled automations, use `getSentinelResults` (cached, instant) rather than `runSentinels` (re-computes) to avoid latency in time-sensitive triggers. ### 6.4 Report (`reports`) | Operation | Key inputs | Notes | | -------------------- | ---------------------------------------------------- | ----------------------------------------------------- | | `generateReport` | `reportType`, `date`, `includeNarrative`, `sections` | Narrative adds 2–5 s. Omit `sections` to include all. | | `listReportSections` | — | Discover section IDs for selective report generation | **Report types**: `start_of_day`, `midday`, `close_of_business`, `day_review`, `start_of_week`, `midweek`, `end_of_week`. Set workflow/node timeout to ≥ 30 s for narrative reports. ### 6.5 Investigate (`investigate`) | Operation | Key inputs | Notes | | ------------------ | ------------------------------------------ | --------------------------------------------------------------------------------------------------------- | | `runInvestigation` | `question` (free text), `maxEvidenceItems` | Multi-step hybrid search across the intelligence layer. Expensive — 10–25 s. Do not use in polling loops. | ### 6.6 Case (`cases`) | Operation | Notes | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | | `createCase` | `title` + `caseType` required. Types: `audit`, `case_study`, `compliance`, `incident`, `investigation`, `project_review` | | `listCases` | Filter by `status`, `type`, `priority`, `ownerId` | | `searchCases` | Full-text search across title and description | | `getCase` | Returns participants, items, latest activity | | `updateCase` | Patch — only provided fields change | | `transitionCase` | Lifecycle-validated status changes. Statuses: `draft` → `open` → `in_progress` → `under_review` → `resolved` → `closed` / `archived` | | `addComment` | Adds to activity timeline | | `addCaseItem` | Links a job, customer, site, engineer, job group, note, or document | | `listCasesForItem` | Reverse lookup — find all cases referencing a specific record | ### 6.7 Connie (`connie`) | Operation | Key inputs | Notes | | -------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `connieChat` | `message`, `sessionId` (optional), `contactId`, `userId` | Pass `sessionId` to continue an existing conversation. Set `experimentalMode: true` for the experimental pipeline. | | `listSessions` | `userId`, `contactId` | — | | `connieGetSessionMessages` | `sessionId` | — | | `connieSearchHistory` | `query`, `userId`, `contactId` | — | For AI Agent workflows, use `connieChat` with `sessionKey`-scoped `sessionId` so follow-up messages retain context. ### 6.8 Email (`email`) | Operation | Notes | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `classifyEmail` | `subject` + `emailBody` + `senderAddress` required. Supports attachment via URL or binary data. | | `batchClassifyEmail` | JSON array of up to 50 email objects. Portal/pre-filter hits are instant; novel emails consume LLM tokens. | | `ingestEmail` | Extracts structured job data from FM portal emails. Returns resolved entities and a `status` field. Always switch on `status` downstream. | | `listTriageCategories` | Returns active categories with priority, destination, and prompt rules. | | `listTaxonomyRules` | Filter by `phase`: `pre_classify` (noise filters) or `post_classify` (routing decisions). | **`ingestEmail` status values** — every implementation must route on this field: | Status | Meaning | | --------------- | ------------------------------------------------------- | | `Create` | Entities resolved, confident — proceed to job creation | | `Review` | Ambiguity or missing data — route to human review queue | | `Unprocessable` | Email could not be parsed as a portal job email | | `Rejected` | Matched a noise or exclusion rule — discard silently | **PDF vs HTML input**: Many FM portals send job orders as PDF attachments rather than HTML body. The `ingestEmail` operation accepts plain text (`emailText`) — it does not process binary PDFs directly. For PDF-based portals, extract the text first using n8n's **Extract From File** node before passing it to `ingestEmail`. Build your workflow to switch on whether the email has a PDF attachment and handle both paths feeding the same `ingestEmail` node. ### 6.9 Briefing (`briefing`) | Operation | Key inputs | Notes | | ------------------ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `generateBriefing` | `jobId` + `contactId` required | Generates structured pre-visit briefing + call script. Use `jobPayload` (JSON) if the job was created very recently and may not yet be indexed in the intelligence layer. | ### 6.10 Account Report (`accountReport`) | Operation | Key inputs | Notes | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `generateAccountReport` | `contactId` required | Pass any contact in the account hierarchy — the report resolves the full tree. `month` in `YYYY-MM` format, defaults to previous calendar month. | ### 6.11 Pulse (`pulse`) | Operation | Notes | | ---------- | ------------------------------------------------------------------------------------------ | | `getPulse` | No inputs. Returns cached snapshot of pipeline, performance, workforce, and asset metrics. | ### 6.12 Intelligence (`intelligence`) | Operation | Key inputs | Notes | | ------------------ | -------------------------------- | -------------------------------------------------------- | | `listProfiles` | `profiledOnly` (default: `true`) | Filter to only types with a generated profile. | | `getProfile` | `typeId` | Gets the intelligence profile for a specific job type. | | `generateProfiles` | `typeIds` (JSON array), `scope` | Regenerate profiles — use sparingly, runs in background. | ### 6.13 Weather (`weather`) | Operation | Key inputs | Notes | | ------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------- | | `getWeatherForJob` | `jobId` | Fastest — resolves location from the job record automatically | | `getWeatherForSite` | `siteKey`, optional `startDate`/`endDate` | Current or historical conditions by date range | | `getForecast` | `latitude`, `longitude`, optional `startHour`/`endHour`/`timezone` | Point forecast for a raw coordinate | | `getHistorical` | `latitude`, `longitude`, optional `startDate`/`endDate`/`timezone` | Historical conditions for a raw coordinate | ### 6.14 Users (`users`) | Operation | Key inputs | Notes | | ---------------- | --------------------------------------------- | ---------------------------------------- | | `listUsers` | — | Returns active users only | | `listInvites` | — | Returns pending (unaccepted) invitations | | `inviteUser` | `email`, `role`, `companyName`, `inviterName` | Roles: `admin`, `manager`, `user` | | `updateUserRole` | `userId`, `role` | — | | `deleteUser` | `userId` | Soft-delete (archive) — not permanent | *** ## 7. BigChange CRUD resources — operation summary All BigChange resources follow a consistent pattern. Key operations per resource: ### Jobs (`jobs`) `create`, `update`, `get`, `getAll`, `delete`, `schedule`, `unschedule`, `start`, `setResult`, `cancel`, `addStock`, `deleteStock`, `updateStockQty`, `addWaypoint`, `deleteWaypoint`, `addRecurrence` ### Contacts (`contacts`) `create`, `update`, `get`, `getAll`, `getByRef`, `delete`, `getGroups` ### Resources/Engineers (`resources`) `get`, `getAll`, `getGroups` ### Vehicles (`vehicles`) `get`, `getAll`, `create`, `update`, `getGroups` ### Invoices (`invoices`) `get`, `getAll`, `create`, `addLine`, `markSent`, `markPaid`, `cancel` ### Notes (`notes`) `create`, `update`, `get`, `getAll`, `delete` ### Persons (`persons`) `create`, `update`, `get`, `getAll`, `delete`, `getConsentHistory` ### Quotes (`quotes`) `get`, `getAll`, `create`, `update`, `addLine`, `markSent`, `markAccepted`, `markRejected` ### Sales Opportunities (`salesOpportunities`) `get`, `getAll`, `update`, `addLine`, `deleteLine`, `listProbabilities`, `listStages` ### Purchase Orders (`purchaseOrders`) `get`, `getAll`, `create`, `update`, `addLine`, `listSeries` ### Job Groups (`jobGroups`) `get`, `getAll`, `getStatusHistory` ### Stock (`stock`) `getCategories`, `getDetails`, `getItems`, `getMovements`, `getSuppliers` ### Reference Data (`referenceData`) `getDepartmentCodes`, `getNominalCodes` ### Worksheets (`worksheets`) `get`, `getAll`, `getQuestions`, `getAnswers` ### Worksheet Groups (`worksheetGroups`) `get`, `getAll` ### Job Types (`jobTypes`) `getAll` *** ## 8. Using the node as an AI Tool sub-node Because `usableAsTool: true` is set, the node can be attached directly to an AI Agent node as a tool. The agent reads each operation's `description` field at runtime to decide which to call. ### Architecture for an agent workflow ``` Trigger (Slack / Webhook / Schedule / Chat) ↓ AI Agent node ├── Language model (OpenAI / Anthropic / Gemini, BYOK) ├── Memory (Buffer Window — sessionKey scoped to channel/user) ├── System Prompt (see /agent-kits/n8n-agents) └── VH3 AI Tool (community node, all operations) ↓ Reply / next workflow step ``` ### Key agent configuration notes 1. **System prompt**: Copy the system message from [/agent-kits/n8n-agents](/agent-kits/n8n-agents). It encodes the time-axis rules, identity scoping, and response format. Do not re-describe parameter enums in the system prompt — they live in the tool descriptions already. 2. **Memory**: Use Buffer Window with `contextWindowLength: 10`. Set `sessionKey` to the channel ID or user ID so follow-up queries retain context. 3. **Timeouts**: Set the VH3 AI Tool timeout to ≥ 30 s. Investigation and narrative reports regularly take 20–25 s; default short timeouts will fail silently. 4. **Token cost**: Each tool call adds tokens. Prefer fast operations (`search`, `jobFeed`, `sentinel`) in high-frequency triggers. Reserve `investigate` and `reports` for steps that genuinely need language synthesis. ### Combining the VH3 AI Tool with other LangChain sub-nodes Complex ingestion workflows often pair the VH3 AI Tool with other LangChain nodes in the same agent or as adjacent steps. A common pattern is using the **Information Extractor** node (with a lightweight model such as Gemini Flash) to extract typed custom field values from unstructured email or document text — using the custom field schema fetched from Job Types at runtime to build the extraction prompt. This keeps field extraction data-driven rather than hardcoded to a specific job type, and handles schema changes without workflow edits. See Pattern F in section 9. ### When to use deterministic nodes vs. an AI Agent | Use VH3 AI nodes directly (deterministic) | Add an AI Agent node | | ---------------------------------------------------------------------- | ------------------------------------------------------------------- | | Steps are fixed (daily report, sentinel digest, email triage pipeline) | Trigger is a free-form question (Slack mention, webhook body, chat) | | No LLM cost desired on every run | The model should choose which VH3 operation fits the question | | Syncing data to CRM, spreadsheets, or storage | Building a conversational ops assistant | | Scheduled automations | Natural language queries against operational data | *** ## 9. Workflow patterns ### Pattern A: Daily sentinel digest to Slack ``` Schedule trigger (07:00) → VH3 AI: Sentinel — Run Sentinels (all) → IF node: triggered alerts > 0 → Slack: post formatted alert list → [else] Slack: post "All clear" ``` ### Pattern B: Email triage pipeline ``` Microsoft Outlook trigger (new email) → VH3 AI: Email — Classify Email → Switch node (on classification) → "new_job": VH3 AI: Job — Create + Slack notify → "update": VH3 AI: Job — Update → "noise": [no action] ``` ### Pattern C: Enriched job briefing on job creation ``` Webhook trigger (BigChange job-created event) → VH3 AI: Briefing — Generate Briefing (jobId, contactId) → Slack / SMS: send briefing to assigned engineer ``` ### Pattern D: Monthly account report loop ``` Schedule trigger (1st of month, 08:00) → VH3 AI: Contact — Get All (filter: account contacts) → Loop Over Items → VH3 AI: Account Report — Generate Account Report → Email: send report to account manager ``` ### Pattern E: Conversational ops assistant (AI Agent) ``` Slack trigger (app mention) → AI Agent ├── OpenAI GPT-4o ├── Buffer Window memory (sessionKey: channelId) ├── System prompt from /agent-kits/n8n-agents └── VH3 AI Tool (all operations) → Slack: reply in thread ``` ### Pattern F: FM portal email → job creation with custom field extraction This is the core portal ingestion pattern. The key non-obvious steps are the PDF/HTML split, the Information Extractor for custom fields, and the Wait + verify step that handles indexing lag between BigChange creation and FSI visibility. ``` Outlook trigger (new email) → Set node (centralised config: job type IDs, default contact, etc.) → Switch: has PDF attachment? → [PDF] Get Binary Attachment → Extract From File (PDF→text) → [HTML] extract body text → VH3 AI: Email — Ingest Email (emailText + preferredTypeIds from config) → Switch: ingestEmail.status → "Create": → VH3 AI: Job Type — Get All (fetch schema for matched type) → Information Extractor LLM node (Gemini Flash) prompt built from job type custom field definitions + email text → Code: assemble job payload with extracted custom field values → VH3 AI: Jobs — Create → Wait (30 s — allow FSI indexing) → VH3 AI: Job Feed — Get Enriched Job (lightweight verify) → Reply email: confirmation with job reference → "Review": send to human approval queue (email / Slack) → "Unprocessable" / "Rejected": log to spreadsheet / case and exit ``` Any workflow with more than two configurable values — type IDs, contact IDs, email addresses, Slack channels — should centralise them in a Set node at the start. This makes the workflow easy to adapt per tenant without hunting through individual node parameters. ### Pattern G: Bulk tabular import (CSV / XLSX → jobs) Converting spreadsheet rows into synthetic portal email bodies lets the same `ingestEmail` pipeline handle both live emails and bulk imports without duplicating job creation logic. ``` Form trigger (file upload — xlsx or csv) → Switch: file format → Extract From File (xlsx) / Extract From File (csv) → Code: build synthetic portal email body from each row → Split in Batches (configurable batch size, e.g. 5) → VH3 AI: Email — Ingest Email (per row) → Switch: status → "Create" path (same as Pattern F) / record result → [loop continues] → Summary email: total created / review / failed ``` *** ## 10. Important constraints ### General * **Never expose internal IDs** in agent replies. Use job references, engineer names, customer names, and site addresses. * **`companyId` in credentials** is required for single-record Get operations on BigChange resources. It is not required for VH3 AI intelligence operations. * **`simplify: true`** (where available) strips null, empty string, and empty array fields from responses — recommended when passing data downstream. * **`returnAll: true`** on list operations uses automatic pagination. Only use it when you genuinely need the full dataset; large tenants can have thousands of jobs. * **Batch email classification** (`batchClassifyEmail`) is significantly more efficient than calling `classifyEmail` in a loop. Use it whenever you have multiple emails to process in the same step. * **Binary data in workflows.** Any workflow that handles file attachments (PDFs, spreadsheets, images) should have **Binary mode** set to **Filesystem** in the workflow settings. Without this, binary payloads are stored inline with execution records, which causes memory pressure and can silently fail on large files. Set this before building any attachment-handling or import workflow. ### Destructive actions — confirm before generating Any operation that **creates, updates, deletes, cancels, or transitions** a BigChange record is irreversible or difficult to undo. Before generating a workflow that includes these operations: 1. **Confirm intent explicitly** with the user — do not infer that a write is needed from context alone. 2. **Check for existing records** before creating. Duplicate jobs, contacts, or invoices are a common source of data quality problems. 3. **Scope updates narrowly** — patch only the fields the user specified. Do not reset or overwrite fields that were not mentioned. 4. If you are unsure about the correct approach for a write operation, say so and ask the user rather than proceeding on an assumption. ### Custom fields on jobs — fetch the job type first BigChange jobs support custom fields whose schema is defined per job type. The available fields, their IDs, and their value types vary by tenant configuration. Before constructing a Create Job or Update Job payload that includes custom fields, always fetch the job type first using `Job Type (BigChange) → getAll` and inspect the returned custom field definitions. Do not guess field IDs or types — they are not portable between job types or tenants. The same principle applies to other entities with custom field support (contacts, resources). If you are unsure whether custom fields are involved, ask. ### Polling frequency * Avoid high-frequency polling loops with expensive operations. `investigate`, `generateReport`, and `generateBriefing` are not suitable for loops that run more than once per trigger event. * For sentinel monitoring, prefer `getSentinelResults` (cached, returns pre-computed results instantly) over `runSentinels` (re-computes) in any schedule that runs more than once or twice per day. * Where BigChange supports webhooks or event-based triggers, use them in preference to polling on a tight schedule. * If a workflow needs to wait for a job status to change, use a wait/delay node with a reasonable interval rather than a tight loop. ### Relative timestamps in expressions Hardcoded dates make workflows brittle. Use n8n's Luxon-based `$now` expression for any date that should be calculated at runtime. ``` Today (ISO): {{ $now.toISO() }} Start of today: {{ $now.startOf('day').toISO() }} 7 days ago: {{ $now.minus({ days: 7 }).toISO() }} Start of this week: {{ $now.startOf('week').toISO() }} Start of last month: {{ $now.minus({ months: 1 }).startOf('month').toISO() }} End of last month: {{ $now.minus({ months: 1 }).endOf('month').toISO() }} YYYY-MM (for reports): {{ $now.minus({ months: 1 }).toFormat('yyyy-MM') }} ``` Use these patterns when populating `dateFrom`, `dateTo`, `startDate`, `endDate`, and `month` fields. Never hardcode a date string in a workflow intended to run on a schedule. *** ## 11. Workflow authoring practice ### Sticky notes Use n8n's **Sticky Note** node liberally on the canvas. Add a sticky note: * At the top of every workflow describing its purpose, trigger conditions, and any VH3 or BigChange-specific context a future editor will need. * Beside any node that calls a write operation, explaining why the write is necessary and what happens if it fails. * Wherever a parameter value is non-obvious (e.g. a specific contact ID, hardcoded job type, or calculated expression) to explain the reasoning. * At branch points (Switch, IF) to document the routing logic in plain English. Sticky notes have no execution cost and make a significant difference when workflows are revisited weeks later or handed to another developer. ### Capturing user preferences and recurring patterns When building workflows for a specific tenant or user, notice patterns that emerge in how they describe their work: * Preferred job statuses, result values, or engineer groupings they always filter by. * Specific customers or sites they monitor closely. * Report cadences and delivery channels they rely on. * Naming conventions for workflows, notes, and cases. Where the same preference appears more than once, consider surfacing it as a workflow-level variable or a dedicated config node at the top of the workflow rather than embedding it in multiple node parameters. This makes the workflow easier to adapt without hunting through individual nodes. If you observe a pattern that suggests a repeating automation opportunity (e.g. the user manually runs the same report every Monday), point it out and offer to formalise it. *** ## 12. Quick reference: n8n JSON node block shape ```json theme={null} { "id": "", "name": "VH3 AI", "type": "n8n-nodes-vh3ai.vh3Ai", "typeVersion": 1, "position": [800, 300], "credentials": { "vh3AiApi": { "id": "", "name": "VH3 AI API" } }, "parameters": { "resource": "jobFeed", "operation": "aggregateJobs", "metric": "job_count", "period": "last_7_days", "timeAxis": "actualStartAt", "additionalFields": { "groupBy": "resourceId", "compareTo": "previous_period" } } } ``` The `subtitle` expression on the node is: `={{$parameter["operation"] + " (" + $parameter["resource"] + ")"}}` — you do not need to set it manually in JSON. *** ## Related Installation, credentials, hosting, and operation list. System prompt for AI Agent node workflows. Official integration page and full action catalogue. Source code, changelog, and contribution guide. # Agent Starter Kits Source: https://docs.vh3.ai/agent-kits/overview Ready-to-use configurations for connecting AI agents and coding assistants to the VH3 intelligence layer # Agent Starter Kits VH3 AI exposes the full intelligence layer, graph, semantic index, aggregation, sentinels, reports, through a standard API and an MCP surface. These starter kits give your AI tools the exact configuration they need to use that surface correctly from day one. Each kit is self-contained. Pick the one that matches how your team works. **Operators:** these kits are for builders connecting AI tools to the platform. If you run the operation day to day (coordinator, dispatcher, account manager, engineer, owner), start at [Working with your operation](/guides/working-with-your-operation) instead. ## For AI agents (documentation) This site is optimised for LLMs and coding agents. Use these endpoints to learn the VH3 API. They search **documentation only**, not your live field service data. | Resource | URL | | ----------------------- | ------------------------------------------------------------------ | | Site index | [docs.vh3.ai/llms.txt](https://docs.vh3.ai/llms.txt) | | Full docs (single file) | [docs.vh3.ai/llms-full.txt](https://docs.vh3.ai/llms-full.txt) | | Any page as Markdown | Add `.md` to the page URL, or use **Copy page** in the header menu | | Documentation MCP | [docs.vh3.ai/mcp](https://docs.vh3.ai/mcp) | **Two different MCP servers.** The URL above is Mintlify's **documentation** MCP (search and read these docs). To query live jobs, sentinels, and reports, use the [VH3 product MCP](/agent-kits/mcp-setup) with your tenant JWT, not the docs MCP. npx skills add [https://docs.vh3.ai](https://docs.vh3.ai) On any page, open the **contextual menu** (top of page) to copy the page as Markdown, open it in Claude or ChatGPT, or connect the documentation MCP to Cursor or VS Code in one click. A drop-in context file for AI coding agents (Cursor, Claude Code, GitHub Copilot). Tells the agent which endpoint to call for which question, the correct field names, and the API conventions. Three `.cursor/rules/` files that shape every VH3-related code generation in Cursor, domain vocabulary, API call patterns, and n8n workflow conventions. Connect any MCP-compatible client (Claude Desktop, Cursor, custom agents) directly to the VH3 intelligence layer. No middleware required. Project instructions for Claude.ai, for operations managers who want to query VH3 in plain English without writing code. Anthropic SKILL.md template for Claude Code and MCP clients: tool routing, valid parameters, and ops response format. System prompts for n8n AI Agent workflows using the VH3 AI node and 1,000+ app connectors. Verified community node on n8n — install steps, full action list, and integration overview. ## Which kit should I use? | Your situation | Recommended kit | | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | You're a developer using Cursor | [AGENTS.md](/agent-kits/agents-md) + [Cursor Rules](/agent-kits/cursor-rules) | | You want to connect Claude Desktop or another MCP client | [MCP Server](/agent-kits/mcp-setup) | | You're building an AI-powered Claude.ai workspace for your ops team | [Claude.ai Projects](/agent-kits/claude-projects) | | You're using Claude Code or Anthropic-format skills with the VH3 MCP server | [Claude Skills](/agent-kits/claude-skills) | | You're building automations in n8n with an LLM decision layer | [n8n Agent Prompts](/agent-kits/n8n-agents) · [Install the verified node](https://link.vh3.ai/n8n) | | You want everything | Start with AGENTS.md, add MCP, then layer in the tool-specific kits | ## What the kits don't do These kits configure AI tools to use the VH3 API correctly. They do not replace the API itself, you still need a valid `company_id` and `api_key` to make calls. See [Authentication](/authentication) for how to obtain those. The kits reference endpoints from the [API Reference](/api-reference/overview). If an endpoint behaves unexpectedly, cross-check the spec there, the starter kits are tuned for the current API version. # Contacts Source: https://docs.vh3.ai/api-reference/bigchange/contacts BigChange contacts, groups, and site access hours # Contacts BigChange contacts, groups, and site access hours. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Date filters (list) `POST /contacts/list` accepts optional `createdAtFrom` (ISO 8601 UTC). Any creation-date window used with an upper bound must stay within the **12-month** BigChange limit. See [overview](/api-reference/bigchange/overview#date-ranges). ## Contacts Customer and site records. ### `GET` `/contacts/contact` Get contact. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/contacts/contact" \ -H "X-API-Key: your-api-key" \ --data-urlencode "contactId=12345" ``` ### `POST` `/contacts/create` Create contact. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme", "reference": "ACME-01" }' ``` ### `POST` `/contacts/edit` Update contact. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "name": "Acme Ltd" }' ``` ### `POST` `/contacts/list` List contacts. | Field | Type | Required | Description | | --------------- | ------ | -------- | ------------------------------------------- | | `createdAtFrom` | string | No | Contacts created on or after (ISO 8601 UTC) | | `sortBy` | string | No | `createdAt` or `name` | | `direction` | enum | No | `ascending` or `descending` | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50, "createdAtFrom": "2025-04-01T00:00:00Z", "sortBy": "name", "direction": "ascending" }' ``` ### `POST` `/contacts/on_stop` Put on stop. **Enum values:** * **status:** `contactOnStop`, `creditLimitOnStop` ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/on_stop" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "status": "contactOnStop", "stopReason": "Credit hold" }' ``` ### `POST` `/contacts/unstop` Remove stop. **Enum values:** * **appliesTo:** `contactOnly`, `contactAndChildren` ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/unstop" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "appliesTo": "contactOnly" }' ``` ### `POST` `/contacts/site_access_hours_list` List access hours. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/site_access_hours_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "pageNumber": 1, "pageSize": 10 }' ``` ### `POST` `/contacts/site_access_hours_update` Update access hours. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contacts/site_access_hours_update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "body": [ { "dayOfWeek": "monday", "startTime": "08:00", "endTime": "17:00" } ] }' ``` ## Contact groups Organise contacts. ### `GET` `/contact_groups/contact_group` Get group. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/contact_groups/contact_group" \ -H "X-API-Key: your-api-key" \ --data-urlencode "contactGroupId=99" ``` ### `POST` `/contact_groups/create` Create group. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contact_groups/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "Retail" }' ``` ### `POST` `/contact_groups/list` List groups. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contact_groups/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/contact_groups/update` Update group. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/contact_groups/update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactGroupId": 99, "name": "Retail UK" }' ``` # Invoices Source: https://docs.vh3.ai/api-reference/bigchange/invoices BigChange invoices and line items # Invoices BigChange invoices and line items. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Date filters (list) `POST /invoices/list` accepts an optional creation-date window. **`createdAtTo` minus `createdAtFrom` must not exceed 12 months\`** (BigChange API limit, see [overview](/api-reference/bigchange/overview#date-ranges)). | Param | Type | Required | Description | | --------------- | ------ | -------- | --------------------------------------------------------- | | `createdAtFrom` | string | No | Invoices created on or after this instant (ISO 8601 UTC) | | `createdAtTo` | string | No | Invoices created on or before this instant (ISO 8601 UTC) | Combine with `id`, `jobId`, `jobGroupId`, `contactId`, or `reference` (comma-separated lists, max 50 IDs each). Use `sortBy: "createdAt"` with `direction` when reporting by period. ## Invoices Billing. ### `GET` `/invoices/invoice` Get invoice. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/invoices/invoice" \ -H "X-API-Key: your-api-key" \ --data-urlencode "invoiceId=5001" ``` ### `POST` `/invoices/create` Create invoice. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "createdAt": "2026-04-01T00:00:00Z" }' ``` ### `POST` `/invoices/edit` Update invoice. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001 }' ``` ### `POST` `/invoices/list` List invoices with optional filters and a creation-date range (max **12 months** between `createdAtFrom` and `createdAtTo`). **Request body (filters):** | Field | Type | Required | Description | | --------------- | ------- | -------- | --------------------------------------- | | `pageNumber` | integer | No | Page index (1-based) | | `pageSize` | integer | No | Items per page | | `createdAtFrom` | string | No | Created on or after (ISO 8601 UTC) | | `createdAtTo` | string | No | Created on or before (ISO 8601 UTC) | | `contactId` | string | No | Contact IDs (comma-separated, max 50) | | `jobId` | string | No | Job IDs (comma-separated, max 50) | | `jobGroupId` | string | No | Job group IDs (comma-separated, max 50) | | `id` | string | No | Invoice IDs (comma-separated, max 50) | | `reference` | string | No | References (comma-separated, max 50) | | `sortBy` | string | No | `createdAt` | | `direction` | enum | No | `ascending` or `descending` | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50, "createdAtFrom": "2026-01-01T00:00:00Z", "createdAtTo": "2026-03-31T23:59:59Z", "contactId": "12345", "sortBy": "createdAt", "direction": "descending" }' ``` ### `POST` `/invoices/cancel` Cancel. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/cancel" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001 }' ``` ### `POST` `/invoices/mark_paid` Mark paid. Optional `paidAt` (ISO 8601 UTC); defaults to now if omitted. Single timestamp, not a date range. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/mark_paid" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001, "paidAt": "2026-04-15T12:00:00Z" }' ``` ### `POST` `/invoices/mark_sent` Mark sent. Optional `sentAt` (ISO 8601 UTC); defaults to now if omitted. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/mark_sent" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001, "sentAt": "2026-04-10T09:00:00Z" }' ``` ### `POST` `/invoices/document/create` Generate PDF. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/document/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001 }' ``` ## Invoice line items Line-level charges. ### `GET` `/invoices/line_item` Get line. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/invoices/line_item" \ -H "X-API-Key: your-api-key" \ --data-urlencode "invoiceId=5001" \ --data-urlencode "lineItemId=1" ``` ### `GET` `/invoices/line_item/edit` Update line. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/invoices/line_item/edit" \ -H "X-API-Key: your-api-key" \ --data-urlencode "invoiceId=5001" \ --data-urlencode "lineItemId=1" ``` ### `POST` `/invoices/line_item/create` Create line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/line_item/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001, "description": "Labour", "quantity": 2, "unitSellingPrice": 85 }' ``` ### `POST` `/invoices/line_item/delete` Delete line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/line_item/delete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001, "lineItemId": 1 }' ``` ### `POST` `/invoices/line_item/list` List lines. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/invoices/line_item/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": 5001, "pageNumber": 1, "pageSize": 50 }' ``` # Jobs Source: https://docs.vh3.ai/api-reference/bigchange/jobs BigChange jobs, constraints, stock, groups, and types # Jobs BigChange jobs, constraints, stock, groups, and types. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Date filters (list) `POST /jobs/list` requires **`createdAtFrom` and `createdAtTo`** (job creation time, ISO 8601 UTC). The span between them **must not exceed 12 months**. See [overview](/api-reference/bigchange/overview#date-ranges). ## Jobs Job lifecycle. ### `GET` `/jobs/job` Get job. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/jobs/job" \ -H "X-API-Key: your-api-key" \ --data-urlencode "jobId=12345" ``` ### `POST` `/jobs/create` Create job. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "typeId": 42, "contactId": 12345, "description": "Blocked toilet" }' ``` ### `POST` `/jobs/edit` Update job. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "description": "Updated description" }' ``` ### `POST` `/jobs/list` List jobs. **`createdAtFrom` and `createdAtTo` are required.** Max **12 months** between them. **Request body (key fields):** | Field | Type | Required | Description | | --------------- | ------- | -------- | ---------------------------------------- | | `createdAtFrom` | string | **Yes** | Jobs created on or after (ISO 8601 UTC) | | `createdAtTo` | string | **Yes** | Jobs created on or before (ISO 8601 UTC) | | `pageNumber` | integer | No | Page index | | `pageSize` | integer | No | Items per page | | `direction` | enum | No | `ascending` or `descending` | | `contactId` | string | No | Filter by contact IDs (comma-separated) | | `resourceId` | string | No | Filter by engineer IDs | | `status` | string | No | Filter by job status | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 20, "createdAtFrom": "2026-01-01T00:00:00Z", "createdAtTo": "2026-03-31T23:59:59Z", "direction": "descending" }' ``` ### `POST` `/jobs/cancel` Cancel job. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/cancel" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "reason": "Customer cancelled" }' ``` ### `POST` `/jobs/start` Start job. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/start" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "comment": "On site" }' ``` ### `POST` `/jobs/result` Set result. **Enum values:** * **status:** `completedOk`, `completedWithIssues` ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/result" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "status": "completedOk", "result": "Job complete" }' ``` ### `POST` `/jobs/scheduling` Schedule job. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/scheduling" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "resourceId": 100, "vehicleId": 50, "plannedStartAt": "2026-04-20T09:00:00Z" }' ``` ### `POST` `/jobs/status/history` Status history. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/status/history" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "pageNumber": 1, "pageSize": 50 }' ``` ## Job constraints Scheduling constraints. ### `POST` `/jobs/constraints/create` Create constraint. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/constraints/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345 }' ``` ### `POST` `/jobs/constraints/delete` Delete constraint. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/constraints/delete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "constraintId": 1 }' ``` ### `POST` `/jobs/constraints/list` List constraints. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/constraints/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "pageNumber": 1, "pageSize": 20 }' ``` ## Job stock Parts on jobs. ### `POST` `/jobs/stock/create` Add stock line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/stock/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "stockDetailsId": 10, "quantityPlanned": 1 }' ``` ### `POST` `/jobs/stock/delete` Remove stock line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/stock/delete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "jobStockId": 5 }' ``` ### `POST` `/jobs/stock/get` Get stock line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/stock/get" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "jobStockId": 5 }' ``` ### `POST` `/jobs/stock/list` List stock lines. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/stock/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "pageNumber": 1, "pageSize": 20 }' ``` ## Job groups Multi-job programmes. ### `POST` `/job_groups/create` Create group. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "Refurb phase 1" }' ``` ### `POST` `/job_groups/edit` Update group. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobGroupId": 10, "name": "Refurb phase 1" }' ``` ### `POST` `/job_groups/job_group` Get group. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/job_group" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobGroupId": 10 }' ``` ### `POST` `/job_groups/list` List groups. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 20 }' ``` ### `POST` `/job_groups/status_history` Group status history. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/status_history" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobGroupId": 10, "pageNumber": 1, "pageSize": 20 }' ``` ### `POST` `/job_groups/job_group_results_as_complete` Mark complete. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/job_group_results_as_complete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobGroupId": 10 }' ``` ### `POST` `/job_groups/job_group_results_as_financially_complete` Mark financially complete. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_groups/job_group_results_as_financially_complete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobGroupId": 10 }' ``` ## Job types Job type catalogue. ### `POST` `/job_types/job_types` Get type. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_types/job_types" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobTypeId": 42 }' ``` ### `POST` `/job_types/list` List types. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/job_types/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 100 }' ``` # Notes Source: https://docs.vh3.ai/api-reference/bigchange/notes Notes and note types # Notes Notes and note types. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Notes Entity notes. ### `GET` `/notes/note` Get note. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/notes/note" \ -H "X-API-Key: your-api-key" \ --data-urlencode "id=7001" ``` ### `POST` `/notes/create` Create note. **Enum values:** * **entityType:** `contact`, `job`, `resource`, `stockItem`, `vehicle`, `salesOpportunity`, `contract` ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/notes/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "entityType": "job", "entityId": 12345, "typeId": 1, "subject": "Follow-up" }' ``` ### `POST` `/notes/edit` Update note. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/notes/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "noteId": 7001, "subject": "Updated" }' ``` ### `POST` `/notes/list` List notes. **Enum values:** * **status:** `open`, `completed`, `cancelled` ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/notes/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "entityType": "job", "entityId": 12345, "status": "open", "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/notes/progress_update` Update progress. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/notes/progress_update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "noteId": 7001, "percentage": 50 }' ``` ## Note types Note type definitions. ### `GET` `/note_types/note` Get type. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/note_types/note" \ -H "X-API-Key: your-api-key" \ --data-urlencode "noteTypeId=1" ``` ### `POST` `/note_types/list` List types. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/note_types/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` # BigChange API Overview Source: https://docs.vh3.ai/api-reference/bigchange/overview BigChange API Integration, jobs, contacts, finance, stock, and worksheets # BigChange API Unified read/write proxy to your BigChange field service data. Covers jobs, contacts, invoices, quotes, sales opportunities, purchase orders, resources, vehicles, stock, worksheets, and reference data. Tenant scope is resolved from your API key. No `company_id` is required on these requests. We've added some usefuil features such as pre handled authentication, compactions and data output optimisation. ## Base URL ``` https://api.vh3connect.io/api:YdihQNr3 ``` ## Authentication Pass your VH3 API key in the `X-API-Key` header on every request. This is the same key issued for the [VH3 AI Intelligence](/api-reference/overview) layer; only the transport differs. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 20 }' ``` | Header | Required | Description | | -------------- | ---------- | ------------------- | | `X-API-Key` | Yes | Your tenant API key | | `Content-Type` | Yes (POST) | `application/json` | Missing or invalid keys return `401 Unauthorised`. See [Authentication](/authentication) for the full two-API comparison. ## Common response codes | Code | Meaning | | ----- | ------------------------------------------ | | `200` | Success | | `201` | Created | | `400` | Bad request, invalid or missing parameters | | `401` | Unauthorised, missing or invalid API key | | `403` | Forbidden, insufficient permissions | | `404` | Not found | | `422` | Validation error | | `429` | Rate limited | | `500` | Internal server error | ## Pagination List endpoints accept `pageNumber` (1-based) and `pageSize`. Finance list responses also include `pageItemCount` (items in the current page, use to detect the last page). | Param | Default | Max | | ---------- | ------- | ---- | | `pageSize` | 100 | 1000 | ## Sorting Most list endpoints accept: | Param | Values | | ----------- | --------------------------------------------------------- | | `sortBy` | Field name (varies by endpoint, e.g. `name`, `createdAt`) | | `direction` | `ascending` or `descending` | ## Date ranges BigChange enforces a **maximum 12-month window** on date-range filters. If `createdAtTo` minus `createdAtFrom` (or equivalent pair) exceeds twelve calendar months, the API returns a validation error. | Rule | Detail | | ------------ | --------------------------------------------------------------------------------------- | | Format | ISO 8601 UTC, e.g. `2026-01-01T00:00:00Z` | | Typical pair | `createdAtFrom` + `createdAtTo`, inclusive bounds on record creation time | | Max span | **12 months**, always; not configurable per tenant | | Sort tie-in | Finance lists (`invoices`, `quotes`) usually sort by `createdAt` when filtering by date | **Where date ranges apply:** | Endpoint | Date filter fields | Notes | | -------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------ | | `POST /jobs/list` | `createdAtFrom`, `createdAtTo` | Required for job list queries | | `POST /contacts/list` | `createdAtFrom` | Optional lower bound on contact creation | | `POST /invoices/list` | `createdAtFrom`, `createdAtTo` | Optional; combine with `contactId`, `jobId`, `reference`, etc. | | `POST /quotes/list` | `createdAtFrom`, `createdAtTo` | Optional; same pattern as invoices | | `POST /purchase_orders/list` | `createdAtFrom`, `createdAtTo` | At least one non-date filter still required | | `POST /sales_opportunities/list` | `createdAtFrom`, `createdAtTo`, `dueDateFrom`, `dueDateTo` | At least one filter required; due-date pair also subject to 12-month max | Status timestamps on write endpoints (`paidAt`, `sentAt`, `plannedStartAt`, note `dueAt`) are single instants, not ranges, they are not subject to the 12-month window rule. ## Custom fields Pass custom fields as an array when creating or updating records: ```json theme={null} { "customFields": [ { "definitionId": 123, "value": "High priority" }, { "definitionId": 456, "value": null } ] } ``` Set `value` to `null` to clear an existing value. ## Common enum values | Domain | Field | Values | | --------- | ------------------------- | ------------------------------------------------------------------------------------ | | All lists | `direction` | `ascending`, `descending` | | Contacts | `status` (on stop) | `contactOnStop`, `creditLimitOnStop` | | Contacts | `appliesTo` (stop/unstop) | `contactOnly`, `contactAndChildren` | | Jobs | `status` (result) | `completedOk`, `completedWithIssues` | | Notes | `status` | `open`, `completed`, `cancelled` | | Notes | `entityType` | `contact`, `job`, `resource`, `stockItem`, `vehicle`, `salesOpportunity`, `contract` | | Persons | `consent.status` | `awaiting`, `refused`, `granted` | | Persons | `consent.medium` | `email`, `click`, `telephone` | Endpoint-specific enums are listed on each page where they apply. ## Path format Request URLs are `{baseUrl}{path}` with **one** slash between base and path, e.g. `https://api.vh3connect.io/api:YdihQNr3` + `/jobs/list`. Some BigChange routes include repeated segments by design (e.g. `/stock/stock/item_get`); that is not a double-slash error. ## Endpoint groups | Group | Description | | ------------------------------------------------------------------- | ------------------------------------------------------ | | [Contacts](/api-reference/bigchange/contacts) | Contacts, groups, site access hours, on-stop | | [Jobs](/api-reference/bigchange/jobs) | Jobs, constraints, stock, groups, types | | [Invoices](/api-reference/bigchange/invoices) | Invoices and line items | | [Quotes](/api-reference/bigchange/quotes) | Quotes and line items | | [Sales opportunities](/api-reference/bigchange/sales-opportunities) | Opportunities, stages, probabilities, line items | | [Purchase orders](/api-reference/bigchange/purchase-orders) | Purchase orders, series, line items | | [Notes](/api-reference/bigchange/notes) | Notes and note types | | [Persons](/api-reference/bigchange/persons) | Site contacts and consent | | [Resources](/api-reference/bigchange/resources) | Engineers/technicians and resource groups | | [Vehicles](/api-reference/bigchange/vehicles) | Fleet vehicles | | [Stock](/api-reference/bigchange/stock) | Stock details, items, movements, suppliers, categories | | [Worksheets](/api-reference/bigchange/worksheets) | Worksheet definitions, questions, answers | | [Reference data](/api-reference/bigchange/reference-data) | Department and nominal codes | # Persons Source: https://docs.vh3.ai/api-reference/bigchange/persons Site contacts and consent # Persons Site contacts and consent. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Persons People on accounts. ### `GET` `/persons/person` Get person. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/persons/person" \ -H "X-API-Key: your-api-key" \ --data-urlencode "personId=550e8400-e29b-41d4-a716-446655440000" ``` ### `POST` `/persons/create` Create person. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/persons/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "firstName": "Jane", "surname": "Smith", "email": "jane@example.com" }' ``` ### `POST` `/persons/edit` Update person. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/persons/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "personId": "550e8400-e29b-41d4-a716-446655440000" }' ``` ### `POST` `/persons/list` List persons. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/persons/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "pageNumber": 1, "pageSize": 25 }' ``` ### `POST` `/persons/consent/set` Set consent. **Enum values:** * **status:** `awaiting`, `refused`, `granted` * **medium:** `email`, `click`, `telephone` ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/persons/consent/set" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "personId": "550e8400-e29b-41d4-a716-446655440000", "status": "granted", "medium": "email" }' ``` ### `POST` `/persons/consent/history` Consent history. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/persons/consent/history" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "personId": "550e8400-e29b-41d4-a716-446655440000", "pageNumber": 1, "pageSize": 20 }' ``` # Purchase Orders Source: https://docs.vh3.ai/api-reference/bigchange/purchase-orders POs, series, and lines # Purchase Orders POs, series, and lines. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Date filters (list) `POST /purchase_orders/list` requires **at least one filter** (`id`, `jobId`, `jobGroupId`, `contactId`, `reference`, or a date pair). Optional `createdAtFrom` / `createdAtTo` on PO creation time, **max 12 months** between them. See [overview](/api-reference/bigchange/overview#date-ranges). ## Purchase orders Procurement. ### `GET` `/purchase_orders/purchase_order` Get PO. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/purchase_order" \ -H "X-API-Key: your-api-key" \ --data-urlencode "id=4001" ``` ### `POST` `/purchase_orders/create` Create PO. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "supplierId": 999, "contactId": 12345 }' ``` ### `POST` `/purchase_orders/edit` Update PO. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "id": 4001 }' ``` ### `POST` `/purchase_orders/list` List purchase orders. **At least one filter is required.** Date range optional; max **12 months** on `createdAtFrom` → `createdAtTo`. | Field | Type | Required | Description | | --------------- | ------- | --------- | ----------------------------------- | | `jobId` | integer | One of… | Filter by job | | `contactId` | integer | …required | Filter by contact | | `id` | integer | filters | Filter by PO id | | `reference` | string | | Filter by reference | | `createdAtFrom` | string | | Created on or after (ISO 8601 UTC) | | `createdAtTo` | string | | Created on or before (ISO 8601 UTC) | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jobId": 12345, "createdAtFrom": "2026-01-01T00:00:00Z", "createdAtTo": "2026-03-31T23:59:59Z", "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/purchase_orders/series/list` List series. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/series/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ### `GET` `/purchase_orders/series` Get series. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/series" \ -H "X-API-Key: your-api-key" \ --data-urlencode "id=10" ``` ## Line items PO lines. ### `GET` `/purchase_orders/line_item` Get line. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/line_item" \ -H "X-API-Key: your-api-key" \ --data-urlencode "purchaseOrderId=4001" \ --data-urlencode "id=1" ``` ### `POST` `/purchase_orders/line_item/list` List lines. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/line_item/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": 4001, "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/purchase_orders/line_item/create` Create line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/line_item/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": 4001 }' ``` ### `POST` `/purchase_orders/line_item/edit` Update line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/line_item/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": 4001, "id": 1 }' ``` ### `POST` `/purchase_orders/line_item/delete` Delete line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/purchase_orders/line_item/delete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": 4001, "id": 1 }' ``` # Quotes Source: https://docs.vh3.ai/api-reference/bigchange/quotes BigChange quotes and line items # Quotes BigChange quotes and line items. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Date filters (list) `POST /quotes/list` supports the same creation-date window as invoices: `createdAtFrom` and `createdAtTo` (ISO 8601 UTC). **The range must not exceed 12 months.** See [overview](/api-reference/bigchange/overview#date-ranges). | Param | Type | Required | Description | | --------------- | ------ | -------- | ---------------------------------------- | | `createdAtFrom` | string | No | Quotes created on or after this instant | | `createdAtTo` | string | No | Quotes created on or before this instant | Optional filters: `id`, `jobId`, `jobGroupId`, `contactId`, `reference` (comma-separated, max 50 each). ## Quotes Quotations. ### `GET` `/quotes/quote` Get quote. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/quotes/quote" \ -H "X-API-Key: your-api-key" \ --data-urlencode "quoteId=3001" ``` ### `POST` `/quotes/create` Create quote. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345 }' ``` ### `POST` `/quotes/edit` Update quote. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001 }' ``` ### `POST` `/quotes/list` List quotes with optional filters and creation-date range (max **12 months** between `createdAtFrom` and `createdAtTo`). **Request body (filters):** | Field | Type | Required | Description | | --------------- | ------- | -------- | --------------------------------------- | | `pageNumber` | integer | No | Page index (1-based) | | `pageSize` | integer | No | Items per page | | `createdAtFrom` | string | No | Created on or after (ISO 8601 UTC) | | `createdAtTo` | string | No | Created on or before (ISO 8601 UTC) | | `contactId` | string | No | Contact IDs (comma-separated, max 50) | | `jobId` | string | No | Job IDs (comma-separated, max 50) | | `jobGroupId` | string | No | Job group IDs (comma-separated, max 50) | | `id` | string | No | Quote IDs (comma-separated, max 50) | | `reference` | string | No | References (comma-separated, max 50) | | `sortBy` | string | No | Typically `createdAt` | | `direction` | enum | No | `ascending` or `descending` | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50, "createdAtFrom": "2026-01-01T00:00:00Z", "createdAtTo": "2026-06-30T23:59:59Z", "contactId": "12345", "sortBy": "createdAt", "direction": "descending" }' ``` ### `POST` `/quotes/mark_sent` Mark sent. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/mark_sent" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001 }' ``` ### `POST` `/quotes/mark_accepted` Mark accepted. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/mark_accepted" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001 }' ``` ### `POST` `/quotes/mark_rejected` Mark rejected. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/mark_rejected" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001 }' ``` ## Quote line items Quote lines. ### `GET` `/quotes/line_item` Get line. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/quotes/line_item" \ -H "X-API-Key: your-api-key" \ --data-urlencode "quoteId=3001" \ --data-urlencode "lineItemId=1" ``` ### `POST` `/quotes/line_item/create` Create line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/line_item/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001, "description": "Boiler service", "quantity": 1 }' ``` ### `POST` `/quotes/line_item/edit` Update line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/line_item/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001, "lineItemId": 1 }' ``` ### `POST` `/quotes/line_item/delete` Delete line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/line_item/delete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001, "lineItemId": 1 }' ``` ### `POST` `/quotes/line_item/list` List lines. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/quotes/line_item/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "quoteId": 3001, "pageNumber": 1, "pageSize": 50 }' ``` # Reference Data Source: https://docs.vh3.ai/api-reference/bigchange/reference-data Department and nominal codes # Reference Data Department and nominal codes. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Department codes Departments. ### `POST` `/reference_data/department_codes_list` List codes. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/reference_data/department_codes_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 100 }' ``` ### `GET` `/reference_data/retrieves_details` Get code. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/reference_data/retrieves_details" \ -H "X-API-Key: your-api-key" \ --data-urlencode "departmentCodeId=1" ``` ## Nominal codes Nominal accounts. ### `POST` `/reference_data/normalt_codes_list` List codes. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/reference_data/normalt_codes_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 100 }' ``` ### `GET` `/reference_data/nominal_code_id` Get code. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/reference_data/nominal_code_id" \ -H "X-API-Key: your-api-key" \ --data-urlencode "nominalCodeId=1" ``` # Resources Source: https://docs.vh3.ai/api-reference/bigchange/resources Engineers and resource groups # Resources Engineers and resource groups. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Resources Engineers/technicians. ### `GET` `/resources/resource_get` Get resource. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/resources/resource_get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "resourceId=100" ``` ### `POST` `/resources/resource_create` Create resource. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/resources/resource_create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "name": "Alex Engineer", "groupId": 5 }' ``` ### `POST` `/resources/update` Update resource. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/resources/update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "resourceId": 100, "name": "Alex Engineer" }' ``` ### `POST` `/resources/resources_list` List resources. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/resources/resources_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ## Resource groups Teams. ### `GET` `/resource_groups/resource_group/get` Get group. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/resource_groups/resource_group/get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "resourceGroupId=5" ``` ### `POST` `/resource_groups/list` List groups. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/resource_groups/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` # Sales Opportunities Source: https://docs.vh3.ai/api-reference/bigchange/sales-opportunities Pipeline and line items # Sales Opportunities Pipeline and line items. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Date filters (list) `POST /sales_opportunities/list` requires **at least one filter**. Two independent windows are available; each pair is limited to **12 months**: | Param | Filters on | | ------------------------------- | ------------------------- | | `createdAtFrom` / `createdAtTo` | Opportunity creation time | | `dueDateFrom` / `dueDateTo` | Opportunity due date | See [overview](/api-reference/bigchange/overview#date-ranges). ## Sales opportunities CRM pipeline. ### `GET` `/sales_opportunities/sales_opportunity` Get opportunity. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/sales_opportunity" \ -H "X-API-Key: your-api-key" \ --data-urlencode "id=2001" ``` ### `POST` `/sales_opportunities/list` List opportunities. **At least one of:** `id`, `status`, `contactId`, `ownerId`, `reference`, `createdAtFrom`/`createdAtTo`, or `dueDateFrom`/`dueDateTo`. | Field | Type | Description | | --------------- | ------- | ------------------------------------------------------------------------ | | `contactId` | integer | Customer contact | | `createdAtFrom` | string | Created on or after (ISO 8601 UTC, max 12-month span with `createdAtTo`) | | `createdAtTo` | string | Created on or before | | `dueDateFrom` | string | Due on or after (max 12-month span with `dueDateTo`) | | `dueDateTo` | string | Due on or before | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "contactId": 12345, "createdAtFrom": "2026-01-01T00:00:00Z", "createdAtTo": "2026-06-30T23:59:59Z", "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/sales_opportunities/edit` Update. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "id": 2001 }' ``` ### `POST` `/sales_opportunities/probabilities/list` List probabilities. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/probabilities/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/sales_opportunities/stages/list` List stages. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/stages/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ## Line items Opportunity lines. ### `GET` `/sales_opportunities/line_item` Get line. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/line_item" \ -H "X-API-Key: your-api-key" \ --data-urlencode "salesOpportunityId=2001" \ --data-urlencode "id=1" ``` ### `POST` `/sales_opportunities/line_item/list` List lines. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/line_item/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "salesOpportunityId": 2001, "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/sales_opportunities/line_item/create` Create line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/line_item/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "salesOpportunityId": 2001 }' ``` ### `POST` `/sales_opportunities/line_item/edit` Update line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/line_item/edit" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "salesOpportunityId": 2001, "id": 1 }' ``` ### `POST` `/sales_opportunities/line_item/delete` Delete line. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/sales_opportunities/line_item/delete" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "salesOpportunityId": 2001, "id": 1 }' ``` # Stock Source: https://docs.vh3.ai/api-reference/bigchange/stock Inventory, movements, suppliers # Stock Inventory, movements, suppliers. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | Note: path `/stock/stock/item_get` is correct, the segment `stock` appears twice in the BigChange route, not a documentation typo. ## Stock details Product catalogue. ### `GET` `/stock/stock_details` Get details. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/stock/stock_details" \ -H "X-API-Key: your-api-key" \ --data-urlencode "stockDetailsId=10" ``` ### `POST` `/stock/stock_details_create` Create details. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_details_create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "Thermostat T100" }' ``` ### `POST` `/stock/stock_details_update` Update details. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_details_update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "stockDetailsId": 10 }' ``` ### `POST` `/stock/stock_details_list` List details. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_details_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ## Stock items Physical stock. ### `GET` `/stock/stock/item_get` Get item. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/stock/stock/item_get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "stockItemId=20" ``` ### `POST` `/stock/stock_item_create` Create item. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_item_create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "stockDetailsId": 10, "quantity": 5 }' ``` ### `POST` `/stock/stock_item_update` Update item. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_item_update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "stockItemId": 20 }' ``` ### `POST` `/stock/stock_item_list` List items. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_item_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ## Movements Stock movements. ### `POST` `/stock/stock_movements_list` List movements. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_movements_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ## Product categories Categories. ### `GET` `/stock/product_categories/get` Get category. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/stock/product_categories/get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "productCategoryId=3" ``` ### `POST` `/stock/product_categories_list` List categories. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/product_categories_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ## Suppliers Stock suppliers. ### `GET` `/stock/stock_supplier_get` Get supplier. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/stock/stock_supplier_get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "id=1" ``` ### `POST` `/stock/stock_supplier_create` Add supplier. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_supplier_create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "stockDetailsId": 10, "contactId": 999 }' ``` ### `POST` `/stock/stock_supplier_update` Update supplier. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_supplier_update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "id": 1 }' ``` ### `POST` `/stock/stock_supplier_list` List suppliers. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/stock/stock_supplier_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "stockDetailsId": 10, "pageNumber": 1, "pageSize": 20 }' ``` # Vehicles Source: https://docs.vh3.ai/api-reference/bigchange/vehicles Fleet vehicles # Vehicles Fleet vehicles. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Vehicles Fleet. ### `GET` `/vehicles/vehicle_get` Get vehicle. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/vehicles/vehicle_get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "vehicleId=50" ``` ### `POST` `/vehicles/create` Create vehicle. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/vehicles/create" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "registration": "AB12 CDE" }' ``` ### `POST` `/vehicles/update` Update vehicle. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/vehicles/update" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "vehicleId": 50 }' ``` ### `POST` `/vehicles/list` List vehicles. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/vehicles/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` # Worksheets Source: https://docs.vh3.ai/api-reference/bigchange/worksheets Forms and answers # Worksheets Forms and answers. Auth: `X-API-Key` header. Base: `https://api.vh3connect.io/api:YdihQNr3`. ## Shared parameters | Param | Type | Description | | ------------ | ------- | -------------------------------------- | | `pageNumber` | integer | Page index (1-based) | | `pageSize` | integer | Items per page (default 100, max 1000) | | `sortBy` | string | Sort field (endpoint-specific) | | `direction` | enum | `ascending` or `descending` | ## Worksheets Digital forms. ### `GET` `/worksheet/worksheet_get` Get worksheet. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/worksheet/worksheet_get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "worksheetId=1" ``` ### `POST` `/worksheet/worksheet_list` List worksheets. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/worksheet/worksheet_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` ### `POST` `/worksheet/worksheet_questions_get` Get questions. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/worksheet/worksheet_questions_get" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "worksheetId": 1, "pageNumber": 1, "pageSize": 100 }' ``` ### `POST` `/worksheet/worksheet_answers_list` List answers. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/worksheet/worksheet_answers_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "worksheetId": 1, "pageNumber": 1, "pageSize": 50 }' ``` ## Worksheet groups Form groups. ### `GET` `/worksheet_groups/worksheet_group_get` Get group. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/worksheet_groups/worksheet_group_get" \ -H "X-API-Key: your-api-key" \ --data-urlencode "worksheetGroupId=1" ``` ### `POST` `/worksheet_groups/worksheet_group_list` List groups. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/worksheet_groups/worksheet_group_list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 50 }' ``` # Briefings Source: https://docs.vh3.ai/api-reference/briefings Pre-visit engineer briefings with full operational context # Briefings Generate a structured pre-visit briefing and call script for an engineer assigned to a job. Pulls job and customer context from the intelligence layer (regenerates the account summary when requested) and produces markdown briefing content plus a natural-language call opener. Designed for `onTheWay` or `scheduled` job transitions. ## POST /briefing/generate Generate an engineer briefing for a specific job. **Request body:** | Field | Type | Required | Description | | -------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `job_id` | integer | Yes | Job to brief | | `contact_id` | integer | Yes | Customer contact for the job | | `force_regenerate_summary` | boolean | No | Bypass the cached customer summary and regenerate | | `job_payload` | object | No | Raw job fallback when the job is not yet in the intelligence layer (ignored if the job already exists in the graph) | **Response fields:** | Field | Type | Description | | ------------------ | ------ | ---------------------------------------------------------------------------- | | `briefing` | string | Structured field service briefing (markdown) | | `call_script` | string | Natural-language call opener for voice agents | | `customer_summary` | string | Full customer analytical report used as context | | `job_data` | object | Job reference, status, type, customer, engineer, planned times, site address | | `resource_contact` | object | Engineer `mobile` and `email` from the graph | | `parent_contact` | object | Parent customer `contact_id` and `name` when `HAS_PARENT` exists | | `engineer_name` | string | Assigned engineer name | | `generated_at` | string | ISO 8601 generation timestamp | | `usage` | object | Token usage for AI generation | **Example:** ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/briefing/generate" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "job_id": 12345, "contact_id": 678 }' ``` **Use cases:** * **Pre-visit pack:** Deliver site history, equipment context, and diagnostic precedents before arrival. * **Voice briefing:** Feed `call_script` to an outbound call agent; send `briefing` via `POST /briefing/send-email` after the call. * **Dispatcher assist:** Regenerate with `force_regenerate_summary: true` when account context has changed since the last visit. **Notes:** * Uses platform AI; subject to capacity limits (`503` with `Retry-After` when saturated). * Returns `404` when the job or contact cannot be resolved. * Typical latency 5–15s depending on summary cache hit. # Cases Source: https://docs.vh3.ai/api-reference/cases Case management for multi-step operational workflows # Cases The Cases endpoints provide a lightweight case management system for tracking multi-step operational workflows, escalations, customer complaints, follow-up work, and anything that spans multiple jobs or interactions. ## POST /cases/create Create a new case. **Request body:** | Field | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `title` | string | Yes | Case title | | `type` | string | Yes | Case type (e.g. `escalation`, `complaint`, `follow_up`) | | `description` | string | No | Detailed description | | `priority` | string | No | Priority level (`low`, `medium`, `high`, `critical`) | | `actor_type` | string | No | Who created the case (`user`, `system`, `automation`) | | `actor_id` | integer | No | ID of the creating actor | | `tags` | object | No | Tags for categorisation | | `metadata` | object | No | Arbitrary metadata | | `due_date` | number | No | Due date (unix timestamp) | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/cases/create" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "title": "Repeat boiler failure at Tesco Manchester", "type": "escalation", "priority": "high", "description": "Third callout in 6 weeks for the same unit. Needs senior engineer assessment." }' ``` *** ## GET /cases/list List cases with optional filtering. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------- | -------- | ---------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `status` | string | No | Filter by status | | `type` | string | No | Filter by case type | | `priority` | string | No | Filter by priority | | `owner_id` | integer | No | Filter by case owner | | `search` | string | No | Full-text search across case titles and descriptions | | `page` | integer | No | Page number | | `per_page` | integer | No | Results per page | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/cases/list" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "status=open" \ --data-urlencode "priority=high" ``` *** ## GET /cases/search Full-text search across all cases. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/cases/search" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "q=boiler Manchester" ``` *** ## GET /cases/ Retrieve a specific case with full details. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## PATCH /cases/ Update a case (title, description, priority, status, etc.). ```bash theme={null} curl -X PATCH "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "priority": "critical" }' ``` *** ## POST /cases//transition Transition a case to a new status. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001/transition" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "status": "resolved" }' ``` *** ## POST /cases//comments Add a comment to a case. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001/comments" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "body": "Senior engineer booked for Friday. Parts on order." }' ``` *** ## GET /cases//activity Retrieve the full activity timeline for a case, all updates, comments, transitions, and linked items. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001/activity" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## POST /cases//participants Add a participant to a case. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001/participants" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "user_id": "user-42" }' ``` *** ## POST /cases//items Link an item (job, contact, site) to a case. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/cases/case-001/items" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "item_type": "job", "item_id": "12345" }' ``` # Connie Source: https://docs.vh3.ai/api-reference/connie Conversational AI assistant with full operational context # Connie Connie is VH3 AI's conversational assistant. She has access to the full operational context (intelligence layer, semantic search, reports, and sentinel results) and responds to questions in natural language with cited, data-backed answers. Capabilities, sessions, and how Connie uses the intelligence layer. `toolCallOutputs`, usage, and verifying provenance in production UIs. ## POST /connie/chat Send a message to Connie and receive a response grounded in your operational data. **Request body:** | Field | Type | Required | Description | | ----------------------- | ------ | -------- | ---------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `message` | string | Yes | Your question or instruction | | `session_id` | string | No | Session identifier for conversation continuity | | `user_id` | string | No | Identifier for the user asking | | `user_name` | string | No | Display name (personalises responses) | | `user_company_name` | string | No | Company name for context | | `summary` | string | No | Prior conversation summary (for long sessions) | | `contact_id` | string | No | Scope to a specific customer context | | `current_job_reference` | string | No | Job currently being discussed | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/connie/chat" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "message": "Which sites had the most repeat visits in the last 30 days?", "session_id": "session-abc-123", "user_name": "Sarah" }' ``` **Example questions Connie can answer:** * "Which engineers are consistently late on HVAC jobs?" * "What is the repeat failure rate at Tesco sites?" * "Has anyone seen this fault before?" (with a description) * "Show me the top 5 customers by job volume this quarter" * "What happened at the Manchester site last week?" * "Give me a performance summary for engineer John Smith" Connie maintains conversation context within a session. Follow-up questions like "What about last month?" reference the previous exchange automatically. Each response can include `toolCallOutputs` (structured results per tool) and `usage` (token counts). See [Agent observability](/guides/agent-observability). *** ## POST /connie/chat/voice Send a voice interaction to Connie, designed for voice-first interfaces where the input is a transcribed audio message. Optimised for concise, text-to-speech-friendly responses. **Request body:** Same fields as `/connie/chat`. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/connie/chat/voice" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "message": "How many jobs did we complete yesterday?", "session_id": "voice-session-001" }' ``` *** ## POST /connie/generate-summary Generate an AI summary for a contact, useful for pre-call preparation or account review. **Request body:** | Field | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `contact_id` | string | Yes | Contact to summarise | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/connie/generate-summary" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "contact_id": "contact-789" }' ``` *** ## POST /connie/history/search Search across past conversation history. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/connie/history/search" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "SLA breach discussion" }' ``` *** ## GET /connie/sessions List chat sessions for a company. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/connie/sessions" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## GET /connie/sessions//messages Retrieve all messages for a specific session. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/connie/sessions/session-abc-123/messages" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` # Contacts Source: https://docs.vh3.ai/api-reference/contacts Contact feed and detail lookup # Contacts The Contacts endpoints provide access to the people associated with your operation, engineers, customers, site contacts, and other stakeholders enriched from your FMS and connected systems. ## GET /contacts/feed Returns a paginated feed of contacts for your company. **Query parameters:** | Param | Type | Required | Description | | ------------------ | ------- | -------- | ------------------------------ | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `page_size` | integer | No | Results per page | | `page_number` | integer | No | Page number | | `q` | string | No | Search query (name, reference) | | `contact_id` | string | No | Filter by specific contact | | `reference` | string | No | Filter by contact reference | | `contact_group_id` | string | No | Filter by contact group | | `account_status` | string | No | Filter by account status | | `compact` | boolean | No | Return compact response | **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/contacts/feed" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "page_size=20" \ --data-urlencode "q=tesco" ``` *** ## GET /contacts/ Returns the full contact record including associated jobs, sites, and AI-generated summary. **Path parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `contact_id` | string | Yes | The contact identifier | **Query parameters:** | Param | Type | Required | Description | | ----------------- | ------- | -------- | ------------------------------------ | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `include_summary` | boolean | No | Include AI-generated contact summary | | `compact` | boolean | No | Return compact response | **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/contacts/456" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "include_summary=true" ``` # Dashboard Source: https://docs.vh3.ai/api-reference/dashboard Cached tenant business-health snapshot for KPI tiles # Dashboard Returns a cached, dashboard-ready snapshot of tenant operational health. Five sections (pipeline, performance, workforce, assets, and knowledge) map to dashboard KPI payloads. Near-zero AI cost at read time; aggregated from the intelligence layer. ## GET /dashboard Tenant pulse snapshot. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------- | -------- | --------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `refresh` | boolean | No | Bypass cache and force a fresh snapshot (default `false`) | **Response fields:** | Field | Type | Description | | ---------------------- | ------ | ------------------------------------------------------------------------------------- | | `company_id` | string | Tenant identifier | | `generated_at` | string | ISO 8601 snapshot time | | `cached_until` | string | ISO 8601 cache expiry (5-minute TTL) | | `sections.pipeline` | object | Job lifecycle: totals, active, unassigned, in progress, completions, status breakdown | | `sections.performance` | object | Last 30 days: completion rate, first-visit-fix rate, avg start/end delta (minutes) | | `sections.workforce` | object | Engineer counts, active today, avg jobs per engineer, top engineer | | `sections.assets` | object | Customers, sites, vehicles, job types, job categories | | `sections.knowledge` | object | Knowledge depth: intake records, outcomes, customer summaries, chat sessions | **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/dashboard" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` Force refresh: ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/dashboard" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "refresh=true" ``` **Use cases:** * **Home screen:** Single call to populate KPI tiles on first load. * **Mobile summary:** Lightweight operational overview without running separate aggregate calls. * **Health monitoring:** Internal or partner views of data coverage and knowledge-base completeness. * **Scheduled snapshots:** n8n cron to archive pulse metrics for trend reporting. **Notes:** * Cached 5 minutes per tenant; uncached typically 200–800ms, cached under 10ms. * Deterministic: the same underlying data yields the same metrics. * Returns `502` if search or graph queries fail. # Email Ingest Source: https://docs.vh3.ai/api-reference/ingest Extract structured job data from FM portal emails # Email Ingest Extract structured job fields from emails sent by known FM portals (Verisae, Bellrock, Access Maintain, Greene King, and tenant-specific overrides). Resolves customers, sites, and job types against the knowledge graph, evaluates confidence, and returns a review or auto-create outcome. Use this endpoint when the sender domain is already identified as a portal. For unknown senders, use the general triage ingest path or classify first with `POST /triage/classify`. ## POST /ingest/email/portal Portal ingest, structured extraction from a known FM portal email. **Request body:** | Field | Type | Required | Description | | -------------------- | ------ | -------- | ------------------------------------------------------------------ | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant BigChange API key (verified against `company_id`) | | `email_html` | string | Yes | HTML body of the email | | `email_text` | string | No | Plain-text fallback when HTML is sparse | | `email_subject` | string | No | Subject line | | `email_from` | string | No | Sender address (used for portal detection) | | `email_date` | string | No | Send time (ISO 8601) | | `attachments` | array | No | Each item: `filename`, `content_base64`, `url`, `mime_type` | | `preferred_type_ids` | array | No | Job type IDs to boost during classification (+0.05 when plausible) | **Response fields:** | Field | Type | Description | | ----------------------- | ------- | ------------------------------------------------------------------------------------ | | `status` | string | `auto_created`, `pending_review`, or `unprocessable` | | `extraction` | object | Parsed work order fields and confidence | | `resolution` | object | Matched `customers`, `sites`, `types`, `categories`, `parent_candidates` with scores | | `reasoning` | string | Human-readable resolution summary | | `job_created` | boolean | Whether a job was written to BigChange | | `job_id` | integer | Created job ID when `job_created` is true | | `extraction_id` | string | Pending-extraction UUID for review-queue flows | | `review_flags` | array | Flags requiring human attention | | `job_preview` | object | Dry-run BigChange payload when write-back is not yet live | | `case_id` | string | Case management ID when a review case was created | | `engineer_hints` | array | Ranked engineer suggestions from contact/type history | | `job_options` | array | Selectable job drafts when status is `pending_review` | | `recommended_option_id` | string | Suggested option from `job_options` | | `surface` | string | Always `portal` for this endpoint | **Example:** ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/ingest/email/portal" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "email_html": "
Work Order116222840
", "email_subject": "PureGym 449 Newhaven, Work Order 116222840", "email_from": "noreply@verisae.com", "email_date": "2026-04-18T10:00:00Z" }' ``` **Use cases:** * **FM portal automation:** Ingest Verisae, Bellrock, or other portal work orders without manual re-keying. * **n8n inbound mail:** Trigger after `POST /triage/classify` returns `portal_ingest`, or when the sender domain is pre-filtered upstream. * **Review queue:** When `status` is `pending_review`, use `extraction_id` with `POST /ingest/email/confirm` or `POST /ingest/email/reject`. * **Quality evaluation:** Inspect `job_preview` and `resolution` scores before enabling auto-create to BigChange. **Notes:** * Uses platform AI for extraction; typical latency 3–10s. * `api_key` is verified against your tenant credentials before any BigChange-facing step; mismatch returns `403`. * Tenant settings (`portal_ingest_enabled`, `disabled_portals`, thresholds) gate behaviour without code changes. # Jobs Source: https://docs.vh3.ai/api-reference/jobs Job feed, account job feed, and job details # Jobs The Jobs endpoints provide access to your enriched job records, including AI-extracted fault types, outcomes, timings, and relationships to engineers, sites, and customers. ## GET /jobs/feed Returns a paginated feed of enriched jobs for your company. Supports filtering by entity, status, date range, and sort direction. All filters are optional and composable as AND conditions. **Query parameters:** | Param | Type | Required | Default | Description | | ------------- | ------- | -------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | | `company_id` | string | Yes | - | Your tenant identifier | | `api_key` | string | Yes | - | Your tenant API key | | `page_size` | integer | No | 20 | Results per page (max 200) | | `page_number` | integer | No | 1 | Page number (1-indexed) | | `contact_id` | string | No | - | Filter by customer contact ID | | `resource_id` | string | No | - | Filter by engineer/resource ID | | `type_id` | string | No | - | Filter by job type ID | | `category_id` | string | No | - | Filter by job category ID | | `status` | string | No | - | Filter by status, single value or comma-separated (e.g. `completedOk,completedWithIssues`) | | `result` | string | No | - | Filter by job result | | `date_from` | string | No | - | ISO date/datetime, include jobs on or after (inclusive) | | `date_to` | string | No | - | ISO date/datetime, exclude jobs on or after (exclusive) | | `date_field` | string | No | `createdAt` | Which timestamp `date_from`/`date_to` apply to: `createdAt`, `plannedStartAt`, `plannedEndAt`, `actualStartAt`, `actualEndAt` | | `direction` | string | No | `desc` | Sort direction on `createdAt`, `asc` or `desc` | | `compact` | boolean | No | false | Strip nulls/empties to return a compact payload for AI agents | **Example: completed jobs from May 2026** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/jobs/feed" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "page_size=20" \ --data-urlencode "status=completedOk,completedWithIssues" \ --data-urlencode "date_from=2026-05-01" \ --data-urlencode "date_to=2026-06-01" \ --data-urlencode "date_field=actualEndAt" ``` *** ## GET /jobs/feed/account Returns a paginated feed of jobs scoped to a **parent account and all its child contacts**. Pass any contact ID, parent or child, and the endpoint resolves the full hierarchy automatically. This endpoint resolves the parent/child account hierarchy. If you pass a child contact ID, the parent is found and all sibling contacts are included. If you pass a parent, all children are included. Standalone contacts return only their own jobs. **How hierarchy resolution works:** | You pass | What happens | | ----------------------- | -------------------------------------------------------- | | A parent contact ID | Returns jobs for the parent + all child contacts | | A child contact ID | Finds the parent, returns jobs for parent + all siblings | | A standalone contact ID | Returns jobs for that contact only | **Query parameters:** | Param | Type | Required | Default | Description | | ------------- | ------- | -------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | | `company_id` | string | Yes | - | Your tenant identifier | | `api_key` | string | Yes | - | Your tenant API key | | `contact_id` | string | Yes | - | Any contact ID in the account hierarchy (parent or child) | | `page_size` | integer | No | 20 | Results per page (max 200) | | `page_number` | integer | No | 1 | Page number (1-indexed) | | `resource_id` | string | No | - | Filter by engineer/resource ID | | `type_id` | string | No | - | Filter by job type ID | | `category_id` | string | No | - | Filter by job category ID | | `status` | string | No | - | Filter by status, single value or comma-separated (e.g. `completedOk,completedWithIssues`) | | `result` | string | No | - | Filter by job result | | `date_from` | string | No | - | ISO date/datetime, include jobs on or after (inclusive) | | `date_to` | string | No | - | ISO date/datetime, exclude jobs on or after (exclusive) | | `date_field` | string | No | `createdAt` | Which timestamp `date_from`/`date_to` apply to: `createdAt`, `plannedStartAt`, `plannedEndAt`, `actualStartAt`, `actualEndAt` | | `direction` | string | No | `desc` | Sort direction on `createdAt`, `asc` or `desc` | | `compact` | boolean | No | false | Strip nulls/empties to return a compact payload for AI agents | **Response** includes an `account` block with the resolved hierarchy context: ```json theme={null} { "account": { "parentContactId": 1234, "parentName": "Whitbread PLC", "parentReference": "W140", "childCount": 462, "contactIds": [1234, 5678, 5679, "..."], "contactGroup": "Parent - Agreed rates" }, "jobs": ["..."], "page": 1, "pageSize": 25, "totalJobs": 312, "totalPages": 13 } ``` **Example: all completed jobs for an account in Q1 2026** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/jobs/feed/account" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "contact_id=5589521" \ --data-urlencode "status=completedOk,completedWithIssues" \ --data-urlencode "date_from=2026-01-01" \ --data-urlencode "date_to=2026-04-01" \ --data-urlencode "page_size=50" ``` **Use cases:** * **Monthly account reviews**, scope by `date_from`/`date_to` with `date_field=actualEndAt` to see all work delivered to a customer account in a period. * **Account + type filtering**, add `type_id` to see only fire alarm or HVAC jobs across the whole account hierarchy. * **Account performance**, combine with `status=completedOk,completedWithIssues` to measure first-visit fix rate across all child sites. *** ## GET /jobs/ Returns the full enriched record for a specific job, including AI-extracted fields, linked relationships from the intelligence layer, and timing data. **Path parameters:** | Param | Type | Required | Description | | -------- | ------ | -------- | ------------------ | | `job_id` | string | Yes | The job identifier | **Query parameters:** | Param | Type | Required | Description | | -------------------- | ------- | -------- | ----------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `include_worksheets` | boolean | No | Include worksheet data | | `compact` | boolean | No | Return compact response | **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/jobs/12345" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "include_worksheets=true" ``` *** ## POST /aggregate/jobs Job metrics with groupBy dimensions and period comparison, powers dashboard charts and trend analysis. **Request body:** | Field | Type | Required | Description | | ------------ | ------- | -------- | --------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `metric` | string | Yes | Metric to compute (e.g. `count`, `sla_punctuality`, `first_time_fix`) | | `time_axis` | string | No | Time bucketing (`day`, `week`, `month`) | | `period` | string | No | Period to analyse (e.g. `last_30_days`, `last_quarter`) | | `compare_to` | string | No | Comparison period (e.g. `previous_period`) | | `group_by` | string | No | Dimension to group by (`engineer`, `customer`, `job_type`, `site`) | | `filters` | object | No | Additional filters | | `limit` | integer | No | Max groups to return | **Example:** ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/aggregate/jobs" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "metric": "count", "time_axis": "week", "period": "last_30_days", "group_by": "engineer" }' ``` # VH3 AI Intelligence Source: https://docs.vh3.ai/api-reference/overview Semantic search, relationship-aware intelligence, Connie, sentinels, reports, and email triage # VH3 AI Intelligence The intelligence layer exposes enriched operational data, semantic search, proactive sentinels, reports, Connie, and email triage. Every endpoint requires `company_id` and `api_key`. For direct BigChange read/write (jobs, contacts, invoices, stock), use the separate [BigChange API](/api-reference/bigchange/overview), same API key, `X-API-Key` header only. ## Base URL ``` https://api.vh3connect.io/api:kP8T1CK7 ``` ## Authentication Pass `company_id` and `api_key` on every request. POST: JSON body. GET: query parameters. See [Authentication](/authentication) for the full two-API comparison and User Auth (JWT). ## Endpoint groups | Group | Description | | ------------------------------------- | -------------------------------------------------------------------------------- | | [Search](/api-reference/search) | Semantic search, autocomplete, enriched outcomes, customer summary sections | | [Jobs](/api-reference/jobs) | Job feed, job details, and aggregation | | [Contacts](/api-reference/contacts) | Contact feed and contact detail lookup | | [Dashboard](/api-reference/dashboard) | Cached tenant KPI snapshot (pipeline, performance, workforce, assets, knowledge) | | [Sentinels](/api-reference/sentinels) | Run and query proactive sentinel monitors | | [Reports](/api-reference/reports) | Generate daily, weekly, and account-level reports | | [Briefings](/api-reference/briefings) | Pre-visit engineer briefings and call scripts | | [Weather](/api-reference/weather) | Forecast, historical, and graph-resolved weather | | [Email Triage](/api-reference/triage) | Classify inbound emails | | [Email Ingest](/api-reference/ingest) | Extract structured data from FM portal emails | | [Connie](/api-reference/connie) | Conversational AI with cited answers | | [Cases](/api-reference/cases) | Case management | | [Teams](/api-reference/teams) | Team management and access scoping | ## Request format ### POST endpoints ```json theme={null} { "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "boiler fault", "limit": 10 } ``` ### GET endpoints ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/jobs/feed" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` ## Error format ```json theme={null} { "code": "ERROR_CODE_INPUT_ERROR", "message": "Missing param: company_id", "payload": { "param": "company_id" } } ``` | Status code | Meaning | | ----------- | ----------------------------------------------------- | | `400` | Bad request, missing or invalid parameters | | `401` | Unauthorised, invalid API key | | `404` | Not found, resource does not exist for your tenant | | `409` | Conflict, a task is already running for this resource | | `422` | Validation error | | `429` | Rate limited | | `500` | Server error | ## Task-based endpoints Long-running operations return a `task_id` immediately. Poll the status endpoint until complete. Possible statuses: `pending`, `running`, `completed`, `failed`, `cancelled`. # Reports Source: https://docs.vh3.ai/api-reference/reports Automated operational reporting # Reports The Reports endpoints let you generate automated operational reports. Eight report types are available, covering daily operations, weekly summaries, and account-level performance analysis. ## Report types | Type | Description | | ----------------------- | ------------------------------------------------------------ | | `daily_operations` | Daily job completions, SLA performance, and notable events | | `weekly_summary` | Weekly trends, engineer rankings, and operational highlights | | `account_monthly` | Per-customer monthly performance report | | `executive_health` | Five-dimension health check across up to 3 years of history | | `engineer_performance` | Individual engineer performance breakdown | | `site_health` | Site-level fault and maintenance trends | | `customer_intelligence` | Customer relationship and risk summary | | `sentinel_digest` | Summary of all sentinel triggers in period | ## POST /reports/generate Trigger generation of a report. **Request body:** | Field | Type | Required | Description | | ------------------- | ------- | -------- | -------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `report_type` | string | Yes | Report type identifier (from table above) | | `sections` | array | No | Specific sections to include (omit for all) | | `date` | string | No | Report date (YYYY-MM-DD) | | `include_narrative` | boolean | No | Include AI-generated narrative text | | `contact_id` | integer | No | Scope to a specific customer (for account reports) | | `month` | string | No | Month to report on (YYYY-MM) | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/reports/generate" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "report_type": "weekly_summary", "date": "2024-11-10", "include_narrative": true }' ``` *** ## GET /reports/sections Returns available report sections and their metadata. **Query parameters:** | Param | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------ | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `report_type` | string | No | Filter sections by report type | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/reports/sections" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "report_type=weekly_summary" ``` # Search Source: https://docs.vh3.ai/api-reference/search Semantic and keyword search across your operational history # Search The Search endpoints let you find relevant past jobs, outcomes, and intake records by describing what you're looking for in natural language. The platform uses hybrid search, combining meaning-based matching with keyword retrieval, to surface relevant results even when terminology differs. ## POST /search/outcomes Search across AI-enriched job outcomes. This is the primary search endpoint for finding jobs by what happened, what was done, or what the result was. **Request body:** | Field | Type | Required | Description | | ------------- | ------- | -------- | -------------------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `query_text` | string | Yes | Natural language search query | | `limit` | integer | No | Max results to return (default: 10) | | `type_id` | string | No | Filter by job type | | `category_id` | string | No | Filter by job category | | `resource_id` | string | No | Filter by engineer/resource | | `contact_id` | string | No | Filter by customer (contact). Preferred scope for account-level precedent search | | `cleanup` | boolean | No | Whether to clean the results metadata | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/outcomes" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "air conditioning unit not cooling", "limit": 5 }' ``` *** ## POST /search/outcomes/enriched Semantic search over job outcomes with relationship enrichment from the intelligence layer. Same request body and filters as `POST /search/outcomes`. Adds `related_works` grouped by job type, engineer, and site for each hit set. **Request body:** | Field | Type | Required | Description | | -------------- | ------- | -------- | ------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `query_text` | string | Yes | Natural language search query (3–2000 characters) | | `limit` | integer | No | Max results (default 10, max 100) | | `type_id` | integer | No | Filter by job type | | `category_id` | integer | No | Filter by job category | | `job_group_id` | integer | No | Filter by job group | | `vertical` | string | No | Filter by AI-classified vertical | | `sub_vertical` | string | No | Filter by AI-classified sub-vertical | | `resource_id` | integer | No | Filter by engineer | | `contact_id` | integer | No | Filter by customer contact | | `site_key` | string | No | Filter by site | | `start_date` | string | No | Lower bound on `actual_start_at` (`YYYY-MM-DD`) | | `end_date` | string | No | Upper bound on `actual_start_at` (`YYYY-MM-DD`) | | `status` | string | No | Filter by job status | | `result` | string | No | Filter by job result | **Response fields:** | Field | Type | Description | | --------------- | ------- | ----------------------------------------------------------------------------------------- | | `hits` | array | Slim outcome hits (`job_id`, `job_ref`, `score`, `contact_id`, `status`, `summary`, etc.) | | `count` | integer | Number of hits | | `related_works` | object | `by_type`, `by_engineer`, `by_site` aggregates derived from the hit set | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/outcomes/enriched" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "replaced PCB on Vaillant ecoTEC, F28 fault cleared", "limit": 10, "contact_id": 12345 }' ``` **Use cases:** * **Fault resolution:** Find similar past fixes and see completion patterns for that job type. * **Engineer fit:** Check whether engineers on matched outcomes have history with the customer or fault class. * **Site risk:** Surface repeat failures at the site alongside semantically similar outcomes. **Notes:** * Slower than `/search/outcomes` due to relationship enrichment (\~500ms–1s additional). * `related_works` keys are derived from returned hits only, not the full matching corpus. * Returns `502` if semantic search or enrichment fails. *** ## POST /search/intake Search across raw job intake text, the original fault descriptions as entered by dispatchers or customers. **Request body:** | Field | Type | Required | Description | | ------------ | ------- | -------- | ----------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `query_text` | string | Yes | Natural language search query | | `limit` | integer | No | Max results to return (default: 10) | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/intake" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "heating system tripping", "limit": 5 }' ``` *** ## POST /search/intake/enriched Semantic search over job intake text with relationship enrichment, returns richer context by joining linked records to each result. **Request body:** | Field | Type | Required | Description | | ------------ | ------- | -------- | ----------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `query_text` | string | Yes | Natural language search query | | `limit` | integer | No | Max results to return | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/intake/enriched" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "fire alarm fault", "limit": 5 }' ``` *** ## GET /search/autocomplete Fuzzy / phonetic / email-aware lookup across contacts, persons (site contacts and account holders), engineers, jobs, and taxonomy entities. Returns results grouped by entity type plus a flat `results[]` array for back-compat. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `q` | string | Yes | Search text, name, postcode, email address, UUID personId, phone, reference, or numeric id | | `limit` | integer | No | Max results per group (default 10, max 50) | | `types` | string | No | Comma-separated filter. Allowed: `contact`, `person`, `engineer`, `job`, `job_type`, `job_category`, `contact_group`, `resource_group` | **Search capabilities:** * **Name / phonetic:** `Smyth` finds `Smith`; `PureGym` finds `Pure Gym` * **Email:** type a full or partial email (`ric@vezzahub.com`, `ric@`) to find the matching person directly. Results carry `matchedVia: "email"`. * **UUID / personId:** paste a standard UUID to resolve the person directly via their `ids` array. Returns `matchedVia: "person_id"` with score 1.0. * **Postcode:** UK postcodes with or without a space (`NN10 5AB` / `NN105AB`) * **Reference:** job reference or order number prefix * **Numeric id:** bare integer resolves `contactId`, `resourceId`, or `jobId` ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/search/autocomplete" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "q=ric@vezzahub.com" \ --data-urlencode "limit=10" ``` The response groups results under `groups.contacts`, `groups.people`, `groups.engineers`, `groups.jobs`, `groups.jobTypes`, `groups.jobCategories`, `groups.contactGroups`, and `groups.resourceGroups`. Each result includes a `matchedVia` field indicating why it was returned (`name`, `email`, `person_id`, `postcode`, `phonetic`, `reference`, `id`, `site_bridge`, etc.). **Use cases:** * **Typeahead UI:** Power customer, site, and job pickers in dispatch or ingest review screens. * **Email entity resolution:** Resolve portal payloads to `contact_id` and `site_key` before `POST /ingest/email/portal`. * **Connie grounding:** Disambiguate names or postcodes before semantic search or graph queries. **Notes:** * Minimum query length is 2 characters. Accepts any entity Id such as contact, job, job\_group\_id, reference, resource etc * Use `GET /search/autocomplete/diagnose` when all groups return empty (index health). *** ## GET /search/autocomplete/diagnose Health check for the autocomplete index pipeline (always returns 200; inspect `missing`, `populating`, `advice`). **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/search/autocomplete/diagnose" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## POST /search/summary-sections Hybrid search across **Customer Summary** knowledge sections. Each customer can have up to seven modular sections (overview, job history, equipment, analyses, performance, communication, risk). Each section is indexed independently so you can search one dimension or all of them. Results are ranked without an LLM call. **Request body:** | Field | Type | Required | Description | | ------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `query_text` | string | Yes | Natural language search query | | `section_key` | string | No | Limit to one section. Allowed: `customer_overview`, `job_history_patterns`, `systems_equipment`, `key_analyses`, `operational_performance`, `communication_summary`, `risk_opportunity` | | `contact_id` | string | No | Scope to one customer | | `limit` | integer | No | Max results (default: 10) | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/summary-sections" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "recurring boiler issues on PPM contracts", "section_key": "risk_opportunity", "limit": 5 }' ``` *** ## GET /search/summary-sections/by-contact// Return the full stored Customer Summary for one contact (all sections). Use when you need the complete account brief in a single call rather than a ranked search. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/search/summary-sections/by-contact/your-company-id/your-contact-id" \ --data-urlencode "api_key=your-api-key" ``` Summaries are generated from the operational graph and refreshed incrementally by the account summary pipeline. See [Operational discovery](/guides/operational-discovery) for how summaries stay current in Connie sessions. Incremental refresh endpoint: `POST /backfill/summary-kb` (tenant-authenticated; same `company_id` + `api_key` envelope). # Sentinels Source: https://docs.vh3.ai/api-reference/sentinels Proactive operational and growth opportunity monitoring # Sentinels Sentinels are proactive monitors that continuously watch your operational data for emerging risks and revenue opportunities. They run as structured reads on the operational graph with near-zero AI cost at detection. Thresholds, exclusion filters, and result limits are all configurable per tenant. See `GET /sentinels/registry` for active sentinel IDs and current defaults. Implementation notes (May 2026): * For `repeat_failure_escalation`, `customer_risk_escalation`, and `customer_noncomplete_anomaly`, "non-complete" is derived from `Job.status = completedWithIssues` (not `JobResult` labels). * In `customer_risk_escalation`, late finishes are counted only when `endDeltaMins > 0` (strictly late). * In `engineer_performance_slip`, `evidence.recentJobs` contains the jobs that formed the triggering streak, and `evidence.latestJobs` provides the latest context. * Treat `GET /sentinels/registry` as the source of truth for active sentinel IDs and defaults. ## Sentinel types ### Operational (13 sentinels) | Sentinel | What it detects | | ---------------------------- | ----------------------------------------------------------------- | | `engineer_performance_slip` | Engineers whose completion rates or SLA punctuality have degraded | | `site_deterioration` | Sites with increasing fault frequency or repeat visits | | `sla_breach_cluster` | Concentrated SLA breaches by geography, engineer, or customer | | `scheduling_drift` | Growing gaps between job creation and completion | | `repeat_visit_spike` | Abnormal repeat visit rates for specific job types or sites | | `first_time_fix_decline` | Drop in first-time-fix rates by engineer or job category | | `response_time_degradation` | Increasing time between job raised and first attendance | | `workload_imbalance` | Uneven job distribution across engineers | | `completion_rate_drop` | Falling job completion rates | | `customer_complaint_pattern` | Emerging complaint clusters | | `equipment_failure_trend` | Recurring equipment failures at specific sites | | `certification_gap` | Engineers approaching or past certification expiry | | `data_quality_alert` | Missing or inconsistent data in recent job records | ### Growth opportunity (6 sentinels) | Sentinel | What it detects | | ---------------------------- | -------------------------------------------------------------------- | | `dormant_customer` | Customers with no recent activity who may be ready for re-engagement | | `overdue_service_interval` | Equipment or sites past their recommended service interval | | `single_service_cross_sell` | Customers using only one service line, cross-sell candidates | | `engineer_flagged_follow_up` | Follow-on work flagged by engineers in job notes | | `seasonal_buying_pattern` | Historical patterns suggesting upcoming demand | | `geographic_upsell_cluster` | Concentration of existing customers near prospects | ## POST /sentinels/run Execute one or more sentinels against your data and return current results. **Request body:** | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `sentinel_ids` | object | No | Specific sentinels to run (omit to run all) | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/sentinels/run" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "sentinel_ids": ["site_deterioration", "engineer_performance_slip"] }' ``` To run all sentinels, omit `sentinel_ids`: ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/sentinels/run" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key" }' ``` *** ## POST /sentinels/run/ Run a single named sentinel. **Path parameters:** | Param | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------------- | | `sentinel_id` | string | Yes | Sentinel identifier (from tables above) | **Request body:** | Field | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/sentinels/run/dormant_customer" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key" }' ``` *** ## GET /sentinels/registry Returns all available sentinel definitions and their configuration. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/sentinels/registry" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## GET /sentinels/results Returns the latest cached sentinel results for your tenant. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/sentinels/results" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` # Teams Source: https://docs.vh3.ai/api-reference/teams Team management, membership, and entity scoping # Teams The Teams endpoints manage organisational teams, groups of users that can be scoped to specific customers, sites, or other entities. Teams enable access control and filtered views across the platform. ## GET /teams/list List all teams for your company. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------- | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `purpose` | string | No | Filter by team purpose | | `search` | string | No | Search by team name | | `page` | integer | No | Page number | | `per_page` | integer | No | Results per page | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/teams/list" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## POST /teams/create Create a new team. **Request body:** | Field | Type | Required | Description | | ------------- | ------- | -------- | --------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `name` | string | Yes | Team name | | `description` | string | No | Team description | | `purpose` | string | No | Team purpose/category | | `metadata` | object | No | Arbitrary metadata | | `actor_type` | string | No | Who created the team (`user`, `system`) | | `actor_id` | integer | No | ID of the creating actor | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/teams/create" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "name": "North Region", "description": "Engineers and accounts in the northern region" }' ``` *** ## GET /teams/ Retrieve a specific team with its members and linked entities. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## PATCH /teams/ Update team details. **Request body:** | Field | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `name` | string | No | New team name | | `description` | string | No | Updated description | | `purpose` | string | No | Updated purpose | | `metadata` | object | No | Updated metadata | | `is_active` | boolean | No | Activate or deactivate the team | ```bash theme={null} curl -X PATCH "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "name": "North Region, HVAC" }' ``` *** ## GET /teams//members List all members of a team. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001/members" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## POST /teams//members Add a member to a team. **Request body:** | Field | Type | Required | Description | | ----------------- | ------- | -------- | ------------------------------------ | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `user_id` | integer | Yes | User to add | | `role` | string | Yes | Role within team (`member`, `admin`) | | `is_default_team` | boolean | No | Set as default team for this user | | `actor_type` | string | No | Who performed the action | | `actor_id` | integer | No | ID of the acting user | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001/members" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "user_id": 42, "role": "member" }' ``` *** ## DELETE /teams//members/ Remove a member from a team. ```bash theme={null} curl -X DELETE "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001/members/membership-99" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key" }' ``` *** ## GET /teams//entities List all entities linked to a team. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `type` | string | No | Filter by entity type | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001/entities" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## POST /teams//entities Link an entity (customer, site, job type) to a team. **Request body:** | Field | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `entity_type` | string | Yes | Entity type (e.g. `customer`, `site`, `job_type`) | | `entity_id` | string | Yes | Entity identifier | | `label` | string | No | Display label for this link | | `context` | string | No | Additional context | | `metadata` | object | No | Arbitrary metadata | | `actor_type` | string | No | Who performed the action | | `actor_id` | integer | No | ID of the acting user | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001/entities" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "entity_type": "customer", "entity_id": "contact-456" }' ``` *** ## DELETE /teams//entities/ Unlink an entity from a team. ```bash theme={null} curl -X DELETE "https://api.vh3connect.io/api:kP8T1CK7/teams/team-001/entities/link-77" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key" }' ``` *** ## GET /teams/search Search teams by name or description. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------- | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `q` | string | Yes | Search term | | `page` | integer | No | Page number | | `per_page` | integer | No | Results per page | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/teams/search" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "q=north region" ``` *** ## GET /entities///teams Find which teams a given entity belongs to (reverse lookup). ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/entities/customer/contact-456/teams" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` *** ## GET /users//teams Get all teams a specific user belongs to. ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/users/42/teams" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` # Email Triage Source: https://docs.vh3.ai/api-reference/triage Classify inbound emails by category, urgency, and routing action # Email Triage Classify inbound emails against your tenant taxonomy. Returns category, urgency, sentiment, and a deterministic routing decision. Known FM portal senders can short-circuit to `portal_ingest` without AI classification. ## POST /triage/classify Classify a single email. **Request body:** | Field | Type | Required | Description | | ------------------- | ------- | -------- | --------------------------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `body` | string | Yes | Email body (plaintext or stripped HTML) | | `subject` | string | No | Email subject line | | `sender_address` | string | Yes | Sender email address | | `sender_name` | string | No | Sender display name | | `timestamp` | string | No | ISO 8601 send time | | `attachments` | array | No | Attachment metadata (`filename`, `mime_type`, `size_bytes`) | | `is_reply` | boolean | No | Email is a reply (default `false`) | | `is_forward` | boolean | No | Email is a forward (default `false`) | | `source_ref` | string | No | External message ID for deduplication | | `skip_portal_check` | boolean | No | Skip portal sender detection when the caller has already routed portal traffic upstream | **Response fields:** | Field | Type | Description | | ------------------------------------ | ------- | ------------------------------------------------------------------ | | `classification.category` | string | Taxonomy category code | | `classification.category_confidence` | number | Category confidence (0–1) | | `classification.urgency` | string | `emergency`, `urgent`, `standard`, or `low` | | `classification.sentiment` | string | `frustrated`, `neutral`, or `positive` | | `classification.safety_override` | boolean | H\&S language forced a safety category | | `classification.is_follow_up` | boolean | Repeated chase or escalation | | `classification.reasoning` | string | Classification rationale | | `decision.action` | string | `route`, `archive`, `priority_alert`, or `portal_ingest` | | `decision.destination` | string | Target queue or team | | `decision.priority` | boolean | Elevated attention required | | `decision.flags` | array | Routing flags (e.g. `cs_attention`, `urgency_bumped`) | | `decision.reasoning` | string | Routing rationale | | `portal_match` | string | Matched portal ID when sender is a known FM portal; otherwise null | | `pre_filter_hit` | boolean | Caught as noise without AI classification | | `processed_at` | string | ISO 8601 processing timestamp | **Example:** ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/triage/classify" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "subject": "RE: Cabin delivery for site WX-4821", "body": "We need to change the delivery date for the cabin order.", "sender_address": "john@contractor.example.com", "sender_name": "John Smith", "timestamp": "2026-03-05T10:30:00Z", "is_reply": true }' ``` **Use cases:** * **Inbox routing:** Branch n8n or helpdesk workflows on `decision.action` and `decision.destination` before human review. * **Portal handoff:** When `decision.action` is `portal_ingest`, forward the message to `POST /ingest/email/portal` instead of a generic queue. * **Priority escalation:** Filter on `classification.urgency` and `decision.priority` for same-day handling. * **Volume analytics:** Aggregate `classification.category` counts to measure inbound mix by type. **Notes:** * Pipeline order: portal short-circuit → pre-filter → AI classification → rule-based routing. * Pass `skip_portal_check: true` when upstream logic has already separated portal traffic. * Typical latency: instant for portal/pre-filter hits; 2–5s when AI classification runs. * Use `GET /triage/categories` to fetch the active taxonomy for UI pickers. *** ## GET /triage/categories Return the category taxonomy for UI rendering (system default plus tenant overlay). **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------------------------- | | `company_id` | string | No | Tenant scope; omit for system default taxonomy | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/triage/categories" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` **Response:** `categories[]` with `value` (category code), `label`, and `description`. # User Authentication (JWT) Source: https://docs.vh3.ai/api-reference/user-auth Per-user login and JWT session management for interactive applications built on VH3 # User Authentication (JWT) These endpoints provide per-user login and JWT session management for **interactive applications:** custom front-ends, customer portals, and embedded tools where individual users need to sign in and maintain a session. **Base URL:** `https://api.vh3connect.io/api:lBQnyyZL` Login requires only `email` and `password`. The user's tenant is resolved server-side. After login, every call uses `Authorization: Bearer `, no API key is ever sent from the client. Need to manage users from a back-end script or integration (no user session)? Use the [Users](/api-reference/users) endpoints on the main FSI API with `company_id` + `api_key`. Those endpoints are **server-side only:** the API key must never appear in client-side code. *** ## POST /auth/login Authenticate a user with email and password. Returns a JWT token valid for 24 hours. The user's tenant is resolved server-side from their account, no API key is required from the client. **Request body:** | Field | Type | Required | Description | | ---------- | ------ | -------- | ------------------ | | `email` | email | Yes | User email address | | `password` | string | Yes | User password | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:lBQnyyZL/auth/login" \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "securepassword" }' ``` **Response:** ```json theme={null} { "authToken": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0..." } ``` **Error responses:** | Status | Error | Cause | | ------ | --------------------------- | ------------------------------------------------ | | `401` | `Invalid email or password` | Wrong email, wrong password, or no account found | | `401` | `Account is deactivated` | User has been archived | *** ## POST /auth/refresh Refresh an expiring JWT token. Returns a new token with a fresh 24-hour expiry. **Headers:** | Header | Value | | --------------- | ---------------- | | `Authorization` | `Bearer ` | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:lBQnyyZL/auth/refresh" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "authToken": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0..." } ``` *** ## GET /auth/me Get the current user profile from the JWT token. Includes the user's company information. **Headers:** | Header | Value | | --------------- | ---------------- | | `Authorization` | `Bearer ` | ```bash theme={null} curl "https://api.vh3connect.io/api:lBQnyyZL/auth/me" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "id": 42, "first_name": "Jane", "last_name": "Smith", "company_id": "abc-123-def", "email": "jane@example.com", "role": "admin", "phone": null, "profile_picture": { "url": null }, "_company": { "id": "abc-123-def", "name": "Acme Field Services" } } ``` *** ## POST /users/invite Invite a new user by email to the authenticated user's company. Returns an invitation token valid for 7 days. **Requires `admin` or `developer` role.** **Headers:** | Header | Value | | --------------- | ---------------- | | `Authorization` | `Bearer ` | **Request body:** | Field | Type | Required | Default | Description | | ------------ | ------ | -------- | ---------- | ---------------------------------------------------------- | | `email` | email | Yes | None | Email address to invite | | `role` | string | No | `standard` | Role to assign: `admin`, `manager`, `standard`, `engineer` | | `first_name` | string | No | None | First name of the invited user | | `last_name` | string | No | None | Last name of the invited user | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:lBQnyyZL/users/invite" \ -H "Authorization: Bearer eyJhbGciOi..." \ -H "Content-Type: application/json" \ -d '{ "email": "newuser@example.com", "role": "standard", "first_name": "John", "last_name": "Doe" }' ``` **Response:** ```json theme={null} { "email": "newuser@example.com", "role": "standard", "invite_token": "eyJhbGciOi...", "expires_in": 604800 } ``` **Error responses:** | Status | Error | Cause | | ------ | --------------------------------------- | -------------------------------------- | | `401` | `Only admin users can invite new users` | Requesting user is not admin/developer | | `400` | `A user with this email already exists` | Duplicate email | *** ## GET /users/list List all active users belonging to the authenticated user's company. Supports pagination. **Requires `admin` or `developer` role.** **Headers:** | Header | Value | | --------------- | ---------------- | | `Authorization` | `Bearer ` | **Query parameters:** | Param | Type | Required | Default | Description | | ---------- | ------- | -------- | ------- | -------------- | | `page` | integer | No | `1` | Page number | | `per_page` | integer | No | `25` | Items per page | ```bash theme={null} curl "https://api.vh3connect.io/api:lBQnyyZL/users/list?page=1&per_page=25" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "items": [ { "id": 42, "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com", "role": "admin", "phone": null, "profile_picture": { "url": null }, "email_verified": true }, { "id": 43, "first_name": "John", "last_name": "Doe", "email": "john@example.com", "role": "standard", "phone": null, "profile_picture": { "url": null }, "email_verified": true } ], "curPage": 1, "nextPage": null, "prevPage": null } ``` *** ## DELETE /users/ Soft-delete a user by setting their account to archived. The user will no longer be able to log in. Cannot delete your own account. **Requires `admin` or `developer` role.** **Headers:** | Header | Value | | --------------- | ---------------- | | `Authorization` | `Bearer ` | **Path parameters:** | Param | Type | Description | | --------- | ------- | ------------------------ | | `user_id` | integer | ID of the user to delete | ```bash theme={null} curl -X DELETE "https://api.vh3connect.io/api:lBQnyyZL/users/43" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "success": true, "user_id": 43 } ``` **Error responses:** | Status | Error | Cause | | ------ | ------------------------------------------ | ----------------------------------------- | | `401` | `Only admin users can delete users` | Requesting user is not admin/developer | | `400` | `Cannot delete your own account` | `user_id` matches the authenticated user | | `400` | `User not found` | No user with this ID | | `401` | `Cannot delete users from another company` | Target user belongs to a different tenant | *** ## Roles reference | Role | Data access | User management | | ----------- | ----------- | -------------------------- | | `admin` | Full | Invite, list, delete users | | `developer` | Full | Invite, list, delete users | | `manager` | Full | No | | `standard` | Full | No | | `engineer` | Full | No | # Users Source: https://docs.vh3.ai/api-reference/users User management, list, invite, update roles, and remove users from your company # Users The Users endpoints manage the team members associated with your company. They use the standard `company_id` + `api_key` authentication, the same as all other VH3 AI endpoints. **Base URL:** `https://api.vh3connect.io/api:kP8T1CK7` These endpoints are **server-side only**. The `api_key` must never be sent from a browser, mobile app, or any client-side code. If you are building an interactive front-end, use the [User Authentication (JWT)](/api-reference/user-auth) endpoints instead, your users log in once and every subsequent call uses a Bearer token, with no API key in the browser. *** ## GET /users/list List all active (non-archived) users for your company. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/users/list" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` **Response:** ```json theme={null} [ { "id": 42, "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com", "username": "jsmith", "role": "admin", "profile_picture": { "url": null } }, { "id": 43, "first_name": "John", "last_name": "Doe", "email": "john@example.com", "username": "jdoe", "role": "standard", "profile_picture": { "url": null } } ] ``` *** ## GET /users/invites List pending (not yet accepted) invitations for your company. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/users/invites" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` **Response:** ```json theme={null} [ { "id": "uuid-token-id", "company_id": "your-company-id", "email": "newuser@example.com", "role": "standard", "created_at": "2026-05-17T19:57:00Z", "expires_at": "2026-06-17T19:57:00Z", "accepted_at": null } ] ``` *** ## POST /users/invite Invite a user to your company by email. Sends an invitation email via SendGrid with an accept link. If the email address already exists in the system without a company, they are immediately linked to your company. **Request body:** | Field | Type | Required | Description | | -------------- | ------ | -------- | -------------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `email` | email | Yes | Email address to invite | | `role` | string | Yes | Role to assign: `admin`, `manager`, `standard`, `engineer` | | `company_name` | string | Yes | Your company display name, shown in the invitation email | | `inviter_name` | string | Yes | Name of the person sending the invite, shown in the invitation email | ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/users/invite" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "email": "newuser@example.com", "role": "standard", "company_name": "Acme Field Services", "inviter_name": "Jane Smith" }' ``` **Response:** ```json theme={null} { "success": true, "message": "Invitation sent to newuser@example.com" } ``` **Error responses:** | Status | Error | Cause | | ------ | ----------------------------------- | ---------------------------------------------- | | `400` | `User already exists in the system` | Email exists and already belongs to a company | | `400` | `User has already been invited` | A pending invite for this email already exists | | `400` | `Failed to send invitation email` | SendGrid delivery failure | *** ## PUT /users//role Update the role of a user within your company. Returns the updated user record. **Request body:** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `user_id` | string | Yes | ID of the user to update | | `role` | string | Yes | New role: `admin`, `manager`, `standard`, `engineer`, `developer` | ```bash theme={null} curl -X PUT "https://api.vh3connect.io/api:kP8T1CK7/users/42/role" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "user_id": "42", "role": "manager" }' ``` **Response:** ```json theme={null} { "id": 42, "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com", "username": "jsmith", "role": "manager", "profile_picture": { "url": null } } ``` **Error responses:** | Status | Error | Cause | | ------ | --------------------------------------------------- | -------------------------------------------------- | | `401` | `User not found or does not belong to this company` | `user_id` invalid or belongs to a different tenant | *** ## DELETE /users/ Archive (soft-delete) a user. The user's record is preserved but `is_archived` is set to `true`, they can no longer log in and will not appear in `GET /users/list`. **Request body:** | Field | Type | Required | Description | | ------------ | ------ | -------- | ------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `user_id` | string | Yes | ID of the user to archive | ```bash theme={null} curl -X DELETE "https://api.vh3connect.io/api:kP8T1CK7/users/43" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "user_id": "43" }' ``` **Response:** ```json theme={null} { "success": true, "user_id": "43" } ``` **Error responses:** | Status | Error | Cause | | ------ | --------------------------------------------------- | -------------------------------------------------- | | `401` | `User not found or does not belong to this company` | `user_id` invalid or belongs to a different tenant | # Weather Source: https://docs.vh3.ai/api-reference/weather Forecast and historical weather for coordinates, jobs, and sites # Weather Weather lookups for field service planning and retrospective analysis. Backed by a third-party weather provider. Responses include hourly conditions and a summary with `outdoor_work_risk` (`low`, `moderate`, or `high`). ## GET /weather/forecast Forecast weather for a latitude/longitude. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | -------------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `latitude` | float | Yes | Latitude (-90 to 90) | | `longitude` | float | Yes | Longitude (-180 to 180) | | `start_hour` | string | No | Window start (ISO 8601 partial, e.g. `2026-03-06T08:00`) | | `end_hour` | string | No | Window end (ISO 8601 partial, e.g. `2026-03-06T18:00`) | | `timezone` | string | No | IANA timezone (default `Europe/London`) | **Response includes:** `mode` (`forecast`), `period_start`, `period_end`, `summary` (avg/min/max temp, precipitation, wind, `dominant_condition`, `outdoor_work_risk`), and `hourly[]` (temperature, humidity, precipitation, rain, weather code/label, wind, cloud cover). **Enum, `summary.outdoor_work_risk`:** `low`, `moderate`, `high` **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/weather/forecast" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "latitude=51.5074" \ --data-urlencode "longitude=-0.1278" \ --data-urlencode "start_hour=2026-03-06T08:00" \ --data-urlencode "end_hour=2026-03-06T18:00" ``` **Use cases:** * **Dispatch planning:** Check conditions for a postcode centroid before assigning outdoor work. * **Briefing enrichment:** Pair with `POST /briefing/generate` to surface visit-day risk in engineer packs. *** ## GET /weather/historical Historical weather for a latitude/longitude and date range. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `latitude` | float | Yes | Latitude (-90 to 90) | | `longitude` | float | Yes | Longitude (-180 to 180) | | `start_date` | string | Yes | Start date (`YYYY-MM-DD`) | | `end_date` | string | Yes | End date (`YYYY-MM-DD`) | | `timezone` | string | No | IANA timezone (default `Europe/London`) | **Response:** Same shape as forecast; `mode` is `historical`. Archive data is available from 1940 onwards. **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/weather/historical" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "latitude=51.5074" \ --data-urlencode "longitude=-0.1278" \ --data-urlencode "start_date=2026-02-10" \ --data-urlencode "end_date=2026-02-12" ``` **Use cases:** * **Delay analysis:** Correlate completed jobs with heavy rain or high wind on the service date. * **SLA disputes:** Provide objective weather evidence for missed appointments. *** ## GET /weather/for-job/ Weather for a specific job. Coordinates and time window are resolved from the intelligence layer. **Path parameters:** | Param | Type | Required | Description | | -------- | ------ | -------- | ------------------- | | `job_id` | string | Yes | Job ID or reference | **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | **Behaviour:** * Completed jobs (actual end in the past) → historical weather for the job window. * Future or in-progress jobs → forecast for planned/actual start–end. * Response includes a `job` object: `job_id`, `reference`, `site_address`, `status`. **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/weather/for-job/FAB310221" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" ``` **Use cases:** * **Connie / agent tools:** Answer “was weather a factor on job X?” without manual coordinate lookup. * **Investigation:** Combine with outcome search when diagnosing repeat failures or delays. **Errors:** `404` if the job or linked site is missing; `422` if the site has no latitude/longitude. *** ## GET /weather/for-site Weather for a customer or site over a date range. Coordinates are resolved from the graph. **Query parameters:** | Param | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------------------------------- | | `company_id` | string | Yes | Your tenant identifier | | `api_key` | string | Yes | Your tenant API key | | `start_date` | string | Yes | Start date (`YYYY-MM-DD`) | | `end_date` | string | Yes | End date (`YYYY-MM-DD`) | | `contact_id` | string | No | Customer contact ID (preferred) | | `site_key` | string | No | Site key (SHA-256); use when `contact_id` is unknown | One of `contact_id` or `site_key` is required. When `contact_id` has no coordinates, the API falls back to the most recent linked site with lat/lon. **Response includes:** Standard weather payload plus `site` (`contact_id`, `site_key`, `site_address`). **Example:** ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/weather/for-site" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "contact_id=12345" \ --data-urlencode "start_date=2026-03-10" \ --data-urlencode "end_date=2026-03-12" ``` **Use cases:** * **Account planning:** Review forecast for a key customer across a multi-day PPM window. * **Site risk:** Assess outdoor-work risk at a repeat-failure location before scheduling. **Notes:** * `outdoor_work_risk` uses rule-based thresholds (heavy rain, gusts >60 km/h, freezing, snow/ice codes). * Forecast horizon is up to 16 days; historical archive from 1940. * Weather service errors return `502`. # Authentication Source: https://docs.vh3.ai/authentication Two API surfaces, VH3 AI Intelligence (company_id + api_key) and BigChange API (X-API-Key header), plus per-user JWT for interactive apps # Authentication **Two server-to-server APIs, one key:** the same VH3 API key is used for both surfaces; transport differs. 1. **VH3 AI Intelligence** (`api:kP8T1CK7`): `company_id` + `api_key` on every request (POST body / GET query). 2. **BigChange API** (`api:YdihQNr3`): `X-API-Key` header only, no `company_id`; tenant resolved from the key. **Interactive apps:** User Auth JWT (`Authorization: Bearer`) on `api:lBQnyyZL` and Bearer-enabled intelligence routes. Never send `api_key` from browser or mobile clients. **Docs vs live data:** `https://docs.vh3.ai/mcp` or `https://docs.vh3.ai/llms.txt` for documentation search, not the VH3 product MCP. VH3 Connect exposes **two REST API groups** for server-to-server integration, plus a **User Auth** API for interactive applications. You receive a single API key during onboarding; how you send it depends on which API you call. ## Two API surfaces | API | Base URL | Auth | Tenant scope | | -------------------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------------------------------------- | | [VH3 AI Intelligence](/api-reference/overview) | `https://api.vh3connect.io/api:kP8T1CK7` | `company_id` + `api_key` (body or query) | Explicit `company_id` on every request | | [BigChange API](/api-reference/bigchange/overview) | `https://api.vh3connect.io/api:YdihQNr3` | `X-API-Key` header only | Resolved from the API key | The API key is the same credential for both groups. Intelligence endpoints require your company ID in addition; BigChange proxy endpoints do not. ### VH3 AI Intelligence, quick reference ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/outcomes" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "boiler fault", "limit": 5 }' ``` ### BigChange API, quick reference ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:YdihQNr3/jobs/list" \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "pageNumber": 1, "pageSize": 20 }' ``` ### User Auth (interactive apps) Login with email and password on `api:lBQnyyZL`; use the returned JWT as `Authorization: Bearer`. No API key in client code. See [User Authentication](#user-authentication) below. *** ## VH3 AI Intelligence authentication All intelligence-layer endpoints require **company ID** and **API key** on every request. | Field | Type | Description | | ------------ | ------ | ---------------------------------------------------- | | `company_id` | string | Your tenant identifier, identifies your organisation | | `api_key` | string | Your tenant API key, authenticates the request | These are passed on every request. For `POST` endpoints, they go in the JSON body. For `GET` endpoints, they go as query parameters. Required on every VH3 data endpoint unless using Bearer JWT on User Auth–scoped routes. Missing either field returns HTTP 400 with `Missing param`. ### POST example (most endpoints) ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:kP8T1CK7/search/outcomes" \ -H "Content-Type: application/json" \ -d '{ "company_id": "your-company-id", "api_key": "your-api-key", "query_text": "boiler intermittent fault", "limit": 5 }' ``` ### GET example (feeds, detail lookups) ```bash theme={null} curl -G "https://api.vh3connect.io/api:kP8T1CK7/jobs/feed" \ --data-urlencode "company_id=your-company-id" \ --data-urlencode "api_key=your-api-key" \ --data-urlencode "page_size=20" ``` Requests missing `company_id` or `api_key` will receive a `400` response with a `Missing param` error. *** ## BigChange API authentication BigChange proxy endpoints use the **same API key** as the intelligence layer, passed only in the **`X-API-Key`** HTTP header. Do not send `company_id` on these requests, the gateway resolves your tenant and BigChange session from the key. ```bash theme={null} curl -G "https://api.vh3connect.io/api:YdihQNr3/contacts/contact" \ -H "X-API-Key: your-api-key" \ --data-urlencode "contactId=12345" ``` | Header | Required | Description | | -------------- | ---------- | ------------------- | | `X-API-Key` | Yes | Your tenant API key | | `Content-Type` | Yes (POST) | `application/json` | Missing or invalid `X-API-Key` returns `401 Unauthorised`. Do not put the API key in the JSON body for BigChange endpoints. Full endpoint list: [BigChange API reference](/api-reference/bigchange/overview). *** ## User Authentication For interactive applications, custom dashboards, customer portals, embedded tools, VH3 provides per-user authentication with JWT tokens. Users log in with email and password only. The tenant is resolved server-side from their account. After login, every call from the client uses the JWT, no API key is ever involved in client-side code. ### How it works ```mermaid theme={null} sequenceDiagram participant App as Your Application participant Auth as User Auth API participant API as VH3 Data API App->>Auth: POST /auth/login (email, password) Auth-->>App: { authToken: "eyJ..." } Note over App: Tenant resolved server-side, JWT used for everything App->>Auth: GET /auth/me (Authorization: Bearer token) Auth-->>App: { id, first_name, last_name, email, role, ... } App->>API: POST /connie/chat (Authorization: Bearer token) API-->>App: { response data } ``` ### Login Authenticate a user with email and password. The user's tenant is resolved server-side, no API key is required from the client. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:lBQnyyZL/auth/login" \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "securepassword" }' ``` **Response:** ```json theme={null} { "authToken": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0..." } ``` Store the `authToken` in your application (e.g. `httpOnly` cookie in production). All subsequent requests use `Authorization: Bearer `, no API key is ever sent from the client. ### Token refresh Refresh an expiring token before it expires. Requires a valid Bearer token. ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:lBQnyyZL/auth/refresh" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "authToken": "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0..." } ``` ### Get current user Retrieve the profile of the authenticated user. ```bash theme={null} curl "https://api.vh3connect.io/api:lBQnyyZL/auth/me" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "id": 42, "first_name": "Jane", "last_name": "Smith", "company_id": "abc-123-def", "email": "jane@example.com", "role": "admin", "phone": null, "profile_picture": { "url": null }, "_company": { "id": "abc-123-def", "name": "Acme Field Services" } } ``` ### Token shape JWT tokens issued by the User Auth API: | Claim | Description | | --------- | ------------------------------------------------- | | `id` | User ID (integer) | | `company` | Company ID (UUID), the tenant the user belongs to | | `iss` | Token issuer | | `exp` | Expiry timestamp (24 hours from issue) | The same token works across both the User Auth endpoints and the main VH3 data API when configured with Bearer auth middleware. ### Using the token in your application The example below stores the token in `localStorage` and calls the VH3 API directly from the browser. **This is for local development and testing only.** In any app that real users can access — including internal tools, partner portals, and MVPs — the token must be stored in an `httpOnly` secure cookie and all VH3 API calls must originate from your backend server. Calling the VH3 API from browser code means anyone who can open the browser network tab can replay those calls directly against your organisation's data. ```typescript theme={null} // Development only — do not use this pattern in any user-facing application const token = localStorage.getItem('vh3_token'); const response = await fetch('https://api.vh3connect.io/api:kP8T1CK7/connie/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ message: 'How many jobs were completed this week?', }), }); ``` **In production:** store the `authToken` from `/auth/login` in an `httpOnly` secure cookie on your backend. On every request, your server reads the cookie, calls `GET /auth/me` to validate the token and retrieve the user's company, then makes the VH3 API call server-side. The browser never sees the token directly and never calls the VH3 API. See [Deploying secure apps](/guides/deploying-secure-apps) for the full frontend/backend pattern. *** ## User Management VH3 provides two ways to manage users depending on your integration type: | Use case | Endpoint set | Auth | | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | **Back-end / server-to-server:** cron jobs, admin scripts, integrations | [`GET /users/list`, `POST /users/invite`, `PUT /users/{id}/role`, `DELETE /users/{id}`](/api-reference/users) on `api:kP8T1CK7` | `company_id` + `api_key` (server-side only, never sent from a browser) | | **Interactive front-end:** custom dashboards, portals, embedded tools | [`POST /users/invite`, `GET /users/list`, `DELETE /users/{id}`](/api-reference/user-auth) on `api:lBQnyyZL` | Bearer JWT, no API key in client code | Never call the `api:kP8T1CK7` user management endpoints from a browser or mobile app, doing so exposes your API key in client-side code. Use the JWT-authenticated equivalents on `api:lBQnyyZL` instead. The section below covers the JWT-based variants for interactive applications. For the server-side `company_id` + `api_key` variants, see the [Users API reference](/api-reference/users). Admin users can manage team members via the User Auth API. All user management endpoints require a valid Bearer token from a user with the `admin` or `developer` role. ### Invite a user Send an invitation to a new user. Returns an invitation token (valid for 7 days). ```bash theme={null} curl -X POST "https://api.vh3connect.io/api:lBQnyyZL/users/invite" \ -H "Authorization: Bearer eyJhbGciOi..." \ -H "Content-Type: application/json" \ -d '{ "email": "newuser@example.com", "role": "standard", "first_name": "John", "last_name": "Doe" }' ``` **Response:** ```json theme={null} { "email": "newuser@example.com", "role": "standard", "invite_token": "eyJhbGciOi...", "expires_in": 604800 } ``` | Parameter | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------------------------------------------------------------- | | `email` | email | Yes | Email address to invite | | `role` | string | No | Role to assign: `admin`, `manager`, `standard`, `engineer`. Defaults to `standard` | | `first_name` | string | No | First name of the invited user | | `last_name` | string | No | Last name of the invited user | ### List users List all active users in the authenticated user's company. ```bash theme={null} curl "https://api.vh3connect.io/api:lBQnyyZL/users/list?page=1&per_page=25" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "items": [ { "id": 42, "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com", "role": "admin", "phone": null, "profile_picture": { "url": null }, "email_verified": true } ], "curPage": 1, "nextPage": null, "prevPage": null } ``` ### Delete a user Soft-delete a user (sets `is_archived` to true). Cannot delete your own account. ```bash theme={null} curl -X DELETE "https://api.vh3connect.io/api:lBQnyyZL/users/42" \ -H "Authorization: Bearer eyJhbGciOi..." ``` **Response:** ```json theme={null} { "success": true, "user_id": 42 } ``` ### Roles | Role | Permissions | | ----------- | ----------------------------------------------- | | `admin` | Full access, can invite, list, and delete users | | `developer` | Same as admin | | `manager` | Standard data access, no user management | | `standard` | Standard data access, no user management | | `engineer` | Standard data access, no user management | *** ## Your credentials During onboarding you receive: * **Company ID:** your unique tenant identifier * **API Key:** your tenant authentication key Both are provided by your account manager or visible in your VH3 Connect dashboard settings. ## Error responses All errors follow a consistent format: ```json theme={null} { "code": "ERROR_CODE_INPUT_ERROR", "message": "Missing param: company_id", "payload": { "param": "company_id" } } ``` | Status code | Meaning | | ----------- | ------------------------------------------------------------- | | `400` | Bad request, missing or invalid parameters | | `401` | Unauthorised, invalid API key or expired token | | `403` | Forbidden, insufficient role permissions | | `404` | Not found, resource does not exist for your tenant | | `409` | Conflict, a task is already running for this resource | | `422` | Validation error, request understood but semantically invalid | | `429` | Rate limited, too many requests | | `500` | Server error, contact support | ## Security * HTTPS only. Rotate API keys via account manager; do not log or echo keys in tool output. * Intelligence: `company_id` + `api_key`. BigChange: `X-API-Key` header only (same key value). * JWT `exp` is 24h; refresh before expiry. Claims: `id` (user), `company` (tenant UUID). * Server-side user management: `api:kP8T1CK7` + `company_id`/`api_key`. Client-side user management: `api:lBQnyyZL` + Bearer only. Your API key is tenant-scoped and grants access to your organisation's data only. Treat it like a password, store it in server-side environment variables only. **Never include it in client-side code, browser bundles, or mobile apps.** For interactive front-ends, use [User Authentication (JWT)](/api-reference/user-auth), users log in with email and password only, and the API key is never involved. * All requests must use HTTPS * API keys can be rotated on request via your account manager * JWT tokens expire after 24 hours, use the refresh endpoint to obtain a new token before expiry * Store JWT tokens in `httpOnly` secure cookies in production. `localStorage` is acceptable for local development only — never in user-facing apps # Changelog Source: https://docs.vh3.ai/changelog/overview New features, updates, and fixes shipped in VH3 AI No product changes shipped this week. The intelligence layer, [Connie](/guides/connie), [sentinels](/guides/sentinels), [reports and briefings](/guides/reports), [email triage](/faq/email-triage), and the [BigChange integration](/api-reference/bigchange/overview) continue to run as documented — see the [API overview](/api-reference/overview) for the current surface. No product changes shipped this week. The intelligence layer, [Connie](/guides/connie), [sentinels](/guides/sentinels), [reports and briefings](/guides/reports), [email triage](/faq/email-triage), and the [BigChange integration](/api-reference/bigchange/overview) continue to run as documented — see the [API overview](/api-reference/overview) for the current surface. ## New features **Intelligence layer launch.** The VH3 AI intelligence layer is live: a maintained operational graph, meaning-based search, structured job enrichment, and continuous monitoring across your field service data. See [Intelligence layer](/intelligence-layer) and [Introduction](/introduction). **Connie.** Ask plain-language questions against your live operational graph and get cited, synthesised answers. See the [Connie guide](/guides/connie) and [Connie API](/api-reference/connie). **Sentinels, cases, and teams.** Sentinels watch the graph 24/7 for repeat visits, SLA drift, dormant customers, and emerging risk — and can open a [case](/api-reference/cases), draft context with Connie, and route it to the responsible [team](/api-reference/teams). Read the [Sentinels guide](/guides/sentinels) and [Users and teams](/guides/users-and-teams). **Email triage.** Inbound emails are classified, linked to the right job or account, and queued for the right team. See [Triage API](/api-reference/triage) and [Email triage FAQ](/faq/email-triage). **Reports and briefings.** Scheduled and on-demand operational reports and briefings draw from the live graph. See [Reports](/api-reference/reports), [Briefings](/api-reference/briefings), and the [Reports guide](/guides/reports). **Weather context.** Weather data is now available as first-class operational context for jobs and sites. See [Weather API](/api-reference/weather). **Agent Starter Kits.** Ready-to-use configurations for connecting AI tools to the intelligence layer, including [AGENTS.md](/agent-kits/agents-md), [Cursor rules](/agent-kits/cursor-rules), the [VH3 product MCP](/agent-kits/mcp-setup), [Claude Projects](/agent-kits/claude-projects), [Claude Skills](/agent-kits/claude-skills), and [n8n agents](/agent-kits/n8n-agents). **Verified n8n community node.** The official `n8n-nodes-vh3ai` node is [verified on n8n](https://link.vh3.ai/n8n), works on Cloud and self-hosted, and is usable as a tool by n8n AI agents. See [n8n community node](/n8n-node) and the [node reference](/agent-kits/n8n-node-reference). **BigChange native integration.** Direct BigChange API coverage through the intelligence layer and the n8n node: contacts, jobs, invoices, quotes, sales opportunities, purchase orders, notes, persons, resources, vehicles, stock, worksheets, and reference data. See the [BigChange API overview](/api-reference/bigchange/overview). ## Updates **Unified API surface.** A single OpenAPI specification now covers jobs, contacts, search, sentinels, reports, briefings, weather, triage, ingest, Connie, cases, teams, users, and user auth. Start at the [API overview](/api-reference/overview). **Authentication and user auth.** End-to-end docs for tenant API keys plus end-user authentication flows. See [Authentication](/authentication) and [User auth API](/api-reference/user-auth). **Ingest pipeline.** Continuous ingest with entity resolution keeps the operational picture current as customer hierarchies, sites, and job types change. See [Ingest API](/api-reference/ingest) and [Keeping the graph current](/guides/keeping-the-graph-current). **Technology partners program.** Partner program details for FMS vendors, agencies, and platform integrators. See [Technology partners](/partners/technology-partners). **Pricing published.** Transparent pricing for the intelligence layer, Connie, sentinels, and ingest. See [Pricing](/pricing) and the [pricing FAQ](/faq/pricing). # Frequently asked questions Source: https://docs.vh3.ai/faq Common questions about VH3 AI — from what it is and how to get started through security, pricing, and building on the intelligence layer. # Frequently asked questions # Architecture and APIs Source: https://docs.vh3.ai/faq/architecture-and-apis API surfaces, authentication, and where your data lives. ## Architecture and APIs You receive a single VH3 API key during onboarding. It is used across both server-to-server surfaces: | API | Base URL | Auth | | ------------------- | ---------------------------------------- | -------------------------------------------- | | VH3 AI Intelligence | `https://api.vh3connect.io/api:kP8T1CK7` | `company_id` + `api_key` in the request body | | BigChange API | `https://api.vh3connect.io/api:YdihQNr3` | `X-API-Key` header only | Intelligence endpoints require your company ID on every request. BigChange proxy endpoints resolve your tenant from the API key alone. For interactive applications and custom portals, users authenticate with email and password. The returned JWT is used for all subsequent calls. No API key is ever involved in client-side code. See [Authentication](/authentication) for the complete surface map and code examples. The public API reference documents the customer-facing subset. Additional endpoints exist for platform engineering, pollers, and operational tooling. Those internal endpoints are outside the integration contract. For integrations, use the endpoints documented here or the OpenAPI export your CSM provides. | Layer | What is stored | | --------------------- | ---------------------------------------------------------------------------------------------------- | | Knowledge graph | Jobs, engineers, customers, outcomes, relationships, and SLA analytics, traversable in any direction | | Semantic search index | Intake descriptions and diagnostic outcomes, indexed by meaning for fault discovery | | Platform data | Cases, teams, notifications, usage, and configuration | | Your FMS | Your operational system of record for dispatch, scheduling, worksheets, and job execution | # Case management and teams Source: https://docs.vh3.ai/faq/case-management-and-teams Cases, teams, and how they enable continuous follow-through. ## Case management and teams Case management is the place where agent signals become owned work. A case can represent an escalation, investigation, project review, audit, complaint, or follow-up item. It holds participants, linked operational records, comments, status changes, and a full activity timeline. Operational records stay in the intelligence layer. Cases reference jobs, customers, sites, engineers, and other evidence so the team can review and act without copying data into a separate system. Case management runs inside VH3 AI. It tracks ownership, evidence, and follow-through around operational work. Any BigChange write-back or job creation flow is handled by the configured ingest or integration pipeline for your tenant. Teams are dynamic groups for shared ownership. A team can represent a region, customer portfolio, service line, escalation room, onboarding sprint, or temporary working group. Teams can link to customers, sites, jobs, job types, or other entities. Sentinels, reports, Connie, and automations can then route work to the group that owns the relevant account, site, or problem. Teams are created around the work. Some are permanent, such as a regional operating patch or customer portfolio. Others are temporary, such as a major incident room or a discovery sprint review group. Use `purpose`, `description`, and `metadata` to describe the group in the language your operation uses. # Connie and AI agents Source: https://docs.vh3.ai/faq/connie-and-ai-agents Who Connie is, what BYOK means, models, tools, and MCP. ## Connie and AI agents Connie is VH3 AI's field service operations agent in VH3 Connect. She reads your full intelligence layer: knowledge graph, semantic search, reports, weather, and enriched operational records. She runs on Anthropic's model family, with intelligent routing across multiple models and prompt caching built in so the right model handles each type of work efficiently. Connie handles multi-turn operational reviews, account prep, diagnostics, and follow-through that depends on context from earlier in the session. VH3 AI runs on an open AI harness. For conversational AI, you connect your own Anthropic account key. Every token Connie spends goes directly to your Anthropic account at your contracted rate. VH3 adds no margin. You see exactly what each session cost on your AI provider dashboard. With BYOK, model usage is visible on your provider account. You can switch models, adjust usage, and see the full economics. If you build your own agents or automations via the API or n8n, you can use the model, harness, or framework you choose. Connie uses Anthropic's model family, routed across multiple models depending on the task, with prompt caching for efficiency. Company-level context is cached across all users in your organisation, so every session benefits from prior cache warming. Enrichment and extraction pipelines use best-in-class structured output models selected by VH3. Embeddings are generated server-side by the platform. Customers developing on the API or via n8n can use any model and framework they choose. By default, Connie answers and investigates. Job creation from email goes through the portal ingest pipeline with review queues where configured. Write-back behaviour is integration-specific. Confirm with your CSM for your tenant's setup. Tools are structured API operations that the agent can call with validated parameters: search, aggregate, investigate, job lookup, reports, briefings, and more. They give Connie and your custom agents precise access to the intelligence layer. Yes. VH3 AI exposes a read-only MCP surface for approved agent clients such as Claude Desktop, Cursor, and coding agents. See [MCP setup](/agent-kits/mcp-setup) for configuration, authentication, and available operations. # Data, graph, and search Source: https://docs.vh3.ai/faq/data-graph-and-search What lives in the knowledge graph, how search works, and data export. ## Data, graph, and search Jobs are the central node, connected to customers, engineers, job types, outcomes, worksheets, equipment, and operational history. The graph captures relationships that match field service reality: the same engineer across different customers and locations, the same equipment across different sites, and patterns that cross account boundaries. That connected structure makes questions answerable when they involve more than one record, for example repeat failures across a customer estate or engineer performance on one job type. Finding semantically similar past jobs, for example "boiler pressure fault on a commercial site," using intake descriptions and diagnostic outcomes. Results are often combined with keyword search for exact part numbers or fault codes, giving precision and meaning-based discovery in the same query. Job enrichment runs as data lands from your FMS. Customer summaries and some aggregate views refresh on scheduled tasks. The intelligence layer stays current as new jobs, outcomes, and customer activity arrive. Discuss export and portability with your account team. Your operational records remain in your FMS. VH3 holds enriched analytics and the operational graph. On cancellation, export arrangements are handled according to your commercial agreement and data processing terms. # Email triage and FM portals Source: https://docs.vh3.ai/faq/email-triage Email pipelines, portal routing, triage categories, and safety overrides. ## Email triage and FM portals Four related but distinct pipelines: | Pipeline | Creates jobs? | Purpose | | -------------------- | -------------------------- | ------------------------------------------------------------------------ | | Portal ingest | Yes (or queued for review) | Structured FM portal emails — Verisae, Bellrock, Greene King, and others | | General triage | Yes (via pipeline) | Non-portal email extraction and routing | | Classification only | No | Route and classify without job creation | | Batch classification | No | Up to 50 emails per batch | Portal emails are routed by sender before classification. If the sender matches a known portal, the email goes directly to portal ingest, saving classification cost. Extraction then combines deterministic parsing with structured AI to resolve customers, sites, job details, and priority from the portal format. The default taxonomy includes ten categories, such as Technical Support and Maintenance, Health Safety and Compliance, Finance and Billing, and Delivery and Logistics. Tenants can apply custom taxonomies, including industry-specific category sets. System-level safety overrides apply across all tenants for certain classifications, such as health and safety signals. These overrides are part of the shared safety policy and stay enabled for every tenant. Portal and triage extraction use structured pipelines that combine pattern matching with targeted AI. They are optimised for high-volume, schema-driven output across varied email formats. Connie uses a conversational AI layer for reasoning, multi-turn dialogue, and cited answers. # Getting started and onboarding Source: https://docs.vh3.ai/faq/getting-started What you need to connect, how quickly you see value, and how sentinels are configured. ## Getting started and onboarding A typical onboarding needs: * A VH3 tenant (company ID) in VH3 Connect * Your VH3 API key, issued during onboarding * Initial historical job sync (CSV or API poller) * Optional: email routing, team and case setup Your Customer Success Manager will confirm the connection path, data volume, exclusions, and first use cases before sync starts. | Capability | Typical timeline | | ---------------------------------------- | -------------------------------------------------------------------------------------- | | Data flowing into the intelligence layer | Hours after sync starts | | Search and basic analytics | As soon as jobs are ingested | | Sentinels | Immediately — sentinels run against your full synced history from day one | | Full enrichment backfill | Depends on volume; large tenants may take up to 12 hours for tens of thousands of jobs | During onboarding, VH3 pre-configures your sentinels and syncs your full job history, so sentinels start detecting patterns against real data immediately. Noisy signals common to most field service operations are excluded from the start. You can refine thresholds and exclusions further with your CSM. Yes. Sentinel exclusions filter specific engineers, job types, customers, and locations from individual sentinels. Contact your CSM to configure exclusions for your tenant. BigChange is live in production with full ingestion, polling, enrichment, and entity resolution. Joblogic, Simpro, and others are on the integration roadmap. Ask VH3 for current partner pilot status. # Pricing Source: https://docs.vh3.ai/faq/pricing Tiers, visit-based pricing, and the difference between Core and Core+. ## Pricing VH3 AI uses a five-tier model from API through Core, Core+, Connect, and Enterprise, plus optional White Glove service tiers. Pricing is based on visit volume: the number of jobs enriched per month on graduated tiers. There are no per-seat fees. Plans and pricing are on [vh3.ai](https://vh3.ai). For a tailored projection, contact [hello@vh3.ai](mailto:hello@vh3.ai). **Core** includes the full intelligence layer: Connie, AI agents, the operational graph, semantic search, sentinels, and reports. **Core+** adds the native integrations layer: preconfigured connectors to third-party systems, user-based permissions mapping, and advanced workflow automation. It is the tier for operations that want structured data flows between VH3 AI and their wider tool stack. # Reports, notifications, and operations Source: https://docs.vh3.ai/faq/reports-and-notifications Available report types and how notifications are delivered. ## Reports, notifications, and operations VH3 AI supports daily operations reports, weekly summaries, account monthly reports, executive health checks, engineer performance, site health, customer intelligence, and sentinel digests. Reports draw from the same intelligence layer as Connie, discovery, and sentinels. Notifications can appear in VH3 Connect, email, and deep links into specific surfaces such as a sentinel board, report, case, or job briefing. Automations can also route notifications to Slack, Teams, WhatsApp, or connected systems through n8n. # Security and API keys Source: https://docs.vh3.ai/faq/security-and-api-keys Credentials, AI usage, and PII handling. ## Security and API keys Each company receives a company ID and a VH3 API key during onboarding. Admin users can generate and manage API keys from the VH3 Connect dashboard. The key is issued by VH3 and scopes access to your organisation. For intelligence endpoints, pass the API key alongside your company ID in the request body. For BigChange proxy endpoints, send it in the `X-API-Key` header. For interactive apps, users log in with email and password and all client calls use a short-lived JWT — no API key in client-side code. See [Authentication](/authentication) for exact request shapes and examples. Sentinel detection uses structured analytics on the operational model, keeping AI cost near zero at the watch layer. When a sentinel triggers, the result can be enriched with an AI-generated narrative so downstream agents and automations have context. Connie and email enrichment use LLMs where configured. Enrichment pipelines normalise and, where appropriate, strip PII from text destined for semantic search. Contact records in the platform may hold PII for operational matching and are accessed only through authenticated VH3 surfaces. For contractual detail on data residency and processing, ask for your data processing agreement. # Sentinels Source: https://docs.vh3.ai/faq/sentinels How sentinels work, severity levels, and false positive handling. ## Sentinels 24/7 automated monitors on engineer performance, customer risk, SLA clusters, and commercial signals. They run immediately against your full job history from day one — no warm-up period, no waiting for data to accumulate. They alert when thresholds are breached, not on every minor fluctuation, keeping the noise low and the signal meaningful. Sentinels prioritise attention. They give the ops manager a daily or weekly list of the patterns that merit human review, so the team can spend less time scanning jobs and more time deciding what to do. Thresholds are calibrated during onboarding to minimise noise. You can tune sensitivity per sentinel and apply exclusions for training roles, contractors, or entities that are not relevant to a particular signal. | Level | Meaning | Suggested action | | -------- | ----------------------- | ---------------- | | Critical | Significant risk | Same-day review | | Warning | Negative trend | Within 48 hours | | Info | Heads-up or opportunity | Weekly digest | Severity levels are fully configurable per sentinel. The consistency of levels is what enables deterministic, programmatic actions downstream: automations route Critical alerts to Slack immediately, open a case, or notify an account manager, all based on severity alone. Sentinels also monitor their own threshold performance and suggest adjustments when a setting is generating too much noise or missing signals. Yes. Customer-oriented alerts include the customer name and reference so you can look up the account in BigChange immediately. # Troubleshooting and support Source: https://docs.vh3.ai/faq/troubleshooting Common issues with API keys, sentinels, and email routing, plus who to contact. ## Troubleshooting and support 1. Your company ID matches the VH3 tenant issued at onboarding 2. The API key is your VH3 API key, issued during onboarding 3. You are calling `https://api.vh3connect.io` 4. The key has not been rotated without updating your integration Contact your CSM or [support@vh3.ai](mailto:support@vh3.ai) if none of the above resolves the issue. Confirm that jobs have finished syncing. Sentinels start once data is in place. If your sync is complete and nothing is triggering, check whether exclusion filters or thresholds are removing too much of the signal. Your CSM can inspect the sentinel configuration for your tenant. Classification alone routes and labels the email. Job creation requires the configured portal ingest or triage pipeline. If you are using n8n, check that the automation calls the ingest step after classification. Contact your CSM to verify the pipeline for your tenant. Your Customer Success Manager for onboarding, keys, and sentinel tuning, or [support@vh3connect.io](mailto:support@vh3connect.io) for general support. # VH3 Connect and developer tools Source: https://docs.vh3.ai/faq/vh3-connect VH3 Connect as a product and the generative interface component toolkit. ## VH3 Connect and developer tools VH3 Connect is the managed application built on the VH3 AI intelligence layer. It is where operators use Connie, review reports, manage cases, configure parts of the platform, and work with the intelligence layer through a ready-made interface. VH3 AI ships a toolkit of typed interface components for developers building on the intelligence layer: investigation cards, job detail views, SLA gauges, maps, report sections, and more. These components map directly to the structured JSON that Connie and other tools return, so a developer can move from API response to rendered interface quickly. This is a development toolkit for custom applications, partner integrations, and embedded surfaces. It is separate from VH3 Connect as a product. # What is VH3 AI? Source: https://docs.vh3.ai/faq/what-is-vh3-ai What VH3 AI is, how it differs from your FMS, and what is included. ## What is VH3 AI? VH3 AI is the intelligence layer for a field service operation. It ingests job data from field service management systems, enriches each record with structured analysis, connects jobs to customers, engineers, sites, outcomes, and history, then makes that picture available through Connie, reports, sentinels, search, and API tools. The platform is built around field service work: engineers, customers, outcomes, SLAs, first-visit fix, and repeat failures. Every record is mapped into a structured operational model that compounds with each new job. Your FMS remains the system of record for scheduling, worksheets, and day-to-day job execution. VH3 AI reads and analyses that data, plus email and optional workflows, to surface patterns, risks, and opportunities, without replacing dispatch or job creation in BigChange. | Product | Role | | ------------------------------- | --------------------------------------------------------------------------------------------- | | VH3 Connect | Customer-facing web app — Connie, reports, triage queue, dashboards, teams, and cases | | Connie | Conversational agent with tools over your full operational data | | Sentinels | Automated 24/7 monitors for engineer, site, customer, and commercial signals | | Email triage and portal ingest | Classify and route email; structured FM portal emails into the job pipeline | | Case management | Incidents, investigations, audits — with participants, linked records, and activity timelines | | Generative interface components | Typed components rendered from agent tool responses, for fast custom development | Synthetic Operations Capacity is the extra operating capacity created when AI prepares work and people make the decision. Sentinels watch for patterns, Connie explains what is happening, cases hold the evidence, and dynamic teams own the follow-through. A practical example: a sentinel detects repeat visits at a customer site, a case opens with the linked jobs, Connie drafts the brief, and the coordinator arrives to reviewed work with evidence attached. Detection runs at near-zero AI cost. Enrichment and synthesis use AI where reasoning and narrative add genuine value. # The 2027 blueprint Source: https://docs.vh3.ai/guides/2027-blueprint How field service organisations can turn operational knowledge into tools, automations, and intelligence they own # The 2027 blueprint Field service organisations are entering a period where software capability matters as much as fleet size, engineer coverage, and account relationships. The change is practical. A small team with the right foundation can now build reports, automations, internal tools, and AI-assisted workflows in days. Work that once required a development team, a data engineering function, and months of integration can increasingly be assembled around the systems and knowledge the business already has. The competitive gap is starting to form around that capability. The strongest operators will be the ones that can turn their own operational knowledge into useful tools quickly: a customer risk report before the QBR, a briefing that follows a specific job type, an alert that catches a quiet account before it becomes a churn risk, a workflow that removes a recurring manual step from dispatch. This guide explains what that capability looks like, who should own it, and how VH3 AI helps your team build on top of the intelligence already inside your operation. ## Why this matters now Field service businesses have always adapted their tools around the work. Spreadsheets, exports, inbox rules, shared folders, whiteboards, WhatsApp groups, and local reporting habits all exist because every operation has details that generic products miss. The difference in 2026 is that those local adaptations can become real software. AI coding assistants, workflow automation, connected APIs, and prepared operational data have made lightweight internal tools much easier to create and maintain. Every contractor now needs a practical software capability inside the operating model. Teams that build it can answer questions faster, make account risks visible sooner, brief engineers with better context, and remove manual coordination from work that happens every week. Customers are moving in the same direction. FM managers, housing associations, retail heads, and facilities directors increasingly expect evidence: structured reports, performance data, automated updates, and clear explanations of what happened across the work. They notice the difference between a contractor that can provide that picture and one that still has to assemble it manually. The important shift is ownership. A vendor can provide a platform, integrations, templates, and support. The business still owns the operational knowledge: how job types map to commercial reality, which customer patterns matter, which exceptions are routine, and where the friction actually sits between dispatch, delivery, and billing. The 2027-ready organisation treats that knowledge as a capability to develop. ## The new operating capability The building blocks that were once reserved for large vendors are now available to smaller operators: strong AI models, workflow automation platforms, coding assistants, API-first software, and documentation that AI tools can read directly. The remaining advantage is operational knowledge. Your team knows how engineers describe faults, which account signals usually precede a complaint, where a job type name hides multiple kinds of work, and which customer relationships need careful handling. That knowledge is the raw material for useful intelligence. A modern field service operation needs four connected capabilities: * **Prepared operational data.** Jobs, customers, sites, engineers, outcomes, and history connected into a model that can be searched, analysed, and used by agents. * **Reusable workflows.** Repeated manual work turned into automations that route the right information to the right team at the right time. * **Internal tools.** Lightweight dashboards, forms, briefings, and reports built around how your operation actually runs. * **Agent-ready context.** Coding assistants and AI agents given enough platform knowledge to build on VH3 AI safely and correctly. VH3 AI provides the foundation for the first capability and gives your team the surfaces to build the other three. ## The field intelligence lead Most teams can begin with one operationally fluent person who learns the tools, connects the right data, and turns repeated manual work into reusable workflows. This person might be a new hire. They might be an account manager who already thinks in reports, a field engineer who keeps spotting better ways to work, or an operations coordinator who has been building unofficial spreadsheets and automations for years. Their background matters less than their proximity to the work. Their role is to bridge the operation and the tooling: * Find recurring manual work that can be automated. * Turn common questions into reports, dashboards, and briefings. * Help managers express operational rules clearly enough for tools to act on them. * Maintain the connection between how the business really works and what the software is doing. * Keep learning as AI coding tools, automations, and platform APIs improve. There is a learning curve at the start. The tools are new, and the mental model is different from buying a finished product. The value compounds once the first few workflows are running. Every automation, report, and internal tool reduces the load on the rest of the business and gives the next project a better starting point. For many organisations, this becomes a new operating role: the field intelligence lead. ## The four-part toolkit The path to an intelligent, automated field service operation starts with a small set of tools used together. **VH3 AI.** The intelligence foundation. Your job history, customer relationships, engineer performance, fault patterns, reports, sentinels, and conversational AI all draw from the same prepared operational layer. Your team connects it, configures it, and builds from the output. **Workflow automation.** n8n and similar platforms let your team connect VH3 AI to email, Slack, Teams, WhatsApp, Xero, CRM tools, spreadsheets, and other systems. The VH3 AI n8n node gives builders pre-built operations for jobs, contacts, resources, intelligence feeds, and reports. **AI coding assistants.** Cursor, Claude Code, and similar tools make lightweight internal software much easier to produce. With the VH3 AI starter context in place, a builder can ask for a dashboard, a small internal app, a report generator, or a workflow helper that uses the platform correctly. **Agent starter kits.** The MCP server, AGENTS.md file, Cursor rules, Claude Project instructions, and skills give AI tools the context they need to work with VH3 AI correctly. They reduce the setup work and help the assistant understand the APIs, domain model, and safe patterns before it starts building. Together, these tools let one capable operator build useful software around the way your organisation already works. ## What VH3 AI provides from day one VH3 AI gives your team a foundation that would otherwise take years to assemble. From day one, the platform connects to your FMS, reads your job history, and understands what each record means: engineer notes, outcomes, customer context, and the links between jobs, sites, engineers, and equipment. Reports, sentinels, and Connie all read from the same prepared picture. Your team, automations, and agents build on that output through the API, documentation, and starter kits. That preparation matters because field service work is harder than simple reporting. A repeat fault at the same site should be visible even when engineers describe it differently. Account risk should surface before the complaint arrives. Historical data should stay usable as job types, worksheets, and operating habits change over time. VH3 AI handles that so your team can focus on operational questions: * Which sites are creating repeat visits? * Which accounts need attention before the next review? * Which engineers need a better pre-visit briefing? * Which manual updates can move automatically? * Which report should exist for this contract, region, or job type? The platform is the starting point. The advantage comes from what your team builds on top of it. ## Building capability, not just buying tools Traditional procurement starts with a product search. The team finds vendors, compares feature lists, negotiates a contract, and then adapts the operation around the chosen product. The capability model starts with the operation. The team asks what repeated work should disappear, what questions should be answerable, what risks should surface sooner, and what customers should receive automatically. Then it uses VH3 AI, automations, and agent-assisted building to create the missing pieces. Software buying still matters. Mature systems of record, accounting platforms, CRM tools, and communication products remain part of the stack. The capability sits above and between them, joining those systems together around the work. Useful first projects are usually small: * A weekly account brief that follows the structure your contracts team already uses. * A pre-visit message for a specific class of repeat fault. * A sentinel that opens a case when a risk pattern crosses a threshold. * A dashboard for Monday operations review. * A workflow that sends the right evidence to the right team when a customer escalates. The measure of success is practical: faster answers, earlier action, better evidence, and less manual coordination. ## What VH3 AI commits to VH3 AI is built as a harness for field service intelligence. We add capabilities, expand the API surface, deepen integrations, and evolve the intelligence layer continuously. The agent kits, MCP server, n8n node, SDK, documentation, and API are designed to make the platform accessible to your team and to the AI tools they use. When model capabilities improve, your organisation can use them against the same prepared operational context. When new integrations become available, they connect to the same foundation. The automations and tools you build are yours. The intelligence layer feeds them and keeps the operational context current. If you change workflow tools, the foundation stays. If you add or change field systems, the layer reconnects. The knowledge your organisation builds remains part of your operating capability. ## Where to start Start with a focused first step. Connect your operation to the intelligence layer and run a discovery sprint on recent history. Use the output to see what your data already contains: repeat patterns, customer risks, fault categories, engineer signals, and the questions the operation can answer immediately. Then appoint the person who will own the first set of improvements. Give them one workflow, one report, or one operational question to solve. Keep the scope small enough to ship quickly and useful enough that the team feels the change. Within the first 30 days, aim for one working loop: intelligence produced from your data, routed to the right team, used in a real decision, and improved from feedback. That is how the capability starts to compound. Connect your operation and see what the intelligence layer produces on your own data. Give any AI coding assistant immediate fluency in the VH3 AI platform. The VH3 AI node, pre-built templates, and the automation path from intelligence to action. APIs, coding agents, and custom surfaces built on the intelligence foundation. How the intelligence layer prepares your operational data before any question is asked. If your operation runs on BigChange, start here. # Agent observability Source: https://docs.vh3.ai/guides/agent-observability Why evidenced tool use matters when AI agents run real operations, and how VH3 AI surfaces provenance # Agent observability Non-deterministic systems are now part of running a field service business: routing assistants, diagnostic copilots, account briefings, and workflow agents that decide which API to call. They are fallible, like people, though often faster and more consistent on repetitive analysis. The operational mistake is treating the **final message** as the record. You need to see **where the data came from**, **which tools ran**, and **what they returned** before you act on a recommendation, forward a briefing to a client, or open a case. VH3 AI's flagship agent: long-running context, tool harness, and cited answers. ## The trust model | Approach | What the user sees | Risk | | ------------------- | ------------------------------------------------- | ---------------------------------------------- | | **Black-box chat** | A paragraph of confident prose | No audit trail; hallucinated numbers look real | | **Dashboard only** | Charts without narrative | Context and "why" live in someone's head | | **Evidenced agent** | Answer plus structured tool results and citations | Reviewable, replayable, UI-friendly | VH3 AI is built for the third row. Connie (and the same patterns on the API) returns: 1. **Natural language** for the human (headline, tables, next steps). 2. **`toolsUsed`** so you know which capabilities were invoked. 3. **`toolCallOutputs`** with the structured payload from each tool in that turn. 4. **`usage`** so token cost is visible on your provider account (BYOK-friendly). 5. **Diagnostic blocks** (when applicable) explaining how opening context was assembled. The assistant text is the **interpretation**. The tool outputs are the **evidence**. ## Why this matters in field service Operational decisions have consequences: dispatch changes, client calls, SLA credits, engineer callbacks, compliance sign-off. An agent that says "completion rate is down 12%" without traceability is unusable in a dispute. An agent that shows the aggregation window, the metric definition, and the underlying job references is **operations-grade**. The same applies to **investigations** and **customer summaries**: the value is not only the headline ("roofing jobs are stalling at quote stage") but the **jobs cited**, the **confidence** stated, and the ability to open those records in your own UI. Example: before an account manager tells a client that SLA completion fell last month, they should be able to see the aggregation window, excluded job types, and the job references behind the percentage. ## What the API returns On [`POST /connie/chat`](/api-reference/connie), a typical successful turn includes: | Field | Purpose | | ----------------- | ----------------------------------------------------------------------------------- | | `response` | Markdown answer for the user | | `sessionId` | Thread identifier for follow-ups | | `toolsUsed` | Ordered list of tool names executed this turn | | `toolCallOutputs` | Array of `{ toolName, toolUseId, output }` with full structured results | | `usage` | `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheCreationTokens` | | `route` | How the message was classified (e.g. simple vs full agent), when routing is enabled | | `summaryContext` | How customer opening context was built (server-enriched vs client fallback) | | `preseedContext` | How company operating rules were loaded | Example shape (abbreviated): ```json theme={null} { "sessionId": "session-abc-123", "response": "Last week you completed **218** jobs, up from **195** the prior week...", "toolsUsed": ["jobs_aggregate"], "toolCallOutputs": [ { "toolName": "jobs_aggregate", "toolUseId": "toolu_01...", "output": { "total": 218, "compareTo": { "total": 195, "deltaPercent": 11.8 } } } ], "usage": { "inputTokens": 4200, "outputTokens": 380, "cacheReadTokens": 3100, "cacheCreationTokens": 0 } } ``` Your application can render `toolCallOutputs` as tables, trend cards, or job lists **without parsing the markdown**. `toolCallOutputs` is additive. Existing integrations that only read `response` keep working. New UIs should treat structured outputs as the source of truth for numbers and lists. ## Evidence inside tool results Different tools expose different levels of provenance: ### Aggregations and feeds `jobs_aggregate`, `job_feed`, and related tools return **counts, groups, and rows** with labels suitable for display. Connie is instructed to prefer correct **time axes** for field work (actual start/end vs planned vs created) and to note partial periods when comparing weeks. ### Search and precedent Search tools return **hits linked to operational records**, not disconnected chunks. Your UI can show reference, customer, site, and outcome snippets from `output` while Connie summarises in prose. On the **Connie agent path only**, `search_outcomes` and `search_intake` hits are returned as a shortened result set optimised for chat. The REST `POST /search/outcomes` endpoint still returns the full search API response with all indexed fields for your own UI or downstream tools. Compact field set on the Connie path: | Field | Role | | --------------------------------------------- | -------------------------------------------------- | | `jobRef` | Job reference for citations and drill-down | | `contactName` | Customer/site label as shown on the job | | `contactId` | Chaining to `contact_snapshot`, `job_detail`, etc. | | `summary` | Plain-language outcome/intake summary | | `actualStartAt` / `actualEndAt` | Visit timing (outcomes) | | `createdAt` | Creation time (intake, when present) | | `subVertical`, `status`, `result`, `score` | Classification and relevance | | `jobId`, `typeId`, `categoryId`, `resourceId` | IDs for follow-up tools | Verbose blobs (`text`, `companyId`) and opaque keys (`siteKey`) are omitted on the agent path to keep chat turns compact. ### Investigation Investigation-style tools return a **headline**, **confidence**, **recommendations**, and an **evidence** list with job references. That is the pattern for "why" questions: synthesis with explicit citations and reviewable evidence. ### Customer knowledge Customer Summary tools return **sectioned knowledge** (overview, patterns, risk, and related themes). `summaryContext` on the chat response tells you whether the opening block was server-enriched with recent jobs or supplied by the client. ## Tool recall across a session Substantive tool results in a session can be **persisted and recalled** so later turns can reuse earlier evidence. From an observability perspective, that means: * Turn 1: investigation on a customer issue → evidence stored. * Turn 3: "show me that table again" → recall or re-fetch with continuity. You still inspect `toolsUsed` on each turn to see whether the agent re-ran a tool or answered from session context. ## Generative UI and operational dashboards VH3 Connect and integrator apps can map `toolCallOutputs` to **typed UI components** (metrics, job lists, investigation panels, report sections). The contract is: **one tool invocation → one serialisable payload → one renderer**. That pattern matters because: * **Numbers in the UI** come from JSON, not from regex on markdown. * **Drill-down** uses the same `output` the agent saw. * **Accessibility and export** (PDF, email) can reuse structured data. Your app can render structured outputs without exposing internal field names to end users. **Structured outputs are first-class** in the API contract. See [Generative UI](/guides/generative-ui) for the reference React component library that renders these payloads into investigation cards, gauges, reports, and job detail views. ## Routing and cost transparency When message classification is enabled, `route` describes how the message was classified before the full agent ran. Simple acknowledgements may skip the tool loop entirely; analytical questions use the full set of connected capabilities. That is observability for **cost and behaviour**, not only for correctness. Combine `route` with `usage` to answer: "Was this an expensive turn? Did we need tools at all?" ## Practices for reviewers and builders In internal tools, render `toolCallOutputs` beneath or beside the assistant message. Hide only in consumer-facing views where space is tight, with a "View source data" affordance. API keys belong server-side. Log `sessionId`, `toolsUsed`, and redacted outputs in your own audit store if required for compliance. Investigation and narrative reports take longer than discovery. Observability includes **latency**: if `toolsUsed` is empty and `response` is vague, check for timeout or guardrail routing. For high-stakes checks, cross-call [`POST /search/outcomes`](/api-reference/search) or job feed endpoints with the same scope Connie used. Same substrate, deterministic replay. ## Humans and agents together Agents will not replace accountability. They **compress time to insight** when the harness is sound: prepared data, correct tools, cited results, and transparent usage. Observability is how you keep them **accountable** as you deploy them into dispatch, account management, and leadership workflows. Fallibility does not disappear. It becomes **visible**, which is the difference between a demo and production. ## Related Capabilities, sessions, and efficient use of the layer. Deterministic search and entity resolution for verification. Prepared operational memory vs classic retrieval. Full request and response fields. # AI Act and engineer data Source: https://docs.vh3.ai/guides/ai-act-and-engineer-data How VH3 AI handles engineer-level performance data, what your obligations are as the deployer, and a notice template you can adapt # AI Act and engineer data This guide is for **operations leaders, DPOs, and works-council representatives** at field-service businesses using VH3 AI in the EU or UK. It explains how the platform handles data about your engineers, what we have built in to keep that handling defensible, and the parts that remain your responsibility under the EU AI Act and GDPR. Drop-in Markdown you can adapt and publish on your intranet. ## 1. How responsibility splits VH3 AI Ltd builds and supplies the platform. Your organisation operates it inside your service business and decides which users see what. Under the AI Act, that split has a name: | Role | Who | What that means in practice | | ---------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Provider** of the foundation AI models | Anthropic, Google | Train and supply the underlying language models. Conformity obligations sit with them. | | **Provider** of the operational platform | VH3 AI Ltd | We build the tools, system prompts, evaluation, and guardrails around those models for field service. | | **Deployer** | Your organisation | You decide who can ask what, in what context, and how outputs feed into decisions. The transparency and human-oversight duties for your workforce sit with you. | We design for the deployer obligations on your side — but we do not perform them on your behalf. The notice and oversight steps in section 4 are yours to operate. ## 2. Why engineer-level data is treated differently Most of what VH3 AI processes is operational data about jobs, sites, customers, and equipment. A subset is about named field engineers: who attended a job, when it started and finished, what the outcome was. The AI Act treats AI systems that **monitor and evaluate the performance of workers** as high-risk (Annex III, Category 4). That classification triggers obligations whether you call the system "monitoring" or not. Practical signals that matter: * Reports that name individual engineers alongside completion rate, on-time percentage, or job volume. * Sentinels that flag a specific engineer for review. * Connie answers that compare named engineers or summarise a single engineer's recent work. All three exist in the platform because they are useful for service-quality management. They also need to be handled with care. ## 3. What VH3 AI does at the platform level These are the design choices we have made so that the high-risk surfaces stay defensible. None of them remove your deployer obligations, but they reduce the operational and legal risk of using the features. Engineer dashboards and report sections present individual metrics (completion rate, on-time percentage, job count) separately. The platform does not synthesise a single "engineer quality" number. Connie is instructed to answer operational questions about engineers and to decline questions framed as HR decision support — for example, "who should I put on a performance improvement plan?" or "rank these engineers for promotion." The assistant is instructed not to infer emotional state, motivation, attitude, or mental health from job notes or operational data. Sentiment classification on inbound email is suppressed for internal employee-to-employee communications. Engineer-category sentinel triggers and the engineer performance tool responses both carry an operational-metrics disclaimer. Connie surfaces this caveat when she presents the data. You can exclude individuals (resident engineers, subcontractors, anyone you choose) from engineer sentinels. See [Sentinels](/guides/sentinels) for the exclusion model. Sentinel triggers create [cases](/guides/users-and-teams) for review. They do not write back to HR systems or trigger employment actions automatically. ## 4. What sits with you as the deployer Four things stay your responsibility, regardless of what we build at the platform level. Under GDPR Articles 13 and 14, your engineers should be told that their operational performance data is processed by an AI system and what it is used for. The template in section 5 gives you a starting point. AI outputs should not be the sole basis for any employment decision. Pair them with direct observation and conversation. Note this in your performance-review process. Decide which engineers fall inside the scope of monitoring, and which (typically resident engineers and subcontractors) do not. Use the exclusion controls to reflect that decision. Decide which roles in your organisation can ask engineer-specific questions. Connie session history and operational data retention should align with your wider employment-data retention policy. Speak to your CSM if you need help configuring this. ## 5. Sample engineer notice template A Markdown notice you can adapt and publish to your intranet or staff handbook. Replace each `{{PLACEHOLDER}}` with your own value, review with your DPO, then issue before AI-derived performance data is used in a review or coaching conversation. ```markdown theme={null} # How we use AI to support service-quality management **Issued by:** {{COMPANY_NAME}} **Date:** {{DATE}} **Last reviewed by:** {{DPO_OR_HR_CONTACT}} ## What this is {{COMPANY_NAME}} uses an AI-powered operational intelligence platform (VH3 AI) to help us understand and improve how our field service operation runs. This notice explains, in plain terms, what data about you flows through the platform and how we use it. ## What data about you is processed The platform reads operational data that already exists in our job management system: - Your name and engineer ID. - The jobs you have been assigned and have completed. - For each job: customer, site, planned and actual times, outcome status, and free-text notes added to the job record. - Aggregations derived from the above (your completion rate, on-time rate, job volume over a given period). The platform does **not** access your personal email, calendar, or any communications outside the job system. It does not process biometric or wellbeing data. It does not infer your emotional state or motivation from job notes. It does not produce a single "engineer quality" score. ## Why we process this data We rely on our legitimate interest in monitoring and improving the service we provide to our customers, and in supporting our engineers with timely coaching when patterns suggest it (GDPR Article 6(1)(f)). {{ADJUST IF YOU RELY ON A DIFFERENT BASIS OR HAVE A WORKS-COUNCIL AGREEMENT COVERING THIS PROCESSING.}} ## How the AI is used - **Operational dashboards and reports.** Managers and coordinators can see team-level and engineer-level metrics over time. - **Sentinels.** Background checks flag patterns such as a run of jobs completed with issues. A manager reviews any flag before raising it with you. - **Assistant (Connie).** Managers and coordinators can ask the platform questions about the operation. It is instructed to present operational metrics only and to decline questions framed as employment recommendations. ## Decisions about your employment AI-generated outputs are not the sole basis for any employment decision. Decisions about your performance, role, training, or any disciplinary matter remain decisions made by your manager (and, where appropriate, HR) on the basis of a full picture, including direct observation and your right to provide context. You have the right not to be subject to a decision based solely on automated processing (GDPR Article 22). We do not make such decisions about you using this platform. ## Your rights You have the right to: - Access the operational data we hold about you (Article 15). - Have inaccurate data corrected (Article 16). - Object to processing based on legitimate interests (Article 21). - Lodge a complaint with {{COUNTRY_DPA_NAME}}. To exercise any of these rights, please contact {{DPO_OR_HR_CONTACT}}. ## Retention We retain operational job data for {{RETENTION_PERIOD}}. AI assistant conversation history is retained for {{ASSISTANT_RETENTION_PERIOD}}. ## Third parties The platform is operated by VH3 AI Ltd as our processor under a data processing agreement. It uses foundation AI models from {{LIST_PROVIDERS_IN_USE}} to generate analytical responses. No data is sold to third parties or used to train foundation models. ## Updates If we materially change how we use the platform, we will issue an updated version of this notice. You can find the current version at {{INTERNAL_LINK}}. {{SIGNATORY_NAME}} {{SIGNATORY_ROLE}} ``` ## 6. Checklist before you issue the notice * [ ] DPO or legal counsel review complete. * [ ] All placeholders replaced. * [ ] Lawful basis appropriate for your jurisdiction and any applicable collective agreement. * [ ] Retention periods aligned with your wider data retention policy. * [ ] Internal page set up where engineers can re-read the notice at any time. * [ ] Process in place to handle Article 15, 16, and 21 requests. * [ ] Works-council or employee-representative consultation completed where required. ## Related The monitoring layer and the exclusion controls. Access, roles, and how cases route to the right people. The assistant and the compliance boundaries built into it. Wider governance and IT-checklist view. # AI you can check Source: https://docs.vh3.ai/guides/ai-you-can-check Why traceability matters more than confidence in field service operations, and how VH3 AI builds evidence into every answer # AI you can check There is a version of AI in field service that sounds very useful. Ask it how an account is performing. It produces a confident paragraph: volume is up, first-time fix is strong, no SLA concerns flagged. The paragraph is well written. It sounds authoritative. Nobody in the room knows where the numbers came from. That is the version to be cautious about. ## The gap between the number and the truth Field service operations generate a lot of apparent certainty. The FMS says first-time fix is 77%. That number is real. It is also incomplete. Jobs marked `completedOk` include visits where the engineer resolved the presenting symptom but not the underlying fault. Within 30 days, the same site books again, for the same asset, with the same complaint. That visit appears in the records as a new job — not as evidence that the first visit did not actually fix anything. Adjust for same-fault return visits within 30 days and the first-time fix rate at the same operation might be closer to 68%. Both numbers are "correct" by the definition used to calculate them. Only one is operationally useful. The same pattern appears across most operational metrics. A "Pricing Required" status looks like progress. It might be a quote black hole — work scoped, priced never submitted, or submitted and ignored, with no chase mechanism. An overdue compliance job does not appear on any invoice. It does not show up on any dashboard unless someone specifically builds a query for it. A completed job is not always a resolved fault. An engineer who clears a symptom, closes the job, and moves to the next call is doing their best with the time available — but the operational record will not separate "resolved" from "cleared for now." None of this is a technology problem. It is a characteristic of operational data. Every field service business that runs a serious account review eventually learns to cross-reference, question the source, and build confidence through triangulation, not through a single number. ## Why AI does not automatically solve this AI handles operational data the same way that data actually is: incomplete, inconsistently recorded, and optimised by the people who produced it for the immediate task at hand, not for downstream analysis. A model that is given the raw job record will produce an answer consistent with that record. If the record says `completedOk`, the model has no reason to look for the follow-on visit two weeks later. If the engineer wrote "issue resolved, system operational," the model will reflect that. The problem is not model intelligence. It is what was in the source data, and whether the system was designed to cross-reference it. A clean paragraph of analysis, produced from an incomplete input, is a confident wrong answer. The right question to ask of any AI working inside your operation is not "does this sound plausible?" It is: "what records did this come from, and can I check them?" ## What checkable AI looks like in practice Checkable AI does not mean slow AI. It means AI that carries its evidence. **Citations in answers.** When Connie answers "which engineers had the most repeat visits last month?", the answer includes the job references behind the aggregation. The operations manager can open those jobs and verify the count, check the dates, and confirm the scope. The answer is not just a number. It is a number with a paper trail. **Defined scope.** A report that says "first-time fix rate was 76% last month" should state the aggregation window, the job types included, and whether cancelled or aborted jobs were counted. Without that, the same metric will produce different numbers from different tools, and the operations team spends review meetings arguing about which number is right rather than what to do about it. **Deterministic signals.** Sentinels in VH3 AI run as database checks, not model inference. When a sentinel flags that a customer has had three repeat visits in 60 days, that is a query result, not a model judgement. It can be reproduced. It can be audited. If the threshold is wrong, it can be adjusted. The signal has a definition behind it. **Human review inside the workflow.** Investigations carry the jobs, evidence, and basis in the output — not just the conclusion. A case opened by a sentinel includes the linked job records, the timeline, and the flagging criterion. The account manager who owns the case can look at the evidence and decide whether it is worth acting on. The AI has done the work of surfacing and assembling; the human makes the call. **Visible model usage.** With BYOK, the token spend on Connie and agent sessions is visible on the customer's own model provider account. The model used, the input and output token counts, and the cost are auditable, not bundled into a subscription line item. That gives you transparency about what the model was asked to do, as well as cost control. ## The operational case for traceability An account manager who walks into a customer review with a report produced by an AI system has two choices. They can present the headline numbers and hope the customer does not ask how they were calculated. Or they can walk in with the report, the underlying job references, the evidence behind each finding, and the ability to answer "show me the jobs that drove that number" in real time. The second version builds a different kind of relationship. The same applies internally. An operations director who receives a sentinel alert about engineer performance has to decide whether to act on it. If the alert is a paragraph of analysis with no traceable source, acting on it affects a person based on something unverifiable. If the alert includes the jobs, the dates, the pattern definition, and the threshold, it is a basis for a conversation — not a verdict. Operational AI that carries its evidence makes better conversations possible. It does not replace human judgment. It gives that judgment something solid to work from. ## How VH3 AI is built for this The design principle throughout VH3 AI is that the interpretation is what the AI produces, and the evidence is what the AI carries. Connie's answers include `toolsUsed` and `toolCallOutputs` — the structured results from every tool call in that turn, alongside the natural language response. The assistant text is the synthesis. The tool outputs are the record. Investigation cards expose the jobs, sites, and engineers connected to each finding. SLA gauges show the aggregation window and the criteria. Report sections link to the operational records behind each metric. Sentinels are defined and adjustable. The threshold, the scope, and the frequency are set by the operations team, and the firing criteria are visible to any team member who wants to understand why something was surfaced. VH3 AI is built as operational software where every surface carries its evidence. Connie, investigations, sentinels, and reports all link back to job references, tool outputs, or defined criteria — because field service work has consequences. Dispatch decisions, compliance sign-off, engineer performance conversations, customer escalations, and SLA credits affect real people and real relationships. The AI that supports those decisions should make it easier to get them right, with evidence your team can verify before they act. Tool calls, data sources, cost, and handoffs — what the API returns with every Connie turn. How VH3 AI prepares operational context before any question is asked. How deterministic monitoring works and how to set thresholds your team trusts. How evidence becomes owned work with a defined next step. # VH3 AI for BigChange users Source: https://docs.vh3.ai/guides/bigchange How VH3 AI reads your BigChange history, connects your operation, and puts answers in front of your team # VH3 AI for BigChange users If your operation runs on BigChange, VH3 AI starts with the data your team already depends on: completed jobs, engineer visits, worksheets, customer records, job types, notes, and the shorthand your coordinators use every day. BigChange remains the system of record for dispatch, scheduling, job tracking, and worksheet capture. VH3 AI sits alongside it: reads your job history, connects every record to the right customer, site, and engineer, watches for patterns across thousands of jobs, and puts answers in front of your team before they go looking. Connect BigChange once and your operational history starts feeding search, sentinels, reports, Connie, and the workflows your team uses to follow through. ## We know what your data looks like We built VH3 AI on BigChange data from live field service operations before the product had a name. That matters because real operational data carries years of local decisions. Over years of operation, the shape of your data changes. Custom fields configured at go-live drift in meaning. Worksheet structures get updated and historical answers stop mapping cleanly to how the operation runs today. Contact hierarchies evolve. Job types get renamed or consolidated. The same underlying fault gets described differently by different engineers at different points in time. That is how field service operations actually run. VH3 AI has to understand the drift, resolve the entities, and keep historical records useful without changing the source system. We have processed hundreds of thousands of BigChange jobs across live customer operations. The enrichment pipeline was built around operational reality: messy notes, renamed job types, changing worksheet structures, and long-running customer histories. When your jobs land, VH3 AI extracts the fault type, structures the work performed, identifies equipment context, and links engineers, sites, customers, and history into one connected picture. ## Operational data quality over time Long-term intelligence needs a place to hold corrections, mappings, and operational interpretation above the raw API records. Timing data is particularly unreliable in mature operations: jobs that stayed open because of admin backlogs, completion timestamps that reflect paperwork processing time, SLA calculations distorted by open records that were never formally closed. A job type called "Reactive Maintenance" in 2021 and "Emergency Callout" in 2023 may be the same work. An open job from eighteen months ago may have been completed but never updated. BigChange correctly preserves what was recorded at the time. That immutability is valuable — and accurate long-term intelligence needs more on top of it. VH3 AI holds those corrections above the source system: resolved entity mappings, corrected timing data, unified job categories across historical periods, and open-job handling that reflects operational reality over administrative backlog. When those corrections live in a prepared operation, search, reports, sentinels, and Connie all read from the same reconciled picture — and the intelligence improves as your history grows. ## What building on BigChange data involves Dispatch, scheduling, job tracking, and worksheet capture are one engineering problem. Turning that data into useful intelligence — patterns spotted, precedents findable, risks flagged, briefs ready — is another. Any team that has attempted it directly knows the work involved. Data needs to be fetched, shaped, and normalised before it can be used analytically. Jobs need to be linked to engineers, sites, customers, and history. Similar faults need to be findable even when they were described differently. Patterns need to be watched continuously and routed to the people who own them. All of it has to stay coherent as the data grows and evolves. VH3 AI packages that foundation so your team starts with a prepared operation, ready to search, watch, and brief from day one. ## The right first step into AI for your operation Most organisations thinking about AI for field service are looking for a practical first step. They have heard pitches. They have seen demos. They are rightly cautious about committing to something that locks them into a vendor, requires a long implementation, or produces results six months from now that nobody is sure how to measure. The practical starting point is your own BigChange history. You connect your BigChange account. We process your history, build customer and job profiles, and connect the dots across jobs, engineers, sites, customers, and outcomes. Within hours, you have a working operational picture: job patterns structured, customer knowledge generated, sentinels monitoring your operation, reports running on schedule, and Connie ready to answer questions in plain English against your actual data. Sentinels watch continuously with near-zero AI cost at detection, so your team sees what changed without paying for a model call on every check. Connie's answers come with citations. The source of every number is traceable. Trust builds from evidence: job references, customer names, structured outputs, and reports your team can check. Start with one use case. The discovery sprint gives you a structured operational profile from recent history before you decide what to build next. ## What changes in day-to-day work The value shows up in ordinary operating rhythms: * The morning performance picture arrives before the standup. * A drifting customer account is flagged while there is still time to act. * Repeat visits and SLA clusters appear in sentinel digests during the month. * Engineers arrive on site with a briefing that includes relevant history and similar faults. * Account managers walk into reviews with a report built from the operational record. The same intelligence is available through the API for teams that want custom dashboards, automations, or partner-facing surfaces. New reports and workflows build on the prepared operation. If your stack changes later, your enriched history gives you a stable place to connect the next source system. If BigChange adds new useful fields, they can be ingested. If an acquisition brings another field system, VH3 AI can connect that history into the same picture. ## First week with your BigChange data A simple first-week loop helps the team see the value quickly: 1. Run one discovery search for a fault your team remembers well and inspect the top three precedents. 2. Open Connie on a real customer question and check the job references she cites. 3. Review the first sentinel digest and pick one finding to action. 4. Read the weekly or account report and compare it with the story your team already knows. 5. Open a case for one follow-through item if your tier includes cases and teams. See [Working with your operation](/guides/working-with-your-operation) for the broader operator playbook. ## Time to value Onboarding starts with a discovery sprint. We take a sample of your recent BigChange history and run it through the enrichment pipeline. Within a few days, you have a structured operational profile of your business: top fault categories, repeat failure patterns by site, engineer performance signals, customer risk flags, and the questions your data can answer today. The discovery sprint uses your data and produces an operational profile your team can inspect before a longer commitment. From there, full historical ingestion brings in your complete job history, typically two to three years. Live polling keeps your operation current as new jobs complete in BigChange. Enrichment compounds over time. The patterns that were invisible in raw exports become visible in the connected picture. Automation templates give your team useful workflows from day one: daily briefings, sentinel digest emails, Slack or Teams notifications when something crosses a threshold, report distribution, and more. They are running workflows that you extend when you are ready. ## What we support you with Our team understands BigChange operations from the inside. We know how to map your job types, your worksheet structures, your customer hierarchies, and your custom field configuration so the output is useful from day one — mapped, enriched, and ready to query. That initial configuration work is part of what you get. For automation and integrations, the pre-built n8n workflow templates give most operations a working foundation on day one. If your operation needs something different, we build it. We connect to the tools your team already uses: accounting, CRM, communication, scheduling. Those connections deepen the intelligence over time by bringing more operational context into the same picture. For teams that want to go further, the platform is fully open through the API. Your developers can query the prepared operation, call Connie programmatically, trigger reports, build custom dashboards, and connect the intelligence to any surface your team works from. The starter kits for coding agents, Cursor, and Claude give your technical staff a running start. We work closely with the operations we onboard so the platform becomes part of how the business runs — and your team can own it day to day. ## Related The full BigChange data surface available through VH3 AI: jobs, contacts, finance, worksheets, and more. How VH3 prepares your operational data before any question is asked. Watches your BigChange operation around the clock and surfaces patterns before they escalate. How to get the most from Connie, discovery, and sentinels day to day. The free n8n node and pre-built workflow templates for BigChange operations. For technical staff and developers: APIs, agents, and custom surfaces. # Building on the layer Source: https://docs.vh3.ai/guides/building-on-the-layer Citizen builders, coding agents, and integrations on a secure operational substrate # Building on the layer An operations manager routes a sentinel digest to Slack. A coordinator builds a workflow for engineer follow-ups. A developer opens Cursor and asks it to build an account review panel against the VH3 AI API. Each builder is working on the same prepared operational model. VH3 AI is designed as a secure operational substrate: * Jobs and relationships are enriched once and stored in infrastructure scoped to your organisation. * Fast discovery (search, similarity, entity resolution, customer knowledge sections) reads that model without an LLM. * Agents, reports, and automations read the same model when they need language and narrative. * Connected tools (email, calendar, CRM, storage, field systems) feed **entities back** into the same graph through managed sync and resolution. This guide is for **builders**: operations staff using no-code tools, and technical staff using Claude Code, Cursor, or similar coding agents. **Are you an operator or an IT lead?** Operators should start at [Working with your operation](/guides/working-with-your-operation); IT leads deploying internal apps should read [Deploying secure apps](/guides/deploying-secure-apps) for governance and auth patterns. This page focuses on builder workflows. How search, customer knowledge sections, and entity resolution work on the layer. ## What integrating AI should mean in field service | Maturity | What the business has | | -------------------- | ------------------------------------------------------------- | | **Level 1: Access** | Exports and dashboards; questions wait for manual analysis | | **Level 2: Ask** | Chat over files; answers are not durable or shared | | **Level 3: Model** | Persistent graph, enriched jobs, fast discovery, sentinels | | **Level 4: Operate** | Agents, automations, cases, custom apps on the same substrate | VH3 AI targets levels 3 and 4. Level 2 is where cost and trust break down: every session re-interprets raw text, and nothing belongs to the organisation in a structured form. **Data sovereignty** means your enriched operational intelligence is tenant-isolated, portable, and usable outside a single vendor UI. You can connect your own models (BYOK), your own automations, and your own applications. The platform fee covers the intelligence layer; agent token spend stays visible on your provider account. ## Three builder paths (same foundation) n8n, templates, Connie in Claude Projects. Solve local problems without a development queue. Cursor, Claude Code, MCP. Generate apps and integrations against a documented API. Direct API integration, custom UIs, partner solutions. Full control, full responsibility. All three paths call the **same APIs** and read the **same operational model**. Each builder works from the same resolved customers, jobs, sites, and engineers. One reason that holds: VH3 AI maintains a canonical domain model for field service. Every record that enters the platform, regardless of source system, is resolved into that model before it touches the graph. A job is a job. A customer is a customer. The model's schema is not exposed, but the contract it delivers is: consistent, resolved, connected entities at every endpoint. When you build an app or an automation on this layer, you inherit that consistency. See [The domain model](/intelligence-layer#the-domain-model-why-the-substrate-speaks-one-language) in the intelligence layer guide. ## The tool surface (at a glance) The substrate is only half the story. The other half is the tool surface that sits on top, the same tools Connie uses internally, also available to your agents, automations, and apps. | Class | Tools | What they do | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | **Discovery** (no LLM) | `/search/outcomes`, `/search/intake`, `/search/autocomplete`, `/search/summary-sections`, `/jobs/feed`, `/jobs/aggregate`, `/contacts/feed`, `/dashboard/snapshot`, `/weather/*` | Sub-second lookups: precedents, entity resolution, account hierarchies, KPIs | | **Monitoring** (no LLM at detection) | `/sentinels/run`, `/sentinels/digest`, `/sentinels/results` | 24/7 pattern detection on the graph | | **Synthesis, conversational** (BYOK) | `/connie/chat`, `/investigate` | Cited narrative, multi-step diagnosis | | **Synthesis, platform** (included) | `/briefings/*`, `/reports/generate` | Pre-visit briefings, scheduled report generation | | **Workflow** | `/cases/*`, `/teams/*`, `/users/*`, `/auth/*` | Cases, teams, users, JWT sessions for ownership and access | | **Ingest** | `/triage/classify`, `/ingest/email-portal`, native integrations | Inbound triage and structured extraction | This is the surface a coding agent or n8n workflow calls. Sentinels are how the platform notices things; discovery and synthesis are how it answers; cases and teams are how it follows through. The full inventory, with patterns and evaluation notes for AI agents reading the docs, is on [Platform tools](/guides/platform-tools). Every tool, what it does, when to reach for it, and the patterns that get the most out of them. Use this page if you are evaluating VH3 AI for a build. ## Connected tools and programmatic access Field service runs across more than one system. VH3 AI brings third-party tools into the same operational model so mail, calendar, CRM, storage, and field systems add useful context to the graph. ### Native connections (in the platform) [Native integrations](/native-integrations) are activated inside VH3 AI: OAuth handled for you, sync managed by the platform, health visible to admins. Typical categories: | Category | Examples | What flows into the layer | | ---------------- | -------------------------------------------------- | ------------------------------------------------ | | Field management | BigChange (live), others on roadmap | Jobs, engineers, customers, worksheets | | Communication | Gmail, Outlook, Slack, Teams, WhatsApp | Threads, alerts, context for briefings | | Scheduling | Google Calendar | Per-user availability and planning context | | CRM / finance | Pipedrive, Zoho, Xero, Stripe, Salesforce, HubSpot | Commercial context alongside operational history | | Storage / docs | Drive, OneDrive, Dropbox, PandaDoc | Documents linked to accounts and work | **Per-user connections** matter for agents tied to real people: an engineer's inbox and calendar, scoped to what they authorised, can inform briefings without exposing everyone's mail to the organisation. **Organisation-level connections** matter for shared systems: one Xero or Slack workspace, one CRM, available to automations and reporting across the team. ### Programmatic access (for your agents and apps) Everything the platform does internally is also available **programmatically**: * **REST API** for search, jobs feed, sentinels, reports, Connie, cases, teams, and backfill tasks. * **MCP server** so Claude Desktop, Cursor, and other MCP clients call the same tools Connie uses, with credentials handled server-side after JWT auth. * **n8n node** (community and PRO) for workflow builders who want operations-friendly automation without writing a backend. When email arrives or a calendar event is created, ingestion and **entity resolution** map people, domains, and addresses back to **contacts** in your model. That is how personal agents and shared automations stay aligned with operational truth across inboxes and calendars. Design automations so **fast endpoints** (search, autocomplete, sentinels, jobs feed) handle triggers and filters, and reserve Connie or investigate for steps that need narrative. Predictable latency and visible AI cost follow naturally. ## Operations builders (no-code and low-code) The citizen-builder pattern is how strong field service teams already work when they are not waiting on IT: * An operations manager routes a **sentinel digest** to Slack when SLA performance slips. * A contracts lead schedules an **account monthly report** to a client distribution list. * A service coordinator creates a workflow when **engineer-flagged follow-ups** spike for one customer. None of that requires a development team. It requires **templates**, **connectors**, and an intelligence layer that returns consistent, scoped data. **Starting points:** * [n8n node and templates](/n8n-node) * [Agent kits: n8n agents](/agent-kits/n8n-agents) * [Claude Projects for ops](/agent-kits/claude-projects) ## Coding agents on a secure substrate Tools such as **Claude Code** and **Cursor** work best when they are not guessing your domain. They need: 1. A **stable API contract** (OpenAPI, consistent field names). 2. **Guardrails** (which endpoint for which question, what never to expose to end users). 3. A **tenant boundary** (`company_id`, `api_key`, no cross-customer leakage). VH3 AI ships **Agent Starter Kits** for that: AGENTS.md, Cursor rules, MCP setup, and n8n prompts that encode field service routing (discovery vs synthesis vs sentinels). Drop-in configuration so coding agents use VH3 endpoints correctly from day one. ### What coding agents should build | Application | Discovery / data | Synthesis / action | | ------------------------- | -------------------------------------- | -------------------------------------------------------------------- | | Dispatch assist panel | `search/outcomes`, autocomplete | Optional Connie summary | | Customer 360 internal app | Jobs feed, customer summary by contact | Reports, investigate | | Slack ops agent | `sentinels/run` | Connie with citations ([observability](/guides/agent-observability)) | | Partner portal | Scoped search by `contact_id` | Branded report export | ### Safe patterns **Never call VH3 APIs from browser code.** Your `api_key` and `company_id` are server-side credentials. If they appear in a browser network request — even inside a fetch call in a React component or a bundled environment variable — they are visible to anyone who opens browser developer tools. Build a backend route that holds the credentials and proxies the call. The browser calls your backend; your backend calls VH3. This applies to every endpoint on `api:kP8T1CK7` and `api:YdihQNr3`. For browser-based apps, use [User Authentication (JWT)](/authentication#user-authentication) so users log in with email and password only, and no API key is ever involved in client code. **Never expose internal identifiers** in end-user interfaces: internal company, job, contact, resource, or linkage keys. Use names, references, and addresses in UI copy. Keep IDs in server-side calls only. **Contact-centric scoping.** Build navigation around customers (contacts). Places are addresses under that customer. Engineers are resources. This matches how account managers and dispatchers think. **Timeouts.** Discovery endpoints are typically sub-second. `investigate`, report generation with narrative, and Connie tool loops need longer HTTP timeouts (often 20 to 25 seconds). Agent kits document recommended values. ### MCP: intelligence without middleware The MCP server exposes tools such as search, investigate, sentinels, jobs feed, and reports. A coding agent can call operational discovery directly, then generate UI or workflow code around the responses. See [MCP setup](/agent-kits/mcp-setup). ## Customer knowledge your agents can rely on Builders should understand the **Customer Summary** knowledge object (see [Operational discovery](/guides/operational-discovery)): * Seven **modular sections**, each independently searchable and rankable. * **Refreshed** on a schedule or when job drift thresholds are met, so agents are not stuck with a one-off PDF. * **Injected** into Connie sessions together with recent jobs since generation, so conversations start with current context. Coding agents can call `POST /search/summary-sections` for thematic queries across accounts, or fetch a full brief per contact before rendering a custom account page. ## From signals to owned work AI integration fails when insight has nowhere to go. VH3 AI pairs **detection** with **ownership**: | Concept | Role | | ------------------------ | ------------------------------------------------------------------------------------------- | | **Sentinels** | Continuous pattern detection on the graph (no LLM at detection) | | **Discovery** | Fast precedent, entity, and knowledge-section lookup | | **Connie / investigate** | Cited synthesis and diagnostic narrative | | **Cases** | Multi-step operational work (escalation, complaint, follow-up) with status and participants | | **Teams** | Scoped groups for who owns which customers or regions | **Example flow:** 1. Sentinel flags repeat attendance for a contact. 2. Automation runs `search/outcomes` for similar faults on that account. 3. Case opened: "Third fire panel callout in six weeks" with jobs linked as items. 4. Regional team notified; Connie drafts engineer briefing for the next visit. Cases and teams are intentionally lightweight: enough structure to **close the loop** with status, participants, linked jobs, and ownership. * [Cases API](/api-reference/cases) * [Teams API](/api-reference/teams) ## Why the substrate makes coding agents viable Prepared context is what makes coding agents useful in field service. Each session can start from enriched jobs, resolved accounts, and linked history. VH3 AI front-loads **enrichment**, **multi-entity resolution**, and linking of jobs, customers, sites, and history at ingest. Coding agents then generate thin applications that call well-shaped endpoints. You are not paying an LLM to rediscover your operation on every click. > Built to be built on. Your people, solving their own problems, on their own terms. The platform is the layer your agents and applications sit on while your field system and IDE continue doing their jobs. ## Security and governance (builder-relevant) If you are building any app that a user will open in a browser — even an internal tool, a partner portal, or a quick MVP — read [Deploying secure apps](/guides/deploying-secure-apps) before you ship. Coding agents in particular will produce working code that exposes credentials insecurely unless you give them explicit guidance on the frontend/backend split. The checklist on that page is the minimum bar for any user-facing app. Builders should assume: * **Data scoping** on every call (`company_id` + validated `api_key`). No API call can cross organisation boundaries. * **Built-in user management and auth**: invite users, assign roles, issue JWTs. You do not need to build the auth layer yourself. * **PII handling** aligned with your DPA: do not rebuild sensitive fields into public UIs. * **Read-only field integration** by default; write-back only when explicitly agreed. See [Authentication](/authentication) for the full credential surface map and [Deploying secure apps](/guides/deploying-secure-apps) for the deployment checklist. ## Choose your starting kit | You are | Start here | | ------------------------------ | ------------------------------------------------------------------------------------------------ | | Ops lead, no code | [Claude Projects](/agent-kits/claude-projects), [n8n node](/n8n-node) | | Technical ops / PM with Cursor | [AGENTS.md](/agent-kits/agents-md) + [Cursor rules](/agent-kits/cursor-rules) | | Engineer building a product | [API overview](/api-reference/overview) + [Operational discovery](/guides/operational-discovery) | | Agent in Claude Desktop | [MCP setup](/agent-kits/mcp-setup) | ## Related Architecture narrative for technical buyers. Connect inboxes, calendars, CRM, and storage. Platform principles and sovereignty. Keys, tenancy, and access. # Compounding operational capability Source: https://docs.vh3.ai/guides/compounding-operational-capability How field service organisations build a learning loop between human judgment and operational intelligence — and why the substrate matters more than the model # Compounding operational capability Every platform shift changes what tools an organisation runs. The AI shift changes how an organisation **learns**. In field service, that learning has always happened in two places at once. Your people carry judgment: which customer needs a careful call, which engineer knows the plant room, which fault description in a worksheet actually means something specific, which sentinel threshold has gone noisy. Your systems carry records: jobs, outcomes, sites, engineers, invoices, emails, certificates. AI creates a cognitive loop between those two for the first time. Questions that used to require a report request, a spreadsheet, or someone with five years in the business can be answered in seconds — if the operational intelligence underneath is prepared, owned, and improving. The durable opportunity is building a loop where human judgment and operational intelligence compound together — regardless of which model you use this quarter. ## Human judgment and operational intelligence **Human judgment** is what your team already has: relationships with facilities managers, pattern recognition across accounts, trade knowledge, dispatch judgment, commercial instinct, and the ability to decide what matters when the data is ambiguous. **Operational intelligence** is what your organisation builds in systems: enriched job history, resolved customers and sites, sentinel rules, case records, briefing templates, automation workflows, company preseeds, and the structured memory that survives when people move on. As operational intelligence grows, human judgment becomes more valuable — because your people spend less time assembling context and more time applying judgment. The account manager who used to spend a morning rebuilding the story before a review now walks in with evidence, job references, and time to decide what to do about it. The operations lead who used to manually spot repeat-visit patterns now reviews sentinel findings, adjusts thresholds, and owns the cases that need a human call. The field intelligence lead who used to chase exports now gardens workflows, tunes automations, and ships the next internal tool the operation actually needs. Operational intelligence handles the legwork. Human judgment directs what gets built next. ## The learning loop A field service operation that compounds capability runs a loop: 1. **Jobs and signals enter** — from the FMS, email, documents, integrations. 2. **Records are enriched and linked** — fault types structured, entities resolved, history connected. 3. **Intelligence is used** — Connie answers, sentinels fire, reports run, briefings go out, cases open. 4. **People review and act** — thresholds adjusted, ambiguous matches confirmed, cases closed with outcomes recorded. 5. **The substrate improves** — exclusions updated, preseeds refined, workflows tuned, the next question starts from a better foundation. Each pass through the loop makes the next pass cheaper and more accurate. A sentinel that fires correctly three months in a row becomes a trusted signal. A briefing template that account managers actually use gets refined. A workflow that routes portal email correctly stops needing manual review. This is institutional learning encoded in operational systems — not in a model vendor's training run. You can offload a task. You can automate a briefing. You cannot offload the discipline of improving the loop. ## The sovereignty test There is a practical test for whether your organisation owns its operational intelligence or rents it from a vendor: **Can you change the model underneath without losing what your operation has learned?** If your operational memory lives inside a black-box chat product, switching models means starting again. If your intelligence lives in a prepared substrate — enriched records, graph relationships, sentinel definitions, case history, automation logic — the model is interchangeable. Connie can run on your provider account through BYOK. Agent kits can point Cursor or Claude at the same API tomorrow. n8n workflows keep calling the same endpoints regardless of which LLM sits in the decision node. The generalist model changes every six months. The operational veteran — five years of resolved jobs, tuned thresholds, accumulated cases — should not. VH3 AI is built around that separation. The platform fee covers enrichment, graph, sentinels, and synthesis infrastructure. Model spend stays on your provider account, visible and portable. The intelligence compounds in your organisation's account. ## What compounds in your account Operational intelligence that belongs to your organisation includes: * **Enriched job history** — classified faults, structured outcomes, linked engineers, sites, and customers, up to five years loaded on day one. * **Resolved entities** — customers, sites, and engineers connected across naming inconsistencies and source systems. * **Sentinel definitions** — thresholds, scopes, and exclusions your team has tuned to match how the operation actually runs. * **Cases and evidence** — investigations, linked jobs, participant decisions, and the record of what was done about a signal. * **Automations and workflows** — n8n templates, routing rules, digest schedules, and integrations your field intelligence lead maintains. * **Company preseeds and operating rules** — how your business wants Connie and agents to behave, refined as the operation changes. This is the asset that gets harder for a competitor to replicate the longer you run it, because it encodes **your** operation's judgment over time. ## What your team must own VH3 AI provides the substrate. The loop still needs people inside the business: * **Direction** — which problems to solve first, which accounts need attention, which workflows are worth automating. * **Gardening** — sentinel thresholds, triage taxonomies, exclusions, and preseeds that drift as the operation changes. * **Review** — ambiguous entity matches, investigation conclusions, compliance-adjacent signals, and case outcomes. * **Building** — the next report, workflow, briefing, or internal tool that removes a recurring manual step. The [2027 blueprint](/guides/2027-blueprint) describes the person who often owns this loop: the field intelligence lead, close enough to the work to understand it, technical enough to build on the platform. Organisations that invest in upskilling that person — or developing that capability across a small team — compound faster than organisations that treat AI as a subscription to finish. ## A frontier for operators, not just model vendors Field service generates deep operational signal and deep operational judgment. Most of that value has never been encoded in systems that compound — it lived in people's heads, scattered spreadsheets, and FMS records that were never designed to learn. When operational knowledge flows only into a handful of generalist models, operators risk hollowing out while a few platforms capture the returns. Every field service organisation can own the loop that encodes **its** expertise — portable, inspectable, improvable — and ride each new model generation against that foundation. That is what VH3 AI is built to be: a harness on the stack you already run, intelligence that compounds in your account, with human judgment at the centre of the loop. How to organise for capability inside your operation. How operational context is prepared before any question is asked. Why traceability matters more than confidence in operational decisions. APIs, automations, and agents that read the same prepared foundation. How humans and agents work together on the same operational record. The engineering work behind an accurate, live operational picture. # Connie Source: https://docs.vh3.ai/guides/connie VH3 AI's flagship operations agent with long-running context, evidenced answers, and efficient use of your intelligence layer # Connie Connie is VH3 AI's flagship conversational agent: a field service operations specialist wired into your full intelligence layer. She reads the same enriched operational model as search, sentinels, reports, and automations, and she is built for real work: multi-turn reviews, account prep, diagnostics, and follow-through that depends on what was said five minutes ago. How operators brief Connie: three principles, role playbooks, and session habits. Start here if you have not used Connie before. Fast precedent search and entity resolution (no LLM). Connie calls these when she needs facts; she synthesises when you need narrative. How to verify Connie's answers: tool outputs, citations, usage, and structured evidence. Connie handles ambiguous questions and short prompts well. For operator habits that get the most out of her on harder asks, see [Working with your operation](/guides/working-with-your-operation). ## Connie on the harness VH3 AI separates **discovery** from **synthesis**. Discovery handles fast lookup: search, autocomplete, feeds, and customer knowledge sections. Connie handles synthesis: explaining, comparing, investigating, briefing, and recommending with citations. Connie is disciplined about when to spend tokens. Simple greetings and meta questions can be answered without a full tool loop. Analytical questions trigger the right operational tools. Heavy diagnostic work routes to investigation flows that return structured evidence, not guesswork. That split is what makes the agent practical at scale: the expensive interpretation runs on **prepared** data (enriched once at ingest), not on re-reading raw field system exports every turn. ## Sessions: focused, managed, and recoverable A Connie session is a conversation about one thing. Keep them concise and to the point. When the topic changes, start a new session. Shorter, focused sessions perform better in three measurable ways: * **Economics.** Token cost grows with the context you carry into each turn. A 40-turn thread that has wandered across three customers spends tokens re-reading its own history. A focused session does not. * **Recall and answer quality.** A focused session keeps the model on the question. Long, drifting threads encourage the model to mix unrelated context into the answer. * **Auditability.** Sessions are managed: stored, recoverable, searchable, and citable. A session per topic gives you a clean record of what was asked, what was answered, and what evidence was used. **Session IDs are issued by the platform.** Do not invent them. Omit `session_id` on the first turn; the response returns a UUID to use on every subsequent turn in that thread. Between topics, drop the ID and let the platform issue a new one. **Between sessions, start fresh.** A new topic, a new account, a new day's standup: omit the ID. Connie loads the right opening context (see below) automatically; you do not carry over yesterday's context or its token cost. ### How to start and continue a session First turn, no `session_id`: ```json theme={null} { "company_id": "your-company-id", "api_key": "your-api-key", "message": "What recurring issues have we seen here in the last 90 days?", "contact_id": "12345", "user_name": "Sarah" } ``` The response includes a `session_id` UUID. Pass it on every follow-up: ```json theme={null} { "company_id": "your-company-id", "api_key": "your-api-key", "message": "Which engineer has the best completion rate on those jobs?", "session_id": "a1b2c3d4-e5f6-...", "contact_id": "12345" } ``` When the topic changes, omit `session_id` again. The platform issues a new one. ### Opening context on new sessions When you start a session with a customer in scope, the server can inject: * **Company operating context** (terminology, rules, and preferences your organisation configured). * **Customer Summary** plus **recent completed jobs** since that summary was generated, so turn one is not stale. You can still pass a `summary` from your app; the server enriches it when possible and reports how that block was built (see [Agent observability](/guides/agent-observability)). ### Recovery and search Sessions are durable. Past sessions can be retrieved, listed, and searched via the [Connie API](/api-reference/connie). Start new threads freely; the platform preserves previous sessions as evidence. ### Contact-scoped by default From a customer or job view, Connie defaults queries to that contact unless you ask a company-wide question. That matches how account managers and coordinators actually work, and it is another reason starting a new session per topic stays cheap: each one starts with the right scope already set. ## Memory that compounds Connie benefits from the same **operational memory** as the rest of the platform: * Jobs are **enriched once** (fault patterns, outcomes, links to customer, site, engineer, equipment). * **Customer Summary** knowledge is stored in modular sections and refreshed on schedule or when job drift thresholds are met. * **Tool outputs** from substantive calls in a session can be retained and recalled within that session so she does not repeat expensive lookups on follow-up turns. * **Background compaction** runs on longer sessions: the platform periodically summarises earlier turns into a compact form so recall stays sharp without carrying the full raw history forward on every message. This is **your organisation's intelligence layer getting richer continuously** and Connie reading that layer on every turn, including what happened earlier in the session. ## Efficient token use Connie is built for production economics (especially with [BYOK](/pricing)): * **Intent routing** classifies messages so lightweight turns can skip the full agent and tool suite. * **Company-level prompt caching.** Shared company context (instruction blocks, tool definitions, organisation operating context) is cached across all users in your organisation. Every person on the team benefits from cache hits that earlier sessions already warmed. `cacheReadTokens` in the usage response shows how much of each turn was served from cache. * **Compact tool results for efficient chat.** Feeds, search, and aggregates return trimmed shapes so the model is not fed empty fields and nested noise. Semantic search hits include `contactName`, `jobRef`, and visit dates so answers can name sites and cite references without extra lookups. * **Discovery-first tools** (`search_outcomes`, `jobs_aggregate`, `job_feed`, autocomplete, customer summary sections) handle lookups without running narrative investigation unless the question requires it. Every chat response includes **usage** (`inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheCreationTokens`) so you can see what a turn cost on your provider account. ## Fully evidenced answers Connie is instructed to **cite job references and names**, never internal database IDs in user-facing text. Behind the narrative: * **Investigation** returns headline findings, ranked recommendations, confidence, and **evidence** tied to real job references. * **Search and feed tools** return graph-linked records, not orphaned text snippets. * **`toolCallOutputs`** on the API response exposes the structured JSON from each tool invocation in that turn, so your UI can render tables, charts, and drill-downs from evidence. If a tool fails, she is instructed to say so and offer another angle, not invent numbers. Treat the assistant message as the summary. Use `toolCallOutputs`, job references in the text, and your own drill-down into discovery endpoints as the source of truth for anything that affects commercial or safety decisions. ## What Connie can do Connie can answer any question the underlying data supports. Examples by shape of work: ### Performance and trends * "Which engineers had the best first-time-fix rate this quarter?" * "How is Mike performing compared to last month?" * "Show me the top five engineers by SLA punctuality." * "How many jobs did we complete yesterday versus the same day last week?" ### Sites and customers * "What happened at the Manchester site last week?" * "Which customers have the most repeat visits?" * "Give me the job history for this account." * "How does this customer's failure rate compare to the company average?" ### Diagnostic and precedent * "Has anyone seen this fault before?" (with a description) * "What usually fixes a boiler intermittent lockout?" * "Find similar jobs to this one." * "Why are roofing jobs running late?" (investigation-style synthesis) ### Operational actions (where enabled) Depending on your setup and integrations, Connie can also drive **email drafts**, **notifications**, **briefings**, **account reports**, **presentations**, and lookups into connected systems (CRM, mail) through the same connected platform capabilities. See the [Connie API](/api-reference/connie) for endpoints and fields. ## Working on your behalf (without a prompt) Most of Connie's value lands without anyone typing. Connie reads the same signals the platform watches continuously, so she can pick up work before the operator asks. * **Sentinels** detect patterns 24/7 with near-zero AI cost at detection: repeat visits, SLA drift, dormant customers, performance slips. See [Sentinels](/guides/sentinels). * **Cases** turn signals into owned work with status, participants, and linked jobs. Connie can open a case for a sentinel trigger, attach the relevant evidence, and draft the brief the assignee will read. * **Teams** route cases to the right people: regional, portfolio, or functional groups own customers and sites so nothing sits in a generic queue. A typical autonomous loop: 1. Sentinel flags repeat HVAC callouts at an account. 2. Automation opens a case, runs discovery for similar precedents, and asks Connie for a draft brief. 3. The regional team finds the case ready, with citations, when they next look at the queue. The operator's job is to steer and verify, not to push the platform into motion. Autonomous loops depend on your tier, enabled integrations, and configured case/team rules. During onboarding, decide which sentinel findings should create cases automatically and which should stay as digest items for human review. ## Specialist capabilities Connie orchestrates **focused sub-tasks handled automatically** for specialist work (for example structured email generation and deeper analytical passes). You interact with one assistant; the platform routes complex sub-tasks without you managing multiple agents. ## Tips for effective questions "Last 30 days" beats "recently." Connie infers ranges when she can, but explicit dates reduce ambiguity. Use engineer names, site addresses, or customer names when you know them. Autocomplete resolves fuzzy input; exact names are faster. Same `session_id` for the same topic. "Tell me more about the third one" or "What caused that?" When the topic changes, start a new session. Ask for tables, comparisons, or bullet recommendations. "Compare Mike and Sarah this quarter" works well. ## Field service playbook | You want | Example prompt | What Connie typically does | | ------------ | -------------------------------------------------------- | ------------------------------------------ | | Quick count | "How many completed jobs last week?" | Aggregation with sensible time axis | | Account prep | "Summarise risk for this customer" | Customer summary + recent jobs + synthesis | | Precedent | "Similar callouts for intermittent lockout" | Semantic search on outcomes or intake | | Root cause | "Why is SLA slipping in the North?" | Investigation with cited evidence | | Briefing | "What should the engineer know before tomorrow's visit?" | Job detail, weather, history, narrative | ## Building with Connie | Surface | Best for | | --------------- | -------------------------------------------------------------------------- | | **VH3 Connect** | Embedded ops UI with generative components from `toolCallOutputs` | | **API** | Custom portals, mobile, partner apps | | **MCP** | Claude Desktop, Cursor, coding agents ([MCP setup](/agent-kits/mcp-setup)) | | **n8n** | Slack or Teams assistants ([n8n Agent Prompts](/agent-kits/n8n-agents)) | Use [Agent observability](/guides/agent-observability) when you build UIs or compliance workflows that must show **why** an answer was given. ## Related Request fields, sessions, voice, and history search. Why relational, semantic, structured, and temporal memory matter. Discovery vs synthesis for builders and integrators. Tenant keys, JWT for interactive apps, BYOK. # Deploying secure internal apps Source: https://docs.vh3.ai/guides/deploying-secure-apps Governance, authentication, and deployment patterns for apps built on the VH3 AI intelligence layer # Deploying secure internal apps This guide is for **IT leads, technical owners, and architects** approving or shipping internal apps on top of VH3 AI. It complements [Building on the layer](/guides/building-on-the-layer), which covers the builder patterns. This page is the governance and deployment view: how access works, what to harden, and which tier you actually need. ## 1. What "built on the substrate" means VH3 AI is one operational model per organisation. Every surface, whether VH3 Connect, a custom portal, a Slack agent, a mobile wrapper, or a coding agent, reads the same intelligence layer: discovery, sentinels, Connie, cases. That means: * **No bespoke data layer per app.** Your portal and your Slack agent agree on what "a job at Berwyn House" is, because both read the same model. * **Thin apps are appropriate.** Internal apps focus on workflow and UX; the substrate handles enrichment, resolution, and synthesis. * **Switching surfaces is cheap.** Replacing a UI does not invalidate the operational picture. ## 2. Access patterns (choose one) Pick the pattern that matches the surface. Do not mix. | Pattern | When to use | Credential | Where it runs | | ----------------------- | ----------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------- | | **VH3 Connect** | You want the managed UI, users, roles, cases out of the box | JWT (managed by VH3 Connect) | Browser, mobile | | **Custom app** | You need bespoke UI/UX for your operators or customers | Per-user JWT ([User Auth](/api-reference/user-auth)) | Browser, mobile | | **Automation** | n8n workflows, back-office scripts, integrations | `company_id` + `api_key` | Server only | | **Coding agents / MCP** | Cursor, Claude, Claude Code, MCP-compatible clients | JWT ([MCP setup](/agent-kits/mcp-setup)) | Developer machines, server-side agents | **Rule:** `api_key` is a server credential. It must never appear in a browser, mobile bundle, or anything a customer can inspect. ## 3. Security model (IT checklist) The platform ships with the controls below. Your job is to use them correctly. ### Data scoping and user management * All API calls are scoped by `company_id`. Tenant resolution happens server-side, no API call can cross organisation boundaries. * The platform ships with built-in user management: invite users, assign roles, organise teams, and issue JWTs without building any of that yourself. See [Users and teams](/guides/users-and-teams). * Dedicated, isolated infrastructure is available on Enterprise plans. ### JWTs and sessions * Login returns a JWT valid for **24 hours**. Refresh issues a new 24-hour token. * Plan a refresh policy: silent refresh during active sessions; re-login at idle thresholds your security team is comfortable with. * Do not store the JWT in non-HTTP-only storage if you can avoid it. Treat it as a session credential. ### Internal IDs and PII * Internal IDs (`company_id`, `job_id`, `contact_id`, `resource_id`) belong on the server. * UI should show **names and job references**, not internal IDs (Connie follows the same rule, see [Connie](/guides/connie)). * PII in UI is a product policy decision. Decide once, enforce in the app layer. ### BYOK (Connie and agents) * Conversational AI runs on **your model provider key**. * Cost lands on your provider account at your contracted rate. No vendor margin. * See [Pricing](/pricing) and [Connie](/guides/connie) for the BYOK model. ### Timeouts * **Discovery** completes sub-second. Set tight client timeouts. * **Connie and `/investigate`** are multi-step. Plan for **20 to 25 seconds**, longer on cold caches. * Apps should surface a loading state for synthesis; do not pretend it is instant. ## 4. Building a custom app: the right architecture If you are building a dashboard, a partner portal, or any browser-based application on top of VH3 AI, the architecture below is the minimum required before connecting to real customer data. Coding agents will produce working code without this separation — but that code will be insecure. ### The required split Your app needs two distinct parts: * **Frontend** (what runs in the browser): handles display, navigation, and user interaction. Contains no credentials. Makes API calls only to your own backend. * **Backend** (a server you control): holds credentials, validates identity, and makes all calls to the VH3 API. The browser never calls VH3 directly. ``` Browser │ calls your backend only (no VH3 credentials) ▼ Your backend server │ validates JWT → calls GET /auth/me → gets company_id │ makes VH3 API call with api_key from environment variable ▼ VH3 API (api.vh3connect.io) ``` A proxy that simply forwards the `api_key` from an environment variable to the browser in a response header, or that passes it through as part of a client-visible request, is not a backend. The credential must stay on the server at all times and must never appear in any response the browser can read. ### Authentication flow for a custom app 1. User visits your app and is redirected to your login page. 2. Your login page posts `email` and `password` to **your backend** (not directly to VH3). 3. Your backend calls `POST https://api.vh3connect.io/api:lBQnyyZL/auth/login` and receives the `authToken`. 4. Your backend sets the `authToken` as an `httpOnly` secure cookie on the response. The browser stores it automatically and sends it on every subsequent request. The token itself is never accessible to JavaScript. 5. On every protected request from the browser, your backend reads the cookie, calls `GET https://api.vh3connect.io/api:lBQnyyZL/auth/me` with the token to validate it and retrieve the user's `company_id`. 6. Your backend uses the verified `company_id` and the `api_key` from its environment variables to call the VH3 API. It returns only the data the frontend needs. The `company_id` that scopes your VH3 API calls must always come from the `GET /auth/me` response on the server. Never accept it from the browser — a user could send any value in a request body or query parameter. ### What this looks like in practice (Node.js / Express) ```javascript theme={null} // Backend route — runs on your server, never in the browser app.get('/api/jobs', async (req, res) => { const token = req.cookies.vh3_token; if (!token) return res.status(401).json({ error: 'Not authenticated' }); // Validate the token and get the user's company const meResponse = await fetch('https://api.vh3connect.io/api:lBQnyyZL/auth/me', { headers: { Authorization: `Bearer ${token}` }, }); if (!meResponse.ok) return res.status(401).json({ error: 'Session expired' }); const { company_id } = await meResponse.json(); // Call VH3 with server-side credentials const jobsResponse = await fetch('https://api.vh3connect.io/api:kP8T1CK7/jobs/feed', { method: 'GET', headers: { 'Content-Type': 'application/json' }, // company_id and api_key stay on the server // pass them as query params or body per the API spec }); // Return only what the frontend needs — strip internal IDs const data = await jobsResponse.json(); res.json(data); }); ``` ### Environment variables and deployment Store credentials as server-side environment variables only. On Railway, Render, Fly.io, or any similar platform, set these in the service settings — not in any file committed to your repository: ``` VH3_COMPANY_ID=your-company-id VH3_API_KEY=your-api-key ``` The frontend service should have zero secrets in its environment. If a coding agent suggests adding `NEXT_PUBLIC_VH3_API_KEY` or any credential prefixed for browser exposure, that is a mistake — reject it. ### CORS Lock your backend to accept requests only from your frontend's exact origin: ```javascript theme={null} app.use(cors({ origin: 'https://your-frontend-domain.railway.app', // your frontend origin only credentials: true, // required for httpOnly cookie support })); ``` When you add a custom domain later, update this to the production domain. Do not use `origin: '*'` at any point in a user-facing deployment. ## 5. Typical internal apps | Internal app | Auth pattern | Discovery surfaces | Synthesis surfaces | Ownership | | ------------------------------- | ------------------------------- | ------------------------------------------ | ------------------------------------- | ---------------------------------- | | Dispatch assist | VH3 Connect or custom JWT app | `/search/outcomes`, `/search/autocomplete` | Connie for "who has done this before" | Cases assigned to dispatch team | | Customer 360 portal (internal) | Custom JWT app | Summary sections, jobs feed | Connie account brief | Cases per regional team | | Slack ops agent | n8n on server (`api_key`) | Discovery + sentinels | Connie for narrative replies | Cases linked from Slack messages | | Partner / sub-contractor portal | Custom JWT app, restricted role | Scoped jobs feed | Connie with restricted toolset | Cases visible only to partner team | Each pattern reuses the same substrate. The differences are UX and the role mapping in front of it. ## 6. Users, teams, and cases as governance Governance on this platform comes from using the user, team, and case model correctly. * **Users and roles** ([Users](/api-reference/users), [User Auth](/api-reference/user-auth)) decide who can sign in and what they can do. * **Teams** ([Teams](/api-reference/teams)) decide what each user sees and owns. * **Cases** are the audit surface: status, participants, linked jobs, activity timeline. On Connect tier, cases are first-class. The end-to-end loop: 1. A **sentinel** detects a pattern continuously (near-zero AI cost at detection). 2. A **case** is opened against the team that owns the affected customer or region. 3. The team uses **discovery** for precedents and **Connie** for a brief. 4. Decisions, replies, and follow-ups are logged against the case. See [Building on the layer](/guides/building-on-the-layer) for the sentinel-to-case flow in code, and section 4 above for the custom app architecture that puts this in a secure deployment. ## 7. Tier and capability map | Tier | Best for | Auth surfaces | Notable governance features | | ------------------ | -------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------ | | **VH3 API** | Builders integrating BigChange and automation only | `company_id` + `api_key` | No intelligence layer in this tier | | **VH3 Core** | Operational AI, single team | API key, JWT for custom apps, BYOK | Intelligence layer, semantic search, reports, sentinels | | **VH3 Core+** | Multi-team operations needing role mapping | All Core + per-user OAuth | **User-based permissions, role mapping**, native integration layer | | **VH3 Connect** | Managed UI, multi-agent governance, cases | All Core+ + Connect UI | VH3 Connect platform UI, case management, audit trails, multi-agent governance | | **VH3 Enterprise** | Dedicated 90-day programme, custom commercials | All Connect + bespoke | Programme manager, custom controls | Choose the access point that matches your UI, permission, and governance needs. A team that already has a strong front-end may start on Core and build its own UI. A team that wants to skip UI work uses Connect. The substrate is the same. See [Pricing](/pricing) for the full feature matrix. ## 8. Deployment checklist Before launching an internal app on the layer: * [ ] Auth choice is explicit (Connect / JWT custom / server `api_key` / MCP JWT). * [ ] `api_key` never appears in client code, browser bundles, or mobile binaries. * [ ] JWT refresh policy is implemented; idle and absolute session limits are agreed with security. * [ ] CORS allowlist is restricted to your app origins. * [ ] Client timeouts: short for discovery, 20 to 25 seconds for synthesis. * [ ] Role mapping is configured for the surfaces the app exposes (Core+ if you need bespoke roles). * [ ] Teams are created and linked to the customers, sites, or regions they own. * [ ] Connie answers in commercial or safety contexts route through [Agent observability](/guides/agent-observability) for evidence standards. * [ ] Generative UI components render structured tool outputs from scoped, authenticated API responses only. * [ ] PII and internal ID policy enforced in the app layer; UI shows names and job refs only. * [ ] BYOK key set per environment; cost dashboards monitored on your provider account. * [ ] Case ownership defined for each sentinel that the app surfaces. ## Related Full credential surface map: VH3 AI Intelligence, BigChange, JWT. Roles, invites, team scoping, Core+ permissions. Builder patterns for citizen builders, coding agents, and integrations. Coding-agent and MCP-client access with JWT. Evidence standards for commercial and safety-critical answers. Tier feature matrix and BYOK economics. # Generative UI Source: https://docs.vh3.ai/guides/generative-ui A drop-in React component library that renders VH3 AI tool outputs as polished operational interfaces, without any host configuration # Generative UI The VH3 AI platform returns structured tool outputs alongside every Connie answer, every report, every investigation, and every customer summary. That structure is the foundation for what we call generative UI: a single contract between the intelligence layer and the surfaces your team works from, so the same operational answer renders consistently in a dashboard, an internal tool, a custom application, or an AI-coded prototype. The `@vh3/field-service-ui` package is the reference implementation of that contract. It is a self-contained React component library, designed to drop into any React application without configuration, that takes a VH3 AI tool response and renders the appropriate operational interface automatically. **Preview.** The `@vh3/field-service-ui` package is in preview. The components, theming system, and contracts shown below are the targeted release surface. Get in touch with VH3 AI if you would like to use it before the public release. ## Why this exists Most AI products either return prose or return raw JSON and leave the rendering problem to the consumer. Both create friction in field service operations. Structured UI lets a coordinator drill into underlying jobs, verify numbers, and compare the picture across accounts without reading raw JSON or parsing a paragraph by hand. The generative UI package solves both. The intelligence layer returns a structured payload. The component library knows how to render that payload. The result is a polished operational interface that looks the same in every application built on the layer, with no custom UI development required. ## The contract The pattern is simple: one tool invocation produces one structured payload, which maps to one renderer. ```tsx theme={null} import { ToolRenderer } from "@vh3/field-service-ui"; ; ``` The renderer dispatches automatically based on the tool name. An investigation response renders as an evidence-cited investigation card. A customer summary response renders as a sectioned customer brief. A report generation response renders as a full dashboard layout. The same JSON your agents already receive becomes a complete interface. ## What is in the package The library includes a set of dedicated components for the most common operational outputs: | Tool name | Component rendered | | ------------------------------------------------------ | ------------------------------------------------------ | | `jobs_aggregate` | Stats, chart, or comparison card, chosen automatically | | `job_lookup`, `job_feed` | Data table | | `job_detail` | Job detail card | | `weather_check`, `weather_for_job`, `weather_for_site` | Weather widget | | `autocomplete` | Option list | | `investigate` | Investigation card with evidence list | | `generate_report` | Dashboard layout or composite report | | `generate_summary` | Customer summary with seven sections | | `contact_snapshot` | Composite contact report | | `search_outcomes`, `search_intake` | Data table | | `case_report` | Case report card | Each component is also exported individually if you want to render a specific layout without going through the dispatcher. ## Live components Browse the full component catalogue: Live, interactive component gallery covering every component, story variant, and rendered tool output the library produces. A selection of representative components below. ### Dashboard layout The `DashboardLayout` component composes a full operational report from a `generate_report` response. Morning briefings, midday updates, weekly reviews, and account monthlies all render through this single layout.