Ulta Beauty API: Search products
Searches Ulta Beauty products by keyword, brand, USD price range and sort order, and returns each product with its starting prices.
Unofficial. Not affiliated with or endorsed by Ulta Beauty.
Inputs
Values from the run on Oct 23, 2026, shown under Output.
- Sort optional
sort Product order, for example best_sellers.
top_rated
One of
best_match,best_sellers,top_rated,newest,price_low_to_high,price_high_to_low. Defaultbest_match.- Brand optional
brand Brand name to filter by, for example Batiste.
Not set
- Query, required
query Product search words, for example dry shampoo.
mascara
- Max Price optional
max_price Maximum price in USD, for example 20.
Not set
Number 0 or more.
- Min Price optional
min_price Minimum price in USD, for example 10.
Not set
Number 0 or more.
- Max Results optional
max_results Maximum products to return, for example 24 (up to 96).
70
Whole number from 1 to 96. Default
24.
Input as JSON
{ "sort": "top_rated", "query": "mascara", "max_results": 70}Output
{ "products": [ { "sku": "77010530", "brand": "Izzy Zero Waste Beauty", "price": 55, "currency": "USD", "image_link": "https://media.ultainc.com/i/ulta/77010530" , "sale_price": null, "star_rating": 5, "product_link": "https://www.ulta.com/p/izzys-best-seller-duo-mkt77006751?sku=77010530" , "product_name": "Izzy's Best Seller Duo", "review_count": 5, "price_as_shown": null, "ulta_product_id": "mkt77006751" }, { "sku": "77010550", "brand": "Izzy Zero Waste Beauty", "price": 27.95, "currency": "USD", "image_link": "https://media.ultainc.com/i/ulta/77010550" , "sale_price": null, "star_rating": 5, "product_link": "https://www.ulta.com/p/izzy-zero-waste-mascara-mkt77006763?sku=77010550" , "product_name": "Izzy Zero Waste Mascara", "review_count": 16, "price_as_shown": null, "ulta_product_id": "mkt77006763" }, { "sku": "77010566", "brand": "Izzy Zero Waste Beauty", "price": 55, "currency": "USD", "image_link": "https://media.ultainc.com/i/ulta/77010566" , "sale_price": null, "star_rating": 5, "product_link": "https://www.ulta.com/p/izzys-zero-waste-beauty-essentials-mkt77006778?sku=77010566" , "product_name": "Izzy's Zero Waste Beauty Essentials", "review_count": 1, "price_as_shown": null, "ulta_product_id": "mkt77006778" } ]}Code
curl https://api.fous.com/v1/runs \ -H "Authorization: Bearer $FOUS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"method":"ulta.com/search_products","input":{"sort":"top_rated","query":"mascara","max_results":70}}' # Save as fous.py, then run: python3 fous.pyimport json, os, timefrom urllib.error import HTTPErrorfrom urllib.request import Request, urlopenAPI = "https://api.fous.com/v1/runs" KEY = os.environ["FOUS_API_KEY"]HEADERS = { "Authorization": f"Bearer {KEY}", "Content-Type": "application/json" ,}def call(url, body=None): data = json.dumps(body).encode() if body else None request = Request(url, data, HEADERS) try: with urlopen(request, timeout=120) as r: return r.status, json.load(r) except HTTPError as error: message = json.load(error)["error"]["message"] raise RuntimeError(message) from errorstatus, run = call(API, { "method": "ulta.com/search_products" , "input": { "sort": "top_rated", "query": "mascara", "max_results": 70 }})# 202: still going after 30 s. Ask again until it ends.while status == 202: time.sleep(2) status, run = call(f"{API}/{run['id']}")print(json.dumps(run["data"], indent=2))// Save as fous.mjs, then run: node fous.mjsconst api = "https://api.fous.com/v1/runs" ;const headers = { Authorization: `Bearer ${process.env.FOUS_API_KEY}`, "Content-Type": "application/json" ,};let response = await fetch(api, { method: "POST", headers, body: JSON.stringify({ "method": "ulta.com/search_products" , "input": { "sort": "top_rated", "query": "mascara", "max_results": 70 } }), signal: AbortSignal.timeout(120_000),});let run = await response.json();// 202: still going after 30 s. Ask again until it ends.while (response.status === 202) { await new Promise((done) => setTimeout(done, 2_000)); response = await fetch(`${api}/${run.id}`, { headers }); run = await response.json();}if (!response.ok) throw new Error(run.error.message);console.log(run.data);# Connect your agent to Fous once, over MCP (Streamable HTTP):# https://api.fous.com/mcp# Set FOUS_API_KEY first: create a key at https://app.fous.com/keys.# Claude Codeclaude mcp add \ --scope user \ --transport http fous https://api.fous.com/mcp \ --header "Authorization: Bearer ${FOUS_API_KEY:?Set FOUS_API_KEY to your Fous API key}"# Codexcodex mcp add fous \ --url https://api.fous.com/mcp \ --bearer-token-env-var FOUS_API_KEY# Cursor, VS Code, Windsurf, Cline and morenpx -y add-mcp https://api.fous.com/mcp -g -n fous \ --header "Authorization: Bearer ${FOUS_API_KEY:?Set FOUS_API_KEY to your Fous API key}"# Then ask your agent:# "Use Fous to run ulta.com/search_products# with {"sort":"top_rated","query":"mascara","max_results":70}"Over HTTP, the answer’s data holds the output. A run still going after 30 seconds answers 202 with its id: ask GET /v1/runs/{id} until it ends.
Schema
Input schema
{ "type": "object", "required": [ "query" ], "properties": { "sort": { "enum": [ "best_match", "best_sellers", "top_rated", "newest", "price_low_to_high", "price_high_to_low" ], "type": "string", "default": "best_match", "description": "Product order, for example best_sellers." }, "brand": { "type": "string", "description": "Brand name to filter by, for example Batiste." }, "query": { "type": "string", "minLength": 1, "description": "Product search words, for example dry shampoo." }, "max_price": { "type": "number", "minimum": 0, "description": "Maximum price in USD, for example 20." }, "min_price": { "type": "number", "minimum": 0, "description": "Minimum price in USD, for example 10." }, "max_results": { "type": "integer", "default": 24, "maximum": 96, "minimum": 1, "description": "Maximum products to return, for example 24 (up to 96).", "x-fous-developer": true } }}Output schema
{ "type": "object", "required": [ "products" ], "properties": { "products": { "type": "array", "items": { "type": "object", "required": [ "product_name", "brand", "price", "currency", "sale_price", "price_as_shown", "star_rating", "review_count", "image_link", "product_link", "ulta_product_id", "sku" ], "properties": { "sku": { "type": [ "string", "null" ], "x-fous-developer": true }, "brand": { "type": [ "string", "null" ] }, "price": { "type": [ "number", "null" ], "description": "Starting regular price in USD." }, "currency": { "type": "string" }, "image_link": { "type": [ "string", "null" ] }, "sale_price": { "type": [ "number", "null" ], "description": "Starting sale price in USD, if on sale." }, "star_rating": { "type": [ "number", "null" ] }, "product_link": { "type": "string" }, "product_name": { "type": "string" }, "review_count": { "type": [ "integer", "null" ] }, "price_as_shown": { "type": [ "string", "null" ], "description": "Displayed price range, when the product has multiple prices." }, "ulta_product_id": { "type": [ "string", "null" ], "x-fous-developer": true } }, "additionalProperties": false } } }, "additionalProperties": false}- Price
- 1 credit per completed run (1¢ with pay as you go); failed runs are free.
- Method
ulta.com/search_products- Returns
- product name, brand, starting price, sale price, rating, review count, image, product link, product id, sku
Use it from your agent
Give your agent this line. It reads SKILL.md, gets a Fous API key and connects the Fous MCP server. Its run then takes the method ulta.com/search_products with the inputs above.
Ask your agent
- Find me the best selling dry shampoo under $15 with the lowest prices first
- Show top rated Batiste products, maximum 10 results
- I need a lipstick between $10 and $30 sorted from highest price to lowest
- Look up newest foundation products from any brand, return 40 results
- What hair serums cost between $5 and $25 on ulta.com, best match order
See more
All Ulta Beauty methodsLooks up one Ulta Beauty product by name or product link and returns its details, prices, sizes or shades, ingredients, directions, ratings and images. Prices and availability may change.
ulta.com/get_productSearches Sephora US beauty products in Sephora's order, with brand and USD price filters and shopper sort options. Loves counts are null when a product page cannot be loaded.
sephora.com/search_productsSearch Nordstrom products by words, price, sale status and sort order. Prices are the lowest listed price. Available sizes may be empty when a product page is unavailable.
nordstrom.com/search_productsSearches Macy's products in the site's order with optional USD price bounds, sale-only results and sorting. Prices for products with a range use the lowest shown price.
macys.com/search_productsSearches AliExpress listings by product words, shipping destination, price range and sort order. Unpriced promotional cards are omitted; free shipping is marked only when the listing explicitly says so.
aliexpress.com/search_productsSearch Chewy products by words, pet type, and sort order. Returns up to 72 products in Chewy's order, including listed and first-order Autoship prices when shown.
chewy.com/search_productsFinds a Sephora US product by name or Sephora link and returns its review summary and customer reviews, sorted and optionally filtered by skin type.
sephora.com/get_product_reviewsSearches Best Buy US products with an optional price range, sort order and page. Prices and availability come from public listings and may vary by location.
bestbuy.com/search_products