Skip to content

Manifest Reference

This reference is authoritative for Agoraform v0.6.0 and is based on the tagged v0.6.0 manifest specification.

Agoraform configuration is a versioned YAML document containing declarative provider configuration and desired resources.

apiVersion: agoraform.io/v1alpha1
providers:
matomo:
publish: true
environment: live
resources:
- address: matomo.goal.trial_started
attributes:
name: Trial Started
matchAttribute: event_action
pattern: trialStarted
FieldRequiredDescription
apiVersionyesMust be agoraform.io/v1alpha1.
providersnoNon-secret provider-specific desired state.
resourcesnoDesired managed resources. Omitted/empty is valid.

Provider credentials, tokens, passwords, and other secrets must never be put in the manifest. They belong in runtime configuration such as environment variables.

Provider configuration is intentionally separate from credentials. For example, these are desired state and belong in Git:

providers:
matomo:
publish: true
environment: live

These do not:

MATOMO_TOKEN_AUTH
MATOMO_URL
GOOGLE_ADS_DEVELOPER_TOKEN
GOOGLE_ADS_REFRESH_TOKEN
META_ACCESS_TOKEN
META_AD_ACCOUNT_ID

See Matomo Tag Manager publication and the Google Ads and Meta providers.

A resource address is three lowercase identifiers separated by dots:

provider.type.name

Example:

matomo.goal.trial_started

Each segment starts with a letter and may then contain lowercase letters, digits, or underscores. Duplicate addresses are rejected.

Provider-neutral dependencies use a $ref object containing a logical Agoraform address. Address-only references stay a single-key map:

resources:
- address: matomo.trigger.trial_started
attributes:
type: customEvent
event: trialStarted
- address: matomo.tag.trial_started
attributes:
type: matomoAnalytics
trigger:
$ref: matomo.trigger.trial_started
eventCategory: signup
eventAction: trialStarted

The $ref value is always a logical Agoraform address, never a provider-native ID. Ordinary strings remain provider-owned values even if they happen to look like an address.

An optional output selector consumes one declared non-sensitive named output from the referenced resource, including across providers:

conversionId:
$ref: googleads.conversion_action.trial_started
output: conversionId

A reference without output still resolves to the full runtime binding (provider-native identity plus computed outputs). A reference with output resolves to that one value. Unknown, sensitive, unavailable, and wrong-kind outputs fail before the dependent mutation. Arbitrary computed fields are not automatically selectable.

Agoraform validates references and builds a directed dependency graph. Missing references, self-references, and cycles fail before remote mutations. Cross-provider output references create the same kind of dependency edge.

At apply time, logical references are resolved in dependency order. Those provider-native values are not written back into the manifest.

resources[].attributes is provider-owned configuration. The core normalizes YAML types and understands $ref; providers validate the actual schema. Computed/read-only provider fields do not belong in configuration and must not produce changes merely because provider-native IDs differ.

v0.1.0 introduced Matomo analytics goals. Common attributes:

AttributeRequiredDescription
nameyesGoal name; immutable once local state binds the resource.
matchAttributeyesGoal matching mode such as event_action, url, or manually.
patternunless manuallyValue to match.
patternTypenocontains (default), exact, or regex; numeric modes use provider defaults.

Provider-native goal IDs live in local state, not attributes.

A Tag Manager container can be declared instead of requiring MATOMO_CONTAINER_ID:

- address: matomo.container.main
attributes:
name: Main Website
context: web

name and context (web, android, or ios) are required. description is optional. Provider-native container IDs stay in local state. v0.6.0 allows at most one matomo.container resource.

When that resource is present, Tag Manager children must reference it:

container:
$ref: matomo.container.main

When it is absent, omit container and set MATOMO_CONTAINER_ID. Mixing the two modes is rejected. See the Matomo provider reference.

v0.2.0 supports Tag Manager Data Layer variables. v0.6.0 also supports Matomo Configuration variables:

- address: matomo.variable.user_id
attributes:
type: dataLayer
key: userId
name: User ID
- address: matomo.variable.config
attributes:
type: matomoConfiguration
name: Matomo Configuration
matomoUrl: https://matomo.example.com
siteId: 1
enableLinkTracking: true

