Agentic Sellar
OpenAPI JSON →

API Reference

v1.0.0 · Every platform capability is available over REST — the dashboard is just another client. AI agents should start from the machine-readable OpenAPI document.

Agent quickstart

  1. Create an account (POST /api/auth/signup) or have a human sign in once.
  2. Mint an API key: POST /api/organizations/{orgId}/api-keys — the raw as_… token is returned exactly once.
  3. Authenticate every call with Authorization: Bearer as_….
  4. The two Amazon OAuth consents (/api/amazon/ads/connect, /api/amazon/sp/connect) need a human in the browser — hand the URL off, everything else is programmatic.
  5. Drive the loop: trigger syncs, read /performance and /actions/pending, approve via /actions/bulk-approve, measure with /outcomes.
curl https://agenticsellar.com/api/organizations/$ORG_ID/actions/pending \
  -H "Authorization: Bearer $API_KEY"

System

GET/api/healthPublic

Liveness and dependency check

GET/api/openapi.jsonPublic

This API description as an OpenAPI 3.1 document

Agents should load this first to discover available operations.

Auth

POST/api/auth/signupPublic

Create an account and organization

Body: email: string (required) · password: string (required, min 12 chars with complexity) · name: string · organizationName: string
GET/api/auth/accept-invitePublic

Validate a team invite token

Query: token — Invite token
POST/api/auth/accept-invitePublic

Accept an invite and create the member account

Body: token: string (required) · name: string · password: string (required)

API keys

GET/api/organizations/{orgId}/api-keysAPI key / session

List API keys (prefix + metadata only)

POST/api/organizations/{orgId}/api-keysAPI key / session

Mint a new API key — the raw token is returned once

Body: name: string (required, ≤80 chars) · expiresInDays: number 1-365 (optional)
Bootstrap: create the first key while logged into the dashboard, or via session cookie.
DELETE/api/organizations/{orgId}/api-keys/{keyId}API key / session

Revoke an API key immediately

Amazon connections

GET/api/amazon/ads/connectAPI key / session

Start the Amazon Ads OAuth flow (browser redirect)

Query: region — na | eu | fe (default na) · next — Internal path to return to after OAuth
Browser flow — an agent should hand this URL to a human for consent.
GET/api/amazon/sp/connectAPI key / session

Start the Selling Partner API OAuth flow (browser redirect)

Query: region — na | eu | fe (default na) · next — Internal path to return to after OAuth
Browser flow — requires Seller Central login + consent.
GET/api/amazon/ads/pending-profilesOAuth session cookies

List advertising profiles available to the pending OAuth grant

POST/api/amazon/ads/selectOAuth session cookies

Bind selected advertising profiles; triggers the 93-day backfill

Body: profileIds: string[] (required)
GET/api/organizations/{orgId}/credentials/amazonAPI key / session

List connected Amazon profiles and their connection status

DELETE/api/organizations/{orgId}/credentials/amazon/{credentialId}API key / session

Disconnect one Amazon profile binding

GET/api/organizations/{orgId}/ads-profilesAPI key / session

List every profile the stored Ads token can access

PATCH/api/organizations/{orgId}/ads-profilesAPI key / session

Switch the bound advertising profile

Body: profileId: string (required)

LLM

GET/api/organizations/{orgId}/credentials/llmAPI key / session

Get active LLM provider metadata (never the key)

POST/api/organizations/{orgId}/credentials/llmAPI key / session

Store the org's LLM API key (BYOLLM)

Body: provider: anthropic | openai | google · apiKey: string (required)

Agent

GET/api/organizations/{orgId}/agent/configAPI key / session

Get agent goals, tier, guardrails, and kill-switch state

PUT/api/organizations/{orgId}/agent/configAPI key / session

Update agent configuration (partial)

