Read this before your first call. It is written for you, not for the person who gave you the key.
Updated
An advertising and marketing intelligence API. It answers questions about brands, categories, audiences, and creative across social and ad platforms — what competitors are running, how a market is talking, who an audience listens to — and it carries an agent OS layer (context, memory, activity) so you can work for the same business over weeks rather than one conversation.
The surface is REST. Reads are GET — the resource id rides the URL (https://api.adveron.com/v1/brands/{id}), filters and paging ride the query string (?limit=&cursor=). Writes and the analysis actions that compute a derivative are POST / PUT / PATCH / DELETE, taking a JSON body. Successful responses are { "data": …, "meta": … }; failures are { "error": { "code", "message", "request_id" } } with an honest HTTP status. A metered read answers Cache-Control: no-store.
Authorization: Bearer adveron_… on every request, plus Content-Type: application/json. The key is workspace-scoped: it decides whose data you see, whose credits you spend, and — via its name — which memory and activity are yours.GET /v1/context first. It returns the workspace’s standing brief, and it is free. Read the slots that matter before you decide anything.GET /v1/balance returns total_spendable, the pools behind it, and overage_debt. Do this before a plan that involves many live lookups.GET /v1/memory/entries for your own notes from previous sessions, GET /v1/activities for what every agent in the workspace reported. Both free. Repeating last week’s analysis is the most common way to waste a run.GET /v1/instructions (MCP: instructions_get) serves the same contract as markdown, with an updated_at date, free and without a browser — this page and that document are two renderings of one set of rules, not two sources. Call it when you start new work and refresh whatever skill or saved instructions you keep whenever the date has moved.adveron.com/docs, machine-readable spec at adveron.com/openapi.json, the short version of this page at adveron.com/llms.txt, and an MCP endpoint at https://mcp.adveron.com if your host speaks MCP instead of HTTP.The first call
{"data": {"items": [{ "slug": "brand_product", "kind": "BRAND_PRODUCT", "label": "Brand & product", "title": "Brand & product", "written": true, "source": "MANUAL", "updated_at": "2026-08-14T09:12:04Z", "updated_by": "ana@northwind.com" },{ "slug": "marketing_strategy", "kind": "MARKETING_STRATEGY", "label": "Marketing strategy", "title": "2026 growth plan", "written": true, "source": "AGENT", "updated_at": "2026-08-14T09:20:41Z", "updated_by": "research-agent" },{ "slug": "competitor_analysis", "kind": "COMPETITOR_ANALYSIS", "label": "Competitor analysis", "title": "Competitor analysis", "written": false, "source": null, "updated_at": null, "updated_by": null }]},"meta": { "request_id": "req_…", "total": 5 }}
This is the distinction to get right, and it is the one that produces most confused agents. Adveron answers live questions about anything, and ongoing questions only about entities your organization has activated. Deciding which mode a task needs is your job, not the API’s.
Use it when the question is “what is happening right now” or “who is this”: a one-off lookup, a name you have never seen before, a URL somebody pasted. Nothing has to be activated; every call spends credits because it spends a vendor call.
q on one platform (x, instagram, tiktok, linkedin, facebook, youtube, reddit). Narrow with since (hour…year) and sort.platform is meta, google, or linkedin. For google, q must be the advertiser’s domain (nike.com), not its name.get, posts, following, search for a creator or account you can already name.search to resolve a name to a handle, then get, jobs, people, posts.lookup a URL, get the post, then comments and reactors for the reaction to it.{id} (the MCP tool argument is video_id).Catalog browse is open too, and free: brand.search, category.list, category.get, audience.list (with q to search by name). Use them to turn a name into an id before anything else — every other brand, category, and audience operation takes an id, never a name.
Anything ongoing runs here: a competitor dashboard, a daily feed of a rival’s creative, share of voice over twelve months, an opportunity tracker. Adveron collects these entities continuously and keeps the history, which is why the entity has to be activated — an activation is a slot on your organization’s subscription, held at the org and shared by every workspace in it. Reads against an activated entity spend no credits; the slot already paid for them.
status (ACTIVE / ENDED), platform, start_date, days_running, and the creative analysis (hook, angle, tone, offers). Siblings: ads.get, summary, and crawl-coverage — per day and per platform, whether we looked at all, so a day with no new ads is legible as “nothing launched” rather than “we didn’t look”.posts.list, posts.get, summary.executives.list, executives.get, and the media itself (posts.list, posts.get, summary). Its own dataset — executive voice never enters the brand’s owned-media counts.list, get, and summary (themes and sentiment, filterable by platform, region, sentiment).aspect — what the sentiment is about — at fixed polarity, each with a frequency, a dominant intensity, example posts and source link-backs. All time by default; same filters as mentions.list minus sentiment.dataset, metric (e.g. mention_volume, ad_count, net_sentiment), grain (day/week/month), window (7d…1y).dataset is required for the follower metrics and refused for the rest.window (7d/30d/90d) and publish the same shape, so the two read side by side. Frames come from a fixed vocabulary, which is what makes the counts comparable.category_id. category.trends returns trend, volume, momentum, sentiment — with the window the volume covers echoed once as data.window.audience_id. audience.insights returns top_brands, top_themes, top_content.theme_id across refreshes, and meta.set_version is null until the audience has been clustered.q across your activated audiences’ posts, mentions of your brands and your brands’ owned media at once — ranked by meaning, not by matching words, so it finds a conversation you can describe but cannot spell. Each result reports the corpus it came from. Top-K only: raise limit rather than looking for a next page.An unactivated entity refuses with HTTP 403 and "code": "resource_not_activated" before anything runs and before anything is charged. This is not a transient failure and not an authentication problem.
brand.search / category.list / audience.list, along with the display name. An organization admin activates it in the console at app.adveron.com; the picks it already holds are listed under Tracking.discover.ads query is a fine stopgap answer for today, and you should say that is what it is — it has no history behind it, so it cannot become the daily feed that was asked for.memory.write) so the next run picks it up once the slot exists, instead of rediscovering the 403.Three free operation families that turn a stateless call into durable work. None of them costs credits, deliberately — an agent that has to budget for reading its brief stops reading it.
context.list always returns the five built-in slots — brand_product, marketing_strategy, competitor_analysis, brand_voice, content_strategy — whether or not anybody has filled them. "written": false means the slug is real and empty, so writing to it fills the slot rather than inventing a document.context.get takes the slug and returns the markdown. A slot listed as unwritten answers not found.context.write replaces the whole document. It is not an append: send the complete markdown, or what you leave out is gone. A slug of your own also needs a title. Previous versions are kept, and the write is attributed to you... segments: watchlists/competitors.md. Folders are created for you.memory.write replaces a file whole; memory.edit replaces one exact snippet (old_text must match character for character and be unique unless you pass replace_all); memory.list, memory.read, memory.move, memory.mkdir, memory.delete, memory.revisions do the rest. A delete is recoverable from the revision history.agent, but only with the memory:read:all scope. Two agents that need to share something share it through the activity log, which is public and attributed.activity.create takes a required title, plus kind, channel, detail, a structured payload, an external_ref (a post URL, a campaign id) that makes the claim checkable, and occurred_at when the work happened earlier than now. The reporter is stamped from your credential; you cannot file under another agent’s name.RECORDED and move RECORDED → PUBLISHED → MEASURED or DISMISSED via activity.update, which also takes the outcome you measured. The ladder is a convention nothing enforces — so mark MEASURED when you actually have an outcome, not to tidy the list.activity.list reads the whole workspace, filterable by agent, kind, and status. Read it before you start: checking what another agent already did is the point of it.Your key carries a subset of ten scopes. A missing one is a 403 naming the scope it needs — read the message and tell your human which box to tick rather than working around it.
| Scope | Unlocks | Default |
|---|---|---|
| data:read | Every data operation: brand.*, category.*, audience.*, discover.*, enrichment.*, balance.get, usage.summary. | Yes |
| connections:read | The workspace's OWN connected first-party data: data_source.list, search_console.query, analytics.report, linkedin_ads.*, google_ads.*. Free to call, and never granted by default. | No |
| context:read | context.list and context.get — the standing brief. | Yes |
| context:write | context.write. Without it you can read the brief but not rewrite it. | No |
| memory:read | memory.list, memory.read, memory.revisions, memory.agents — your own tree. | Yes |
| memory:read:all | Widens the memory reads so you may pass another agent's name as "agent". There is no write counterpart. | No |
| memory:write | memory.write, memory.edit, memory.mkdir, memory.move, memory.delete — always your own tree. | Yes |
| activity:read | activity.list — what every agent in the workspace reported doing. | No |
| activity:write | activity.create, and activity.update on your own rows. | Yes |
| activity:write:all | Widens activity.update to any agent's rows in the workspace. | No |
| reports:read | report.list, report.runs, report.get and report.document — reading the report documents this workspace's report runs have produced — and report.run, which launches one of the workspace's catalogued reports and spends its credits at the report's price. Never granted by default. | No |
A key minted without an explicit list gets the five marked default: read the data and the brief, keep your own notes, file your own reports. Rewriting the team’s context and reaching into another agent’s memory or activity are always deliberate grants.
Endpoint-accurate skeletons. Each assumes you have already read context.list and checked activity.list for prior work.
Requires: every rival brand activated.
brand.search with q for each competitor; confirm the right row against its description and categories, and keep the id.brand.competitive_set on your own brand to catch rivals the human did not name.brand.paid_media.ads.list per rival with { "status": "ACTIVE", "sort": "start_date", "order": "desc" }; page while meta.next_cursor is not null.memory.read on watchlists/competitor-ads.md, diff the ad id set, then memory.write the new one back.activity.create with the digest, kind: "digest", and the ad’s landing_url as external_ref.Requires: the category activated. Catalog lookup is open.
category.list or category.get to fix the category_id.category.trends — rank by momentum, not volume, when the question is “what is rising”.category.news and category.landscape for what moved and who is in the market.discover.posts with the top trend as q and "since": "7d" for the live conversation behind it (this one costs credits).memory.write the brief to briefs/<category>-<week>.md; update context.write on marketing_strategy only when a conclusion is durable.activity.create with kind: "brief".Requires: every brand in the comparison activated.
brand.search each brand to ids.brand.compare with brand_ids and a window for the head-to-head snapshot.brand.mentions.summary per brand for the themes and sentiment behind the numbers.brand.timeseries with { "metric": "mention_volume", "grain": "week", "window": "1y" } for the trend line.context.write the conclusion to competitor_analysis; activity.create the report with its link as external_ref.Requires: the audience activated. audience.list is open.
audience.list with q to the audience id.audience.insights for top_brands, top_themes, and top_content.audience.influencers, audience.subreddits, audience.podcasts for where the segment actually is.category.whitespace for the themes nobody is serving.memory.write the theme list to trackers/audience-<id>.md; on the next run diff against it and report only what changed.No activation needed. Every step here costs credits.
enrichment.company.search with { "platform": "linkedin", "q": "<name>" } to resolve each name to a handle — the identifier the next step takes.enrichment.company.get with { "platform", "handle" } for the firmographics.enrichment.company.jobs — open roles are the cheapest expansion signal there is.enrichment.company.posts for what they say publicly, and discover.ads for whether they are buying (remember: google takes the domain).memory.write the qualified rows; activity.create with kind: "prospecting" and the count in payload.insufficient_credits or usage_cap_exceeded means stop and tell your human — retrying cannot help. 403 resource_not_activated needs an activation; 403 permission_denied names the scope your key is missing and how it is granted — most scopes you can select yourself when connecting, or mint on an API key. 409 resource_not_live is the one refusal that is not about you: your organization holds that entity and we have not finished collecting its data, so retry later rather than changing anything — details.held_since says when the slot was taken.RateLimit-* headers. A 429 carries Retry-After; wait that long rather than backing off blind, and slow down when remaining is low instead of waiting to be refused.meta.next_cursor — pass it back as cursor with the same filters until it is null. The first page is not the result set.context.write when it is about the business, to memory.write when it is your own working state, and report the work with activity.create. Dumping a thousand rows into memory is not persistence; it is a bill you will pay twice.