ACTION_ID: ackdb_entity_lookup NAME: ackDB: Lookup company or contact CATEGORY: Integration CREDITS: 0 Search ackDB per field and return the single best match — a company or a contact, with its traits, identity links and relationships. ================================================================================ PREREQUISITE — USER ACTION REQUIRED ================================================================================ This action only works if the user has connected their ackDB tenant in Floqer. The connection cannot be made by an AI agent. The user must do this themselves before this action will run: 1. Sign in to Floqer at https://app.floqer.com 2. Open the Connections page from the sidebar 3. Click ackDB and enter the tenant Base URL and API key (Base URL is per-tenant, e.g. https://acme.api.ackdb.ai) If the user has not connected ackDB, this action fails with "No ackDB connection found for the user". Before configuring or running this action, confirm with the user that the ackDB connection exists. INDEX: 1. Inputs 2. Outputs 3. How to configure 4. Key notes 5. Where it fits in a workflow 6. When to use 7. When not to use ================================================================================ 1. INPUTS ================================================================================ ackdb_lookup_type (dropdown, required) Lookup type. Picks the record type, which search fields appear, and which endpoint is called. Values: - { id: "entity", name: "Company / Entity" } (default) - { id: "contact", name: "Contact" } Fill at least ONE search field for the selected type. Every field you fill must match — they are ANDed. --- Company / Entity fields (shown when ackdb_lookup_type = "entity") --- entity_name (string, optional) Company name. Case-insensitive, ranked exact > starts-with > contains. entity_domain (string, optional) Domain, e.g. acme.com. entity_identity (string, optional) Identity value. Match ANY ID linked to the company — a Stripe customer ID, Slack channel ID, CRM account ID, email, domain, and so on. query (string, optional) Match any field. Free text matched across the company name and every linked ID. Use when you do not know which field the value belongs to. maxContacts (number, optional) Max contacts. Caps how many of the matched company's contacts are returned (highest-priority first). Leave blank to return all. --- Contact fields (shown when ackdb_lookup_type = "contact") --- contact_name (string, optional) Contact's full name. contact_email (string, optional) Contact's email address. contact_phone (string, optional) Contact's phone number. contact_title (string, optional) Contact's job title. contact_department (string, optional) Contact's department. contact_linkedin (string, optional) Contact's LinkedIn profile URL. contact_query (string, optional) Match any field. Free text matched across all contact fields (name, email, phone, title, department, LinkedIn). ================================================================================ 2. OUTPUTS ================================================================================ The action emits ONE flat union of keys for both lookup types. The keys belonging to the other branch come back blank — a company match blanks the contact keys, a contact match blanks the company-only keys. found (boolean) — Found. --- Company keys --- entityId (string) — Entity ID. On a CONTACT match this carries the contact's PARENT company id. entityName (string) — Entity Name. Company match only. contacts (string) — Contacts. JSON-stringified array. Company match only, capped by maxContacts. --- Contact keys --- contactId (string) — Contact ID. name (string) — Contact Name. email (string) — Contact Email. phone (string) — Contact Phone. title (string) — Contact Title. department (string) — Contact Department. linkedinUrl (string) — Contact LinkedIn URL. isExternal (boolean) — Is External Contact. status (string) — Contact Status. firstSeenSource (string) — First Seen Source. firstSeenAt (string) — First Seen At. lastSeenAt (string) — Last Seen At. entity (string) — Parent Company. JSON-stringified object. --- Shared --- createdAt (string) — Created At. updatedAt (string) — Updated At. traits (string) — Traits. JSON-stringified array. identityLinks (string) — Identity Links. JSON-stringified array. matchedOn (string) — Matched On. JSON-stringified object explaining WHY ackDB matched: { field, value, tier } where tier is exact | prefix | contains. `traits`, `identityLinks`, `contacts`, `matchedOn` and `entity` are JSON STRINGS, not nested objects. Parse them in a format_data_using_js_expression step before reading into them. ================================================================================ 3. HOW TO CONFIGURE ================================================================================ Configure Action body — company by domain: { "inputs": { "ackdb_lookup_type": "entity", "entity_domain": "{{input.domain}}" } } Company by any linked ID (you do not know which system it came from): { "inputs": { "ackdb_lookup_type": "entity", "entity_identity": "{{input.stripe_customer_id}}", "maxContacts": 25 } } Contact by email: { "inputs": { "ackdb_lookup_type": "contact", "contact_email": "{{input.email}}" } } Narrow a contact match by ANDing fields: { "inputs": { "ackdb_lookup_type": "contact", "contact_name": "{{input.full_name}}", "contact_department": "Engineering" } } Field-by-field: - ackdb_lookup_type "entity" or "contact". Everything else is gated on this. - entity_* / contact_* Per-field criteria. All supplied fields are ANDed — more fields means a narrower match. - query / contact_query Match-any free text. Use INSTEAD of the per-field criteria when the value's field is unknown. - maxContacts Company scope only. Caps the returned contacts array. ================================================================================ 4. KEY NOTES ================================================================================ - Returns the SINGLE best match, not a list. Ranking is case-insensitive: exact > starts-with > contains. `matchedOn` tells you which field won and at what tier — check it when a fuzzy match looks surprising. - NO MATCH FAILS THE ROW. When nothing matches, the action does NOT quietly return `found: false` for you to branch on — the row is terminated as a business failure and the UI shows "No data found". Whether downstream actions still run for that row is then governed by this action's `continue_workflow_if_action_fails` flag. For any lookup-then-write pattern, set it explicitly to `true`: the unmatched rows are usually exactly the ones the downstream write is meant to handle. This is the most common configuration mistake with this action. Because a miss fails the row rather than returning cleanly, `found` is only useful for branching when the flag lets the row continue. - On a miss — and on every company lookup — the contact-only outputs come back BLANK (`contactId` is `""`). That is by design. It matters when feeding `contactId` into ackdb_ingest as a person rail; see the ingest doc's KEY NOTES ("pinning to a contact"). - At least one search field is required for the selected type. Sending none fails with a missing-query error. - Both lookups are reads and cost 0 credits. ================================================================================ 5. WHERE IT FITS IN A WORKFLOW ================================================================================ Enrich a row from the event store: ackdb_entity_lookup (entity) -> format_data_using_js_expression (parse `traits`) -> push_data_to_sheet Lookup-first ingest — pin an event to a known human: ackdb_entity_lookup (contact) -> ackdb_ingest (body sets "contactId": "{{lookup.contactId}}") On a hit the event is pinned to that exact contact. On a miss the blank contactId is dropped by ingest and ackDB mints the contact from the event's own mapping — so the row still lands. Set `continue_workflow_if_action_fails: true` on the lookup so the unmatched rows actually reach the ingest. Route on existence: ackdb_entity_lookup -> workflow_if_else on `found` -> ackdb_update_record / ackdb_ingest ================================================================================ 6. WHEN TO USE ================================================================================ Use ackdb_entity_lookup to READ a company or contact out of ackDB — to enrich a row with stored traits, to resolve an authoritative contactId/entityId before writing, or to check whether a record exists. ================================================================================ 7. WHEN NOT TO USE ================================================================================ Need to write an event into ackDB -> ackdb_ingest (https://floqer.com/docs/action-detail/ackdb_ingest.txt) Need to set static fields / owner / identity links on a record -> ackdb_update_record (https://floqer.com/docs/action-detail/ackdb_update_record.txt) Need a LIST of matches rather than the single best one -> Not supported by this action. Query the ackDB API directly with http_api_call (https://floqer.com/docs/action-detail/http_api_call.txt) ================================================================================ This file is maintained manually. Last updated: 2026-07-13. Full interactive reference: https://floqer.com/docs/reference Action catalog: https://floqer.com/docs/action-catalog.txt