Skip to content
IntegrationscontactLookup

Look up contact

Resolves the caller's phone number against your address book and hydrates {{contact.*}} for the rest of the call — display name, company, email, tags, not…


type: contactLookup status: stable sinceVersion: 0.1.0 seeAlso: [integration, httpCall, customScript] keywords: ["contactLookup", "look", "contact", "integrations"]

What it does

Resolves a phone number against your org's address book and hydrates vars._contact for the rest of the call — display name, company, email, notes, and tags. Once the lookup succeeds, every downstream {{contact.x}} template in TTS prompts, screenPop HTML/URLs, and integration inputs resolves through that record without you needing to re-fetch.

The match is exact on E.164 against the contact's numbers JSONB array, so a single contact with a mobile and a desk number resolves from either. By default the node looks up {{event.from}} (the caller's number); override with any template that resolves to E.164 if you'd rather match on a number your flow already gathered (e.g. {{vars.gatheredAccountNumber}}). The node always routes — it has no error path. A miss is a routing decision, not a failure: the notFound branch fires, vars._contact is cleared so stale data from an earlier lookup can't leak through, and the flow continues.

When to use it

  • Personalize a greeting ("Welcome back, {{contact.displayName}}") only when the caller is recognized
  • Drive an agentNotify or screenPop to surface contact context the moment an agent picks up
  • Branch to a different sub-flow for known vs. unknown callers
  • Use the contact's tags (e.g. "vip", "flagged") to skip a menu and route directly to a queue
  • Hydrate {{contact.id}} so a downstream screenPop deep-links straight into your CRM

Configuration

Resolves the caller's phone number against your address book and hydrates {{contact.*}} for the rest of the call — display name, company, email, tags, notes. Routes on "Found" or "Not found" so you can pop a personalized record for known contacts and a generic greeting for new ones. The lookup is exact-match on E.164.

FieldLabelTypeRequiredDefaultNotes
phoneFieldPhone number to look uptextOptional{{event.from}}Defaults to the caller's number. Override with any template that resolves to E.164 (e.g. {{vars.gatheredAccountNumber}}).

Outgoing events: found, notFound

Examples

Caller-aware greeting

Look up the inbound number, then route to a personalized greeting on found and a generic one on notFound.

{
  "id": "lookup",
  "type": "contactLookup",
  "config": {
    "phoneField": "{{event.from}}"
  },
  "on": {
    "found": "say-known",
    "notFound": "say-unknown"
  }
}

Lookup on a gathered account number

Take a number the caller typed into a gatherDigits step and resolve it against the address book instead of the calling number.

{
  "id": "lookup-by-account",
  "type": "contactLookup",
  "config": {
    "phoneField": "{{vars.accountNumber}}"
  },
  "on": {
    "found": "agent-pop",
    "notFound": "voicemail"
  }
}

Gotchas

  • Match is exact-E.164. The query uses a JSONB containment match (numbers @> '[{"e164":"..."}]'::jsonb). A contact stored as +12025550123 won't be hit by a lookup of 2025550123 — same number, different string. The node normalizes the input before querying, but contacts with non-E.164 stored values won't resolve.
  • notFound is the routing default if no edge is wired. When neither found nor notFound has an outgoing edge, the worker falls back to the first transition on node.on. That makes a half-wired flow advance instead of stalling, but it can also send unknown callers down the "found" path if you only wired one edge.
  • vars._contact is cleared on a miss. A previous lookup's record doesn't linger — every notFound branch starts with empty contact vars. If you cache an earlier contact id elsewhere, save it on a separate vars.x first.
  • Tags are an array. {{contact.tags}} renders the array; if you want to test for a specific tag, use a branch node with a contains case on contact.tags rather than a string-equals check.
  • Anonymous callers fall straight to notFound. When the carrier doesn't pass event.from (private/withheld number), the normalized phone is empty and the lookup short-circuits before hitting the database. Wire the notFound branch defensively.
  • No error path — only found/notFound. Database errors are caught upstream and surface as a notFound (with a worker log entry). The flow never halts on a contact lookup, even if the query throws.