How to Build an AI Compliance Reviewer for Outbound Marketing Copy

Submit draft campaign copy to a Spojit webhook, have Miraxa check it against a persistent brand-and-legal guidelines collection, return a pass or fail verdict with cited issues, and pause failures for human review before any send reaches Klaviyo.

What This Integration Does

Marketing teams ship a steady stream of outbound copy: subject lines, hero blurbs, promotional banners, and email body text. Before any of it goes out, someone usually has to read it against a list of brand voice rules and legal constraints (no unsubstantiated claims, required disclaimers, approved discount language, no restricted superlatives). That manual review is slow and inconsistent. This workflow turns the rulebook into a queryable knowledge collection and lets an Agent-mode Connector node grade each draft against it, so reviewers only ever look at the copy that actually trips a rule.

The workflow starts when your content tool, intranet form, or another Spojit workflow sends a draft to a Webhook trigger. A Knowledge query node pulls the most relevant guideline passages from a persistent collection and the agent returns a strict pass/fail verdict with cited issues using a Response Schema. A Condition node routes the result: clean drafts flow straight to a Connector node that creates a Klaviyo campaign, while flagged drafts hit a Human approval node and wait for a person to approve or reject. Each submission runs independently, leaves an entry in your execution history, and re-running the same draft is safe because nothing is written to Klaviyo until the verdict is clean or a human approves.

Prerequisites

  • A Klaviyo connection added under Connections with an API key that can list and create campaigns.
  • A webhook signing connection (scheme Spojit or Custom) so the trigger can verify inbound requests by HMAC.
  • A persistent Knowledge collection (for example brand-legal-guidelines) created in the Knowledge section of the sidebar, with your brand voice and legal documents uploaded and embedded (status READY).
  • At least one approver in your workspace, plus a Slack connection if you want flagged drafts announced to a review channel.
  • Note the embedding model chosen when you created the collection: you must query it with the same model you embedded with.

Step 1: Create the brand-and-legal guidelines collection

In the Knowledge section of the sidebar choose New Collection, name it brand-legal-guidelines, and add a short description. The embedding model is fixed at creation, so pick one (for example Gemini Embedding 001) and keep it consistent. Open the collection, choose Upload Document, and drag in your rulebook files: a brand voice guide, the legal disclaimers sheet, approved discount and claim language, and any region-specific rules. Each file can be PDF, Word, Markdown, or Plain Text. Click Upload & Embed and wait for every document to show status READY in the document table. Because the collection is persistent and workspace-scoped, any workflow you build later can query it, and you maintain the rules in one place.

Step 2: Receive the draft with a Webhook trigger

Create a new workflow and set the trigger to Webhook. Attach your webhook signing connection so inbound POSTs are verified by HMAC, then copy the generated workflow URL into the tool that submits drafts. The trigger output is the parsed JSON body, available as {{ input }}. Send a payload shaped like this:

{
  "campaignName": "June Flash Sale",
  "subject": "48 hours only: the lowest prices we have ever offered",
  "previewText": "Save big before midnight Sunday",
  "bodyText": "Our June Flash Sale is here. Take 30% off everything...",
  "audience": "newsletter-subscribers"
}

The trigger responds 202 with an executionId immediately, so the submitting tool does not block while review runs. If your submitter can include a unique event id header, turn on dedup so a retried POST does not start a second review of the same draft.

Step 3: Query the guidelines for relevant rules

Add a Knowledge node in Query mode. Set Collection to brand-legal-guidelines (not Transient, since the rulebook lives across runs) and set Model to the AI model you want the node to use for synthesis. In the Prompt, fold the draft text directly into the question so the retrieval targets the rules that matter for this copy:

Return the brand voice and legal rules relevant to this draft email.
Focus on claim substantiation, required disclaimers, discount wording,
and restricted superlatives.

Subject: {{ input.subject }}
Preview: {{ input.previewText }}
Body: {{ input.bodyText }}

Set Result Count to a slightly higher value such as 8 so enough rule passages are retrieved, and set Output Variable to guidelines. The retrieved guidance is now available as {{ guidelines }} for the verdict step.

Step 4: Generate a pass/fail verdict with structured output

Add a Connector node in Agent mode (or a second Knowledge query if you prefer to keep retrieval and judgment together). Give the agent a prompt that asks it to grade the draft strictly against the retrieved rules, and attach a Response Schema so the output is forced into reliable JSON instead of prose. A schema like the following keeps downstream branching deterministic:

{
  "type": "object",
  "properties": {
    "verdict": { "type": "string", "enum": ["pass", "fail"] },
    "issues": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "rule": { "type": "string" },
          "excerpt": { "type": "string" },
          "severity": { "type": "string", "enum": ["low", "medium", "high"] }
        },
        "required": ["rule", "excerpt", "severity"]
      }
    },
    "summary": { "type": "string" }
  },
  "required": ["verdict", "issues", "summary"]
}

In the prompt, instruct the agent to return fail if any high-severity rule is violated and to cite the exact phrase from the draft in each issue's excerpt. Pass it both {{ input.bodyText }} (plus subject and preview) and the retrieved {{ guidelines }}. Set the output variable to review so you can read {{ review.verdict }} and {{ review.issues }} later.

Step 5: Branch on the verdict

Add a Condition node that checks whether {{ review.verdict }} equals pass. The true branch is the clean path that proceeds to publishing; the false branch routes flagged copy into human review. Keeping the gate on the structured verdict field (rather than parsing free text) is exactly why the Response Schema in the previous step matters: the branch is unambiguous. Optionally, on the false branch, add a Slack Connector node using send-message to post a heads-up to your review channel with {{ review.summary }} and the count of issues so reviewers know something is waiting.

Step 6: Pause failures for human review

On the false branch add a Human approval node. Set a clear Label (for example Compliance review) and a Message that templates the findings so the approver sees them inline:

Draft "{{ input.campaignName }}" failed automated compliance review.

Summary: {{ review.summary }}
Issues found: {{ review.issues }}

Approve to send as-is, or reject to send it back to marketing.

Fill the Notification title/body, set Urgency to High, and add the marketing-compliance owner to an Approval slot (the only required field). Optionally enable Email approvers so the first reviewers are emailed. Approvers act in the Approvals inbox at /approvals. The node outputs { approved: true, approvalId, outcome: "APPROVED" } on approval; a rejection or timeout halts the run, which is the safe default because nothing reaches Klaviyo on a reject. Note that downstream "on reject do X" branching is not supported in Spojit, so a rejection simply stops the workflow and the draft never sends.

Step 7: Create the Klaviyo campaign on the clean path

Merge both the condition's true branch and the path after the Human node's approval into a Connector node for Klaviyo in Direct mode. Because the verified or approved draft is now safe to send, this node should call a single deterministic tool. Klaviyo's connector does not expose a direct "create campaign" tool, so use raw-api-request to create the campaign from the cleared copy, mapping {{ input.subject }}, {{ input.previewText }}, {{ input.bodyText }}, and the target audience. If your flow only needs to register the recipient or fire an event, you can instead use create-event or add-profiles-to-list. Optionally add a Send Email node afterward to notify the marketer that their draft cleared review and was scheduled.

Tips

  • Keep the Response Schema tight: an enum on verdict and a required excerpt per issue forces the agent to cite real phrases rather than paraphrase, which makes reviewer trust much higher.
  • Update the guideline documents in the collection whenever legal rules change; because the collection is persistent and shared, every workflow that queries it picks up the new rules on the next run with no node edits.
  • Use the same embedding model for queries that you chose when creating the collection, or retrieval quality drops sharply.
  • Ask Miraxa to scaffold the canvas: try "Add a Condition node that checks if {{ review.verdict }} equals pass and connect the false branch to a Human node," then fine-tune fields in the properties panel.

Common Pitfalls

  • Branching on free text instead of the structured field. Always gate the Condition on {{ review.verdict }} from the Response Schema, never on a sentence inside {{ review.summary }}.
  • Forgetting that a rejected Human approval halts the run. There is no reject branch, so do not place "send anyway" logic expecting a rejection path.
  • Querying a collection whose documents are still PROCESSING. Confirm every document shows READY before relying on retrieval.
  • Submitting unsigned webhook requests. Without the matching webhook signing connection the HMAC check fails and the draft never enters review.

Testing

Before connecting your real content tool, test on a small scope. Post one obviously compliant draft and one that clearly breaks a rule (an unsubstantiated "lowest prices ever" claim, say) to the webhook URL with a valid signature. Check the execution history: the clean draft should pass the Condition and reach the Klaviyo node, while the bad draft should land in the Approvals inbox with cited issues in the message. Approve and reject one each to confirm the approve path creates the campaign and the reject path halts cleanly. Only after both paths behave should you point your production submitter at the webhook and enable dedup.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.