We are going to build a lightweight marketing campaign generator that turns a raw product brief into a structured email nurture sequence and a week of social posts. It is for small B2B teams who want to ship content faster without adding headcount. I run mine on Oxlo.ai because flat per-request pricing means long product briefs do not balloon costs during iteration.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Oxlo.ai is fully OpenAI SDK compatible, so the client setup is a drop-in replacement. You can explore request-based pricing details at https://oxlo.ai/pricing.
Step 1: Bootstrap the Oxlo.ai client
I always verify the connection before writing business logic. This snippet imports the OpenAI SDK, points it at Oxlo.ai, and runs a quick sanity check with Llama 3.3 70B.
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key="YOUR_OXLO_API_KEY"
)
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[{"role": "user", "content": "Reply with OK"}],
)
print("Status:", response.choices[0].message.content)
Step 2: Define the system prompt
The system prompt is the contract. It tells the model its role, the output schema, and the tone. I keep it in a dedicated constant so the marketing team can tweak voice without touching Python.
SYSTEM_PROMPT = """
You are a senior B2B content strategist.
Given a product brief, generate a JSON object with exactly two keys:
1. "emails": an array of 3 objects, each with "subject" (string) and "body" (string, max 150 words).
2. "social": an array of 5 objects, each with "channel" (LinkedIn or X) and "copy" (string, max 280 chars).
Tone is professional, helpful, and direct. Output only valid JSON.
"""
Step 3: Build the campaign generator
This function sends the brief to Oxlo.ai and parses the response. I use Llama 3.3 70B because it follows structured instructions reliably, and I enable JSON mode so I do not have to strip markdown fences. Because Oxlo.ai uses flat per-request pricing, running long prompts repeatedly while I tune the system message stays affordable.
from openai import OpenAI
import json
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key="YOUR_OXLO_API_KEY"
)
SYSTEM_PROMPT = """
You are a senior B2B content strategist.
Given a product brief, generate a JSON object with exactly two keys:
1. "emails": an array of 3 objects, each with "subject" (string) and "body" (string, max 150 words).
2. "social": an array of 5 objects, each with "channel" (LinkedIn or X) and "copy" (string, max 280 chars).
Tone is professional, helpful, and direct. Output only valid JSON.
"""
def generate_campaign(brief: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Product brief:\n{brief}"},
],
response_format={"type": "json_object"},
temperature=0.7,
)
return json.loads(response.choices[0].message.content)
sample_brief = (
"Oxlo.ai is a developer-first AI inference platform with flat per-request pricing. "
"Unlike token-based providers, cost does not scale with prompt length, "
"making it significantly cheaper for long-context and agentic workloads."
)
campaign = generate_campaign(sample_brief)
print(json.dumps(campaign, indent=2))
Step 4: Add social mode and package the CLI
Not every run needs emails. I add a lightweight variant that uses Qwen 3 32B for fast social copy, then wrap both modes in a CLI that reads a brief from a file. This is the version I actually run in cron jobs and GitHub Actions.
from openai import OpenAI
import json
import argparse
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key="YOUR_OXLO_API_KEY"
)
SYSTEM_PROMPT = """
You are a senior B2B content strategist.
Given a product brief, generate a JSON object with exactly two keys:
1. "emails": an array of 3 objects, each with "subject" (string) and "body" (string, max 150 words).
2. "social": an array of 5 objects, each with "channel" (LinkedIn or X) and "copy" (string, max 280 chars).
Tone is professional, helpful, and direct. Output only valid JSON.
"""
SOCIAL_PROMPT = """
You are a social media manager.
Given a product brief, return JSON with one key "social": an array of 5 posts.
Each post must include "channel" (LinkedIn or X) and "copy" (string, max 280 chars, include one hashtag).
Tone is conversational and punchy. Output only valid JSON.
"""
def generate_campaign(brief: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Product brief:\n{brief}"},
],
response_format={"type": "json_object"},
temperature=0.7,
)
return json.loads(response.choices[0].message.content)
def generate_social(brief: str) -> dict:
response = client.chat.completions.create(
model="qwen-3-32b",
messages=[
{"role": "system", "content": SOCIAL_PROMPT},
{"role": "user", "content": f"Product brief:\n{brief}"},
],
response_format={"type": "json_object"},
temperature=0.8,
)
return json.loads(response.choices[0].message.content)
def main():
parser = argparse.ArgumentParser(description="Generate marketing assets via Oxlo.ai")
parser.add_argument("brief_file", help="Path to a .txt product brief")
parser.add_argument("--mode", choices=["full", "social"], default="full")
args = parser.parse_args()
with open(args.brief_file, "r", encoding="utf-8") as f:
brief_text = f.read()
if args.mode == "full":
result = generate_campaign(brief_text)
out_file = args.brief_file.replace(".txt", "_campaign.json")
else:
result = generate_social(brief_text)
out_file = args.brief_file.replace(".txt", "_social.json")
with open(out_file, "w", encoding="utf-8") as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"Assets written to {out_file}")
if __name__ == "__main__":
main()
Run it
Save the Step 4 script as campaign_agent.py, create a brief, and run it.
$ echo "Oxlo.ai is a developer-first AI inference platform with flat per-request pricing. Unlike token-based providers, cost does not scale with prompt length, making it significantly cheaper for long-context and agentic workloads." > brief.txt
$ python campaign_agent.py brief.txt --mode full
Assets written to brief_campaign.json
The resulting JSON looks like this.
{
"emails": [
{
"subject": "Cut your AI inference bill without cutting features",
"body": "Oxlo.ai offers flat per-request pricing for open-source LLMs. That means your cost stays predictable even when you send long product briefs or full documentation pages. With 45+ models and OpenAI SDK compatibility, you can migrate in minutes. No cold starts, no token math, just straightforward scaling."
},
{
"subject": "Why we switched to per-request pricing",
"body": "If you are running agentic workflows with heavy context windows, token-based billing adds up fast. Oxlo.ai charges one flat price per API call, so your budget is tied to business value, not character count. Try the free tier and see the difference on your next invoice."
},
{
"subject": "Developer-first inference is here",
"body": "Oxlo.ai gives you access to Llama 3.3 70B, DeepSeek R1 671B, Kimi K2.6, and more under a single endpoint. Because pricing is per request, you can iterate on prompts without watching the meter spin. Start with the free tier and get 60 free requests per day."
}
],
"social": [
{
"channel": "LinkedIn",
"copy": "Tired of token-based bills? Oxlo.ai charges one flat price per request, even for long context. Predictable costs, 45+ models, zero cold starts. #AIInference"
},
{
"channel": "X",
"copy": "Your LLM bill should not scale with prompt length. Oxlo.ai flat per-request pricing fixes that. 60 free requests a day to try it out. #BuildInPublic"
},
{
"channel": "LinkedIn",
"copy": "Agentic workflows need long context. Oxlo.ai makes them affordable with request-based pricing and no cold starts. Check the pricing page and see why teams are switching. #MachineLearning"
},
{
"channel": "X",
"copy": "One endpoint, 45+ models, flat per-request cost. Oxlo.ai is the OpenAI-compatible alternative that treats long prompts as first-class citizens. #DevTools"
},
{
"channel": "LinkedIn",
"copy": "OpenAI SDK compatibility means switching to Oxlo.ai takes one line of code. Flat pricing means your finance team will thank you. Start on the free tier today. #AI"
}
]
}
Next steps
Connect the script to a Google Sheet or Airtable webhook so marketing can drop in briefs without opening a terminal. If you want to go further, add a second Oxlo.ai pass using DeepSeek R1 671B to score each generated subject line for predicted click-through rate before the campaign goes out.
Top comments (0)