For dataLayer, type and key are required; name is optional and defaults to key. For matomoConfiguration, type, name, matomoUrl, and siteId are required; enableLinkTracking is optional.

v0.2.0 supports Custom Event triggers:

- address: matomo.trigger.trial_started
attributes:
type: customEvent
event: trialStarted

type and event are required; name is optional and defaults to event.

v0.2.0 supports Matomo Analytics event tags. Google Ads conversion tags use the Matomo Tag Manager GoogleAdsConversion template:

- address: matomo.tag.trial_started
attributes:
type: matomoAnalytics
trigger:
$ref: matomo.trigger.trial_started
eventCategory: signup
eventAction: trialStarted
matomoConfiguration:
$ref: matomo.variable.config
- address: matomo.tag.google_ads_trial_started
attributes:
type: googleAdsConversion
trigger:
$ref: matomo.trigger.trial_started
conversionId:
$ref: googleads.conversion_action.trial_started
output: conversionId
conversionLabel:
$ref: googleads.conversion_action.trial_started
output: conversionLabel

Supported event fields may be literals or, where documented, references to managed variables. matomoConfiguration is an optional $ref to a managed matomo.variable of type matomoConfiguration and applies to Matomo Analytics tags. Google Ads conversion tags consume conversionId and conversionLabel as literals or as selected outputs from a managed googleads.conversion_action. Agoraform does not emit the application event; the application still pushes the configured data-layer event. See the Matomo provider reference for the complete resource-specific schema, template parameter mapping, and preservation behavior. The v0.5 Matomo + Google Ads lifecycle example is a complete managed-container workflow that consumes those outputs.

v0.4.0 Search resources form a dependency graph. Campaigns require a budget; ad groups, targeting, and campaign conversion goals require a campaign; keywords and Responsive Search Ads require an ad group:

googleads.conversion_action
googleads.customer_conversion_goal
googleads.campaign_budget
└── googleads.campaign
├── googleads.campaign_conversion_goal
├── googleads.campaign_location
├── googleads.campaign_language
└── googleads.ad_group
├── googleads.keyword
└── googleads.responsive_search_ad

New campaigns, ad groups, positive keywords, and Responsive Search Ads default to PAUSED. See the complete Google Ads Search campaign example.

Website conversion actions. Common attributes:

AttributeRequiredDescription
nameyesConversion action name.
categoryyesWebsite category such as SIGNUP or PURCHASE.
valuenoDefault conversion value.
countnoONE or MANY.
primaryForGoalnoWhether the action is primary for its conversion goal.
statusnoENABLED, HIDDEN, or REMOVED.

type is always website (WEBPAGE) and is computed. Provider-native IDs and resource names live in local state, not attributes. Optional conversion windows, currency, and alwaysUseDefaultValue are documented in the Google Ads provider reference.

- address: googleads.conversion_action.trial_started
attributes:
name: Trial Started
category: SIGNUP
value: 0
count: ONE
primaryForGoal: true

See the complete Google Ads conversion example and the complete Google Ads Search campaign example.

Account-default website conversion-goal biddability. Google Ads creates these objects automatically; Agoraform only updates biddable.

AttributeRequiredDescription
categoryyesWebsite category such as SIGNUP or PURCHASE.
originyesWEBSITE.
biddableyesWhether the goal is an account-default optimization goal.
conversionActionno$ref to a managed googleads.conversion_action so apply creates that action first.
- address: googleads.customer_conversion_goal.signup
attributes:
category: SIGNUP
origin: WEBSITE
biddable: true
conversionAction:
$ref: googleads.conversion_action.trial_started

Daily Search campaign budgets. Amounts are declared in account-currency units and normalized to Google Ads micros for API calls and plan comparison.

AttributeRequiredDescription
nameyesBudget name used for creation and unmanaged discovery. For dedicated budgets, Google synchronizes the live name with the attached campaign and Agoraform does not treat that synchronization as drift.
amountyesDaily budget in account-currency units.
explicitlySharedyesfalse for a dedicated budget; true for a shared budget. A shared budget cannot be changed back to dedicated.
deliveryMethodnoSTANDARD only for the supported Search workflow. ACCELERATED is rejected.
- address: googleads.campaign_budget.brand
attributes:
name: Brand daily budget
amount: 50
deliveryMethod: STANDARD
explicitlyShared: false

