Skip to main content

Scenario

Expanding into new markets requires localized messaging. Perigon’s geographic filtering returns news by country, state, or city. This job pulls news from target markets, creates personas representing local consumer segments, runs a Focus Group to test messaging, then generates localized campaign copy. Flow: Perigon GET /all?country={code} → Mavera POST /personasPOST /focus-groupsPOST /generations → Localized copy

Code

import os, requests, time

PG_KEY = os.environ["PERIGON_API_KEY"]
PG_BASE = "https://api.goperigon.com/v1"
MV = os.environ["MAVERA_API_KEY"]
MV_BASE = "https://app.mavera.io/api/v1"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

PRODUCT = "digital payments platform"
MARKETS = [
    {"country": "GB", "label": "United Kingdom", "currency": "GBP"},
    {"country": "DE", "label": "Germany", "currency": "EUR"},
    {"country": "JP", "label": "Japan", "currency": "JPY"},
]

for market in MARKETS:
    # 1. Fetch local news
    r = requests.get(f"{PG_BASE}/all", params={
        "apiKey": PG_KEY, "q": PRODUCT, "country": market["country"],
        "sortBy": "date", "size": 10,
    })
    if not r.ok:
        print(f"{market['label']}: API error {r.status_code}")
        continue
    articles = r.json().get("articles", [])
    print(f"\n{market['label']}: {len(articles)} articles")

    local_context = "\n".join(
        f"- [{a.get('source',{}).get('name','')}] {a.get('title','')}: {a.get('summary', a.get('description',''))[:200]}"
        for a in articles[:8]
    )

    # 2. Create local personas
    LOCAL_PERSONAS = [
        {"name": f"{market['label']} Early Adopter", "desc": f"Tech-forward consumer in {market['label']}. Uses multiple fintech apps. Price-sensitive but values UX. Local payment habits."},
        {"name": f"{market['label']} Traditional Buyer", "desc": f"Established professional in {market['label']}. Prefers banks. Skeptical of fintech. Values security and regulation compliance."},
        {"name": f"{market['label']} Small Business Owner", "desc": f"SMB owner in {market['label']}. Needs payment processing, invoicing, cross-border. Cost is primary concern."},
    ]
    persona_ids = []
    for lp in LOCAL_PERSONAS:
        p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
            "name": lp["name"], "description": lp["desc"],
        }).json()
        persona_ids.append(p["id"])
        time.sleep(0.3)

    # 3. Focus Group with local context
    fg = requests.post(f"{MV_BASE}/focus-groups", headers=MV_H, json={
        "name": f"Market Entry: {market['label']}",
        "persona_ids": persona_ids,
        "questions": [
            f"What matters most when choosing a {PRODUCT} in {market['label']}?",
            f"What local alternatives do you currently use and why?",
            f"What would make you switch to a new {PRODUCT}?",
            f"How important is that the platform operates in {market['currency']}?",
        ],
        "responses_per_persona": 2,
    }).json()

    for _ in range(20):
        time.sleep(5)
        data = requests.get(f"{MV_BASE}/focus-groups/{fg['id']}", headers=MV_H).json()
        if data.get("status") == "completed":
            break

    # 4. Generate localized copy
    fg_summary = "\n".join(
        f"[{r.get('persona_id','')}] {r.get('question','')[:60]}{r.get('answer','')[:200]}"
        for r in data.get("responses", [])[:12]
    )

    copy = requests.post(f"{MV_BASE}/generations", headers=MV_H, json={
        "prompt": f"Generate localized marketing copy for {PRODUCT} entering {market['label']}.\n\n"
            f"LOCAL NEWS CONTEXT:\n{local_context}\n\n"
            f"FOCUS GROUP INSIGHTS:\n{fg_summary}\n\n"
            "Generate:\n"
            f"1. Hero headline (8 words max) — resonates with {market['label']} values\n"
            "2. Subheadline (20 words) — addresses top local concern\n"
            "3. Three feature bullets — localized benefits, not features\n"
            "4. CTA button text (4 words)\n"
            f"5. Social proof line referencing {market['label']} adoption\n\n"
            f"Currency: {market['currency']}. Tone: trustworthy, local, modern.",
    }).json()

    print(f"\n{'='*60}\nLOCALIZED COPY: {market['label']}\n{'='*60}")
    print(copy.get("output", copy.get("content", ""))[:600])
const PG_KEY = process.env.PERIGON_API_KEY;
const PG_BASE = "https://api.goperigon.com/v1";
const MV = process.env.MAVERA_API_KEY;
const MV_BASE = "https://app.mavera.io/api/v1";
const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

