Skip to content

15. Events and Entities Schemas

Events and Entity Schemas

FirstHive’s data model has two layers: an immutable stream of events, and a set of entities — Customer, Transaction, and so on — that are continuously derived from that stream. This page defines the standard (retail/D2C) schema for both, and how one becomes the other.

Architecture: Events First, Entities Derived

  • Events are immutable. Once an event is ingested, it is never edited or overwritten. Every state change — an order shipping, a subscription pausing, a refund issuing — arrives as a new event, not a modification of a past one.
  • FHID is assigned in real time, at ingestion. Every event is resolved against FirstHive’s identity graph and stamped with an fhid the moment it’s ingested — there is no batch or deferred unification step for this. See Unification and Identity Resolution for the matching logic behind this.
  • FHIDs can still merge later. Because two events tracked under different identifiers (say, an email captured in one channel and a phone number in another) can later turn out to belong to the same person, previously separate FHIDs can be merged as identity resolution improves. The events themselves don’t change — only which unified profile they roll up under.
  • A derivation engine builds entities from events. Customer, Transaction, and TransactionItem are not ingested directly — they’re computed and kept current by a derivation engine that reads the event stream. When a new event changes an entity’s state (e.g. an “Order Shipped” event), the engine doesn’t rewrite history; it records the new event and recomputes the entity’s current-state fields (e.g. txn_status, fulfillment.status) from the full event history.
  • Entities themselves are not separately billed. Only events count toward the events quota — creating or enriching an entity is a by-product of the events that feed it. See Understanding Events in FirstHive for the full quota mechanics, including how inbound vs. outbound events are counted and a correction worth knowing if you’re sizing an API-heavy integration: outbound API responses count as two events (one for the request, one for the response), not one.

The Default Schema (Retail / D2C)

FirstHive ships four standard entity schemas by default, applicable out of the box to retail and D2C use cases. Every entity has its own required fhid (binary) and acc_id (account identifier); most also support a large custom-field extension pattern (see below).

Event

The atomic, immutable record. Every tracked interaction is stored as one of these.

FieldTypeRequiredDescription
acc_idlongYesAccount identifier
categorystringYesEvent category
event_idbinaryYesUnique event identifier
event_namestringYesEvent name
event_datestringYesEvent occurrence date
event_timetimestampYesEvent occurrence timestamp
event_typestringYessystem or custom
fhidbinaryYesFirstHive unified identifier, assigned at ingestion
event_labelstringNoLabel of the event source
event_sourcestringNoSource of the event
sidbinaryNoSession identifier

Nested objects on Event:

  • campaign: id, channel, journey_id, template_id, variant_id, msg_id
  • channel: utm_source, utm_medium, utm_campaign, utm_content, utm_term, ad_creative, ad_group, landing_page_url, referral_url, grouping
  • device: id, type, platform, os, os_version, brand, model, browser, screen_resolution, view_port, user_agent, connection_type, network_provider
  • geo: city, region, country, latitude, longitude, timezone
  • tech: ip, app_version
  • custom: pattern-based client-defined fields (see below)

Customer

The unified profile entity, derived from the event stream.

FieldTypeRequiredDescription
acc_idlongYesAccount identifier
fhidbinaryYesFirstHive unified identifier
cidstringNoCustomer identifier
pfhidbinaryNoPrior/parent FHID (pre-merge reference)
unifiedbooleanNoWhether this record has completed unification
tagsarrayNoFree-form tags
created_at / updated_at / updated_datetimestamp/stringNoRecord audit timestamps

Nested objects on Customer:

  • contact: email, mobile, alternate_email, contact_android_device_id, contact_ios_device_id, contact_web_device_id, preferred_contact_method
  • consent: email, sms, whatsapp, rcs, mobilepush, webpush (all boolean)
  • demography: first_name, last_name, middle_name, full_name, salutation, gender, dob, age, marital_status, education_level, occupation, income_bracket, language, region, city, country, zip_code
  • reachability: preferred_channel, best_time_to_contact, and per-channel booleans (email, sms, whatsapp, rcs, mobile_push, web_push)
  • tx (derived behavioral/transactional summary — computed, not ingested): first_purchase_date, last_purchase_date, purchase_count, frequency, recency, monetary_value, aov, average_days_between_purchases, frequent_city, preferred_payment_method, mode, customer_segment, and ML-derived fields: ltv, clv_prediction, churn_risk
  • custom: pattern-based client-defined fields (see below)

Transaction

Any purchase, booking, order, or financial event, derived from the underlying event history.