Body: goalMode: balanced | growth | profitability · targetAcos: string decimal e.g. '0.3' · targetTacos: string decimal (optional) · maxDailyAutoExecutes: string int · maxBidChangePct: string decimal · isActive: 'true' | 'false' · isPaused: 'true' | 'false' (kill switch) · notifyWebhookUrl: string (optional) · notifyEmail: string (optional)
GET/api/organizations/{orgId}/agent/permissionsAPI key / session

List per-category action permission levels

PUT/api/organizations/{orgId}/agent/permissionsAPI key / session

Set the permission level for one action category

Body: actionCategory: bid_adjustment | keyword_addition | keyword_negation | campaign_creation | campaign_pause | budget_change | placement_change · permissionLevel: auto_execute | require_approval | blocked

Actions

GET/api/organizations/{orgId}/actions/pendingAPI key / session

List actions waiting for approval

POST/api/organizations/{orgId}/actions/{actionId}/approveAPI key / session

Approve and synchronously execute one action against Amazon

Stays pending if Amazon execution fails — safe to retry.
POST/api/organizations/{orgId}/actions/{actionId}/rejectAPI key / session

Reject a pending action

POST/api/organizations/{orgId}/actions/bulk-approveAPI key / session

Approve and execute up to 100 actions; per-action results

Body: actionIds: string[] (required, ≤100)
POST/api/organizations/{orgId}/negationsAPI key / session

Queue negative-keyword proposals for a wasted search term

Body: { searchTerm, from, to, marketplace?, profile?, matchType? ('exact' default | 'phrase') }. Never writes to Amazon directly: resolves every (campaign, ad group) placement where the term spent with ZERO attributed orders in the window and inserts one pending keyword_negation action per placement into the audit-log approval queue — same pipeline, executor, and audit trail as agent-proposed actions. Approval (POST /actions/{actionId}/approve) creates the ad-group-level negative on Amazon. Dedup: placements already covered by an existing negative (ad-group or campaign level) or an already-pending proposal are skipped and counted. Capped at 25 placements per request.

Data

GET/api/organizations/{orgId}/exploreAPI key / session

Unified data explorer — commercial and advertising levels

Query: level — Aggregation level: brand | family | product | productCampaign (requires asin) | campaign (API default) | adGroup | target | searchTerm. Commercial levels return the /products response shape and accept its sort keys, focus, brand, and parentAsin filters; profile is advertising-only. adGroup/target aggregate keyword-attributed metrics, so SB/SD contribute only at campaign level. · focus — Commercial levels: comma-separated child ASINs · brand — Commercial levels: filter by brand · parentAsin — Commercial levels: filter by parent ASIN · from — Start date YYYY-MM-DD (default 30 days ago) · to — End date YYYY-MM-DD (default today) · profile — Scope to one Amazon Ads profile ID · mkt — Scope to one marketplace ID, e.g. ATVPDKIKX0DER · type — sponsoredProducts | sponsoredBrands | sponsoredDisplay · state — enabled | paused | archived · q — Substring match on the level's label · campaignId — Drill scope: Amazon campaign ID · asin — Product scope: restrict every level to the campaigns advertising this ASIN (resolved via the ad-group↔ASIN mapping). The account plane (total/organic/TACoS) is omitted under this scope — order metrics cannot be product-scoped. · adGroupId — Drill scope: Amazon ad group ID · keywordId — Drill scope: Amazon keyword/target ID · noSales — true → only rows with zero orders (wasted spend) · minSpend — Only rows with at least this much spend · sort — Ad levels: name|impressions|clicks|spend|sales|orders|acos (default -spend). Commercial levels: netSales|organicSales|units|adSpend|adSales|acos|tacos|netProceeds|totalSales|refunds|grossProfit|netProfit|asin (default -netSales). Prefix - for descending. · limit — 0-500 (default 100); 0 returns summary only · offset — Pagination offset
Same grammar as the dashboard explorer's URL (/dashboard/explore?…) — any UI view is reconstructable via this endpoint and vice versa. Metric definitions: ACoS = spend/sales; ROAS = sales/spend; TACoS = spend ÷ total account sales (order metrics, account-level denominator); organicSales = total sales − ad-attributed sales. All IDs are Amazon-native. noSales/minSpend filter rows only; summary always reflects the full filtered scope. summary.wastedSpend/wastedTerms = total spend and count of (term × marketplace) window aggregates with zero attributed orders — the same rows level=searchTerm&noSales=true lists, so the headline and its drill-down reconcile; recent days can still attribute and leave the bucket. Level extras: campaign rows carry topOfSearchImpressionShare (SP only, 0-1 fraction, impressions-weighted over the window; null for SB/SD). searchTerm rows carry impressionShare and impressionRank from the Ads V1 impression-share plane — the term's ACCOUNT-WIDE share of impressions vs all advertisers (0-1, impressions-weighted) and the best (minimum) rank in the window; both null until that plane has synced. They are account-per-marketplace metrics, not campaign-scoped — Amazon's search-term IS metrics don't break down by campaign.
GET/api/organizations/{orgId}/objects/{objectType}/{objectId}/activityAPI key / session

