03 / Your first automation
Your first automation
This chapter builds one automation: when a product runs out of stock, pause its ads, and resume them when it's restocked. Steps 1 to 4 work on the demo. Steps 5 to 7 need your own account.
1. Ask first
Find products that are out of stock but still spending on ads. Show me the affected campaigns before changing anything.
Your agent reads stock from your listings and matches it against your product ads. On the demo, it finds the Acme
Precision Gooseneck Kettle, SKU ACM-US-004 on Amazon.com. It has had 0 units available for 3 days, and 2
US campaigns still advertise it.
It may also mention Auto - Acme UK Discovery, a UK campaign that advertises the same ASIN. The UK kettle is a separate listing with its own stock, and it's in stock. Stock belongs to a SKU in one marketplace, not to an ASIN everywhere.
2. How stock reaches ads
Amazon Ads advertises products through product ads. Each product ad names a SKU and sits in an ad group, and each ad group sits in a campaign. Pulsify matches product ads to your listing by SKU, marketplace and account, so an automation running for a listing sees that listing's ads and the campaigns they belong to.
A campaign can advertise several products. On the demo, the kettle has 2 product ads:
| Campaign | What it advertises |
|---|---|
| Manual - Acme US Gooseneck Kettle | The kettle only |
| Auto - Acme US Espresso Launch | The kettle and 3 other products |
Pausing Auto - Acme US Espresso Launch would stop ads for 3 products that are still in stock. So the automation pauses the kettle's own product ads and leaves both campaigns running. Pausing a whole campaign is a separate business decision with its own side effects.
3. Draft the automation
Tell your agent what you want:
Write an automation for FBA stock changes. When a SKU's available stock in its marketplace reaches 0, pause its product ads. When stock comes back, resume its paused product ads. Never pause or resume whole campaigns.
It writes something like this:
// Pause this SKU's product ads when its FBA stock in this marketplace reaches 0.
// Resume them on restock.
function handle(event, context) {
const listing = context.listing;
const marketplaceId = context.marketplace.marketplaceId;
const stock = (event.Payload?.FulfillmentInventoryByMarketplace || []).find(
(entry) => entry.MarketplaceId === marketplaceId,
);
if (!stock) return context;
const available = stock.FulfillableQuantity;
for (const ad of listing.ads) {
if (available === 0 && ad.state === "enabled") {
context.mutations.push({ target: ad, action: "update", payload: { state: "PAUSED" } });
} else if (available > 0 && ad.state === "paused") {
context.mutations.push({ target: ad, action: "update", payload: { state: "ENABLED" } });
}
}
return context;
}
-
It runs on
FBA_INVENTORY_AVAILABILITY_CHANGES, the event Amazon sends when FBA stock changes. One event covers every marketplace in a region, so the code picks the entry for this listing's marketplace. -
listing.adsholds this listing's product ads, each with its state as of Pulsify's last Ads reading. -
Each change goes into
context.mutations. The code only asks. Pulsify checks each request against your account before sending it to Amazon. - It asks for a change only when that state differs, so an ad Pulsify already reads as paused stays untouched.
Your agent saves it with
create_automation. On your
account, that's an inactive draft, so nothing runs yet. On the demo, you get a simulated receipt and nothing is saved.
4. Dry-run it against a real event
A dry run executes the code against an event and returns the changes it would ask for. Nothing is applied: no change reaches Amazon and no webhook fires. Ask:
Dry-run it against the kettle's stockout event, then against its restock event.
Your agent finds both events with
list_events and replays each with
run_automation. The stockout event
reports 0 available and returns 2 pause requests, one for the kettle's ad in each campaign (ids shortened):
{
"ok": true,
"mutations": [
{ "target": { "type": "Ad", "id": "…", "state": "enabled", "asin": "B0ACME0004", "sku": "ACM-US-004" }, "action": "update", "payload": { "state": "PAUSED" } },
{ "target": { "type": "Ad", "id": "…", "state": "enabled", "asin": "B0ACME0004", "sku": "ACM-US-004" }, "action": "update", "payload": { "state": "PAUSED" } }
],
"logs": [],
"missing_field_reads": [],
"stimulus_source": "event"
}
The restock event reports 38 available and returns no changes. The kettle's ads are still enabled, and the code only resumes paused ads. On a live account, the stockout run pauses them first, so the restock resumes them.
Check missing_field_reads in each reply. It lists event fields the code read that weren't in the event.
Anything there usually means the code expects the wrong payload shape.
5. Activate it
Activation needs your own account. The demo can't save or activate anything. Ask your agent to activate the draft,
which calls update_automation
with activate. Or open the automation in the console, under Streams, and choose Make active.
Each account runs 1 automation per event type. Activating this one deactivates any other
FBA_INVENTORY_AVAILABILITY_CHANGES automation on the same account.
From then on it runs whenever Amazon reports an FBA stock change for one of your SKUs, whether or not a conversation is open.
6. Check what happened
Each stage is a separate fact. One can be true while the next isn't yet:
- Proposed. Your agent describes the change it has in mind. Nothing has run.
-
Dry run.
run_automationshows what the code would ask for. Nothing is sent. -
Queued. A real event runs the automation. Pulsify validates each request and records an
applieddecision with a separate queued mutation receipt. A worker sends that immutable request to Amazon after the run commits. -
Accepted by Amazon. The receipt records Amazon's outcome, acceptance and raw response. A request
withheld by the listing block or campaign switch is
blocked. Partial or ambiguous results areuncertainand stop later requests for that target instead of being blindly retried. -
Observed. When Amazon returns a matching, current ad representation, Pulsify records it and the
next run reads it in
listing.ads. Otherwise a later event or refresh supplies the observation. Requested values alone never change that reading.
These are the facts How it runs describes, plus the 2 that come before a real run.
After the first real stockout, ask:
What has the stock automation done since yesterday? For each ad it changed, show Amazon's answer and the ad's current state.
Your agent reads the history with
list_automation_actions and
the receipts and current ad state with
list_ads_entities.
7. Stop it
-
For one product, block its listing: choose Block automated changes on the listing's page in the
console, or ask your agent, which calls
update_listing. The automation keeps running and records what it wanted, but Pulsify withholds the listing's changes, including its ad changes. Unblocking doesn't replay them. - For one campaign, turn off its Automation switch on the campaign's page in the console. Pulsify withholds every automated change to that campaign and its ad groups, ads and keywords, including the pauses this automation asks for. Switching it back on doesn't replay them.
-
Everywhere, archive the automation: choose Archive next to it in the console, or ask your agent,
which calls
archive_automation. It stops running, and its code and history stay.
For every control and what each one covers, see Staying in control. For the handler, context and mutation contract, see the Reference.