The SignalSEP 25, 2026 / 22 min read

Email Automation Workflow & Drip Campaign Data Structure

Learn the database schema behind email drip campaigns—tables, workflow states, and event logs that power reliable marketing automation.

Drip Campaign Data Structure: Schema for Email Automation — email marketing automation workflow drip campaign data structure

Marketers ask me what a drip campaign "actually is" almost every week, and there's always a second question hiding behind it: what does the database look like underneath the pretty workflow builder? If you've ever tried to debug why a contact got the wrong email, or you're scoping a custom integration with your CRM, you already know that the visual canvas is just a skin. The real answer lives in tables, foreign keys, and a queue that gets polled every few seconds.

Quick answer: An email marketing automation workflow drip campaign data structure relies on a relational schema made up of at least seven interlocking tables: campaigns, templates, workflows, workflow steps, contacts, a contact queue, and an event log. Together these tables separate three concerns: what should happen (definition), what is currently happening for each contact (state), and what already happened (history). A workflow engine reads this schema on a loop, resolves delays into timestamps, and moves each contact through the sequence one queued row at a time.

That one paragraph is the whole concept in miniature. Everything below unpacks it for two audiences at once: marketers who need to understand what their email service provider is doing behind the scenes, and developers or marketing-ops hybrids who need to design, audit, or debug the actual drip campaign database schema.

What Is the Email Marketing Automation Workflow Drip Campaign Data Structure?

At its core, this data structure is the set of database tables and relationships that let software send the right email, to the right contact, at the right moment, without a human clicking "send" each time. It's the difference between a spreadsheet of email addresses and a system that knows Contact #4821 is on step 3 of the "trial signup" workflow, is due for the next email in six hours, and already opened the last two messages.

Every mature implementation, whether it's a homegrown Postgres schema or the internal architecture of an ESP, answers the same three questions with its tables:

  1. What is supposed to happen? The campaign and workflow definition.
  2. What is happening right now, for this specific person? Contact state.
  3. What already happened? The historical event log.

The Three Core Concerns: Definition, State, and History

Keeping these three concerns in separate tables is the single most important design decision in the whole schema, and it's the mental model worth memorizing before you look at a single field name.

  • Definition tables describe the workflow itself: the campaign, its steps, its delays, its branching rules. These rows rarely change once a campaign is live.
  • State tables describe where each individual contact sits inside that definition right now: which step they're on, when their next action is due, whether they're paused.
  • History tables are an append-only record of what already happened: every send, open, click, bounce, and unsubscribe, timestamped and immutable.

If you mix these concerns into one giant table, you get exactly the kind of bugs that make drip campaigns misbehave: editing a live workflow accidentally rewrites history, or a state change gets lost because it was crammed into a definition row that nobody expected to update.

Why This Matters for Marketers and Developers Alike

A marketer running campaigns inside an ESP dashboard will never write SQL, but the moment a sequence sends step 2 before step 1, or resends an email a contact already received, understanding this structure is what separates "file a support ticket and wait" from "tell support exactly which table to check." For developers, this schema is the actual product. Get it wrong and you'll fight data integrity bugs for years. Get it right and adding a new trigger type or channel is a schema migration, not a rebuild.

If you're building your first automated sequence rather than architecting a database, our companion guide on building an email automation workflow walks through the practical setup steps that sit on top of everything described here.

Why the Data Structure Behind Drip Automation Matters

A badly modeled schema doesn't just create engineering headaches. It quietly destroys the revenue automation is supposed to generate. Segmented, automated campaigns depend entirely on accurate contact state and clean event history. If either is broken, personalization breaks with it.

The Business Case: ROI and Personalization Data

Segmented email campaigns generate significantly more revenue than one-size-fits-all blasts, and personalization has moved from "nice to have" to expected. Consider these numbers:

StatisticSource
Marketers report email remains one of the highest-ROI channels available, frequently cited around $36-$40 for every $1 spentLitmus, State of Email
Companies that excel at personalization generate more revenue from those efforts than average performersMcKinsey & Company, personalization research
Behavior-triggered automated emails consistently outperform generic time-based blasts on engagement metrics across ESP benchmark reportsIndustry ESP benchmark reporting

None of that ROI reaches you without a schema that can hold segmentation logic, behavioral triggers, and accurate send history. The benefits of marketing automation compound only when the underlying data model is sound.