FieldTypeRequiredDescription
acc_idlongYesAccount identifier
fhidbinaryYesFirstHive unified identifier
idbinaryYesUnique identifier
cidstringNoCustomer identifier
id_origstringNoOriginal source-system identifier
invoice_idstringNoInvoice identifier
item_countlongNoNumber of line items
txn_datetimestampNoTransaction date
txn_statusstringNoCurrent transaction status
source, store_id, notes, tagsNoOrigin and free-form metadata

Nested objects on Transaction:

  • amount: subtotal, discount, taxes, total, final
  • billing / shipping: full address blocks (name, first_name, last_name, phone, company, address1, address2, city, province, province_code, country, country_code, zip, latitude, longitude)
  • contact: email, phone
  • payment: method, gateway, status, card_last_four, tx_ref
  • delivery: method, shipping_carrier, shipping_service, estimated_date, actual_date, shipped_date, tracking_number, tracking_url, fee, is_free, is_expedited, shipment_status, instructions
  • cancellation: state, date, reason, initiated_by
  • refund: status, amount, date, reason, transaction_id
  • replacement: state, original_order_id
  • review: status, description
  • points: earned, used, is_used, value
  • order: issue_state, issue_description
  • sales: channel_id, channel_name
  • channel: utm_campaign, utm_medium, utm_source
  • device: ip_address, session_id, user_agent
  • demography: first_name, last_name

TransactionItem

One line item within a Transaction — its own independent entity, linked back via txn_id.

FieldTypeRequiredDescription
acc_idlongYesAccount identifier
fhidbinaryYesFirstHive unified identifier (independent of the parent Transaction’s)
idbinaryYesUnique identifier
id_origstringYesOriginal source-system identifier
txn_idbinaryYesParent Transaction identifier
txn_id_origstringYesParent transaction’s original source-system identifier
created_at / updated_at / updated_dateNoRecord audit timestamps

Nested objects on TransactionItem:

  • item: id, sku_id, variant_id, name, category, subcategory, quantity, serial_no, warranty_info, expiry_date
  • price: mrp, selling, total, taxes, tax_included
  • discount: applied, amount, coupon_code
  • fulfillment: status, date
  • cancellation: state, date, reason
  • return: status, date, reason
  • replacement: state, item_id, reason
  • gift: state, message
  • subscription: enabled, id, status, frequency, iteration_id, iteration_number

Custom Field Extension Pattern

Customer and Event both support the same client-defined custom field mechanism — up to 420 custom fields per entity, addressed by pattern rather than fixed name:

PatternTypeCount
a1–a10array10
b1–b100boolean100
m1–m10map10
n1–n100double100
s1–s100string100
t1–t100timestamp100

The Transaction and TransactionItem schema exports provided don’t show this same custom-field block — that may mean it isn’t supported on those two entities, or simply wasn’t included in the export. Worth confirming rather than assuming either way.

Tracking-Time Events vs. the Stored Event Schema

The FH Tracking API parameters used to send an event in (idsite, e_c category, e_a action, e_n name, e_v value, dimension[1-10]) map onto the stored Event entity above once ingested: e_c → category, e_n → event_name, and the tracking API’s 10 dimension slots are a small subset of the much larger custom-field capacity (420 fields via the a/b/m/n/s/t pattern) available on the stored entity. event_label and event_source capture additional context not present as tracking-time parameters.

One gap: the stored Event schema has no top-level field that obviously corresponds to e_a (event action). This needs confirmation from whoever owns the ingestion pipeline — whether it’s folded into event_name, event_label, or something else.

Vertical-Specific Schema Templates

The schema above is the default, used for retail and D2C. FirstHive maintains additional schema templates for other verticals. Six are documented below from real

implementation/reference material; each has its own dedicated skill reference for full field-level detail.

Real Estate

Two levels exist: a generic 4-entity template (FH_Customer, RE_Lead, RE_Opportunity, RE_Appointment) intended as the reusable starting point, and a 5-entity variant some customers implement (adding a standalone RE_Account custom entity alongside FH_Customer, with PII dual-written to both — RE_Account as the CRM record of truth, FH_Customer as the unified identity). Use the 5-entity variant when the source CRM’s account object carries substantial non-PII operational data (sales assignments, channel partner detail) that belongs with the CRM record rather than the person profile.

Every non-Customer entity carries fh_source_system_id (the CRM’s raw cross-entity key) alongside FHID, and each has its own independent auto-increment PK (lead_pk, opp_pk, appt_pk). Identity resolution priority: system ID (deterministic) → email (deterministic) → mobile (deterministic) → name + city (probabilistic, flagged for review).

Airlines

Airlines don’t fit the simple “one entity type per record type” pattern — a single booking can involve up to three human roles (Passenger, Booker, Agent), and the same real person can occupy more than one. Each role gets its own Custom Entity with its own named FK to FH_Customer (pax_fhid, booker_fhid, agent_fhid) rather than a shared generic FHID; identity resolution — not the schema — determines whether those FKs collapse to one FHID. A self-booking passenger is one FHID; someone booking for a family member is two.

