Endpoints

Brands

A brand is everything Dessert knows about your products: your hero images, ingredients, tone of voice, color palette, and product catalog. You need at least one Active brand before you can generate ads.

One brand per account today In v1 each account is tied to a single brand. Multi-brand orgs are on the roadmap. The brand_id field accepts only your own brand for now.

List brands

GET https://api.dessert.dev/v1/brands Try it →

Returns the brands attached to your account and their onboarding status.

Request

curl
Python
TypeScript
MCP
curl https://api.dessert.dev/v1/brands \
  -H "Authorization: Bearer $DESSERT_API_KEY"
requests.get(
    "https://api.dessert.dev/v1/brands",
    headers={"Authorization": f"Bearer {os.environ['DESSERT_API_KEY']}"},
).json()
await fetch("https://api.dessert.dev/v1/brands", {
  headers: { Authorization: `Bearer ${process.env.DESSERT_API_KEY}` },
}).then(r => r.json());
{ "tool": "dessert.list_brands", "arguments": {} }

Response

FieldDescription
brand_idstringPass to brand_id on POST /v1/ads/generate.
namestringDisplay name.
websitestringOriginal brand URL submitted during onboarding.
ready_for_adsboolean The one field your code should branch on. true = you can call POST /v1/ads/generate right now; false = wait, poll back later.
status_messagestringPlain-English summary of where the brand is (e.g., "Brand ready", "In progress: Scraping products 12/25").
api_access_statusstringOne of Active, Pending Onboarding, Suspended, Trial.
onboarding_status_detailstringRaw pipeline stage if onboarding is still running.
product_countintegerNumber of products currently active on the brand.
total_products_scrapedintegerTotal scraped so far (may exceed active count if some failed validation).
onboarded_atstringISO 8601 timestamp the brand became Active.
list_products_urlstringConvenience link to GET /v1/products.
{
  "brands": [
    {
      "brand_id": "recXXXXXXXXXXXXXX",
      "name": "Aurelia Skincare",
      "website": "https://aureliaskincare.com",
      "ready_for_ads": true,
      "status_message": "Brand ready. You can call /v1/ads/generate.",
      "api_access_status": "Active",
      "onboarding_status_detail": "✅ Full Onboarding Complete",
      "product_count": 7,
      "total_products_scraped": 7,
      "onboarded_at": "2026-05-12T15:08:22.000Z",
      "list_products_url": "https://api.dessert.dev/v1/products"
    }
  ]
}

Create a brand (cold-start ingest)

POST https://api.dessert.dev/v1/brands Try it →

Kicks off the brand scrape pipeline against your website. The endpoint returns 202 Accepted immediately; the actual ingest runs in the background for 15–60 minutes. You'll get a webhook/email when the brand is Active.

This is a one-time onboarding action Calling POST /v1/brands on an account that already has a brand re-runs the scrape against the new URL — useful after a site relaunch, not for adding additional brands.

Request body

FieldDescription
websitestringrequiredPublic homepage URL. Must start with http:// or https://.
curl
Python
TypeScript
MCP
curl https://api.dessert.dev/v1/brands \
  -H "Authorization: Bearer $DESSERT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "website": "https://aureliaskincare.com" }'
requests.post(
    "https://api.dessert.dev/v1/brands",
    headers={"Authorization": f"Bearer {os.environ['DESSERT_API_KEY']}"},
    json={"website": "https://aureliaskincare.com"},
).json()
await fetch("https://api.dessert.dev/v1/brands", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DESSERT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ website: "https://aureliaskincare.com" }),
});
{
  "tool": "dessert.create_brand",
  "arguments": { "website": "https://aureliaskincare.com" }
}

Response — 202 Accepted

{
  "brand_id": "recXXXXXXXXXXXXXX",
  "status": "Pending Onboarding",
  "message": "Brand scrape started. You will receive an email when ready (typically 15-60 minutes).",
  "estimated_completion_minutes": 60
}

While the brand is Pending Onboarding, calls to POST /v1/ads/generate return 425 brand_onboarding_in_progress. Poll GET /v1/brands until status flips to "Active".

Errors

StatusCodeCause
400invalid_websiteMissing or malformed URL.
502scraper_failedThe brand scraper upstream rejected the request. Safe to retry.