What Happens When the Schema Is Missing or Weak

I've seen the failure modes, and they follow a predictable pattern:

  • Duplicate sends. No idempotency key on the queue table means a retry after a timeout fires the same email twice.
  • Stuck contacts. A contact's state row never updates because the workflow engine crashed mid-transaction, leaving them frozen on step 2 forever.
  • Wrong personalization. The Contacts table lacks the custom fields a template references, so merge tags render as blank text or literal {{first_name}} strings.
  • Compliance exposure. No consent or unsubscribe status field means a suppressed contact gets emailed anyway, risking CAN-SPAM or GDPR violations.
  • Broken reporting. Without an append-only event log, marketers can't reconstruct what actually happened, only what the current state looks like.

Every one of these is a data structure problem wearing a marketing costume.

The Core Tables in a Drip Campaign Database Schema

The drip campaign data structure template includes seven core tables almost every email automation system needs, listed in the order data flows through them:

  1. Campaigns
  2. Templates
  3. Workflows
  4. Workflow_Steps
  5. Contacts
  6. Contact_Queue
  7. Event_Logs

Campaigns Table

This is the top-level container. It holds the campaign's name, its owner, its status (draft, active, paused, archived), its overall goal, and timestamps for creation and last edit. Think of it as the folder everything else lives inside.

Templates Table

Templates store the actual email content: subject line, HTML body, plain-text fallback, and a list of the template variables (merge fields) it expects, like first_name or trial_end_date. Keeping templates in their own table, separate from workflow steps, lets one template get reused across multiple campaigns without duplication.

Workflows Table

A workflow is the logical sequence attached to a campaign. It stores the entry trigger type (time-based, behavioral, or a hybrid), re-entry rules (can a contact go through this workflow twice?), and its overall version number. This table is pure definition.

Workflow_Steps Table

Each row here is one email or action inside the workflow: its position in the sequence, which template it uses, its delay configuration (a number plus a unit, like "3 days" or "6 hours"), and any conditional branching rules ("if opened previous email, go to step 4a; if not, go to step 4b"). This is where drip logic and automation logic start to diverge.

Contacts Table

This is the person record: email address, name, custom fields, lifecycle stage, consent and unsubscribe status, and increasingly, enrichment and intent-scoring fields. It's the table every other table eventually points back to via a foreign key.

Contact_Queue Table

This is the state table. Each row represents one contact's current position inside one active workflow: which step they're on, the resolved execute_at timestamp for their next send, and a status flag (pending, processing, sent, failed, skipped). This table changes constantly and should never be confused with the static workflow definition.

Event_Logs Table

This is the history table. Every send, delivery confirmation, open, click, bounce, complaint, and unsubscribe gets an immutable, timestamped row here, referencing the contact and the workflow step that triggered it. Analytics, reporting, and compliance audits all read from this table.

Core Tables Reference

TableTypeKey FieldsPurpose
CampaignsDefinitionid, name, status, owner_id, created_atTop-level container for a marketing initiative
TemplatesDefinitionid, subject, html_body, variables_jsonReusable email content and merge-field contract
WorkflowsDefinitionid, campaign_id, trigger_type, reentry_allowed, versionThe logical sequence and its entry rules
Workflow_StepsDefinitionid, workflow_id, position, template_id, delay_value, delay_unit, branch_conditionIndividual emails/actions and their timing/branching
ContactsDefinition/Referenceid, email, custom_fields_json, consent_status, lifecycle_stage, intent_scoreThe person record every other table references
Contact_QueueStateid, contact_id, workflow_id, current_step_id, execute_at, statusWhere each contact sits right now, and when they're due next
Event_LogsHistoryid, contact_id, workflow_step_id, event_type, occurred_atImmutable record of every send and engagement event

Mental model callout: If you only remember one thing from this section, remember this: Campaigns, Templates, Workflows, and Workflow_Steps define the plan. Contact_Queue tracks the plan's execution for a specific person. Event_Logs proves what actually happened. Confusing any two of these is where most schema bugs are born.

How the Execution Engine Actually Works

The tables above are static furniture until something reads them on a schedule. That "something" is the workflow engine, and this is the part almost no competing guide explains in real mechanical detail.

Resolving Delays Into Timestamps

