Appearance
Common Webhook — Open questions
A running list of questions that came up while reading or working with the common webhook docs. Sandy adds questions as he reads; resolutions get pasted in when they arrive. Each entry has an explicit status so the page is greppable and the "what's still unknown" list stays accurate.
How to read this
Skim the table; jump into individual entries when you have context to add. Entries flagged open are the live ones — answering any of them improves the section's accuracy. Entries flagged answered keep the answer inline so the reasoning trail survives.
Unsolicited Opinion
The docs in this section are first-draft. There are going to be a lot of questions that come up as I read through and as I do migrations. This page is where those accumulate without me having to remember to come back and fix the source pages immediately. When a question turns into a confirmed answer, I update the relevant page AND mark the entry answered here with the answer and the date.
Status at a glance
| ID | Question | Status | Source |
|---|---|---|---|
| Q1 | Why does OASIS have both legacy and common webhook routes? | open | research |
| Q2 | What's the migration order? Is fieldRoutes next? | open | research |
| Q3 | What's jobNimbus's actual state? Live-agent-only? | open | research |
| Q4 | Sunset plan for common/webhook.ts legacy route? | open | research |
| Q5 | Does Inngest actually re-fire runOutcome for pending rows, or is manual retrigger required? | open | research |
Questions
Q1
Question. Why does OASIS have both legacy and common webhook routes?
Context. pages/api/responder/non-st-crm/oasis/webhook.ts exists (legacy route). booking-oasis/ exists (common-webhook package, used by FlooringWorkflowRunTriager). The legacy oasis has no run/handler.ts, so it's likely live-agent-only (assistant-request), while end-of-call goes through common. See legacy-comparison.md.
Hypothesis. Legacy webhook serves assistant-request for some teams (running the older Vapi-resident agent pattern); end-of-call-report goes through common webhook for all OASIS teams.
How to resolve. Ask Avoca team — quick Slack question. Or check Vapi server URLs for a known OASIS team.
Status. open (2026-05-12)
Q2
Question. What's the migration order from here? Is fieldRoutes ("Field Service") really next after HCP?
Context. HCP migration in flight via PR AvocaAI/avoca-next#10249. Sandy mentioned "Field Service or something like that" as the next migration target. fieldRoutes is the closest match in the legacy CRM inventory.
Hypothesis. fieldRoutes is next. Customer-ops prioritization probably driven by team count + integration complexity, not technical readiness.
How to resolve. Confirm in standup. Worth getting the full ordering pinned in writing if it exists somewhere.
Status. open (2026-05-12)
Q3
Question. What's jobNimbus's actual state? Live-agent-only? Already sunset?
Context. pages/api/responder/non-st-crm/jobNimbus/webhook.ts exists. lib/non-st-workflow/jobNimbus/ exists but has no run/handler.ts — the only un-migrated CRM without a post-call entry. No common-webhook package.
Hypothesis. Live-agent-only — Vapi calls the webhook for assistant-request and tool dispatches, but post-call processing was either never implemented or was sunset. The "jobNimbus" customers may not have post-call workflows at all.
How to resolve. Check what teams are configured with crm = 'JOB_NIMBUS' (or equivalent key) and what their responder_webhook_configs look like. Worth a one-line check before any migration work on jobNimbus.
Status. open (2026-05-12)
Q4
Question. What's the sunset plan for pages/api/responder/common/webhook.ts (the legacy ServiceTitan single-shot route, name-colliding with the new common/workflow.ts)?
Context. The legacy route is a synchronous LLM-extraction-then-ST-job-creation handler. Its filename is one character off from the new unified entry, which causes ongoing confusion. See future-brief.md (obs-8) for the PR-ready argument.
Hypothesis. Some teams' Vapi server.url still point at this legacy route. Those teams are themselves migration candidates. Deletion is gated on confirming no live teams hit it.
How to resolve. Query Vapi for server.url configurations across all teams. Or grep Datadog logs for route:/api/responder/common/webhook traffic in the last 30 days.
Status. open (2026-05-12)
Q5
Question. Does the Inngest pipeline actually re-fire runOutcome for rows left pending by a return-shape failure, or does recovery require the manual retrigger tool?
Context. architecture.md § Phase 2 describes the return-shape retry contract: {results: [], errors: [...]} or truthy bookingResponse.error leaves the row pending. The retry semantics of the Inngest step are critical for understanding whether transient failures auto-recover or require ops intervention.
Hypothesis. Per post-call-dispatch-chain.md, the parent Inngest function declares retries: 0 and relies on per-step retry semantics. The per-step retries might re-execute runOutcome, but the row state remains pending regardless. Manual retrigger is the canonical recovery path.
How to resolve. Read EndOfCallReportInngestFunction.ts carefully — specifically the per-step retry config and the onFailure handler. Or test directly by forcing a transient bookingResponse.error in staging and watching whether the row recovers automatically.
Status. open (2026-05-12)
Convention for new entries
When you find a question while reading or working:
- Add a row to the status table at the top with a new ID (
Q{N+1}). - Add a detail block below with the four fields:
- Question. One sentence.
- Context. Where the question came up — page link, file path, PR, conversation.
- Hypothesis. Best guess based on current understanding. OK to be wrong.
- How to resolve. What action would answer it — ask the team, read X, test Y.
- Set
**Status.** \open` (date)`. - When answered: update status to
answered (date), paste the answer below the four fields, and update the source page in the section with the new fact. Don't delete the entry — the reasoning trail is the value.
Status vocabulary:
open— actively unknownanswered (date)— resolved; answer pasted inline, source page updatedparked (date)— won't pursue right now, but kept in case it becomes relevantsuperseded by Q{N}— merged into another questionwrong premise— turned out the question itself was based on a misreading; explanation pasted below
Working notes
Append a row each time you add a question. Lets you see the velocity of question-accumulation and where the docs were unclear enough to prompt them.
| Date | Question ID | Source page | Trigger (one line) |
|---|---|---|---|
| 2026-05-12 | Q1-Q5 | research.md | Seeded from initial code read |