Don’t give the model the keys: an architecture for agents in the ad stack
A language model should never hold credentials that let it change the ad server, an SSP or the CRM. Three planes, an advertising API and a policy engine keep agents useful and under control.
The quickest way to build an advertising agent is to give a language model an API key for Google Ad Manager and a good prompt. It is also the riskiest. A model can misread a request, invent a value or be manipulated by content it reads, and an ad server change can cost real money within minutes.
Our rule is simple: a language model should not hold credentials that let it change the ad server, an SSP or the CRM directly. Execution goes through controlled services that can be tested and audited.
Three planes
- Intelligence plane: language models, agents, retrieval (RAG) and planning. It understands requests and produces intents and proposals.
- Control plane: identity and access management, policies, approvals, budgets and audit. It decides which proposals become authorised commands.
- Execution plane: the advertising API and, behind it, the ad server, SSPs, CRM, data platform and consent platform. It carries out authorised commands, and nothing else.
The model reasons; deterministic services decide and act. This separation is what makes it possible to change model provider, to add agents, or to open the system to external buying agents later, without re-engineering the core.
A publisher advertising API
The advertising API is the business layer between agents and ad technology. The same API should serve the sales agent, a self-service portal, internal tools and, eventually, external buying agents.
| Capability | Example functions | Writes? |
|---|---|---|
| Discovery | searchProducts(), getCapabilities() | No |
| Audience | searchAudience(), getReach() | No |
| Inventory | forecastInventory(), getAvailability() | No |
| Pricing | getPrice(), getEligibleDiscounts() | No, rules only |
| Planning | buildMediaPlan() | No |
| Proposal | requestProposal() | Controlled creation |
| Deal | createDeal() | Yes, under policy and approval |
| Campaign | getCampaignStatus(), controlledUpdate() | Mixed |
| Reporting | getReport(), explainPerformance() | No |
Take a forecast request. The caller authenticates and the gateway identifies its organisation, role and scopes. The request is validated. The policy engine decides whether this caller may see a detailed forecast or only a range. The service translates business identifiers into internal ones, queries the ad server or the data warehouse, normalises the result into catalogue units, adds an uncertainty range and a timestamp, and logs the caller, parameters, latency and policy decision. Only then does the agent receive a structured answer it can explain.
A good contract has stable, versioned identifiers; idempotent critical actions; fine-grained scopes per client and per agent; rate limits and quotas per capability; one audit ID that links the agent’s request, the rule applied, the action and its result; machine-readable errors; and explicit freshness and service levels.
Pricing rules do not belong in a prompt
A negotiation agent should never improvise a discount. Floors, minimum margins, maximum discounts per segment, volume rules, periods, exclusions, the number of negotiation rounds and escalation thresholds live in a versioned pricing and policy service. The agent asks “which price am I allowed to offer?” and explains the answer; it does not decide it. Natural language is for reasoning and explaining. The final price decision is constrained by audited rules.
The right engine for each task
- Exact calculations and SQL: code, SQL or deterministic rules.
- Simple classification: a small model or a classifier.
- Questions on documentation: search and retrieval.
- Complex reasoning: a large language model.
- Forecasts: a statistical or machine-learning model, with validation.
- System actions: a deterministic API behind the policy engine.
Using a large model for every calculation is rarely sensible. Routing tasks to the right engine reduces cost, latency and risk. An AI gateway lets you change model provider and keep fallbacks.
What can go wrong
| Risk | Example | Control |
|---|---|---|
| Prompt injection | Web content tries to hijack the agent. | Content isolation, tool policies, allowlists. |
| Data leaks | The agent reveals a price, a margin or a client. | Attribute-based access, data classification, response filters. |
| Over-permission | A sales agent can modify a campaign. | Least privilege, scoped tools. |
| Adversarial buyer | Thousands of forecasts to infer pricing. | Rate limits, anomaly detection, quotas. |
| Hallucination | The agent invents a reach or a price. | Answers must cite sources; deterministic services. |
| Runaway loop | Agents call each other endlessly. | Limits on steps, tokens, cost and time. |
| Bad write | A wrong floor or deal. | Simulation, approval, rollback, limited blast radius. |
Regulation is already here
Since 2 August 2026, the transparency obligations of Article 50 of the EU AI Act apply: people must be told when they interact with an AI system, unless it is obvious, and AI-generated content must be marked in a machine-readable way, with a grace period until 2 December 2026 for generative systems already on the market. The exact obligations depend on your role and use case, so have them checked by your legal team before you put an agent in front of clients.
Four environments
- Development: mocks and synthetic data.
- Test: reproducible scenarios and reference datasets.
- Staging: real integrations with writes disabled or in a sandbox.
- Production: minimal scopes, monitoring, budgets, a kill switch and rollback.
We apply the same principle in our own tools. In our Brand Matching project, the model proposes targeting criteria, but every value is checked against the data platform’s own list and validated by a person before anything goes live.
Sources
- Not delayed, not deferred: EU AI Act transparency obligations are now in force, Goodwin, August 2026.