A Workflow_Step doesn't store "send in 3 days" as a vague instruction. It stores a delay_value of 3 and a delay_unit of "days." The moment a contact enters that step, the engine calculates a concrete execute_at timestamp by adding that delay to the current time (often normalized to an ISO 8601 UTC timestamp to avoid timezone bugs) and writes it into the Contact_Queue row. From that point forward, the engine only cares about whether execute_at is now in the past.

How the Queue Worker Polls and Fires Sends

A background process, often a cron job or a persistent queue worker, runs on a tight interval (commonly every 30 to 60 seconds in high-volume systems) and asks the database one question: "Which Contact_Queue rows have execute_at in the past and a status of pending?" For every row that matches, the worker:

  1. Locks the row (to prevent a second worker from grabbing it simultaneously)
  2. Loads the associated Contacts row and Workflow_Steps row
  3. Resolves the template's merge fields against the contact's data
  4. Sends the email through the transport layer (SMTP relay or ESP API)
  5. Writes a new Event_Logs row recording the send
  6. Updates the Contact_Queue row to the next step, recalculating execute_at, or marks the workflow complete

This poll-lock-process-log cycle is the entire "engine." There's no magic, just disciplined, repeated database reads and writes.

Retry Logic, Failures, and Idempotency

Sends fail. APIs time out. A worker process can crash mid-send. This is where idempotency, a concept borrowed from distributed systems engineering, becomes essential: each send attempt should carry a unique idempotency key so that if the same job gets picked up twice (say, after a timeout that wasn't actually a failure), the system recognizes the duplicate and skips it rather than emailing the contact twice. Well-designed queues also track a retry_count and a last_error field, backing off exponentially between attempts and eventually marking a row as permanently failed rather than retrying forever.

Here's a simplified flow of the whole pipeline in plain text:

Trigger fires - Contact_Queue row created with resolved execute_at - Queue worker polls and locks due rows - Template resolved and email sent - Event_Logs row written - Contact_Queue row advanced to next step (or marked complete)

Drip Campaign vs. Marketing Automation Workflow: Data Structure Differences

This is the distinction most competing articles gloss over, and it's a genuinely different schema shape, not just a marketing label.

A pure drip campaign is time-based: contact enters, a fixed sequence of delays fires emails in order, done. A marketing automation workflow is behavior-based: it listens for events, evaluates conditions against contact data, and branches accordingly, sometimes looping a contact back through earlier steps or exiting them early.

AspectDrip Campaign SchemaMarketing Automation Workflow Schema
Trigger typeSingle time-based trigger (e.g., "signup date")Multiple trigger types: time-based, behavioral (event listener), or attribute-based
Sequence shapeLinear, fixed order of stepsBranching, with conditional paths and possible loops
Workflow_Steps complexityDelay - template, nothing elseDelay, template, plus branch_condition and next_step_if_true/false fields
Re-entry rulesUsually disallowed (one pass per contact)Often configurable (a contact can re-enter after a cooldown or new event)
Event listeningNot required; the engine only checks the clockRequires an event listener or webhook ingestion layer feeding Event_Logs in near real time
Data needed on ContactsMinimal: email, name, signup_dateExtensive: behavioral flags, lifecycle_stage, custom_fields, intent_score
Typical complexity to buildLow; a junior developer can ship this in daysHigher; requires an event-driven architecture or webhook processing pipeline
Best fitOnboarding sequences, newsletter welcome seriesLead nurturing, re-engagement, cross-channel journeys

The practical takeaway: if your Workflow_Steps table has no branch_condition field and your Contacts table has no behavioral event feed, you have a drip schema, even if the vendor calls it "automation." True behavioral automation requires an event-driven layer sitting on top of the same base tables.

For a deeper look at where drip fits inside the broader discipline, our guide on what a marketing automation workflow actually is breaks down the strategic side of this same technical distinction.

A Worked Example: Tracing One Contact Through the Schema

Theory is fine, but nothing beats watching real rows change. Let's trace a single contact, Maria, through a SaaS trial-signup drip campaign, table by table.

Step 1: Trigger Fires (Signup Event)

Maria signs up for a free trial. The application inserts a new row into Contacts and fires a "trial_signup" event.

{
  "id": 4821,
  "email": "maria@example.com",
  "custom_fields": { "first_name": "Maria", "trial_plan": "Pro" },
  "consent_status": "confirmed",
  "lifecycle_stage": "trial",
  "intent_score": null,
  "created_at": "2026-09-20T14:02:11Z"
}

Step 2: Contact Enters the Queue

The "trial_signup" event matches the trigger on the "Trial Onboarding" workflow (workflow_id: 12). The engine creates a Contact_Queue row, resolving the first step's delay (0 minutes, sent immediately) into an execute_at timestamp.

INSERT INTO contact_queue (contact_id, workflow_id, current_step_id, execute_at, status)
VALUES (4821, 12, 101, '2026-09-20T14:02:11Z', 'pending');

Step 3: Workflow Step Resolves and Sends

The queue worker picks up the row, resolves the template's merge fields against Maria's Contacts row, sends the welcome email, and writes an Event_Logs entry. It then advances Maria to step 2, a "3-day check-in," calculating the new execute_at as September 23 at the same time.

UPDATE contact_queue
SET current_step_id = 102,
    execute_at = '2026-09-23T14:02:11Z',
    status = 'pending'
WHERE contact_id = 4821 AND workflow_id = 12;

Step 4: Event Log Captures Engagement

Maria opens the welcome email four minutes later. A tracking pixel fires a webhook, and the system writes another Event_Logs row.

{
  "id": 88291,
  "contact_id": 4821,
  "workflow_step_id": 101,
  "event_type": "email_opened",
  "occurred_at": "2026-09-20T14:06:55Z"
}

If Maria's plan supports behavioral branching, that open event could also update her intent_score and change which of two possible step 2 templates she receives three days later. That's the exact mechanical difference between a drip schema and an automation schema, made concrete.

If you want to see finished sequences before building your own, our roundup of email drip campaign templates shows what these worked examples look like once they're turned into real copy and timing.

How to Design or Audit Your Own Drip Campaign Data Structure

Whether you're building from scratch or auditing an existing ESP integration, the same checklist applies.

Step-by-Step Build Checklist

  1. Separate definition tables (Campaigns, Workflows, Workflow_Steps, Templates) from state (Contact_Queue) and history (Event_Logs).
  2. Give every table a proper primary key and enforce foreign key constraints between Contact_Queue, Contacts, and Workflows so orphaned rows can't exist.
  3. Store delays as a value plus a unit, never as a pre-baked timestamp inside the workflow definition.
  4. Add an idempotency key or unique constraint on send attempts to prevent duplicate emails.
  5. Include a consent_status and unsubscribe timestamp on Contacts, and check it before every queue insert, not just before sending.
  6. Make Event_Logs append-only. Never update or delete rows; only insert.
  7. Version your Workflows table so editing a live workflow doesn't silently corrupt contacts already mid-sequence.

7-Point Schema Audit Checklist

  • Definition, state, and history live in separate tables
  • Foreign keys enforce referential integrity
  • Delays are stored as value - unit, resolved at runtime
  • Idempotency keys prevent duplicate sends
  • Consent/unsubscribe status gates every queue insert
  • Event_Logs is strictly append-only
  • Workflow definitions are versioned

Common Schema Mistakes to Avoid

  • Storing execute_at as a static field on the Workflow_Steps table instead of the Contact_Queue table, which breaks the moment two contacts enter the same step at different times.
  • Skipping foreign key constraints "for speed," which eventually allows orphaned queue rows pointing at deleted workflows.
  • Treating custom_fields as a rigid set of columns instead of a flexible JSON column, which forces a migration every time marketing wants a new personalization field.
  • Forgetting a status field on Contact_Queue entirely, making it impossible to tell a completed contact from a stuck one.

Troubleshooting: When a Drip Send Looks Wrong

This is the section I wish existed the first time a client asked me why their re-engagement campaign emailed someone who had already unsubscribed three weeks earlier.

When a send looks wrong, work through the schema in this order:

  1. Check the Contact_Queue row first. What step does it say the contact is on, and what's the execute_at value? If the row is missing entirely, the trigger never fired, meaning the problem is upstream in event ingestion, not the workflow.
  2. Check the Workflow_Steps definition second. Does the step the contact is supposedly on actually match the template and delay you expect? A recent edit to a live workflow without proper versioning is the single most common cause of "wrong email" bugs.
  3. Check the Event_Logs table third. Does the history show a duplicate send, a missing send, or an unexpected event type? This tells you whether the problem is in triggering, in the queue worker, or in the transport layer.
  4. Check the Contacts row last. Is consent_status current? Did a custom field the template depends on come back null, producing a broken merge tag?
SymptomMost Likely TableWhat to Check
Contact received duplicate emailsContact_Queue / send layerMissing idempotency key or retry without deduplication
Contact stuck on the same step for daysContact_Queueexecute_at not recalculated after send, or worker crash mid-transaction
Wrong template content sentWorkflow_StepsLive edit changed step order or template_id without versioning
Unsubscribed contact still received emailContactsconsent_status not checked before queue insert
Blank merge fields in the emailTemplates / ContactsTemplate references a custom field the contact record doesn't have
No record of what happenedEvent_LogsLogging not wired into the send function, or logs were mutated instead of appended

Solid execution logic here depends heavily on your sending infrastructure staying healthy. Our email deliverability best practices guide covers the transport-layer half of this troubleshooting picture.

Here's a video that walks through the basic mechanics of a drip campaign for readers who want a visual refresher before going deeper into the AI-era schema below.

How AI Is Changing the Email Automation Data Structure

The seven-table schema above has been stable for roughly two decades. What's changing in 2026 isn't the core shape, it's what gets attached to the Contacts table and how segmentation logic gets evaluated.

Audience Graphs and Intent Scoring

A standard Contacts table is a flat list of rows. An audience graph extends that into a network: relationships between contacts (colleague, referral source, same company domain), weighted by behavioral signals, so segmentation stops being "match this static field" and starts being "find contacts similar to my best customers." Intent scoring adds a continuously recalculated numeric field, often updated by a background job that reads recent Event_Logs activity, that feeds directly into branch_condition logic on Workflow_Steps. A high intent score can route a contact down a faster, more direct path; a cooling score can trigger a re-engagement branch instead.

Enrichment Fields and Contact Profiles

Enrichment services append firmographic and demographic data (company size, industry, job title, technographic signals) onto the Contacts record, typically through an asynchronous API call after signup rather than at the moment of insert. This means the Contacts table increasingly needs nullable, JSON-friendly enrichment fields that get filled in over time, plus a timestamp recording when enrichment last ran. Our breakdown of data enrichment services for B2B marketers covers how these providers actually populate that data, and it's worth reading if you're modeling this layer yourself.

Consent and privacy modeling deserves the same rigor as enrichment. A consent_status field alone isn't enough; mature schemas store the specific legal basis for processing, a timestamp of when consent was captured, and the source of that consent, aligned with the requirements described in the official EU GDPR text. If your list-building practices predate this discipline, our piece on scraped email lists and GDPR explains exactly why skipping this modeling work tends to backfire.

MCP/API Layers for AI-Driven Segmentation

The newest layer sitting on top of this whole structure is a standardized API surface that lets an AI system read and write against the schema without a human writing SQL by hand. The Model Context Protocol (MCP), an open standard for connecting AI assistants to external data sources and tools, is a notable example of this pattern showing up across the software industry, letting an AI agent query a contact's current queue state or intent score and make a segmentation decision in natural language rather than a hardcoded rule.

A practitioner's note on how Breaker extends this schema: Breaker's audience graph and intent-scoring layer sit directly on top of the same core tables described in this article - contacts, workflows, and an event log - but expose them through an API/MCP layer so segmentation logic can be expressed as an intent, not a SQL query. That's a vendor-specific implementation of the general pattern described above, not a claim that every ESP works this way. If you're evaluating whether your current platform's data structure can actually support this kind of AI-native segmentation, our Breaker platform review lays out the specifics.

Choosing the Right Platform for Your Data Structure Needs

Not everyone needs to design a schema from scratch, and that's a legitimate choice, not a shortcut.

ApproachBest ForTrade-offs
DIY relational schema (Postgres/MySQL)Engineering teams building a custom product, or unusual compliance/data-residency requirementsFull control, but you own every bug, migration, and scaling problem
No-code ESP (standard workflow builder)Marketing teams without dedicated engineering support who need reliable time-based and basic behavioral dripsFast to launch, but segmentation logic is limited to what the vendor's UI exposes
AI-native ESP with audience graph and API/MCP layerTeams that want behavioral and intent-based segmentation without writing SQL, and want that logic to evolve automatically as new signals arriveNewer category, so evaluate the vendor's actual data model, not just marketing language

If your team is mostly marketers who need dependable sends and clear reporting without managing infrastructure, Breaker is built specifically for that middle ground: the audience graph and event log described in this article power the platform directly, so you get the reliability of a properly normalized schema with the simplicity of a no-code interface. It's worth comparing directly against a traditional workflow builder like HubSpot or a legacy ESP like Mailchimp on exactly this point: can the platform's underlying data structure support true behavioral branching and intent scoring, or is it a time-based drip schema wearing an "automation" label? For B2B teams specifically, our B2B newsletter strategy guide and our B2B content engine guide both build on this same underlying data model in practice.

You can see the full breakdown of Breaker's approach, pricing, and feature set on the Breaker homepage.

Frequently Asked Questions

What is a drip campaign data structure? It's the set of database tables - typically covering campaigns, templates, workflow steps, contacts, a processing queue, and an event log - that together define, track, and record an automated sequence of timed emails sent to a contact.

What database tables are required to build an email automation workflow? At minimum: a Campaigns table, a Templates table, a Workflows table, a Workflow_Steps table, a Contacts table, a Contact_Queue table for state, and an Event_Logs table for history. Larger systems add supporting tables for segments, tags, and enrichment data.

What's the difference between a drip campaign and a marketing automation workflow at the data level? A drip campaign schema is linear and time-based, with Workflow_Steps containing only a delay and a template. A marketing automation workflow schema adds branch_condition fields, event listeners, and re-entry rules, letting the sequence change direction based on contact behavior rather than the calendar alone.

How does an email workflow engine decide when to send the next email in a sequence? The engine resolves each step's configured delay into a concrete execute_at timestamp the moment a contact enters that step, then a background queue worker polls the database on a fixed interval, sending any queued row whose execute_at timestamp has already passed.

What is a contact queue in email automation? A contact queue is the state table that tracks exactly where each individual contact sits inside an active workflow: their current step, their next scheduled send time, and a status flag like pending, sent, or failed.

What is an event log used for in drip campaigns? An event log is an append-only history table recording every send, delivery, open, click, bounce, and unsubscribe, which powers analytics dashboards, deliverability troubleshooting, and compliance audits.

Can a drip campaign schema support behavioral triggers? Not without modification. A pure drip schema only checks timestamps. Supporting behavioral triggers requires adding an event listener layer that writes to the Event_Logs table in near real time and adding branch_condition logic to the Workflow_Steps table.

How do you debug a drip campaign that sent the wrong email? Check the Contact_Queue row first to see the contact's current step and timestamp, then check the Workflow_Steps definition for recent edits, then check the Event_Logs table for duplicate or missing events, and finally check the Contacts row for stale consent or custom field data.

What fields should a Contacts table include for personalization? At minimum, an email address, name fields, a flexible custom_fields column (often JSON), a lifecycle_stage field, a consent_status field with a timestamp, and increasingly an intent_score and enrichment fields for firmographic data.

Is a drip campaign always time-based? Traditionally yes. A classic drip campaign fires purely on elapsed time since a trigger event. Many modern ESPs blur the line by adding light conditional logic on top of an otherwise time-based sequence, which is technically a hybrid schema rather than a pure drip.

How does an audience graph differ from a standard contacts table? A standard contacts table is a flat list of individual records. An audience graph models relationships and behavioral similarity between contacts, enabling segmentation based on patterns across the whole audience rather than isolated field values on one record.

What database type is best for email automation, SQL or NoSQL? Relational (SQL) databases suit most email automation systems well because the tables have clear foreign key relationships (a contact belongs to a queue row belongs to a workflow). NoSQL document stores can work for very high-volume event logging or flexible custom-field storage, and many production systems use both: SQL for the core schema, a document store or time-series database for event logs at scale.

How do enrichment and intent scoring fit into the data structure? Enrichment services populate additional fields on the Contacts table asynchronously after signup, typically through an API call, while intent scoring is a continuously recalculated numeric field derived from recent Event_Logs activity, both of which then feed into branch_condition logic for smarter segmentation.

Do I need to understand the data structure if I use a no-code ESP? Not to build a basic sequence, but understanding the underlying tables helps you debug send issues, evaluate whether a vendor's "automation" claims match true behavioral capability, and communicate requirements clearly if you ever need custom integration work.

The schema described across this guide isn't going away, but the fields attached to it keep expanding as intent scoring, enrichment, and API-driven segmentation become standard rather than exceptional. Whether you're auditing an existing ESP or scoping a new build, the definition-state-history mental model from the top of this guide will still be the right lens to use.

Sources