Skip to main content

Marketplace advertising API

The Ads API connects spend, channel-attributed sales, campaign settings, and suggested actions across a brand's advertising accounts. Read a brand and sale-channel pair to see where money is going; open its campaigns to understand the drivers; use metrics and items for the time and product views.

A saleChannelId identifies the marketplace and region for grouping, filters, and writes. The saleChannel.console value identifies the advertising console and its rules; it is not an account identifier. The same console name can appear in more than one region. Use advertising coverage to find the channels represented in Ads and whether each has item-level reporting.

Work through an advertising cycle​

  1. Select a brand and channel. Read coverage and identify the intended saleChannelId. Use performance to find its brand × channel pair and its expectationState. A pair marked PausedIntentional or PhasingOut has a different operating decision from one marked Running; do not treat every low-spend pair as a failure.
  2. Choose the campaign and its objective. Read campaigns for that pair. Check family, objective, status, budgetType, settings, and the channel's existing campaigns before creating or editing one. Use ROAS and the pair's floor for conversion spend. Use nativeSuccessMetric for a non-conversion objective instead of assigning it a ROAS target.
  3. Create or change a campaign. Choose the product SKUs, budget, dates, and settings that the selected family and channel support. Send create, or update an existing campaign using only supported writable fields. Read the returned campaign and its status; a write response is not proof that the ad is delivering or has generated attributed sales.
  4. Measure a comparable window. Read metrics for the same brand, channel, and dates. Separate settledKpis from the full-window kpis; compare the settled portion with previousKpis. Use campaign items only where coverage reports item-level data, and preserve null traffic values as unavailable.
  5. Review recommendations and verify edits. Read suggestions, inspect their evidence and every planned edit, then apply only selected edits. Check appliedEditIds[], read the affected campaigns again, and compare later settled metrics. A suggestion with no planned edits is guidance, not a campaign write.

Keep brand and channel filters consistent across performance, campaigns, and metrics. pairs[] and campaigns[] are different grains: a pair aggregates a brand on one sale channel, while a campaign is one advertising configuration within that pair.

Choose the right read​

QuestionOperationWhat comes back
Which brand and channel pairs need attention?List advertising performancepairs[] with spend, attributed sales, conversion ROAS, below-floor share, expectation state, and campaign counts; totals across the full filtered set.
Which campaigns contributed?List campaignscampaigns[] with family, objective, status, budget, settings, and window metrics; statusCounts over the current non-status filters.
How did a window change?Get advertising metricskpis, settledKpis, previousKpis, totalSales, and ordered trend points[].
Which advertised products contributed?List campaign itemsProduct-level spend, attributed sales, and available item-grain traffic for one campaign.
Is item reporting available?Get coveragechannels[] with a saleChannel and itemGrain flag.

For example, request a September window and one brand. Replace the brand ID with one available to your key.

curl -fsS --get "https://backend.nasam.co/v1/ads/performance" \
-H "key: $NASAM_API_KEY" \
-H "Accept: application/json" \
--data-urlencode "startDate=2026-09-01" \
--data-urlencode "endDate=2026-09-30" \
--data-urlencode "brandIds=20" \
--data-urlencode "sort=spend" \
--data-urlencode "dir=desc" \
--data-urlencode "page=1" \
--data-urlencode "limit=25"

pairs[] is paginated when a pagination object is returned; totals still describes the full filtered set. Read floor (a ROAS multiple) and clientTarget separately on each pair. belowFloorShare is a share from 0 to 1, weighted by spend. Pair-level settledRoas blends conversion-campaign spend only and can be null when there is no applicable conversion spend. Use expectationState to distinguish Running, PausedIntentional, PhasingOut, and Unset when interpreting a pair.

For triage, use belowFloorShare to see how much spend is below the floor, then open the pair's campaigns to locate the contributing configurations. A high belowFloorShare does not identify a single bad campaign by itself. floor is the internal operating threshold and clientTarget is the agreed target; they can differ, so label each separately in reports.

Interpret campaign and trend metrics​

attributedSales uses the advertising console's attribution. It is not the same as all order sales or settled profitability. directAttributedSales is the stricter lens — sales of the advertised item itself — and is null where the channel reports one lens. totalSales in metrics is all store sales for the same scope and window, including sales that were not ad-attributed. Money values are in SAR.

settledRoas is a multiple and applies to conversion objectives; it is null for a non-conversion objective or zero spend. Awareness and impression-share campaigns can instead report nativeSuccessMetric. Campaign views, clicks, orders, atc, and item-grain traffic may be null when the channel does not report that metric at that grain; atc (add-to-cart) is null on Amazon Sponsored Products and Trendyol, and the KPI atc is null when no campaign in scope reports it. Null means unavailable, not zero. ecpc is spend divided by clicks and can be null without clicks. ctr and cvr in the KPI response are percentage values: 2.09 means 2.09%, not 209%.

Trend points are in ascending order. Windows longer than 60 days use weekly buckets; shorter windows use daily points. A point's isSettled tells you whether to treat its sales as final. To compare periods, use settledKpis for the settled portion of the requested window against previousKpis for the preceding equal-length, fully settled window. Campaign lastCapturedAt gives the captured-through date for that row. The coverage response describes reporting availability; it has no per-channel capture timestamp.

When a recent point has isSettled: false, avoid calling a lower attributed-sales figure a decline. Use the settled comparison first, and show the full-window KPI as a running view. If settledRoas or nativeSuccessMetric is null, inspect the objective, spend, and reporting coverage before drawing a performance conclusion.

