Docs
Five tools — assess_ad_creative, assess_ad_batch, audit_campaign_structure, analyze_campaign_performance, strategize_targeting. Two front doors: MCP (Streamable HTTP) and REST. One key for both — create it in the dashboard.
Maintained by Dino S. · Founder, Spendict · Updated July 2026
Connect your agent
Drop in the agent Skill (recommended) and your agent gates every ad automatically — or connect over MCP, the CLI, or plain REST. Same five tools, same verdict, same quota.
Add the skill
Same SKILL.md works in Claude Code, Cursor, Codex, and Gemini.
npx skills add spendict/skills
Connect Spendict
The skill calls Spendict over MCP or the CLI — connect once (see the MCP or CLI tab).
Ship only winners
Your agent now gets a run / fix_first / kill on every ad before it recommends launching.
Using a framework? Copy-paste recipes for CrewAI, LangGraph, the Claude Agent SDK, n8n, and plain REST.
The five tools
Every tool is exposed over MCP at /api/mcp and mirrored one-for-one over REST. Same auth, same verdicts.
| assess_ad_creative | POST /api/v1/assess | run / fix_first / kill on one ad creative |
|---|---|---|
| assess_ad_batch | POST /api/v1/assess-batch | score 2–20 variants → ranked best→worst |
| audit_campaign_structure | POST /api/v1/audit-campaign | sound / fix_first / restructure on a build |
| analyze_campaign_performance | POST /api/v1/analyze-performance | healthy / fix_first / kill_or_rebuild / insufficient_data on live metrics |
| strategize_targeting | POST /api/v1/strategize-targeting | a generated targeting strategy (structure-validated) |
assess_ad_creative — gate the creative
The flagship. Judges an ad before a cent is spent and returns a deterministic verdict.
cat > ad.json <<'EOF'
{
"ad_copy": {
"primary_text": "Still paying an agency $3k/mo for ads a robot writes better?",
"headline": "Fire your ad agency"
},
"platform": "meta",
"format": "static",
"product_context": "AI Meta-ads automation tool, $99/mo",
"target_audience": "DTC founders spending $2-20k/mo on Meta ads"
}
EOF
curl -sS -X POST https://www.spendict.com/api/v1/assess \
-H "Authorization: Bearer spd_live_YOUR_KEY" \
-H "Content-Type: application/json" \
--data @ad.jsonThe body goes in a file on purpose: real ad copy is full of characters shells mangle (apostrophes, !, $99). Inside <<'EOF' nothing is interpreted, and --data @ad.json sends it byte-for-byte.
Input
| ad_copy.primary_text | string · required | The main ad body or video script. |
|---|---|---|
| ad_copy.headline | string | Optional headline. |
| ad_copy.description | string | Optional description / subtext. |
| creative_url | https URL | Optional image or video-frame URL — enables visual assessment. |
| platform | meta | tiktok | google | linkedin | youtube · required | Assessment is platform-specific. |
| product_context | string · required | What's being sold, the offer, the key value. |
| target_audience | string | Who it's for, if known. |
| format | video | static | carousel | Defaults to static. |
The verdict
Scores are 0–100 across seven dimensions (hook, angle, clarity, audience_resonance, platform_fit, cta, compliance_safety) plus an authoritative, deterministic launch_recommendation:
run— worth spending on: overall ≥ 78, hook ≥ 60, no hard gate tripped.fix_first— a real spine but a specific fixable problem; the fixes are the path to run. A dead hook or a likely policy rejection always caps an ad here.kill— structurally broken (two or more failing fundamentals); faster to regenerate than to fix.
{
"overall_score": 78,
"launch_recommendation": "run",
"dimension_scores": {
"hook": 78, "angle": 80, "clarity": 82,
"audience_resonance": 80, "platform_fit": 85,
"cta": 0, "compliance_safety": 95
},
"predicted_failure_mode": "No material weakness — would run as-is.",
"prioritized_fixes": [],
"enhancements": [
{ "issue": "No conversion path (CTA scored 0)",
"suggestion": "Add one clear next step — optional; ships as-is." }
]
}assess_ad_batch — which of N to run
Your agent generates 100 variants an hour; this says which few to run. Score 2–20 variants that share one campaign context in a single call and get them back ranked — same seven-dimension scoring and the same deterministic verdict as assess_ad_creative (a variant scored in a batch is identical to scoring it alone).
curl -sS -X POST https://www.spendict.com/api/v1/assess-batch \
-H "Authorization: Bearer spd_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "meta",
"product_context": "AI Meta-ads automation tool, $99/mo",
"target_audience": "DTC founders spending $2-20k/mo on Meta ads",
"variants": [
{ "label": "v1", "ad_copy": { "primary_text": "Still paying $3k/mo for ads a robot writes better?" } },
{ "label": "v2", "ad_copy": { "primary_text": "Introducing our new ad platform for teams." } }
]
}'Input
| platform / product_context | string · required | Shared campaign context, applied to every variant. |
|---|---|---|
| target_audience | string | Optional shared context. |
| format | video | static | carousel | Default for all variants; a variant can override. |
| variants[] | array · 2–20 · required | Each: ad_copy (+ optional label, creative_url, format). One quota per variant. |
The response
Variants ranked by verdict (run > fix_first > kill) then overall score, a summary count, and per-variant errors (e.g. if quota runs out partway). Take the top N run and launch them.
{
"summary": { "total": 2, "assessed": 2, "failed": 0,
"run": 0, "fix_first": 1, "kill": 1, "top_label": "v1" },
"ranked": [
{ "rank": 1, "label": "v1", "launch_recommendation": "fix_first", "overall_score": 74, ... },
{ "rank": 2, "label": "v2", "launch_recommendation": "kill", "overall_score": 46, ... }
],
"errors": []
}audit_campaign_structure — audit the build
Judges a campaign's structure by the correct platform's rulebook before budget flows through it. Verdict: sound / fix_first / restructure.
| platform | meta | google | tiktok | Required. |
|---|---|---|
| objective | string | Required — defines 'correct structure'. |
| campaign_structure | string | Required — the build to audit. |
| total_budget / funnel_stage | string | Optional context. |
analyze_campaign_performance — diagnose live
Judges real metrics against benchmarks and finds the one bottleneck. Verdict: healthy / fix_first / kill_or_rebuild / insufficient_data.
| platform / objective | string | Required — set the benchmarks. |
|---|---|---|
| metrics | object | Required — the real campaign numbers. |
| linked_assessments | object | Optional — reconcile vs pre-flight prediction. |
| campaign_identifier | string | Optional — auto-match fallback. |
strategize_targeting — design the plan
The generative tool. Given a product, budget, and objective, it returns one opinionated, executable targeting strategy — audience approach, segmentation, exclusions, a budget split with a learning-phase check, setup notes, and the single biggest risk. No score here; the server validates the structure of the returned plan.
| platform / product / budget / objective | string | Required. |
|---|---|---|
| funnel_stage / vertical | string | Optional — axes of justified segmentation. |
| audience_data / geo_language | string | Optional — thin data → lower confidence. |
Errors
Always JSON — { error, message }, never a stack trace.
| 400 | invalid_input / invalid_json / empty_body | Schema details; not counted. |
|---|---|---|
| 401 | missing_api_key / invalid_key | Check the Authorization header. |
| 429 | quota_exceeded | Includes upgrade_url; not a crash. |
| 502 / 503 | model_error / config_error | Not counted; retry. |
Quotas
Free: 100/mo · Starter ($19): 1,500/mo · Pro ($49): 5,000/mo · Scale ($199): 25,000/mo. Every tool call counts equally. The quota check happens before inference; failed calls are refunded. Median latency is a few seconds — size your agent's tool timeout to ~30s.