Meta Marketing API v26.0: The Changes of 27 October 2026 and an Audit Script for Existing Integrations

Contents
Meta released Graph API and Marketing API v26.0 on 29 July 2026. Several changes also reach older supported Marketing API versions on 27 October 2026. A version pin therefore needs a second check: the effective date of each individual change. This article covers six changes relevant to ad automation; the full release contains additional changes.
1. Version scope and date are separate checks
Meta documents both version-specific changes and changes that apply across versions. The latter are part of the documented release process, rather than a new guarantee being broken. The Marketing API and Graph API also have different retirement schedules. For example, the Graph API v25.0 end date must not be used as the retirement date for Marketing API v25.0.
As checked on 24 October 2026, Marketing API v24.0 had already reached its listed end date of 6 October 2026. Remaining on an unsupported version is not a migration strategy. The current version table and the individual change notices both belong in the integration inventory.
2. Six changes and their actual scope
- Delivery estimates:
daily_outcomes_curve,budget_guardrailandestimate_daudisappear from delivery-estimate responses in v26.0 and from the remaining supported versions on 27 October. Meta lists no replacement. Both account-level and ad-set-level delivery-estimate reads and downstream calculations need checking. - Web + App campaigns: a creative with
applink_treatment=web_onlycan no longer be attached to an ad in a campaign using Website and App conversion locations. This is not a general ban on website destinations. The documented alternative is automatic routing or a compatible manual configuration. Scope: v26.0, then all supported Marketing API versions on 27 October. - Poll ads:
poll_specand poll components underinteractive_components_specare affected when creating or changing ads and creatives. Updates that leave the creative unchanged can continue. Scope: v26.0, then the remaining supported versions on 27 October. - Messenger Stories:
storyis silently removed frommessenger_positions. Historical targeting can still contain the value. Manual placements need adjustment; Advantage+ Placements require no action for this removal. Scope: v26.0, then all supported Marketing API versions, including unversioned calls, on 27 October. - Instagram Explore Feed: explicitly requesting this placement causes an error from v26.0 onward. The notice does not assign the same all-version deadline of 27 October. Placement values must be checked against the actual request and the relevant placement documentation, not inferred from a display label.
- Advantage+ audience: creating certain non-broad Housing, Employment or Financial Products and Services ad sets with relaxable targeting requires an explicit
targeting_automation.advantage_audiencevalue of 1 or 0. Broad/default configurations are not generally affected. The requirement starts in v26.0; expansion to all versions follows retirement of Marketing API v25.0, whose date was still unspecified at the check date.
A successful HTTP response cannot prove that the requested placement mix survived unchanged. Delivery configuration and effective placements need comparison as well as error monitoring. The magnitude of any performance effect depends on the account and cannot be inferred from the changelog.