Core entities: FH_Customer, AIRL_Passenger, AIRL_Booker, AIRL_Agent, AIRL_Booking (carries all three role FKs at once), AIRL_PaxJourney (Transaction Entity — one row per passenger per flown leg), AIRL_Loyalty, AIRL_SSR (special service requests), AIRL_FlightOps (Event Entity — flight delay/cancellation, joined to passengers via the flight leg rather than tied to a passenger record directly), and AIRL_Voucher.

Identity resolution runs a nine-tier deterministic priority order before falling back to probabilistic matching — frequent flyer number and any pre-computed cross-booking person GUID rank highest, followed by passport/government ID + name, then progressively looser name/email/mobile combinations. Frequent flyer numbers are typically pre-validated by an upstream system and can be trusted without additional name verification.

Fintech / Payments

Covers both card/rewards-led products (credit cards, loyalty coins, lending) and account/banking-led products (savings accounts, wallets, service requests) — a company can need both entity families at once. Core entities: FH_Customer, FIN_CreditCard, FIN_Account, FIN_Wallet, FIN_LoanApplication, FIN_RewardAccount, FIN_ServiceRequest, and FIN_AccountProduct (a generalized multi-product onboarding record, useful when a bank sells many product lines through one KYC flow).

Standard payments and transfers map to the ordinary FH Transaction entity — there’s no separate fintech-specific transaction schema. KYC and compliance fields (kyc_status, PAN, CKYC ID, tokenised Aadhaar reference) are load-bearing: they gate onboarding journeys and regulatory transaction limits, not just informational flags. One identity-resolution nuance specific to this vertical: for mobile-first or telco-linked products, mobile number — not email — is often the primary identity anchor. Raw Aadhaar numbers may never be used as an identity field; only the UIDAI-mandated tokenised reference is permitted.

Insurance

A fixed 4-entity model applies across every line of business (motor, health, travel, fire, marine): Policy (the contract, 1 per policy), Policy Member (who’s covered — 1–6 rows, e.g. proposer + nominee for motor, or a full family floater for health), Asset (what’s insured — polymorphic, with different field sets for vehicle/health-profile/trip/property variants), and Asset Coverage (every coverage, add-on, discount, and deductible as its own row — typically 25–45 rows per motor policy). Every FK uses a dual-column pattern: a binary UUID for performant joins plus a string _orig column for API responses and debugging.

Loyalty

A 5-entity model: Customers (member profile, ingested via CSV or the /customers API), Earn Points, Burn Points, Redemption Data (order-level), and Redemption Items (line-item detail, linked to Redemption Data via redemption_id). All four event entities resolve to a customer profile via mobile as the primary key. Entities must be ingested in dependency order — Customers first, then Earn/Burn/Redemption Data, then Redemption Items last (since it depends on its parent Redemption Data record existing).

AMCs (Asset Management Companies)

Nine entities: FH_Customer (Investor), AMC_Folio (the scheme-level portfolio account — an investor can hold several), AMC_Transaction (purchase/redemption/switch/SIP-credit/dividend), AMC_SIP_Registration and AMC_ACH_Mandate (standing instructions and the bank mandate backing them — mandate failures and expiries are high-priority service triggers), AMC_Scheme_Master and AMC_Distributor (fund and broker catalogues), and AMC_Campaign_Event /

AMC_Investor_Analytics (interaction log and daily AUM/segment snapshot).

Two things worth calling out because they don’t follow the pattern of the other verticals above:

  • Reference Entities. AMC_Scheme_Master and AMC_Distributor are catalogues — many folios and transactions point to a fund or a distributor, but a fund isn’t “owned” by any one investor. These get their own natural-key PK (scheme_code, arn_number) and no FHID column at all — a new entity category beyond Profile/Transaction/Custom/Event, worth generalizing to any vertical with a shared product or partner catalogue (a hotel chain’s property master, a real-estate project master).
  • PAN outranks email as the primary identity key. Unusually for a CDP, the strongest cross-system identity signal here isn’t email or mobile — it’s PAN (India’s tax ID), because it’s mandatory for KYC and, unlike most identifiers, reliably matches the same person across genuinely different AMC source systems. Folio number, by contrast, looks like an identity field but is account-scoped and must never be used to match across AMCs.

Full field-level detail, both source mappings, identity resolution priority order, and 25 activation use cases (SIP payment-failure alerts, KYC/FATCA compliance triggers, NFO launch campaigns, SEBI-mandated Risk-O-Meter change notices, and more) are in the AMC schema reference.

Related