Search campaigns reference the budget by logical address:

- address: googleads.campaign.brand
attributes:
name: Brand
budget:
$ref: googleads.campaign_budget.brand
bidding:
strategy: MANUAL_CPC

Provider-native IDs, resource names, micros, period, and type are computed. Updates use sparse field masks so unchanged sharing fields and Google-managed dedicated-budget names are not resent. Converting a dedicated budget to shared includes its name in the same mutation, as required by Google Ads. See the Google Ads provider reference.

Search campaigns. The advertising channel is SEARCH. New campaigns default to PAUSED. Campaigns must reference a googleads.campaign_budget. Dynamic Search Ads settings are out of scope.

AttributeRequiredDescription
nameyesCampaign name.
budgetyes$ref to a googleads.campaign_budget.
biddingyesSearch bidding strategy such as MANUAL_CPC or MAXIMIZE_CONVERSIONS.
statusnoPAUSED (default) or ENABLED.
networknoSearch network / partner flags.
startDate / endDatenoYYYY-MM-DD.
trackingUrlTemplate / finalUrlSuffixnoOptional URL tracking fields.
locationTargetingnoPresence vs interest geotargeting: positive is PRESENCE, PRESENCE_OR_INTEREST, or SEARCH_INTEREST; negative is PRESENCE or PRESENCE_OR_INTEREST.
- address: googleads.campaign.brand
attributes:
name: Brand
status: PAUSED
budget:
$ref: googleads.campaign_budget.brand
bidding:
strategy: MANUAL_CPC

Unsupported channel types fail validation before mutation. Ads, keywords, and location/language criteria are separate resources. See the Google Ads provider reference.

Search standard ad groups. The type is SEARCH_STANDARD. New ad groups default to PAUSED. Ad groups must reference a googleads.campaign.

AttributeRequiredDescription
nameyesAd group name. Unique within the campaign.
campaignyes$ref to a googleads.campaign.
statusnoPAUSED (default) or ENABLED.
typenoMust be SEARCH_STANDARD when set.
cpcBidnoMax CPC bid in account-currency units.
- address: googleads.ad_group.brand
attributes:
name: Brand
status: PAUSED
campaign:
$ref: googleads.campaign.brand
type: SEARCH_STANDARD
cpcBid: 1.5

Unsupported types fail validation before mutation. Targeting and ads remain separate resources. See the Google Ads provider reference.

Search ad-group keyword criteria, including negative keywords. Keywords must reference a googleads.ad_group. Match types are EXACT, PHRASE, and BROAD. Keyword text is normalized to lowercase without changing user intent. Text, match type, negative, and ad group are immutable after create.

AttributeRequiredDescription
adGroupyes$ref to a googleads.ad_group.
textyesKeyword text without match-type punctuation.
matchTypeyesEXACT, PHRASE, or BROAD.
negativenotrue for a negative keyword. Defaults to false.
statusnoPositive keywords default to PAUSED and may use PAUSED or ENABLED. Negative keywords default to ENABLED; their status is immutable after creation.
cpcBidnoOptional max CPC bid override in account-currency units. Not allowed on negative keywords.
- address: googleads.keyword.brand_exact
attributes:
adGroup:
$ref: googleads.ad_group.brand
text: brand
matchType: EXACT
status: PAUSED
cpcBid: 1.5
- address: googleads.keyword.competitor_neg
attributes:
adGroup:
$ref: googleads.ad_group.brand
text: competitor
matchType: PHRASE
negative: true

New negative keywords are created ENABLED when status is omitted. Creating a new negative keyword as PAUSED is rejected because Google Ads does not allow negative ad-group criteria to be updated later. For an existing negative keyword, a requested status change fails during planning before any mutation. Positive keyword status remains mutable.

Campaign-level negative keywords, Keyword Planner, audience or DSA criteria, and keyword-level URL or tracking overrides are out of scope. See the Google Ads provider reference.

Responsive Search Ads attached to a Search ad group. Ads must reference a googleads.ad_group. Agoraform manages serving copy, URLs, optional display paths, optional pinning, and status. It does not generate headlines or descriptions. Creative changes replace the underlying ad lists; status updates the ad-group-ad relationship.