Glass-box timeline: agent actions + measured outcomes for one object

Query: limit — Max 200 (default 50)
objectType: campaign | keyword. objectId accepts the Amazon-native ID (preferred) or internal UUID. Campaign timelines include actions on the campaign's keywords. Each item carries the change (from→to), the agent's reasoning, approval status, and the 14-day pre/post outcome once attribution has run.
GET/api/organizations/{orgId}/productsAPI key / session

Per-ASIN subject tree — ad spend/sales/ACoS, plus sales, TACoS, profit, margin

Query: from — Start date YYYY-MM-DD (default 30 days ago) · to — End date YYYY-MM-DD (default today) · mkt — Scope to one marketplace ID · group — child (default, one row per ASIN) | parent (roll up by parent ASIN) · sort — adSpend|adSales|acos|netSales|totalSales|refunds|grossProfit|netProfit|units|tacos|netProceeds|asin; prefix - for desc (default -adSpend) · limit — 1-500 (default 200) · asin — Drilldown: when set, returns the campaigns advertising this ASIN (per-ASIN-in-campaign spend/sales/ACoS/clicks/orders/CPC) as data.rows, instead of the product list.
Same grammar as the /dashboard Explore page. Ad columns (adSpend, adSales, acos, adOrders, adUnits, impressions, clicks, ctr, cvr, cpc) come from the Amazon Ads advertised-product report and are live as soon as Ads is connected — adsAvailable=true. Commercial columns come from SP-API Data Kiosk Economics — economicsAvailable=false until the Selling Partner Insights role supplies data. P&L stack per row and in summary: totalSales (gross, pre-refund) | refunds/refundedUnits | netSales (post-refund) | amazonFees (FeeSummary total) | grossProfit = netSales − amazonFees − cogs | grossMargin | netProfit = grossProfit − adSpend | netMargin | roi = netProfit ÷ cogs | asp = totalSales ÷ units | velocity = units/day | ppcShare = adUnits ÷ units (true ad-attributed units from the advertised-product reports: SP unitsSoldClicks7d + SD unitsSold, capped at 1). ACoS = ad spend ÷ ad sales; TACoS = ad spend ÷ total sales. summary.adSpend is the per-ASIN-attributed total (advertised-product reports); summary.unattributedAdSpend is the honest remainder — campaign-level spend across all ad types (same scope/window/FX) minus that attributed total. It is structural (Sponsored Brands has no per-ASIN report, so SB spend can never attribute to a product) plus report-restatement drift, and can be slightly negative when Amazon restates the per-ASIN report ahead of the campaign one; attributed + unattributed always reconciles to the campaign total. Traffic columns (sessions, pageViews, unitSessionPct = units ÷ sessions) come from SP-API Data Kiosk Sales & Traffic (Selling Partner Insights role) — null until traffic rows exist for the ASIN. summary.adsCoverageFrom / summary.economicsCoverageFrom are each plane's earliest data date in scope (null = never synced) — suppress period-over-period comparisons whose PRIOR window reaches before them, or the partial prior period fabricates growth. rows[].inventory (null until FBA inventory has synced) is point-in-time, not windowed: latest snapshot per SKU aggregated to the ASIN — fulfillable/inbound quantities summed, daysOfSupply = MIN across SKUs/marketplaces (Amazon's planning estimate, most urgent), Amazon's alert/recommendedShipInQty, estStorageNextMonth (an ESTIMATE, FX-converted, never an actual charge), agedUnits181Plus, and asOf (newest snapshot date). Parent/brand rollups sum quantities and take the MIN daysOfSupply. Pass ?asin=<ASIN> for the campaign drilldown.
GET/api/organizations/{orgId}/payoutsAPI key / session