3. A local script for review hints
The following Python script scans exported JSON objects and arrays recursively. It finds explicit references to removed fields, Messenger Stories, Instagram placements, web-only routing and potentially relevant creative structures. A match is a review hint, not proof that an API request will fail. For example, an interactive component need not be a poll, and a web-only creative needs campaign context.
The script deliberately does not infer special-ad-category rules from a made-up vertical field. Campaign category, broad versus non-broad targeting, relaxability, API version and operation belong in the separate manual check. JSON embedded inside strings also needs decoding before scanning. Only files directly inside the selected directory are covered.
#!/usr/bin/env python3
"""Local review hints only; no API calls and no automatic fixes."""
import json
import pathlib
import re
import sys
REMOVED = {"daily_outcomes_curve", "budget_guardrail", "estimate_dau"}
def scan(node, path="$", found=None):
found = [] if found is None else found
if isinstance(node, dict):
for key, value in node.items():
here = f"{path}.{key}"
if key in REMOVED:
found.append((here, "REMOVED_FIELD_REFERENCE", key))
if key == "fields":
# Flat field lists only; nested Graph field syntax needs review.
fields = value.split(",") if isinstance(value, str) else value
if isinstance(fields, list):
for field in fields:
if isinstance(field, str):
for token in re.findall(r"[A-Za-z_][A-Za-z_0-9]*", field):
if token in REMOVED:
found.append((here, "REMOVED_FIELD_REQUEST", token))
else:
found.append((here, "INVALID_FIELDS_SHAPE", "review"))
if key == "messenger_positions":
if not isinstance(value, list):
found.append((here, "INVALID_PLACEMENT_SHAPE", "review"))
elif "story" in value:
found.append((here, "MESSENGER_STORY", "review manual placement"))
if key == "instagram_positions":
found.append((here, "INSTAGRAM_PLACEMENT_REVIEW", "check Explore Feed mapping"))
if key == "applink_treatment" and value == "web_only":
found.append((here, "WEB_APP_CONTEXT_REVIEW", "check campaign conversion locations"))
if key in {"poll_spec", "interactive_components_spec"}:
found.append((here, "CREATIVE_REVIEW", "check poll use and operation"))
scan(value, here, found)
elif isinstance(node, list):
for index, value in enumerate(node):
scan(value, f"{path}[{index}]", found)
return found
def main(directory):
files = sorted(pathlib.Path(directory).glob("*.json"))
if not files:
print("INPUT_ERROR: no JSON files", file=sys.stderr)
return 2
findings, errors = 0, 0
for file in files:
try:
node = json.loads(file.read_text(encoding="utf-8"))
if not isinstance(node, (dict, list)):
raise ValueError("expected JSON object or array")
except (OSError, ValueError) as exc:
print(json.dumps({"file": file.name, "error": type(exc).__name__}))
errors += 1
continue
for path, kind, detail in scan(node):
print(json.dumps({"file": file.name, "path": path, "kind": kind, "detail": detail}))
findings += 1
print(json.dumps({"files": len(files), "review_hints": findings, "input_errors": errors}))
return 2 if errors else (1 if findings else 0)
if __name__ == "__main__":
if len(sys.argv) != 2:
raise SystemExit("usage: audit_v26.py DIRECTORY")
raise SystemExit(main(sys.argv[1]))Invocation: python3 audit_v26.py /srv/adops/adset_configs. Exit 1 means review hints, exit 2 means an input error, and exit 0 only means no hints from these checks. An empty directory is an error. The deployment job must preserve the exit code; appending a successful || echo would hide it. File paths and configuration fragments may reveal internal structure, so audit output belongs in access-controlled logs.
4. Complete the inventory and verify changes
- Record the API version, endpoint, operation and owner for each integration. Include stored templates, report consumers and ads created in the interface.
- Use a read-only account inventory to connect ads, creatives, ad sets and campaigns. A local export alone cannot cover later interface changes.
- Check each finding against the scope above. Remove obsolete manual placements, replace affected Web + App routing, and validate the precise audience case before changing a flag.
- Trace removed delivery fields through transformations and dashboards. A persistent nullable column can conceal a lost metric; zero is not a substitute for missing data.
- Validate approved changes in a controlled test setup and compare responses and effective configuration around the deadline. Creating or delivering test ads can incur spend; a local scan itself makes no API calls.
The complete v26.0 changelog also includes legacy protocol changes, Page and Commerce changes, and additional Marketing API features. Six checks cannot certify the whole integration.
5. Check geography changes separately
The DMA-to-Comscore transition is separate from the October deadline. Supermetrics documents its own Facebook Ads connector change: the former DMA dimension stops returning results from 22 June 2026 and is replaced by Comscore market. That is evidence for this connector, not proof that every warehouse has lost rows or that every Meta endpoint changed identically.
The following diagnostic finds fact rows with no usable mapping in an example legacy dimension. NOT EXISTS prevents duplicate dimension rows from multiplying impressions. A null geographic name also remains unmatched. Table and column names are illustrative; this query measures mapping gaps, not the cause of a platform migration.
SELECT f.report_date, f.geo_name, SUM(f.impressions) AS impressions
FROM meta_geo_daily AS f
WHERE f.report_date >= '2026-06-01'
AND NOT EXISTS (
SELECT 1 FROM dim_dma AS d
WHERE d.dma_name = f.geo_name
AND d.dma_code IS NOT NULL
)
GROUP BY f.report_date, f.geo_name
ORDER BY impressions DESC
LIMIT 25;Review unmatched impressions as a share of the total, not only the top 25 rows. Production mappings should use documented geographic identifiers, the geographic system and validity dates instead of display names alone. Historical reprocessing depends on retained raw data and the available mapping. Crosswalks can support defined comparisons, but unequal boundaries need explicit qualifications.
Questions and answers
Does a clean script result establish readiness?
No. Missing exports, campaign context, unsupported versions, string-encoded JSON and changes outside the six checks remain outside this scan. Read-only account inventory, a documented manual decision for each contextual finding and controlled verification are still required.
Does pinning to v25.0 avoid the October deadline?
Not for the four changes with an explicit cross-version deadline: delivery fields, the affected Web + App routing, poll ads and Messenger Stories. Explore Feed and the special Advantage+ audience requirement have different version rules.