LoopLogic · For contractors

Onboarding an AI phone receptionist

Six repeatable steps to wire a roofing contractor onto the LoopLogic AI receptionist: choose a voice platform, seed the tenant in the database, paste a system prompt, set the HMAC secret, test with three scenarios, and turn on dashboard alerts. Estimated setup time: 90 minutes per contractor.

v1 · MVP
Webhook + HMAC
Owner-scoped dashboard
What you’ll have when you finish
A tenant with one inbound number. Every call is transcribed, qualified, scored, and shown in the dashboard. The contractor gets an email summary atlooplogic-2@polsia.app per lead.

At a glance

  1. Pick a voice platform

  2. Seed the contractor + AgentConfig rows

  3. Configure the agent on the voice platform

  4. Set the HMAC signing secret (env var)

  5. Send three test scenarios

  6. Hand off to the contractor

Choose your voice platform

Three supported providers today. Each has a slightly different webhook contract; all three are normalized into the same /api/calls/intake shape. The rule layer in qualifyCall() is provider agnostic.

Vapi
vapi
Most plumbing — assistant + webhook delivery are first-class. We default to Vapi.
  1. Step 1. Provision a new assistant; set the voice + LLM model.
  2. Step 2. In the Server-side tools / Functions tab, add a "Call Ended" function with URL https://<your-deploy>/api/calls/intake.
  3. Step 3. In the assistant prompt, paste the tenant’s AgentConfig.prompt verbatim.
  4. Step 4. Set the HMAC signing secret to the tenant’s VOICE_WEBHOOK_SECRET (generate with `openssl rand -hex 32`).
  5. Step 5. Send a test call and watch the dashboard.
Retell
retell
Strong on routing + transfer-to-human, but transcript delivery is JSON-of-an-array — the rule layer parses turn-by-turn.
  1. Step 1. Create an agent; choose your voice + LLM.
  2. Step 2. Webhook URL: https://<your-deploy>/api/calls/intake. Event: call_ended.
  3. Step 3. Set signing secret = tenant’s VOICE_WEBHOOK_SECRET.
  4. Step 4. Verify the "Enable Call Transcript" toggle is on (label varies by Retell UI).
Bland
bland
Cheapest path-to-live for high-volume pilots. Webhook payload arrvies as a flat object.
  1. Step 1. Build a "phone call" path; add a webhook node pointing at https://<your-deploy>/api/calls/intake.
  2. Step 2. Configure Signatures → paste tenant VOICE_WEBHOOK_SECRET.
  3. Step 3. Map call metadata fields to the schema in §4 — Bland includes `transcript` as a string; we conversationally split if needed.

The webhook payload we expect

POST https://looplogic-2.polsia.app/api/calls/intake with X-Voice-Signature: sha256=<hex> (HMAC of the raw body). A 401 means the secret doesn’t match. A 400 means the payload shape drifted — open the contractor and re-test.

POST /api/calls/intake
application/json
Webhook payload example
{
  "externalCallId": "vapi-call-9b3d4f20-7b4a-4b8c-9a3b-1c2d3e4f5a6b",
  "caller": {
    "phone": "+15551234567",
    "name": "Jamie Rivera"
  },
  "provider": "vapi",
  "contractorSlug": "demo-roofing",
  "startedAt": "2026-07-24T14:32:01.000Z",
  "endedAt": "2026-07-24T14:36:48.000Z",
  "durationSec": 287,
  "transcript": [
    {
      "role": "assistant",
      "text": "Thanks for calling Roof Force — how can I help?"
    },
    {
      "role": "user",
      "text": "We had hail last night and water is dripping in."
    },
    {
      "role": "assistant",
      "text": "I'm sorry to hear that. Is this happening right now?"
    },
    {
      "role": "user",
      "text": "Yeah, in the upstairs bathroom."
    }
  ],
  "hints": {
    "urgency": "immediate",
    "hasInsurance": true
  }
}

End-to-end tests

Run these three calls before handing the dashboard to the contractor. If any scenario lands in the wrong column, edit scoringRules in/dashboard/settings and re-run.

  1. Scenario 1

    Storm damage — immediate response

    Caller reports last-night storm, active leak upstairs, has Homeowner’s Insurance + State Farm.

    Expected score
    >= 60
    Expected status
    qualified
    Booking created
    yes
  2. Scenario 2

    Insurance-active leak — same week

    Ongoing slow leak since last week, Allstate policy, prefers Tuesday afternoon.

    Expected score
    30–60
    Expected status
    qualified
    Booking created
    yes
  3. Scenario 3

    Routine roof replacement — exploratory

    Asking about a full shingle replacement, no insurance involvement, browsing.

    Expected score
    < 30
    Expected status
    new
    Booking created
    no

Day-to-day operations

The CRM is owner-scoped — the contractor only ever sees their own calls, leads, and bookings. There’s no “super-admin” view in v1; LoopLogic ops use the Polsia database tools to investigate issues.

HMAC secret rotation
Rotate VOICE_WEBHOOK_SECRET via set_app_secret. The voice platform must be reconfigured the same minute — webhook deliveries with the old signature will 401 until both sides switch. Rotate after the contractor has a quiet day.
Schema drift on the voice platform
No-code providers change webhook contracts without warning. Our zod parser fails closed with a 400 — the partner surfaces a clear “payload modified” error. The raw column captures every byte so we can investigate without asking the contractor for the tenant-side logs.
Email rate limit
LoopLogic sends one notification email per lead, routed to looplogic-2@polsia.app. Polsia’s free tier caps at 50/day per company. Plan onboarding around it — heavy storm weeks can hit the cap; we degrade gracefully (DB row persists; email is courtesy).
What we don’t ship in MVP
No SMS gateway, no live calendar sync, no multi-tenant theming. The booking flow ends with the contractor confirming the slot manually — that link in the dashboard records confirmedSlot + the meeting URL the contractor pastes in. Calendar integration is next.

Need a hand during onboarding?

Email looplogic-2@polsia.app and tell us which step you’re on. Include the contractor slug and the most recent run identifier if you have one.

Brand color seed for this document: #da9a4c · background seed: #fffaf3.