Settlement summaries, newest first — the cash that actually landed

Query: limit — Max settlements returned (default 12, cap 50)
Each row is one closed settlement: settlementId, startDate, endDate, depositDate (null until Amazon stamps it), totalAmount, currency, marketplace. Amounts stay in the settlement's OWN currency — payouts are region-wide disbursements and the bank deposit is in that currency, so no FX conversion is applied. Only closed settlements exist (Amazon exposes no open-settlement running total); estimate the next close from the account's own cadence between end dates.
GET/api/organizations/{orgId}/feesAPI key / session

Fee line items — the granular breakdown behind the Profit number

Query: from — Start date YYYY-MM-DD (default 30 days ago) · to — End date YYYY-MM-DD (default today) · mkt — Scope to one marketplace ID · asin — Product mode: this ASIN's Amazon fee components (Data Kiosk FeeSummary), one line per fee type. Omit for account mode.
Account mode adds account-level charges from the Finances-API cost ledger (subscription, storage, AGL freight/duty, removals — grains Amazon never attributes to a product; order/SKU-grain fees are excluded to avoid double-counting the per-product fees) and seller-entered indirect expenses booked in the window. Fee-plane semantics: ledger fee families are TAX-INCLUSIVE and bucketed by POSTED date; economics (Data Kiosk) fees are ORDER-date bucketed and tax-split — so family-level comparisons between the two planes are only meaningful at weekly+ granularity (day-level drift is posting lag, not a bug), and order/SKU-grain ledger fees must NEVER be added into account mode (same money as the product-attributed economics fees — double-count). Mixed-currency scopes convert to the org display currency. Payouts are settlement summaries — actual Amazon disbursements whose deposit date (or period end) falls in the window, converted from the settlement's own currency. Informational: not part of the fee waterfall (the fees above already explain where the money went), and region-wide (never scoped by mkt).
GET/api/organizations/{orgId}/costsAPI key / session

Product COGS rows — per-unit cost elements with effective-date periods

Query: asin — Scope to one ASIN
POST/api/organizations/{orgId}/costsAPI key / session

Bulk-upsert product COGS rows (the CSV-import path)

Body: rows: array of { asin, element (unit_cost|packaging|supplier_shipping|inbound_freight|other), amountPerUnit, currency, effectiveFrom, effectiveTo?, marketplace?, note? }
Upserts by (asin, marketplace, element, effectiveFrom) — re-importing a sheet is idempotent; a new effectiveFrom starts a new price period. COGS is date-weighted into Explore's Profit/Margin (marketplace-specific rows win over all-marketplace rows).
DELETE/api/organizations/{orgId}/costsAPI key / session

Delete one product COGS row

Query: id — Cost row id
GET/api/organizations/{orgId}/expensesAPI key / session

Indirect expenses — seller-entered costs Amazon doesn't know about

POST/api/organizations/{orgId}/expensesAPI key / session

Create or update (with body.id) an indirect expense