const PRODUCT = "digital payments platform";
const MARKETS = [
  { country: "GB", label: "United Kingdom", currency: "GBP" },
  { country: "DE", label: "Germany", currency: "EUR" },
  { country: "JP", label: "Japan", currency: "JPY" },
];

for (const market of MARKETS) {
  // 1. Local news
  const r = await fetch(
    `${PG_BASE}/all?apiKey=${PG_KEY}&q=${encodeURIComponent(PRODUCT)}&country=${market.country}&sortBy=date&size=10`);
  if (!r.ok) { console.log(`${market.label}: error ${r.status}`); continue; }
  const articles = (await r.json()).articles || [];
  console.log(`\n${market.label}: ${articles.length} articles`);

  const localContext = articles.slice(0, 8).map(a =>
    `- [${a.source?.name||""}] ${a.title||""}: ${(a.summary||a.description||"").slice(0,200)}`).join("\n");

  // 2. Local personas
  const personaIds = [];
  for (const lp of [
    { name: `${market.label} Early Adopter`, desc: `Tech-forward in ${market.label}. Multiple fintech apps. Price-sensitive.` },
    { name: `${market.label} Traditional Buyer`, desc: `Established in ${market.label}. Prefers banks. Values security.` },
    { name: `${market.label} SMB Owner`, desc: `SMB in ${market.label}. Payment processing, invoicing, cross-border.` },
  ]) {
    const p = await fetch(`${MV_BASE}/personas`, { method: "POST", headers: MV_H,
      body: JSON.stringify({ name: lp.name, description: lp.desc }),
    }).then(r => r.json());
    personaIds.push(p.id);
    await new Promise(r => setTimeout(r, 300));
  }

  // 3. Focus Group
  const fg = await fetch(`${MV_BASE}/focus-groups`, { method: "POST", headers: MV_H,
    body: JSON.stringify({ name: `Market Entry: ${market.label}`, persona_ids: personaIds,
      questions: [`What matters most for ${PRODUCT} in ${market.label}?`, `Local alternatives?`,
        `What makes you switch?`, `How important is ${market.currency} support?`],
      responses_per_persona: 2 }),
  }).then(r => r.json());

  let data;
  for (let i = 0; i < 20; i++) {
    await new Promise(r => setTimeout(r, 5000));
    data = await fetch(`${MV_BASE}/focus-groups/${fg.id}`, { headers: MV_H }).then(r => r.json());
    if (data.status === "completed") break;
  }

  const fgSummary = (data.responses || []).slice(0, 12)
    .map(r => `${(r.question||"").slice(0,60)}${(r.answer||"").slice(0,200)}`).join("\n");

  // 4. Localized copy
  const copy = await fetch(`${MV_BASE}/generations`, { method: "POST", headers: MV_H,
    body: JSON.stringify({ prompt: `Localized copy for ${PRODUCT} in ${market.label}.\n\nNEWS:\n${localContext}\n\nFOCUS GROUP:\n${fgSummary}\n\n1. Hero headline (8 words)\n2. Subheadline (20 words)\n3. Three feature bullets\n4. CTA (4 words)\n5. Social proof for ${market.label}\n\nCurrency: ${market.currency}. Tone: trustworthy, local.` }),
  }).then(r => r.json());

  console.log(`\n${"=".repeat(60)}\nLOCALIZED COPY: ${market.label}\n${"=".repeat(60)}`);
  console.log((copy.output || copy.content || "").slice(0, 600));
}

Example Output

United Kingdom: 10 articles

LOCALIZED COPY: United Kingdom
============================================================
1. HEADLINE: Payments That Move at London Speed
2. SUBHEADLINE: FCA-regulated, instant GBP settlements, and the integrations
   UK businesses actually use.
3. FEATURES:
   • Faster Payments rails — settle in seconds, not days
   • Open Banking ready — connect your high-street bank directly
   • HMRC-compatible invoicing built in
4. CTA: Start Free in GBP
5. SOCIAL PROOF: Trusted by 2,400 UK businesses from Bristol to Edinburgh.

LOCALIZED COPY: Germany
============================================================
1. HEADLINE: Zahlungen, Die Einfach Funktionieren
2. SUBHEADLINE: BaFin-konform, SEPA-Sofortüberweisung, und die Integrationen
   die deutsche Unternehmen tatsächlich nutzen.

Error Handling

Some country codes return few results. Broaden the query or remove sourceGroup filter. For APAC markets, try region instead of country.
Generated copy may default to USD. Explicitly include the target currency in the prompt and add "Do NOT mention USD" if needed.
Focus groups are async. The polling loop waits up to 100 seconds. Increase for complex multi-persona groups.