AttributeRequiredDescription
adGroupyes$ref to a googleads.ad_group.
finalUrlsyesOne or more absolute http or https landing-page URLs.
headlinesyes3–15 headlines as strings or {text, pin} objects.
descriptionsyes2–4 descriptions as strings or {text, pin} objects.
path1noOptional display-path segment. Requires no /.
path2noOptional second path segment. Requires path1.
statusnoPAUSED (default) or ENABLED.
- address: googleads.responsive_search_ad.brand
attributes:
adGroup:
$ref: googleads.ad_group.brand
status: PAUSED
finalUrls:
- https://example.com/
path1: shoes
headlines:
- text: Buy shoes online
pin: HEADLINE_1
- Free shipping today
- Shop the collection
descriptions:
- Find shoes that fit your style.
- Free returns on every order.

Dynamic Search Ads, Display, video, and Performance Max ads are out of scope. See the Google Ads provider reference.

Search campaign location criteria, including excluded locations. Locations must reference a googleads.campaign. Prefer canonical names or country codes; Agoraform resolves them to Google Ads geo target constants and fails when a name is missing or ambiguous. Campaign, location, and negative are immutable after create.

AttributeRequiredDescription
campaignyes$ref to a googleads.campaign.
locationyesCanonical name, ISO country code, or geoTargetConstants/{id}.
negativenotrue to exclude the location. Defaults to false.
- address: googleads.campaign_location.united_states
attributes:
campaign:
$ref: googleads.campaign.brand
location: United States
- address: googleads.campaign_location.exclude_canada
attributes:
campaign:
$ref: googleads.campaign.brand
location: Canada
negative: true

Radius/proximity targeting and audience segments are out of scope. Presence vs interest behavior is locationTargeting on googleads.campaign. See the Google Ads provider reference.

Search campaign language criteria. Languages must reference a googleads.campaign. Prefer ISO codes such as en. Campaign and language are immutable after create.

AttributeRequiredDescription
campaignyes$ref to a googleads.campaign.
languageyesISO code, language name, or languageConstants/{id}.
- address: googleads.campaign_language.english
attributes:
campaign:
$ref: googleads.campaign.brand
language: en

See the Google Ads provider reference.

Campaign-level website conversion-goal biddability. Google Ads creates these objects automatically; Agoraform only updates biddable.

AttributeRequiredDescription
campaignyes$ref to a managed googleads.campaign.
categoryyesWebsite category such as SIGNUP or PURCHASE.
originyesWEBSITE.
biddableyesWhether the goal is a campaign-level optimization goal.
conversionActionno$ref to a managed googleads.conversion_action so apply creates that action first.
- address: googleads.campaign_conversion_goal.trial_signup
attributes:
campaign:
$ref: googleads.campaign.search_acquisition
category: SIGNUP
origin: WEBSITE
biddable: true
conversionAction:
$ref: googleads.conversion_action.trial_started

See the complete Google Ads Search campaign example.

v0.6.0 supports one complete Meta website-conversion campaign graph. Declare the provider with an empty configuration block:

providers:
meta: {}

The provider block accepts no fields. META_ACCESS_TOKEN and META_AD_ACCOUNT_ID are runtime settings and must not be placed in YAML.

The supported resources form this graph:

meta.ad
├── meta.ad_set
│ ├── meta.campaign
│ ├── meta.custom_conversion
│ │ └── meta.pixel
│ └── meta.pixel
└── meta.ad_creative

Managed relationships use logical $ref values. External Page, Instagram, image, and video identifiers remain literal attributes.

New campaigns, ad sets, and ads default to PAUSED. Meta money attributes — dailyBudget, lifetimeBudget, and bidAmount — are declared in ad account currency units with at most two decimal places.

See the Meta provider and the complete Meta website conversion campaign example.

Declares an existing Pixel/Dataset event source by name:

- address: meta.pixel.website
attributes:
name: Website
AttributeRequiredDescription
nameyesExact Pixel/Dataset name used for unique adoption.

Agoraform does not create, rename, or delete Pixels/Datasets.

Website Custom Conversions reference a managed Pixel/Dataset:

- address: meta.custom_conversion.trial_started
attributes:
name: Trial Started
eventType: START_TRIAL
pixel:
$ref: meta.pixel.website
rule:
and:
- event:
eq: StartTrial
defaultValue: 0
AttributeRequiredDescription
nameyesCustom Conversion name.
pixelyes$ref to a managed meta.pixel.
ruleyesMeta rule object, such as an event or URL condition.
eventTypeyesMeta custom_event_type, such as START_TRIAL, PURCHASE, or LEAD.
defaultValuenoNon-negative default conversion value.

pixel, rule, and eventType are immutable after creation.

- address: meta.campaign.website_acquisition
attributes:
name: Website Acquisition
objective: OUTCOME_SALES
status: PAUSED
specialAdCategories: []
buyingType: AUCTION
adSetBudgetSharingEnabled: false
AttributeRequiredDescription
nameyesCampaign name.
objectiveyesSupported OUTCOME_* objective.
specialAdCategoriesyesApplicable categories, or an empty list when none apply.
statusnoPAUSED (default) or ACTIVE.
buyingTypenoAUCTION (default and only supported value).
dailyBudget / lifetimeBudgetnoMutually exclusive positive amounts in account-currency units.
bidStrategynoCampaign bid strategy; valid only with a campaign-level budget.
adSetBudgetSharingEnablednoDefaults to false; cannot be true with a campaign-level budget.

Objective, buying type, and budget ownership/type cannot change in place.

- address: meta.ad_set.instagram_trial
attributes:
name: Instagram Trial Acquisition
status: PAUSED
campaign:
$ref: meta.campaign.website_acquisition
dailyBudget: 50
billingEvent: IMPRESSIONS
optimizationGoal: OFFSITE_CONVERSIONS
bidStrategy: LOWEST_COST_WITHOUT_CAP
destinationType: WEBSITE
pixel:
$ref: meta.pixel.website
customConversion:
$ref: meta.custom_conversion.trial_started
targeting:
countries: [US]
publisherPlatforms: [INSTAGRAM]
instagramPositions: [FEED, STORIES, REELS]

For OFFSITE_CONVERSIONS, both pixel and customConversion are required and must reference the same pixel. The campaign objective must be OUTCOME_SALES.

- address: meta.ad_creative.instagram_trial
attributes:
name: Instagram Trial Creative
pageId: "123456789012345"
instagramUserId: "234567890123456"
destinationUrl: https://example.com/trial
primaryText: Start organizing your catalog today.
headline: Start Your Free Trial
callToAction: LEARN_MORE
imageHash: "0123456789abcdef0123456789abcdef"

Use exactly one external imageHash or videoId. Only name is mutable.

- address: meta.ad.instagram_trial
attributes:
name: Instagram Trial Ad
adSet:
$ref: meta.ad_set.instagram_trial
creative:
$ref: meta.ad_creative.instagram_trial
status: PAUSED

name, status, and creative can be updated. The parent adSet is immutable after creation.

v0.2.0 recognizes:

providers:
matomo:
publish: true
environment: live
FieldRequiredDescription
publishnoBoolean; default false. When true, converge the configured Tag Manager container into the target environment through normal plan/apply/destroy.
environmentnoTag Manager environment; default live.

Unknown provider configuration fields are rejected.

Terminal window
agoraform validate
agoraform validate -f path/to/manifest.yaml
agoraform validate path/to/manifest.yaml

Validation covers:

  • YAML and apiVersion;
  • provider names and provider-specific configuration;
  • resource address syntax and duplicates;
  • $ref and { $ref, output } validity and dependency cycles;
  • registered provider/resource support;
  • provider connectivity;
  • provider-specific resource fields;
  • managed-container versus MATOMO_CONTAINER_ID exclusivity.

Matomo runtime connection settings come from MATOMO_URL, MATOMO_TOKEN_AUTH, and MATOMO_SITE_ID; Tag Manager resource/publication work also requires either a matomo.container resource or MATOMO_CONTAINER_ID. Google Ads connection settings come from GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_REFRESH_TOKEN, and GOOGLE_ADS_CUSTOMER_ID. Meta connection settings come from META_ACCESS_TOKEN and META_AD_ACCOUNT_ID.

See plan, apply, import, destroy, and local state.