Skip to main content

Overview

A Contact represents a person across their entire lifecycle with your product — from anonymous visitor, to form lead, to authenticated user. All three stages live in the same collection and are distinguished by a kind discriminator: In the dashboard, all three live under Contacts: /contacts (users), /contacts/leads, and /contacts/anonymous.

Identity lifecycle

  • An anonymous contact is promoted to lead when a strong identifier (external id, email, or E.164 phone) arrives — contact.identified is emitted and identifiedAt is set.
  • A lead becomes a user when promoted from the dashboard, assigned to an existing user, or when the person signs up with the same email (the user record is enriched — “the user always wins” — and contact.merged is emitted).
  • identityStatus tracks where the contact stands: anonymous, identified, or conflict.

Identity resolution

Incoming submissions are matched against active contacts in priority order: externalUserIdemail (normalized lowercase) → phone (E.164 only) → anonymousId.
  • One match → the contact is updated. Traits merge per key; profile fields never overwrite existing values.
  • No match → a new contact is created.
  • Multiple matches → an identity conflict. Hacktionbase never auto-merges: the contact is flagged identityStatus: conflict with its candidates in conflictsWith, a contact.identity_conflict event is emitted, and the conflict banner appears on the lead’s detail page. Resolve it by assigning the contact to a user (API or UI). The one exception: an exact email match on a user is our default identifier, so the submission enriches that user directly.
Every submission appends an entry to the contact’s sources[]: source, formId, formType, ip, userAgent, receivedAt. A contact arriving from several forms keeps the full trail. Consent (marketing, termsAccepted) is captured and timestamped on every submission. Contacts are created regardless of consent — consent gating for specific channels is the client’s responsibility as data controller.

Events

Every capture emits events — system events (contact.created, contact.updated, contact.form_submitted, contact.identified, contact.merged, contact.identity_conflict) plus an optional business event supplied by the caller (e.g. quote.requested). They feed segments, automations, inbox, campaigns, analytics, and AI like any other event, and can be consolidated in Analytics → Discovery via the Map Events modal.

Organizing contacts

Leads share tags and categories with users and accounts, and have their own statuses (lead-only pipeline states). Notes work on leads exactly as they do on users. Segments can target contacts by kind.

Contact Capture API

Push form submissions into Hacktionbase with a single POST.