Body: name: string (required) · amount: positive number (required) · currency: ISO code (required) · recurrence: one_time (default) | monthly | yearly · startDate: YYYY-MM-DD (required; one_time: the date, recurring: first occurrence) · endDate: YYYY-MM-DD | null (recurring: last occurrence date) · marketplace: marketplace ID | null (null = account-wide) · asin: ASIN | null · category: free-form label | null · countAsAdvertising: boolean — reclass into advertising in P&L groupings · id: expense id (update instead of create)
Occurrences book in full on their date (monthly bills clamp short months, e.g. Jan 31 → Feb 28). Expenses surface in /fees account mode.
DELETE/api/organizations/{orgId}/expensesAPI key / session

Delete one indirect expense

Query: id — Expense id
GET/api/organizations/{orgId}/campaignsAPI key / session

List synced campaigns (SP, SB, and SD)

Query: profileId — Filter to one advertising profile
GET/api/organizations/{orgId}/campaigns/{campaignId}API key / session

Campaign drill-down: series, summary, top keywords

Query: days — Lookback 1-90 (default 30)
campaignId accepts the Amazon campaign ID (preferred) or internal UUID.
GET/api/organizations/{orgId}/performanceAPI key / session

Org-wide daily performance series + summary

Query: days — Lookback 1-90 (default 30) · profileId — Filter to one advertising profile
GET/api/organizations/{orgId}/outcomesAPI key / session

Agent impact: measured 14-day pre/post action outcomes

GET/api/organizations/{orgId}/audit-logAPI key / session

List audit log entries (every agent decision + execution)

Query: limit — Max 200 (default 50)
GET/api/organizations/{orgId}/audit-log/exportAPI key / session

CSV export of the full audit log

GET/api/organizations/{orgId}/exportAPI key / session

GDPR/CCPA full data export (JSON)

Explore

GET/api/organizations/{orgId}/campaigns/{campaignId}/productsAPI key / session

Products a campaign advertises — the inverse of /explore?asin=

Query: from — Start date YYYY-MM-DD (default 30 days ago) · to — End date YYYY-MM-DD (default today)
campaignId is the Amazon-native campaign id (same as /explore rows). Each product carries asin/title/image plus its spend/sales inside the campaign for the window (SP/SD, per-ASIN report). SB creative ASINs list with null spend/sales — SB attribution is campaign-level.

Organization

GET/api/organizations/{orgId}API key / session

Org profile + preferences (reporting currency, plan)

displayCurrency null = auto (currency of the largest connected marketplace). Combined-marketplace money in /explore, /kpi and /products is converted into this currency at daily ECB rates.
PATCH/api/organizations/{orgId}API key / session

Update org preferences — currently displayCurrency

Body: { displayCurrency: string | null }. Null = auto. Must be one of the supported ECB-covered currencies; unsupported codes 400.
GET/api/organizations/{orgId}/invitesAPI key / session

List team invites

POST/api/organizations/{orgId}/invitesAPI key / session

Invite a teammate (owner only)

Body: email: string (required) · orgRole: operator | viewer
DELETE/api/organizations/{orgId}API key / session

GDPR deletion: nuke credentials now, cascade after 30 days

Query: confirm — Must be 'yes-i-am-sure'

Sync

GET/api/organizations/{orgId}/syncAPI key / session

List data sync jobs and their status

POST/api/organizations/{orgId}/syncAPI key / session

Trigger a manual sync (campaigns, performance, search terms, order metrics)

Body: profileId: string (preferred) · marketplace: string (legacy fallback) · syncTypes: string[] of campaigns | campaign_performance | search_terms (default all three) · startDate: YYYY-MM-DD (default 14d ago) · endDate: YYYY-MM-DD (default today)
Returns 202 with Inngest event ids; poll GET /sync for completion.

Billing

POST/api/billing/checkoutAPI key / session

Create a Stripe Checkout session

Body: priceId: Stripe price id
POST/api/billing/portalAPI key / session

Create a Stripe customer portal session

Notes: admin endpoints (/api/admin/*) require a staff session and are not listed. Webhook receivers (Stripe, Inngest) authenticate by signature. Rate limits are per-organization; 429 responses include Retry-After.