← Back

Building a List Import Agent

Nov 27, 2025 (2mo ago)

List imports are one of those pain points in marketing operations that everyone deals with but nobody loves. Validating data, checking for mismatches, normalizing formats. It's tedious work that eats up time and introduces room for error.

So we built something to fix it: the List Import Agent.

What it does

The List Import Agent is a Next.js application deployed on Vercel that validates, normalizes, and sends contact lists to our Tray.io import endpoints. It automatically performs quality reviews and flags data mismatches, enabling inline data editing and record preview before anything hits Salesforce or downstream systems.

The goal was simple: let stakeholders self-serve imports with proper guardrails, without requiring manual review for every single record.

The two-phase validation approach

We use a two-phase approach to validation:

Phase 1: Deterministic checks

  • Header validation
  • Email format verification
  • Required fields check
  • Campaign ID consistency

These are the straightforward, rules-based checks that catch obvious issues immediately.

Phase 2: AI-powered checks

For everything else (the fuzzy edge cases where rules become brittle or hard to maintain) we use the Vercel AI SDK with OpenAI models. This allows us to intelligently validate records where context matters, such as inconsistent formatting, ambiguous values, or subtle data mismatches that are difficult to capture with deterministic logic alone.

Using the Vercel AI SDK gives us a clean abstraction for working with AI inside a Next.js app, while keeping the implementation flexible and provider-agnostic if we ever need to change models in the future. You can learn more about the SDK and agent patterns at https://ai-sdk.dev.

Below is a simplified example of how we use the AI SDK with OpenAI to perform contextual validation on a single row of imported data:

import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
 
export async function validateRow(rowData: string) {
  const { text } = await generateText({
    model: openai('gpt-5'),
    prompt: `Review the following row for data quality issues, inconsistencies, or missing context:
 
${rowData}`,
  });
 
  return text;
}

This pattern allows us to keep deterministic validation logic separate, while delegating nuanced, context-aware checks to the model.

The stack

We built this quickly using:

  • Next.js for the application framework
  • Vercel for deployment
  • v0 for rapid UI prototyping
  • Cursor for AI-assisted development
  • Vercel AI SDK for AI integration and agent patterns
  • OpenAI models for intelligent validation
  • Tray.io for the import workflow endpoints

The impact

The projected outcome is reducing manual review time by 90%. We're not removing human oversight entirely. Records that need additional validation still get flagged for review. But the bulk of the work that used to require manual checking is now automated.

We've successfully tested this in production and are rolling it out for broader testing now.

Why this matters

This is the kind of operational tooling that doesn't get a lot of attention, but it compounds. Every list import that doesn't require manual review is time back for the team. Every data quality issue caught before it hits Salesforce is a cleanup task avoided downstream.

The combination of deterministic rules and AI-powered validation gives us the best of both worlds: predictable, fast checks for the obvious stuff, and intelligent review for everything else.