← Back to Work
Automation[PIPELINE][SIM][REAL BUILD SHOWN]

Campaign Intake Automation

AI-drafted campaign briefs with built-in conflict detection

An n8n workflow that turns a new campaign task into a structured brief, flags conflicting sources instead of guessing, and waits for a person to approve before any downstream work is created.

My role
Designed and built the n8n orchestrator and its sub-workflows, the Claude brief drafting, both Slack approval gates, and the Asana handoffs.
Built with
n8n, Slack, Claude API, Asana, Google Docs
Status
Client work

Before

The problem

Every new campaign started with someone reading the task, its comments, and related Slack threads, then writing the brief by hand. Sources often disagreed, and nothing flagged which one should win.

How a request moves through it

One sample task, followed from the moment it arrives to the moment the next team can start.

  1. Intake

    A new campaign request enters the workflow

    A task lands in the campaign request project with what a media buyer needs to start: client, platform, package, priority, campaign type, and due date.

    › Trigger today is a manual webhook. A scheduled trigger is not live yet.

  2. Structure

    The brief is built from the task

    Instead of rebuilding the brief by hand, the workflow reads the task fields and comment history and sorts them into a structured brief. Where two sources disagree, it flags the conflict instead of choosing one.

    › Before this, someone read the fields and comments and wrote the brief by hand.

  3. Approval

    People decide where judgment is needed

    The brief is posted to Slack for approval with the conflict called out. The workflow waits for the configured approver before anything is created.

    › Reactions are polled and attributed to the approver.

  4. Routing

    One approved brief becomes separate requests

    Once approved, landing-page copy and a creative brief are drafted as docs. A second approval then releases the downstream landing page and creative requests.

    › Landing-page defaults are platform-aware unless the brief says otherwise.

  5. Handoff

    The next team can start immediately

    Each request arrives with the client, platform, priority, and requirements already filled in, so the team does not start by chasing missing details.

    › Runs so far used test-mode destinations. Real-channel posting is not live yet.

SIM: the client, task, comments, and values shown are invented sample data. The steps mirror the real workflow, which has passed full test-mode runs.

Proof

The real build

Real buildn8n sub-workflow
The approval gate. One reusable sub-workflow posts to the approver in Slack, then polls for a reaction until it resolves or times out. Both human checkpoints in the run call this same gate.
n8n sub-workflow · original resolution

After

What changed

› Both approval gates, downstream task creation, and team handoffs have passed full test-mode runs end to end.
› During testing the first gate caught a genuine disagreement between two sources describing the same client's core service line on a real task, and surfaced it for a human to confirm instead of guessing either direction.
› Doc generation produces on-brief landing-page copy and creative briefs against real task data, including detecting which platform's landing-page default applies.

Hardest bug

After the workflow moved a task into its Asana section, its own response still reported the pre-move section. Everything downstream of that response looked healthy while the task's real state said otherwise.

› Caught by verifying Asana's state through direct API calls instead of trusting the workflow's output.
› Root cause: the response was built from the stale pre-move snapshot of the task.
› Fix: read from the live post-move re-fetch instead. Confirmed fixed in a later live run.

Known next steps

› Reject-and-revise path: a rejection currently halts the workflow instead of looping back for changes.
› Real-channel posting: runs so far used test-mode destinations, not live team channels.
› Scheduled trigger: replace the manual webhook so intake starts on its own.

Stack

For technical readers

Technical detail

The problem, in detail

Building a new campaign meant someone manually reading through a task's fields, its comment history, and any related Slack threads, then hand-writing a structured brief before creative or landing-page work could even start.

› A task's own fields and a stakeholder's comment don't always agree with each other, and a flat task view gives no signal for which source should win, or whether the disagreement is even worth raising.
› Two ad platforms need genuinely different landing-page structures by default. Treating every build the same produced briefs that didn't match how the work actually needed to ship.

Build notes

A separate n8n workflow from Digest, the scheduled ads-reporting pipeline covered elsewhere on this site. Different trigger shape and a different blast radius, so a bug in one can't take down the other. Today it starts from a manual webhook.

› Given a new campaign-build task, pulls its custom fields, full comment history, and the matched client profile from a linked Asana project, fuzzy-matched by name since no explicit link field exists between the two.
› Claude drafts a structured brief (platform, budget, geo, services, creative requirements) from that pulled context, and is explicitly instructed to flag any disagreement between sources rather than pick one silently.
› Slack is checked only when the task itself is incomplete or ambiguous, and is treated as supplementary corroboration only. A Slack comment can't silently override an unresolved conflict from the task's own fields.
› The draft brief goes to a Slack approval checkpoint before anything downstream happens. Reactions are polled and attributed to the configured approver.
› Landing-page copy and a creative brief generate next as Google Docs, with platform-aware defaults (one shared landing page for a campaign on one platform, one landing page per ad group on the other) unless the brief's own instructions say otherwise. A second approval gate then releases downstream Asana task creation and team handoffs.

Pipeline breakdown

01
Triggermanual webhook with a campaign-build task; scheduled trigger not yet live
02
Intakepulls task fields, full comment history, fuzzy-matched client profile
03
Brief Draft (Claude)structured JSON brief, source conflicts flagged explicitly, not resolved silently
04
Slack Enrichmentchecked only when the task itself is incomplete; supplementary, never authoritative
05
Approval Gate 1brief DM'd for approval; reactions polled and attributed
06
Doc Generationlanding-page copy + creative brief via Google Docs, platform-aware defaults
07
Approval Gate 2docs approved before anything is created downstream
08
Handoffdownstream Asana task creation + team handoffs

Run log

Activity Log — Campaign Intake
RUNNING

SIM: invented task and figures, not a real client run. Both approval gates, downstream task creation, and handoffs have passed full test-mode runs. The reject-and-revise path, real-channel posting, and the scheduled trigger are not yet live.