The query below selects two channels and live or paused campaigns. Array filters use comma-separated values. The filter value Live selects campaigns whose returned status is Delivering.

curl -fsS --get "https://backend.nasam.co/v1/ads/campaigns" \
-H "key: $NASAM_API_KEY" \
-H "Accept: application/json" \
--data-urlencode "brandIds=20" \
--data-urlencode "saleChannelIds=12,13" \
--data-urlencode "statuses=Live,Paused" \
--data-urlencode "adTypes=Product" \
--data-urlencode "page=1" \
--data-urlencode "limit=25"

Campaign family is SponsoredProduct, SponsoredBrand, or SponsoredDisplay. objective is Conversion, PageVisits, ImpressionShare, NewCustomers, or Awareness; costModel is CPC, VCPM, CPS, or Fixed. A CPS campaign is charged a share of each sale (settings.costPerSalePct) and carries no bid. The campaign operation lists the allowed filters. Its statusCounts reflect the current brand, channel, date, type, targeting, and search filters before the statuses filter is applied.

Create and update campaigns​

Create a campaign with its name, brand, numeric sale-channel ID, family, budget type and amount, and start date. targeting, objective, endDate, itemSkus, and settings depend on the campaign family and channel. Use a SKU belonging to the selected brand and a channel that supports the selected family. The example shows the request shape for an automatically targeted Sponsored Product campaign; replace its identifiers, SKU, and date with your own.

curl -fsS -X POST "https://backend.nasam.co/v1/ads/campaigns" \
-H "key: $NASAM_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{
"name": "Sponsored products — January",
"brandId": 20,
"saleChannelId": 12,
"family": "SponsoredProduct",
"targeting": "Auto",
"budgetType": "Daily",
"budgetAmount": 100,
"startDate": "2027-01-05",
"itemSkus": ["SKU-1001"]
}'

Update a campaign with a partial body containing supported fields: name, budgetAmount, budgetType, status, endDate, or settings. The writable status values are Live and Paused. The returned campaign can still use other lifecycle statuses, including Scheduled, Draft, PendingApproval, Rejected, OutOfBudget, OutOfFunds, OutOfStock, and Ended. Settings such as bids, placement boosts, creative, or targeting clauses vary by family; send only fields supported for that campaign.

The returned status determines the next check: Delivering means the campaign is running; PendingApproval calls for another status read after review; Rejected calls for correction of the campaign's approval issue; OutOfBudget calls for a budget decision; OutOfFunds calls for funding the advertiser account, since a higher campaign budget changes nothing; OutOfStock clears when the advertised stock is replenished; Scheduled starts on its start date; and Ended is no longer running. Paused can be intentional. Do not send any status other than Live or Paused; the update request accepts only those two.

curl -fsS -X PATCH "https://backend.nasam.co/v1/ads/campaigns/CAMPAIGN_ID" \
-H "key: $NASAM_API_KEY" \
-H "Content-Type: application/json" \
--data '{"budgetAmount":120,"status":"Live"}'

Review suggestions before applying edits​

List suggestions for a brand or channel to receive evidence, a suggested action, its source note, an estimated stakeSarPerWeek when available, and plannedEdits[]. Each edit identifies a campaign, its current and suggested display values, and a kind of Update or ExcludeItem. An Update can carry a campaign patch in update; an ExcludeItem can carry an excludeSku. An empty plannedEdits[] means the suggestion is guidance only.

To act on a suggestion, choose the edit objects you approve from its returned plannedEdits[] and apply them at POST /v1/ads/suggestions/{id}/apply. The JSON body has the same suggestionId as the path's suggestion and an edits array containing the selected edit objects. The response reports appliedEditIds[]. Review the returned edit targets and values before sending a write; do not synthesize edit IDs or patches.

This example builds the write body from a returned suggestion, using the SUGGESTION_ID and EDIT_ID you selected after reviewing its evidence and planned changes:

curl -fsS --get "https://backend.nasam.co/v1/ads/suggestions" \
-H "key: $NASAM_API_KEY" \
-H "Accept: application/json" \
--data-urlencode "brandIds=20" > suggestions.json

jq -e --arg suggestionId "$SUGGESTION_ID" --arg editId "$EDIT_ID" \
'.suggestions[] | select(.id == $suggestionId) |
{suggestionId: .id, edits: [.plannedEdits[] | select(.id == $editId)]} |
select(.edits | length > 0)' suggestions.json > apply.json

Inspect apply.json to confirm the edit and target campaign. Then send it:

curl -fsS -X POST \
"https://backend.nasam.co/v1/ads/suggestions/$SUGGESTION_ID/apply" \
-H "key: $NASAM_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data-binary @apply.json

Advertising health and ad balance​

Advertising health cells accept comma-separated brandIds and return one cell per brand with band, offendingFactEn, offendingFactAr, and bandEnteredAt. These are a separate Ads resource from the nine-dimension Brand Health response. There is no advertising field in that nine-dimension object.

curl -fsS --get "https://backend.nasam.co/v1/ads/brand-health-cells" \
-H "key: $NASAM_API_KEY" \
-H "Accept: application/json" \
--data-urlencode "brandIds=20,21"

For a brand and sale-channel pair on noon or Trendyol, read its ad balance for usableBalance, allocated, and currency. usableBalance is what a new campaign or a budget raise can draw on. On Trendyol, allocated is money already committed to running campaigns, so ads keep running while usableBalance is 0. The response is JSON null on Amazon, which bills a payment method instead of a balance; it is not a zero balance. The operation is a read; it does not add funds.