08 / Reference
Reference
Exact contracts for agents and developers. The tables on this page render from the running code, so they match what your agent sees over MCP.
- MCP server
- Tools
- Event types
- The handler
- Context by scope
- Mutations
- Store and console
- Webhooks
- Errors
- Limits
- Retention
MCP server
| Endpoint | Sign-in | Data |
|---|---|---|
https://pulsify.dev/mcp |
OAuth | Your connected accounts |
https://demo.pulsify.dev/mcp |
None | Acme Brands, a fictional seller. Writes are validated and simulated: nothing is saved or sent to Amazon. |
Setup is on Connect your agent. The changelog is also an MCP
resource: resource://pulsify/changelog.md.
Most tools take account, an id from connection_status. Reads without it cover every
connected account and label each row with its account. Writes need it once you've connected more than 1 account.
Tools
Reads never change anything. Writes change something in Pulsify or queue a request to Amazon. If your only connection is a Vendor Central account, seller tools are hidden. The demo leaves out a few more.
| Tool | Kind | Availability |
|---|---|---|
archive_automation |
Write | Simulated on the demo |
connection_status |
Read | Everywhere |
create_automation |
Write | Simulated on the demo |
describe_stream_type |
Read | Everywhere |
duplicate_automation |
Write | Simulated on the demo |
get_ads_summary |
Read | Everywhere |
get_automation |
Read | Everywhere |
get_event |
Read | Everywhere |
get_product_type_schema |
Read | Not on the demo |
get_sales_summary |
Read | Not for Vendor Central-only users |
list_automation_actions |
Read | Everywhere |
list_automations |
Read | Everywhere |
list_campaigns |
Read | Everywhere |
list_events |
Read | Everywhere |
list_keywords |
Read | Everywhere |
list_listings |
Read | Not for Vendor Central-only users |
list_sales_by_listing |
Read | Not for Vendor Central-only users |
list_streams |
Read | Everywhere |
list_targets |
Read | Everywhere |
patch_listing |
Write | Not for Vendor Central-only users. Simulated on the demo |
query_data |
Read | Everywhere |
report_bug |
Write | Not on the demo |
run_automation |
Read | Everywhere |
suggest_idea |
Write | Not on the demo |
update_automation |
Write | Simulated on the demo |
update_listing |
Write | Not for Vendor Central-only users. Simulated on the demo |
archive_automation
Archive an automation. Deactivates it first if live, drops it from your list, and keeps its history. There is no hard delete.
| Parameter | Type | Description |
|---|---|---|
automation_id (required) |
string | The automation to archive |
connection_status
Whether the user's Amazon SP-API (selling) and Ads connections are live, per connected account. accounts lists every account: id (the account argument the other tools take), name, and both connections. For each connection: connected means authorized with Amazon; active means connected with billing in good standing. Check this first when events or automations seem inactive. ads.profiles lists the advertising profiles (marketplace, country, currency, account name and id); use them to scope the advertising read tools - profiles are per country and currency. entity_type is vendor for a Vendor Central account, which has no listings and no seller sales. changelog lists recent Pulsify product changes; the full history is the MCP resource resource://pulsify/changelog.md.
No parameters.
create_automation
Create a new draft automation for an Amazon event type. Inactive until you activate it. Returns its id. With more than one connected account, account names which one owns it. Use run_automation to dry-run the code before activating; its missing_field_reads catches a wrong payload shape.
| Parameter | Type | Description |
|---|---|---|
stream_type (required) |
string | Event type code, e.g. ANY_OFFER_CHANGED |
code |
string | Optional JavaScript. Defaults to the event type's template. |
account |
string | Account id from connection_status. Required when more than one account is connected. |
describe_stream_type
The contract for automation code on one event type: what handle(event, context) receives, field by field, with units and nullability. Read it before writing or editing automation JavaScript. event is the payload Amazon sends, shown as a complete fixture because a live event carries only the fields that changed. context is the object your code reads and writes. Every currency value on context is in major units (15.27); list_listings reports the same figures in minor units (1527). writable on each setter is what that entity accepts, and anything else throws.
| Parameter | Type | Description |
|---|---|---|
stream_type (required) |
string, 1 of 22 event type codes | Event type code, e.g. ANY_OFFER_CHANGED |
account |
string | Account id from connection_status; the contract's webhooks are that account's. Defaults to the first account that can run the event type. |
duplicate_automation
Copy any automation's code into a new draft for the same event type. Works on an active or a draft source. Returns the new id.
| Parameter | Type | Description |
|---|---|---|
automation_id (required) |
string | The automation to copy |
get_ads_summary
Advertising spend and attributed sales per marketplace profile. Money fields are integer minor units of each row's currency (USD cents; JPY whole yen); never sum across rows, the currencies differ. sales is Amazon's 7-day attributed figure, not shipped revenue, and recent days are still maturing (Amazon restates roughly the last 14), so the last days of a window read low and acos high - do not report that as a trend. acos is cost/sales, null when sales is 0. Empty rows mean unsynced data or no activity, never confirmed zero spend; check each row's latest_report_date and freshness.entities_synced_at for staleness, and connection_status for the full profile list. Windows cut on report date (profile-local), default trailing 30 days. Rows carry account_id and account_name, ordered by account then country; pass account to read one.
| Parameter | Type | Description |
|---|---|---|
since |
string | ISO 8601 date; default 30 days before until |
until |
string | ISO 8601 date; default today |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
compare_to_previous |
boolean | Include the immediately preceding window of equal length as previous |
get_automation
One automation in full, including its JavaScript code.
| Parameter | Type | Description |
|---|---|---|
automation_id (required) |
string | The automation's id |
get_event
The full payload (SP-API notification, Amazon Marketing Stream record, or a synthetic row with stream_type: null and synthetic: true: a polled listing-detail read, or Amazon's answer to a listing push Pulsify made) plus identity for one event, by id. Use this after list_events to see exactly what changed, or to replay the event against an automation.
| Parameter | Type | Description |
|---|---|---|
event_id (required) |
string | The event's id |
get_product_type_schema
Get Amazon's full JSON Schema for a product type before writing listing patches or automation mutations. Includes required attributes, allowed values, conditional requirements and nested selectors. schema.properties describes /attributes/; required fields describe a full listing, not every patch. Values are specific to the target seller and marketplace and cached for 24 hours.
| Parameter | Type | Description |
|---|---|---|
product_type (required) |
string | Amazon product type, e.g. LUGGAGE or COFFEE_MAKER |
marketplace_id |
string | Amazon marketplace ID; defaults to the target account's marketplace |
account |
string | Account id from connection_status. Required when more than one account is connected. |
get_sales_summary
Your sales over a date range, one row per marketplace. revenue is in minor units of that row's currency (USD cents; JPY has no subunits, so whole yen) and rows are never summed together - an account spanning several currencies has no single revenue number, and converting is your call, not this tool's. Revenue is confirmed-order revenue: orders that are Shipped, Unshipped, or PartiallyShipped count, unless later Canceled - Amazon reports cancellation the same way whether it happened before or after shipping, so every canceled order is excluded, matched case-insensitively. Pending orders carry no line items and are excluded too. A return or refund after shipping is untracked and still counts as revenue, since no refund data is synced. freshness tells you how much is missing: orders_without_items counts in-window orders with no line items yet, and earliest_order_at and last_order_at mark the boundaries of synced order history. No rows means no confirmed sales in the window, which is not the same as zero sales - check freshness before reporting a number. A response with no freshness at all means the Amazon connection isn't set up; use connection_status for that. When compare_to_previous is set, previous is biased: the current window always holds more orders still Pending or awaiting item backfill than the settled window before it, so a flat month can render as a decline - each block's own orders_without_items lets you size the effect. since and until are ISO 8601 and cover whole days in the marketplace's local time; the default window is the trailing 30 days and the span is capped at 400. Rows carry account_id and account_name, one row per account and marketplace; freshness spans every account in the response. Pass account to read one.
| Parameter | Type | Description |
|---|---|---|
since |
string | ISO 8601 date; window opens at local midnight on this day |
until |
string | ISO 8601 date; window includes all of this local day |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
compare_to_previous |
boolean | Add a previous block for the window just before |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_automation_actions
What your automations have actually done: the changes they applied to your listings and ads. This is history, not a preview (that is run_automation). Most rows are one change to one target; rows with kind "warning" instead report a probable event-shape mismatch (missing_fields lists event keys the code read that the payload lacked). For a Listing or Ad target the row carries its asin, sku, marketplace_id, and title. value is in the marketplace's major currency unit: dollars for USD (list_listings reports cents); JPY has no subunits, so both report whole yen. status is queued, applied, failed, or blocked: withheld and never sent, because the source listing is blocked or the target's campaign has its Automation switch off (the switch also sets error_message). Filter by automation_id, status, or since (ISO8601). Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
automation_id |
string | Only this automation's actions |
status |
string | queued, applied, failed, or blocked |
since |
string | ISO8601 time; only actions at or after it |
limit |
integer | Max actions to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_automations
Your automations, for each Amazon event type. Returns metadata only (id, event type, state, title) plus subscription: active means events are flowing, none means no subscription yet (expected for a draft, not a fault), failed means the subscription errored. Use get_automation for the code. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
stream_type |
string | Filter to one event type code, e.g. ANY_OFFER_CHANGED |
include_archived |
boolean | Include archived automations (default false) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_campaigns
Your ad campaigns with a performance rollup over the window (default trailing 30 days, cut on profile-local report date). Money fields (budget_amount, cost, sales) are integer minor units of the row's currency. asin returns campaigns advertising that ASIN; the rollup stays campaign-level, so treat per-ASIN spend as exact only for single-product campaigns. sales is 7-day attributed and recent days are still maturing. acos is cost/sales, null when sales is 0. A campaign with no metrics in the window shows zeros; zeros everywhere plus a stale freshness block means unsynced data, not zero spend. Pass id to list_keywords as campaign_id to drill in. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
state |
string | enabled, paused, or archived |
name |
string | Case-insensitive substring of the campaign name |
asin |
string | Only campaigns with a product ad for this ASIN |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
since |
string | ISO 8601 date; default 30 days before until |
until |
string | ISO 8601 date; default today |
order_by |
string | cost (default) or sales, descending over the window |
limit |
integer | Max campaigns to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_events
Recent Amazon events (SP-API notifications, Amazon Marketing Stream records, and synthetic rows with stream_type: null and synthetic: true: polled listing-detail reads) for this account, newest first by occurred_at. Each summary names the listing by ASIN, SKU, and title, with associated listings in a listings array. A shared event is counted once; SKU is null when targets have different SKUs. since and until are ISO 8601: a full timestamp is an exact instant, a bare date covers the whole UTC day, and until is exclusive at an instant but inclusive of its named day. total counts every event the filters matched, before limit, so counting questions never need to pull rows. Filter by stream type, exact ASIN or SKU, marketplace, or time; use get_event for a full payload. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
stream_type |
string | Stream type code, e.g. ANY_OFFER_CHANGED |
since |
string | ISO 8601 date or time; a bare date opens at UTC midnight |
until |
string | ISO 8601 date or time; a bare date covers its whole UTC day |
asin |
string | Exact ASIN |
sku |
string | Exact seller SKU |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
limit |
integer | Max events to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_keywords
Your keywords (search targets) with a performance rollup over the window (default trailing 30 days). Default order is cost descending, so rows with high cost and sales 0 at the top are wasted spend. Money fields (bid, cost, sales) are integer minor units of the row's currency. sales is 7-day attributed and recent days are still maturing. acos is cost/sales, null when sales is 0. Filter by campaign_id (the id from list_campaigns), state, or match_type. Empty rows with a stale freshness block mean unsynced data, not zero activity. Keywords only; auto and product targets live in list_targets. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
campaign_id |
string | Only this campaign (id from list_campaigns) |
state |
string | enabled, paused, or archived |
match_type |
string | exact, phrase, or broad |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
since |
string | ISO 8601 date; default 30 days before until |
until |
string | ISO 8601 date; default today |
order_by |
string | cost (default), sales, or clicks, descending |
limit |
integer | Max keywords to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_listings
Your listings, found by keyword, ASIN, or SKU. keyword matches a substring of the title or SKU, or an exact ASIN; asin and sku are exact. A SKU is one listing per marketplace, so a SKU can return several rows: each row is a single (SKU, marketplace) listing that states its currency, with floor, ceiling, and price in minor units of it (USD cents; JPY has no subunits, so values are whole yen). conditionType is Amazon's full condition token; condition is its family. Never generalize a floor or ceiling (or its absence) across marketplaces. price, floor, ceiling, b2b_price, handling_time, restock_date and shipping_group are Amazon's last reading; mutations shows all queued requests and the latest submitted one, with each id, immutable payload, accepted (true, false) and Amazon's raw response, oldest first. Use patch_listing for Amazon attributes and update_listing to block or allow automated changes. status is null until a crawl reports listing status. active is true only when Amazon reports BUYABLE or DISCOVERABLE; it is false while status is unknown. data retains raw Amazon sources: FBA stock under fba.inventory, MFN attributes and availability under listings_item, and the latest stock notification envelopes under notifications. Keys and units are unchanged. since and until window on when the listing was added (ISO 8601; a bare date covers the whole UTC day). Ordering is newest first. total counts every match before limit. Filter by marketplace for EU accounts that span several. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
keyword |
string | Substring of title or SKU, or an exact ASIN |
asin |
string | Exact ASIN |
sku |
string | Exact seller SKU |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
since |
string | ISO 8601 date or time; only listings added at or after it |
until |
string | ISO 8601 date or time; a bare date covers its whole UTC day |
order_by |
string: created_at | created_at for newest first, the only ordering |
limit |
integer | Max listings to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_sales_by_listing
What sold, broken down by listing. One row per (ASIN, SKU, marketplace), so a SKU sold in two marketplaces is two rows in two currencies. revenue is in minor units of that row's currency (USD cents; JPY has no subunits, so whole yen). Revenue is confirmed-order revenue: Shipped, Unshipped, and PartiallyShipped count, unless later Canceled - Amazon reports cancellation the same way whether it happened before or after shipping, so every canceled order is excluded, matched case-insensitively. Pending orders carry no line items and are excluded too. A return or refund after shipping is untracked and still counts as revenue, since no refund data is synced. Ranking by revenue needs marketplace_id when the account spans several currencies, because yen and cents cannot be ordered against each other; order_by units works across all of them. title is null when the listing has since been deleted. freshness.earliest_order_at and freshness.last_order_at mark the boundaries of synced order history, and freshness.orders_without_items is the account-wide count of in-window orders with no line items yet, so an empty rows list can be told apart from an unsynced account. A response with no freshness at all means the Amazon connection isn't set up; use connection_status for that. since and until are ISO 8601 and cover whole days in the marketplace's local time; the default window is the trailing 30 days and the span is capped at 400. Rows carry account_id and account_name; freshness spans every account in the response. Pass account to read one.
| Parameter | Type | Description |
|---|---|---|
since |
string | ISO 8601 date; window opens at local midnight on this day |
until |
string | ISO 8601 date; window includes all of this local day |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
asin |
string | Exact ASIN |
sku |
string | Exact seller SKU |
order_by |
string: revenue, units | revenue (default) or units |
limit |
integer | Max rows to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_streams
Your event subscriptions and whether each is live. status answers 'did the subscription actually happen': active means events are flowing, inactive means not subscribed, and pending means an Amazon Marketing Stream subscription is waiting on Amazon to confirm. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
account |
string | Account id from connection_status. Omit to read across every connected account. |
list_targets
Your Sponsored Products targets of every kind: keywords, auto-targeting buckets (close-match, loose-match, substitutes, complements), and product targets, with a performance rollup over the window (default trailing 30 days). Auto and product targets are where auto campaigns spend; list_keywords shows keywords only. Default order is cost descending, so rows with high cost and sales 0 at the top are wasted spend. Money fields (bid, cost, sales) are integer minor units of the row's currency. sales is 7-day attributed and recent days are still maturing. acos is cost/sales, null when sales is 0. Filter by campaign_id (the id from list_campaigns), state, or target_type (keyword, auto, product, product_category). Empty rows with a stale freshness block mean unsynced data, not zero activity. Rows carry account_id and account_name; pass account to read one account.
| Parameter | Type | Description |
|---|---|---|
campaign_id |
string | Only this campaign (id from list_campaigns) |
state |
string | enabled, paused, or archived |
target_type |
string | keyword, auto, product, or product_category |
marketplace_id |
string | Only this marketplace, e.g. ATVPDKIKX0DER |
since |
string | ISO 8601 date; default 30 days before until |
until |
string | ISO 8601 date; default today |
order_by |
string | cost (default), sales, or clicks, descending |
limit |
integer | Max targets to return (default 20, max 100) |
account |
string | Account id from connection_status. Omit to read across every connected account. |
patch_listing
Queue Amazon JSON Patch operations against one listing's attributes. Any writable attribute of its product type is supported; Amazon validates the attribute names and values. Each request creates its own immutable mutation, preserving the patches and their order. Each patch names op (add, replace, delete or merge), path (/attributes/) and the value required by Amazon's Product Type Definitions. Call get_product_type_schema to look up attribute shapes, allowed values and selectors before patching. Include the attribute's required selectors, such as marketplace_id, currency and audience for purchasable_offer. merge can update a pricing sub-attribute without resending other prices or bounds. product_type defaults to the listing's known product type, or PRODUCT when unknown. The request is queued immediately for a worker; list_listings shows queued mutations and the latest submitted one, with accepted and Amazon's raw response. Listing fields remain Amazon's last reading until a new reading arrives. A SKU in several marketplaces needs marketplace_id. With several connected accounts, account identifies whose listing to change.
| Parameter | Type | Description |
|---|---|---|
account |
string | Account id from connection_status. Required when more than one account is connected. |
sku (required) |
string | Exact seller SKU |
marketplace_id |
string | Required only when the SKU sells in several marketplaces, e.g. ATVPDKIKX0DER |
product_type |
string | Amazon product type; defaults to the listing's known type |
patches (required) |
array of objects | Patch operations against /attributes/<name>, applied in order |
query_data
Run one read-only SQL SELECT over the curated views below and get rows back. Prefer the dedicated
tools for lookups; use this for set questions where a join is the filter (e.g. ASINs with ad
spend but no organic sales). One statement, 3s timeout. The views cover every account you have
connected and expose account_id on every row so you can group or filter by account across connections
(or pass account to scope one call to one account). Results under 500 rows return inline. Larger
results (or queries with export: true) return a downloadable compressed CSV URL with column definitions
and a 5-row preview.
v_sales_lines - one row per order line, confirmed orders only (cancellations excluded; pending
orders carry no lines). Columns: order_id uuid, amazon_order_id text, sold_at timestamptz
(UTC), order_status text, is_business_order boolean, marketplace_id text, currency text, asin
text, sku text, title text (null when the listing is gone), price integer (line total, minor
units), quantity integer, account_id uuid. Seller accounts only.
v_ad_performance - one row per campaign per day. Columns: campaign_id uuid, campaign_name
text, campaign_state text, advertising_profile_id uuid, marketplace_id text, currency text,
report_date date (profile-local), impressions integer, clicks integer, cost integer (minor
units), attributed_sales_7d integer (minor units; 7-day ad-attributed sales, never comparable
to organic revenue), account_id uuid. The most recent ~14 days of report_date read artificially low
while Amazon restates them.
v_advertised_products - one row per product ad. Columns: campaign_id uuid, asin text, sku
text, state text (enabled/paused/archived), advertising_profile_id uuid, marketplace_id text,
account_id uuid. Spend is campaign-level; joining it through this view shares cost across every product
the campaign advertises.
v_listings - one row per SKU per marketplace: sku, asin, marketplace_id, title, account_id.
Presence means the listing record exists, not that it is buyable. Seller accounts only.
v_listing_mutations - one row per listing mutation: sku text, marketplace_id text, account_id uuid,
status text (queued/submitted), payload jsonb, submission_id text, submitted_at timestamptz,
created_at timestamptz. Seller accounts only.
v_catalog_items - one row per ASIN per marketplace: asin text, gtin text (GTIN-14, zero-padded,
null until the catalog sync lands), identifiers jsonb (identifier type to values, e.g. EAN, UPC,
GTIN, ISBN), marketplace_id text, title text, data jsonb (the full raw Amazon catalog payload
including dimensions, bullet points, and classifications), account_id uuid. Accessible to seller
and advertiser accounts.
v_marketplaces - reference data (23 rows): marketplace_id, name, country_code, domain_name,
currency.
v_search_query_performance - Amazon Brand Analytics Search Query Performance, seller accounts
only. One row per ASIN per search query per closed reporting window: report_period is WEEK/MONTH/QUARTER
and start_date/end_date bound that window. Grain matters — summing across periods, or across more
than one window of the same period, double- or triple-counts. Columns: asin text, report_period
text, start_date date, end_date date, search_query text, search_query_score bigint,
search_query_volume bigint, total_query_impression_count bigint, asin_impression_count bigint,
asin_impression_share numeric (0-1), total_click_count bigint, total_click_rate numeric (0-1),
asin_click_count bigint, asin_click_share numeric (0-1), total_median_click_price integer
(minor units), asin_median_click_price integer (minor units), total_cart_add_count bigint,
total_cart_add_rate numeric (0-1), asin_cart_add_count bigint, asin_cart_add_share numeric
(0-1), total_median_cart_add_price integer (minor units), asin_median_cart_add_price integer
(minor units), total_purchase_count bigint, total_purchase_rate numeric (0-1),
asin_purchase_count bigint, asin_purchase_share numeric (0-1), total_median_purchase_price
integer (minor units), asin_median_purchase_price integer (minor units), marketplace_id text,
account_id uuid. total_* columns describe the whole search query across every ASIN Amazon tracks
for it; asin_* columns describe this seller's ASIN specifically. Join v_marketplaces on
marketplace_id for currency.
v_seller_economics - Data Kiosk Seller Economics, seller accounts only. One row per SKU per
day. Columns: sku text, asin text, date date, marketplace_id text, currency text,
ordered_product_sales bigint (minor units), net_product_sales bigint (minor units), referral_fee
bigint, fulfillment_fee bigint, storage_fee bigint, other_fees bigint, total_fees bigint, net_proceeds
bigint, net_proceeds_per_unit bigint, net_units_sold integer, units_ordered integer, units_refunded
integer, account_id uuid. Fees are signed - charges are negative, so net_product_sales + total_fees =
net_proceeds; add, don't subtract. referral_fee + fulfillment_fee + storage_fee + other_fees
always equals total_fees, where other_fees is whatever Amazon charged under a label the three
named columns don't recognise; a named column is null on a day carrying no such fee, and
storage is billed monthly so most days carry none. The most recent ~7 days restate while
Amazon settles them. Grain matters - several SKUs can share an ASIN, so grouping on asin, or
joining to order-line-grain v_sales_lines, double-counts unless this view is aggregated first.
v_vendor_metrics - Data Kiosk vendor analytics, for vendor accounts only. One row per view per
marketplace per day per ASIN, plus a row with a null asin carrying that day's catalog-wide
totals - filter on asin IS NOT NULL unless you want both grains. Columns: marketplace_id text,
view text (manufacturing or sourcing), date date, asin text, currency text, ordered_units
bigint, ordered_revenue bigint (minor units), unfilled_ordered_units bigint, net_ordered_gms
bigint (minor units), net_shipment_gms bigint (minor units), shipped_units bigint,
shipped_revenue bigint (minor units), average_selling_price bigint (minor units), glance_views
bigint, lost_featured_offer numeric, net_ppm numeric, shipped_cogs bigint (minor units),
contra_cogs bigint (minor units), sales_discount bigint (minor units), sell_through_rate
numeric, sellable_on_hand_units bigint, unsellable_on_hand_units bigint,
sellable_in_transit_units bigint, sourceable_roos numeric, open_purchase_order_units bigint,
confirmed_units bigint, net_received_units bigint, received_fill_rate numeric,
vendor_confirmation_rate numeric, overall_vendor_lead_time numeric, account_id uuid. The two
views overlap: manufacturing covers every ASIN the vendor makes, sourcing only those it sells
directly to Amazon, so summing across both double-counts - always filter on view. Orders and
traffic columns are null in the sourcing view, which does not expose them. Inventory and
sourcing columns are end-of-day snapshots captured once, so they carry a value on recent days
only and must never be summed across dates. Data lands two days late; the most recent two days
are empty by design.
Money is integer minor units of the row's currency (JPY: whole yen). Never sum across
currencies; group by marketplace_id or currency instead. Empty results can mean data not yet
synced, not zero sales.
| Parameter | Type | Description |
|---|---|---|
sql (required) |
string | One SQL SELECT statement over the views |
export |
boolean | Optional. When true, exports full dataset as a downloadable CSV URL with preview. |
account |
string | Account id from connection_status. Omit to read across every connected account. |
report_bug
File a bug report with the Pulsify team for something that broke or behaved wrong. Summarize the problem in your own words. Do NOT paste raw event payloads, listing data, or other Amazon business data into the report.
| Parameter | Type | Description |
|---|---|---|
title (required) |
string | Short summary of the bug |
what_happened |
string | What actually happened or failed. Summarize in your own words; no raw payloads or business data. |
expected |
string | What was expected to happen. |
tool_name |
string | Name of the Pulsify tool involved if the bug occurred during a tool call. |
detail |
string | Additional context in your own words. No raw payloads or business data. |
run_automation
Dry-run a saved automation, or JavaScript you pass as code, against a sample or real event and return the changes it would make, plus its console output. Nothing is applied: no webhooks fire and no data is written. Pass automation_id to run a saved automation, or code with stream_type to try JavaScript before saving it. By default it uses a canned sample for the event type. Pass event_id to replay one of your real events, or sample_event to supply your own JSON. Choose listing_id when a real event has multiple listing targets. When fabricating, copy the shape of a real event and set marketplaceId to one of your connected marketplaces; pricing events carry marketplace-specific currency and thresholds. missing_field_reads lists event keys the code read that are absent from the payload, with the keys actually available at that level — a non-empty list usually means the code expects the wrong payload shape.
| Parameter | Type | Description |
|---|---|---|
automation_id |
string | The saved automation to run |
code |
string | JavaScript to run instead of a saved automation; requires stream_type |
stream_type |
string | Event type code the code handles, e.g. FBA_INVENTORY_AVAILABILITY_CHANGES. Only with code. |
event_id |
string | Replay this real event's payload |
listing_id |
string | Listing to replay against; required when an event has multiple listings |
sample_event |
object | A fabricated event payload to run against |
suggest_idea
Suggest a feature or improvement to the Pulsify team. Summarize the idea in your own words. Do NOT paste raw event payloads, listing data, or other Amazon business data into the suggestion.
| Parameter | Type | Description |
|---|---|---|
title (required) |
string | Short summary of the idea |
what_happened |
string | Current limitation, friction, or problem encountered. No raw payloads or business data. |
expected |
string | Desired capability, behavior, or improvement. |
tool_name |
string | Name of the Pulsify tool if this idea relates to a specific tool. |
detail |
string | Additional context in your own words. No raw payloads or business data. |
update_automation
Edit an automation's code or title, and optionally activate it. Activating deactivates any other live automation for the same event type and subscribes the stream. The subscribe call can be slow; on a hiccup the automation is active but the subscription stays pending, visible via list_streams. Use run_automation to dry-run the code before activating; its missing_field_reads catches a wrong payload shape.
| Parameter | Type | Description |
|---|---|---|
automation_id (required) |
string | The automation to update |
code |
string | Replacement JavaScript |
title |
string | New title |
activate |
boolean | Promote this automation to live for its event type |
update_listing
Block or allow automated changes to your listings. true stops Pulsify sending this listing's changes, and its advertising changes, to Amazon; the automation still runs and its request is recorded. false allows them again, without replaying anything blocked earlier. Each row names a sku and blocked. Each row is independent and reports saved. Use patch_listing for all Amazon attribute changes, including prices, bounds and quantity. Listing fields show Amazon's last reading; mutations includes queued requests and the latest submission. A SKU in several marketplaces needs marketplace_id. With several connected accounts, account identifies whose listings to change.
| Parameter | Type | Description |
|---|---|---|
account |
string | Account id from connection_status. Required when more than one account is connected. |
updates (required) |
array of objects | One entry per listing to change |
Event types
Each automation handles 1 event type. describe_stream_type returns the full contract for any of them,
with a complete sample payload. Context names the shape of context, described
below.
SP-API notifications
These need a selling connection. Envelopes are PascalCase (NotificationType, EventTime,
Payload) except PRICING_HEALTH, ACCOUNT_STATUS_CHANGED, FEED_PROCESSING_FINISHED, ITEM_SALES_EVENT_CHANGE, DETAIL_PAGE_TRAFFIC_EVENT, which use
camelCase (notificationType, eventTime, payload).
| Type | Fires when | Context | Subscribed |
|---|---|---|---|
ANY_ |
Changes to the top 20 offers, Buy Box, or external prices for items you sell | Listing | While an automation needs it |
B2B_ |
B2B offer changes for items you sell, including quantity discount pricing | Listing | While an automation needs it |
PRICING_ |
Your offer loses Buy Box eligibility due to uncompetitive pricing | Listing | While an automation needs it |
LISTINGS_ |
Listing status changes, including buyability transitions and suppressions | Listing | Always |
LISTINGS_ |
Listing issues are created, fixed, or updated | Listing | Always |
LISTINGS_ |
Available quantity changes for MFN listings from orders, inventory updates, or cancellations | Listing | Always |
DATA_ |
DataKiosk query has finished processing with results ready to download | None: handled internally | Always |
ORDER_ |
Order created, updated, or cancelled, enabling order-driven automations | Listing | Always |
FBA_ |
FBA stock level changes across all marketplaces in a region | Listing | Always |
ACCOUNT_ |
Seller account health transitions (NORMAL, AT_RISK, DEACTIVATED) | Selling partner | Always |
FEED_ |
Feed submissions reach a terminal state (DONE, CANCELLED, FATAL) | Selling partner | Always |
FBA_ |
FBA outbound shipments transition to a notable lifecycle state (e.g. Shipped, Cancelled) | Selling partner | Always |
FULFILLMENT_ |
Multi-Channel Fulfillment orders transition between lifecycle states (e.g. Received, Processing, Complete, Cancelled) | Selling partner | Always |
ITEM_ |
Hourly ordered units and revenue per ASIN. Requires Brand Analytics. | Selling partner | Always |
DETAIL_ |
Hourly detail page glance views per ASIN. Requires Brand Analytics. | Selling partner | Always |
BRANDED_ |
Detail page content changes (title, bullets, description, images) for brand-owned ASINs. Brand protection and listing hijack detection. | Listing | Always |
REPORT_ |
A report has finished processing and is ready to download | None: handled internally | Always |
Amazon Marketing Stream
These need an advertising connection. event is the Marketing Stream message, and its keys differ by
dataset.
| Type | Fires when | Context | Subscribed |
|---|---|---|---|
BUDGET_ |
A campaign or portfolio budget consumption crosses a 5% increment, in near real time | Campaign or portfolio | While an automation needs it |
SP_ |
Hourly Sponsored Products impressions, clicks, and spend per campaign, ad group, ad, and keyword | Hourly metrics | While an automation needs it |
SP_ |
Hourly Sponsored Products attributed conversions and sales per campaign, ad group, ad, and keyword | Hourly metrics | While an automation needs it |
CAMPAIGN_ |
A campaign is created or changes (state, name, budget), in near real time | Entity change | While an automation needs it |
AD_ |
An ad group is created or changes (state, name, default bid), in near real time | Entity change | While an automation needs it |
AD_ |
An ad is created or changes (state), in near real time | Entity change | While an automation needs it |
TARGET_ |
A keyword or product target is created or changes (state, bid), in near real time | Entity change | While an automation needs it |
The handler
An automation is JavaScript that defines handle(event, context) with exactly 2 parameters. Saving checks
the syntax and that signature. Saving never runs the code.
function handle(event, context) {
// Read event and context, decide, then queue changes:
// context.mutations.push({ ... });
return context;
}
The return value is ignored. After handle returns, Pulsify reads context.mutations. The
templates return context by convention.
event is the payload exactly as Amazon sent it, with no flattened fields.
A live event carries only the fields that changed. This fixture is complete.
Reading a key the payload doesn't have is recorded. run_automation returns those reads as
missing_field_reads. When a live run changes nothing and read a top-level key the payload lacks, Pulsify
records a warning action, at most 1 a day per automation.
Projected currency values on context are in major units (15.27). Raw listing.data retains Amazon's units and types. The list_listings tool reports the same figures in minor units (1527). Never mix them. Some advertising amounts arrive as decimal strings rather than numbers; each says so, and they need parseFloat before arithmetic.
Context by scope
The shape of context depends on what the event is about. Every context also carries
mutations, webhooks and store.
Listing
Event types: ANY_OFFER_CHANGED, B2B_ANY_OFFER_CHANGED, PRICING_HEALTH, LISTINGS_ITEM_STATUS_CHANGE, LISTINGS_ITEM_ISSUES_CHANGE, LISTINGS_ITEM_MFN_QUANTITY_CHANGE, ORDER_CHANGE, FBA_INVENTORY_AVAILABILITY_CHANGES, BRANDED_ITEM_CONTENT_CHANGE.
| Field | Type | Notes |
|---|---|---|
listing |
object | |
listing. |
array | |
listing. |
number | Distinct ASINs advertised in the ad group. |
listing. |
string or null, major units | Decimal string rather than a number ("0.75"). parseFloat before comparing. |
listing. |
string or null | |
listing. |
object | |
listing. |
number or null | cost / sales over the trailing 30 days. Null when sales is zero. |
listing. |
number | |
listing. |
number, major units | Spend over the trailing 30 days. |
listing. |
number | |
listing. |
number or null | sales / cost over the trailing 30 days. Null when cost is zero. |
listing. |
number, major units | Attributed sales over the trailing 30 days. |
listing. |
string or null | |
listing. |
string or null | |
listing. |
array | |
listing. |
string or null | |
listing. |
string or null | |
listing. |
string or null | |
listing. |
string or null | |
listing. |
string | |
listing. |
number or null, major units | Null when the listing has no B2B offer. |
listing. |
number | Trailing 30 days, rolled up eagerly. Always a number: zero rather than absent with no B2B sales. |
listing. |
boolean | |
listing. |
boolean or null | Null while statuses is null. Do not read a null as false. |
listing. |
array | |
listing. |
number | Distinct ASINs advertised in the campaign, not just this listing's. |
listing. |
string or null, major units | Daily budget in major units, and a decimal string rather than a number ("50.0"). parseFloat before comparing. |
listing. |
string or null | |
listing. |
object | |
listing. |
number or null | cost / sales over the trailing 30 days. Null when sales is zero. |
listing. |
number | |
listing. |
number, major units | Spend over the trailing 30 days. |
listing. |
number | |
listing. |
number or null | sales / cost over the trailing 30 days. Null when cost is zero. |
listing. |
number, major units | Attributed sales over the trailing 30 days. |
listing. |
string or null | |
listing. |
string or null | |
listing. |
string or null | |
listing. |
number or null, major units | Upper price bound as Amazon last reported it. Null when unset. Same lifecycle as floor. |
listing. |
string or null | Family of conditionType: new, used, collectible, refurbished or club. Null until Amazon reports it. |
listing. |
string or null | Amazon's full condition token, such as used_very_good. Null until the listing item reports it. |
listing. |
object | Raw Amazon source snapshots, with original keys and units. Contents vary with the sources received; missing sources are absent. FBA report stock is under data.fba.inventory (afn-fulfillable-quantity, afn-inbound-shipped-quantity, etc.). Submitted MFN stock is under data.listings_item.attributes.fulfillment_availability; observed availability is under data.listings_item.fulfillmentAvailability. data.notifications holds the latest accepted envelope of each type, including EventTime. Notifications do not overwrite report or crawl snapshots. Choose the source and stock measure your automation needs. |
listing. |
boolean or null | Null while statuses is null. Do not read a null as false. |
listing. |
boolean or null | Null while statuses is null. Do not read a null as false. |
listing. |
object or null | FBA inventory and planning report data, camelCased from Amazon's hyphenated report columns. Null for MFN listings. Keys vary by report, so treat anything below it as optional. |
listing. |
object | Unit counts per age bucket, as decimal strings. |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
object | Quantities arrive as decimal strings, not numbers. parseInt before arithmetic. |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
object | Restock planning figures, as decimal strings. |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
string | |
listing. |
object or null | Fulfillment-centre report data. Null when no report has landed. Keys vary by report. |
listing. |
object | |
listing. |
string | |
listing. |
number | |
listing. |
number or null, major units | Lower price bound as Amazon last reported it. Null when unset. A bound you set goes to Amazon and shows here once Amazon's next reading reflects it; until then list_listings lists it under mutations. |
listing. |
string | Either "Amazon" (FBA) or "Merchant" (MFN). Never null. |
listing. |
number or null | Business days from order to ship (Amazon's lead_time_to_ship_max_days). Null when the SKU uses the account's default handling time. Writable on listings you fulfil yourself. A write queues only the requested handling time; it does not resend observed stock. |
listing. |
string | |
listing. |
array | |
listing. |
string or null, major units | Decimal string rather than a number ("0.85"). parseFloat before comparing. |
listing. |
string or null | |
listing. |
string or null | |
listing. |
object | |
listing. |
number or null | cost / sales over the trailing 30 days. Null when sales is zero. |
listing. |
number | |
listing. |
number, major units | Spend over the trailing 30 days. |
listing. |
number | |
listing. |
number or null | sales / cost over the trailing 30 days. Null when cost is zero. |
listing. |
number, major units | Attributed sales over the trailing 30 days. |
listing. |
string or null | |
listing. |
string or null | The keyword expression. Named text here and expression in the Ads API. |
listing. |
array | Recent mutations for the listing: all queued requests and the latest submission. Use status === "queued" to check for in-flight changes. |
listing. |
boolean | Whether Amazon accepted the request for processing; false when rejected. |
listing. |
string | |
listing. |
string | |
listing. |
object | |
listing. |
object | |
listing. |
string | "queued" (awaiting submission) or "submitted" (Amazon response recorded). |
listing. |
string | Amazon's submissionId for the patch that carried this mutation. |
listing. |
string | ISO 8601 timestamp when Amazon's response was recorded. |
listing. |
number or null, major units | Major units (15.27). list_listings reports the same figure as 1527. |
listing. |
string or null | YYYY-MM-DD the listing is back in stock. Null when unset. Writable on listings you fulfil yourself. |
listing. |
number or null, major units | Zero when Amazon fulfils. On a listing you fulfil, null until an offer event carries your own offer; Pulsify no longer polls for it. |
listing. |
string or null | Merchant shipping template id, not its display name. Null until Amazon reports one; FBA listings have none. Writable on listings you fulfil yourself. |
listing. |
array or null | Null until Amazon first reports listing status. Null means unknown, not empty. buyable, discoverable and deleted derive from it and are null alongside it. |
listing. |
string | One of "BUYABLE", "DISCOVERABLE", "DELETED". |
marketplace |
object | |
marketplace. |
string | The listing's marketplace, e.g. "ATVPDKIKX0DER". Matches the MarketplaceId Amazon sends on region-wide events, so use it to pick the entry for this listing rather than reading marketplace id out of raw listing data. |
marketplace. |
string | IANA zone for the listing's marketplace. Use it for any hour-of-day logic. |
mutations |
array | Mutation outbox array, drained by the runtime after handle returns. Name the target with the object the context gave you: context.listing, or an entry from listing.campaigns, listing.adGroups, listing.keywords or listing.ads. A listing write carries a non-empty patches array of native Amazon operations; flat fields such as price, floor and quantity are not accepted, and update_listing is what blocks or allows automated changes. An ads write carries action "pause" or "resume", or names an allowlisted attribute directly: state and budget on a campaign, state and defaultBid on an ad group, state on an ad, state and bid on a keyword. Automations on advertising events queue campaign writes only; the ad group, ad and keyword attributes apply on selling events. |
store |
object | |
webhooks |
object | One entry per enabled webhook on the account, keyed by name. Call webhooks.<name>.post(payload); a string payload is wrapped as { text: ... }. Empty when the account has none. |
store. |
function | Removes a key immediately. |
store. |
function | Per-automation key/value store. Returns null for a missing key. Values expire after 1 day. |
store. |
function | Persists a JSON-serializable value under a key for 1 day. |
Selling partner
Event types: ACCOUNT_STATUS_CHANGED, FEED_PROCESSING_FINISHED, FBA_OUTBOUND_SHIPMENT_STATUS, FULFILLMENT_ORDER_STATUS, ITEM_SALES_EVENT_CHANGE, DETAIL_PAGE_TRAFFIC_EVENT.
| Field | Type | Notes |
|---|---|---|
mutations |
array | Mutation outbox array, drained by the runtime after handle returns. Name the target with the object the context gave you: context.listing, or an entry from listing.campaigns, listing.adGroups, listing.keywords or listing.ads. A listing write carries a non-empty patches array of native Amazon operations; flat fields such as price, floor and quantity are not accepted, and update_listing is what blocks or allows automated changes. An ads write carries action "pause" or "resume", or names an allowlisted attribute directly: state and budget on a campaign, state and defaultBid on an ad group, state on an ad, state and bid on a keyword. Automations on advertising events queue campaign writes only; the ad group, ad and keyword attributes apply on selling events. |
selling_ |
object | |
selling_ |
string | |
selling_ |
string | snake_case, as above. |
selling_ |
string | snake_case, unlike every other context key. Historic, and renaming it would break live automations. |
store |
object | |
webhooks |
object | One entry per enabled webhook on the account, keyed by name. Call webhooks.<name>.post(payload); a string payload is wrapped as { text: ... }. Empty when the account has none. |
store. |
function | Removes a key immediately. |
store. |
function | Per-automation key/value store. Returns null for a missing key. Values expire after 1 day. |
store. |
function | Persists a JSON-serializable value under a key for 1 day. |
Campaign or portfolio
Event types: BUDGET_USAGE.
| Field | Type | Notes |
|---|---|---|
budget |
object | |
budget. |
number, major units | The budget figure carried by the firing event, not the campaign's current budget. Null outside budget-usage events. |
budget. |
string | Which half of the context you were handed: "CAMPAIGN" means context.campaign is present, "PORTFOLIO" means context.portfolio is present. Null outside budget-usage events. |
budget. |
string | ISO 8601 event time. Null outside budget-usage events. |
budget. |
number | Percentage of budget consumed, 0-100. Amazon emits one per 5% increment. Null outside budget-usage events. |
campaign |
object | Campaign events only. |
campaign. |
string | Campaign events only. |
campaign. |
number, major units | Campaign events only. Daily budget in major units. A number on budget-usage events and a decimal string on entity-change events. parseFloat handles both. |
campaign. |
number | Campaign events only. |
campaign. |
string | Campaign events only. Pulsify's own id. Null when the changed campaign has not been synced yet. |
campaign. |
string | Campaign events only. |
campaign. |
string | Campaign events only. |
campaign. |
string | Campaign events only. |
hourlyConversions |
array | Campaign events only. |
hourlyConversions[]. |
number | Campaign events only. |
hourlyConversions[]. |
string | Campaign events only. |
hourlyConversions[]. |
number, major units | Campaign events only. |
hourlyConversions[]. |
number | Campaign events only. |
hourlyTraffic |
array | Campaign events only. |
hourlyTraffic[]. |
number | Campaign events only. |
hourlyTraffic[]. |
number, major units | Campaign events only. |
hourlyTraffic[]. |
string | Campaign events only. |
hourlyTraffic[]. |
number | Campaign events only. |
mutations |
array | Mutation outbox array, drained by the runtime after handle returns. Name the target with the object the context gave you: context.listing, or an entry from listing.campaigns, listing.adGroups, listing.keywords or listing.ads. A listing write carries a non-empty patches array of native Amazon operations; flat fields such as price, floor and quantity are not accepted, and update_listing is what blocks or allows automated changes. An ads write carries action "pause" or "resume", or names an allowlisted attribute directly: state and budget on a campaign, state and defaultBid on an ad group, state on an ad, state and bid on a keyword. Automations on advertising events queue campaign writes only; the ad group, ad and keyword attributes apply on selling events. |
portfolio |
object | Portfolio events only. Present instead of context.campaign when a portfolio budget crosses an increment. Check budget.scopeType, or the presence of this object, before reading context.campaign. |
portfolio. |
number, major units | Portfolio events only. The portfolio's own budget cap, not the figure from the firing event. That one is budget.amount. Null when the portfolio has no cap set. |
portfolio. |
string or null | Portfolio events only. Date the budget window closes, ISO 8601. Null for an open-ended recurring budget, which is the common case, and null when the portfolio has no budget at all. |
portfolio. |
string | Portfolio events only. How Amazon renews the cap, e.g. "MONTHLY_RECURRING" or "DATE_RANGE". Null when the portfolio has no budget. |
portfolio. |
string | Portfolio events only. Date the budget window opens, ISO 8601 (2026-06-01). Null when the portfolio has no budget. |
portfolio. |
string | Portfolio events only. |
portfolio. |
boolean | Portfolio events only. Whether Amazon still considers the portfolio within its budget. Always a boolean, never null. |
portfolio. |
string | Portfolio events only. |
portfolio. |
number | Portfolio events only. |
portfolio. |
string | Portfolio events only. |
store |
object | |
webhooks |
object | One entry per enabled webhook on the account, keyed by name. Call webhooks.<name>.post(payload); a string payload is wrapped as { text: ... }. Empty when the account has none. |
store. |
function | Removes a key immediately. |
store. |
function | Per-automation key/value store. Returns null for a missing key. Values expire after 1 day. |
store. |
function | Persists a JSON-serializable value under a key for 1 day. |
Hourly metrics
Event types: SP_TRAFFIC, SP_CONVERSION.
| Field | Type | Notes |
|---|---|---|
budget |
object | |
budget. |
number or null, major units | The budget figure carried by the firing event, not the campaign's current budget. Null outside budget-usage events. |
budget. |
string or null | Which half of the context you were handed: "CAMPAIGN" means context.campaign is present, "PORTFOLIO" means context.portfolio is present. Null outside budget-usage events. |
budget. |
string or null | ISO 8601 event time. Null outside budget-usage events. |
budget. |
number or null | Percentage of budget consumed, 0-100. Amazon emits one per 5% increment. Null outside budget-usage events. |
campaign |
object | |
campaign. |
string | |
campaign. |
string, major units | Daily budget in major units. A number on budget-usage events and a decimal string on entity-change events. parseFloat handles both. |
campaign. |
number | |
campaign. |
string or null | Pulsify's own id. Null when the changed campaign has not been synced yet. |
campaign. |
string | |
campaign. |
string | |
campaign. |
string | |
hourlyConversions |
array | |
hourlyTraffic |
array | |
metrics |
object | One hour of Sponsored Products performance for one campaign. Traffic feeds carry impressions, clicks and cost; conversion feeds carry conversions, sales and unitsOrdered. Read defensively: which keys are present depends on the stream type. |
metrics. |
number | |
metrics. |
number, major units | Spend for the hour. Traffic feeds only. |
metrics. |
string | Which feed produced it: "sp-traffic" or "sp-conversion". |
metrics. |
string | The hour this summary covers, ISO 8601. Not the time it was delivered. |
metrics. |
number | |
metrics. |
number | How many raw feed rows were rolled up into this summary. |
mutations |
array | Mutation outbox array, drained by the runtime after handle returns. Name the target with the object the context gave you: context.listing, or an entry from listing.campaigns, listing.adGroups, listing.keywords or listing.ads. A listing write carries a non-empty patches array of native Amazon operations; flat fields such as price, floor and quantity are not accepted, and update_listing is what blocks or allows automated changes. An ads write carries action "pause" or "resume", or names an allowlisted attribute directly: state and budget on a campaign, state and defaultBid on an ad group, state on an ad, state and bid on a keyword. Automations on advertising events queue campaign writes only; the ad group, ad and keyword attributes apply on selling events. |
store |
object | |
webhooks |
object | One entry per enabled webhook on the account, keyed by name. Call webhooks.<name>.post(payload); a string payload is wrapped as { text: ... }. Empty when the account has none. |
store. |
function | Removes a key immediately. |
store. |
function | Per-automation key/value store. Returns null for a missing key. Values expire after 1 day. |
store. |
function | Persists a JSON-serializable value under a key for 1 day. |
Entity change
Event types: CAMPAIGN_CHANGE, AD_GROUP_CHANGE, AD_CHANGE, TARGET_CHANGE.
| Field | Type | Notes |
|---|---|---|
budget |
object | |
budget. |
number or null, major units | The budget figure carried by the firing event, not the campaign's current budget. Null outside budget-usage events. |
budget. |
string or null | Which half of the context you were handed: "CAMPAIGN" means context.campaign is present, "PORTFOLIO" means context.portfolio is present. Null outside budget-usage events. |
budget. |
string or null | ISO 8601 event time. Null outside budget-usage events. |
budget. |
number or null | Percentage of budget consumed, 0-100. Amazon emits one per 5% increment. Null outside budget-usage events. |
campaign |
object | |
campaign. |
string | |
campaign. |
string, major units | Daily budget in major units. A number on budget-usage events and a decimal string on entity-change events. parseFloat handles both. |
campaign. |
number | |
campaign. |
string or null | Pulsify's own id. Null when the changed campaign has not been synced yet. |
campaign. |
string | |
campaign. |
string | |
campaign. |
string | |
change |
object | The raw entity-change payload as Amazon sent it, camelCase and unmodified. Keys differ per stream type, so read defensively. |
change. |
string | |
change. |
string | |
change. |
object | |
change. |
number, major units | The campaign's new daily budget. |
change. |
string | |
change. |
string | |
change. |
string | snake_case, as Amazon sends it. |
change. |
string | |
change. |
string | |
change. |
string | |
change. |
string | |
change. |
string | |
hourlyConversions |
array | |
hourlyTraffic |
array | |
mutations |
array | Mutation outbox array, drained by the runtime after handle returns. Name the target with the object the context gave you: context.listing, or an entry from listing.campaigns, listing.adGroups, listing.keywords or listing.ads. A listing write carries a non-empty patches array of native Amazon operations; flat fields such as price, floor and quantity are not accepted, and update_listing is what blocks or allows automated changes. An ads write carries action "pause" or "resume", or names an allowlisted attribute directly: state and budget on a campaign, state and defaultBid on an ad group, state on an ad, state and bid on a keyword. Automations on advertising events queue campaign writes only; the ad group, ad and keyword attributes apply on selling events. |
store |
object | |
webhooks |
object | One entry per enabled webhook on the account, keyed by name. Call webhooks.<name>.post(payload); a string payload is wrapped as { text: ... }. Empty when the account has none. |
store. |
function | Removes a key immediately. |
store. |
function | Per-automation key/value store. Returns null for a missing key. Values expire after 1 day. |
store. |
function | Persists a JSON-serializable value under a key for 1 day. |
Mutations
Push objects onto context.mutations. Pulsify drains it after handle returns. Name the target
with the object the context gave you: context.listing, an entry from one of its advertising arrays, or
context.campaign.
Listing patches
context.mutations.push({
target: context.listing,
patches: [{
op: "replace",
path: "/attributes/purchasable_offer",
value: [{ our_price: [{ schedule: [{ value_with_tax: 19.99 }] }] }],
}],
});
Illustrative: a real price patch also carries the marketplace and audience selectors your listing uses. Ask
get_product_type_schema for an attribute's shape.
-
patchesis a non-empty array of Amazon's own patch operations, as the Listings Items API takes them. Flat fields such aspriceorquantityare rejected. -
productTypeis optional. It defaults to the listing's product type, thenPRODUCT. - A run can patch only the listing it was built for.
-
Each push becomes its own request on the listing's ledger, repeats included. Pulsify submits them 1 at a time and
records Amazon's answer:
accepted, asubmission_idand the raw response. - An accepted request means Amazon took it for processing. The listing's readings change only when Amazon's next report shows the new value.
Advertising changes
context.mutations.push({ target: campaign, action: "pause" });
context.mutations.push({ target: campaign, budget: 25 });
| Target | Where the script finds it | Attributes it can set |
|---|---|---|
| Campaign | listing.campaigns[], context.campaign |
state, budget |
| AdGroup | listing.adGroups[] |
state, defaultBid |
| Ad | listing.ads[] |
state |
| Keyword | listing.keywords[] |
state, bid |
action: "pause" sets state: "paused", action: "resume" sets state: "enabled".
- Automations on advertising events change campaigns only. Ad group, ad and keyword changes come from automations on selling events, through the listing's arrays.
-
A target must belong to your Pulsify user. Anything else is dropped without a record, and so is a campaign whose
idis null because Pulsify hasn't synced it yet. -
Each change becomes an automation action:
queued, thenappliedwhen Amazon accepts it,failedwith anerror_messagewhen Amazon refuses it, orblockedwhen the listing the run came from is blocked or the campaign it touches has its Automation switch off. Throttling and server errors retry. -
Pulsify's copy of a campaign updates on the next entity-change event or the daily Ads sync, so
listing.campaigns[].statecan lag behind a change Amazon has applied.
Store and console
context.store keeps small JSON values between runs of 1 automation. Values expire
1 day after they're written. Dry runs get an empty store of their own, so they never
read or change the live one.
const last = context.store.get("last-price");
context.store.set("last-price", 19.99);
context.store.delete("last-price");
console.log, .warn, .error and .info write to 1 buffer per run.
run_automation returns it as logs. Live runs don't keep their logs.
Webhooks
Add a webhook under Settings with a name, a URL and optional headers. The name must be a valid JavaScript identifier, because scripts call it by name:
context.webhooks.alerts?.post({ text: "Stock hit zero on " + context.listing.asin });
The ?. keeps the script working when no enabled webhook has that name. Dry runs never post.
-
Pulsify sends a JSON POST with your headers and an
X-Pulsify-Delivery-Idheader. A string payload becomes{ "text": ... }. A webhook of type Slack always sends Slack'stextshape. -
Delivery is asynchronous. Timeouts, network errors,
429and5xxretry with backoff, up to 5 attempts. Other4xxresponses don't retry. - The delivery id stays the same across retries of 1 delivery. If Pulsify reruns the automation after a failed run, that run posts again with a new id, so make your endpoint tolerate repeats.
- Each enabled webhook has a Send test button in Settings. Activity lists every delivery with its status and response.
Errors
Tools answer a known problem with an error code and, where it helps, a detail. Saving
invalid JavaScript is the exception: create_automation and update_automation answer with a
generic internal error that doesn't say why. Dry-run new code with run_automation first; it returns the
syntax error.
Accounts
account_required |
More than 1 account is connected and the tool writes. Pass account. |
account_not_found |
No connected account has that id. detail lists the ones that do. |
not_connected |
The account has no selling connection. |
owner_not_connected |
The connection that runs this event type isn't authorized: selling for SP-API types, advertising for Marketing Stream types. |
stream_type_not_for_entity |
A seller event type on a Vendor Central account. |
Input
invalid |
A value failed validation. detail says which and why. |
unknown_argument |
The tool doesn't take that argument. |
invalid_window |
since or until can't be read, or the range is out of bounds. |
unknown_stream_type |
No event type has that code. |
code_too_large |
The JavaScript is over the size limit. |
event_too_large |
The fabricated event is over the size limit. |
marketplace_required |
Ordering by revenue across currencies. Pass marketplace_id. |
listing_not_found |
No listing on the account has that SKU. |
ambiguous_sku |
The SKU exists in several marketplaces. Pass marketplace_id. |
no_updates, too_many_updates, no_fields |
update_listing got no rows, too many rows, or a row with nothing to change. |
Load
rate_limited |
Too many dry runs, activations or reports in the window. Wait and retry. |
throttled |
Too many query_data calls in the window. |
busy |
Another call of the same kind is still running. Retry shortly. |
Automations and dry runs
automation_not_found |
No automation on your accounts has that id. |
activation_conflict |
Another automation for the same event type was activated at the same moment. Check which is live. |
automation_or_code_required |
Pass automation_id or code. |
ambiguous_target |
Pass automation_id or code, not both. |
stream_type_required |
Inline code needs a stream_type. |
event_not_found |
No event on your accounts has that id. Events expire after 1 month. |
stream_type_mismatch |
The event is a different type from the automation. |
listing_required |
The event reached several listings. Pass listing_id. |
event_not_replayable |
That listing didn't receive the event, or no context can be built for it. |
execution_error |
The JavaScript threw, timed out or ran out of memory. message has the error. |
Listings and Amazon
blocked |
Automated changes are blocked for this listing. Allow them with update_listing. |
conflict |
The listing changed while update_listing was saving. Retry. |
amazon_error, schema_unavailable |
Amazon couldn't return the product type definition. Retry shortly. |
not_found |
Amazon has no definition for that product type and marketplace. |
query_data
missing_sql |
Pass a sql statement. |
timeout |
The statement ran past its time limit. Narrow it. |
query_failed |
PostgreSQL rejected the statement. detail has its message when it's safe to share. |
unavailable |
The query service isn't reachable. Retry later. |
Limits
| Run time | 5 seconds per run |
| Memory | 64 MB per run |
| Console output | 100 lines of up to 2000 bytes per run |
| Code size | 100,000 bytes |
| Fabricated event size | 100,000 bytes |
| Dry runs | 30 per 60 seconds, 1 at a time |
| Activations | 20 per 60 seconds |
| Store values | Expire 1 day after they're written |
| Webhook delivery | 10 second timeout, 5 attempts, the first 10 KB of each response kept |
| query_data | 3 second statement timeout, 500 rows inline, 300 queries per 3600 seconds |
| List tools | 20 rows by default, up to 100 |
| update_listing | 50 rows per call |
| report_bug and suggest_idea | 20 each per day |
Automation code has no network or file access. Use a webhook to reach your own systems.
Retention
| Record | Kept for | Counted |
|---|---|---|
| Events and their deliveries | 1 month | From receipt |
| MCP tool calls | 1 month | From the call |
| Webhook deliveries | 30 days | From the attempt |
| Listing requests and Amazon's answers | 30 days | From submission. Queued requests aren't pruned by age; blocked ones go 30 days after the block |
| Hourly Marketing Stream metrics | 35 days | From the hour they describe |
| Automation actions | 1 year | From the decision |
| Automation code versions | 1 year | From the edit |
| Store values | 1 day | From the write |
| Raw Amazon data for an inactive seller or advertiser | 30 days | From the day it goes inactive |
Daily sales, traffic and economics, daily advertising metrics, vendor and search query metrics, and order history are kept. When Amazon reports a listing as deleted, Pulsify removes it with its requests the next night. Its sales history stays.