curl --request POST \
--url https://api.context.dev/v1/brand/ai/products \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"domain": "<string>",
"maxProducts": 6,
"maxAgeMs": 604800000,
"tags": [
"production",
"team-alpha"
]
}
'import requests
url = "https://api.context.dev/v1/brand/ai/products"
payload = {
"domain": "<string>",
"maxProducts": 6,
"maxAgeMs": 604800000,
"tags": ["production", "team-alpha"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
domain: '<string>',
maxProducts: 6,
maxAgeMs: 604800000,
tags: ['production', 'team-alpha']
})
};
fetch('https://api.context.dev/v1/brand/ai/products', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.context.dev/v1/brand/ai/products",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'domain' => '<string>',
'maxProducts' => 6,
'maxAgeMs' => 604800000,
'tags' => [
'production',
'team-alpha'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.context.dev/v1/brand/ai/products"
payload := strings.NewReader("{\n \"domain\": \"<string>\",\n \"maxProducts\": 6,\n \"maxAgeMs\": 604800000,\n \"tags\": [\n \"production\",\n \"team-alpha\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.context.dev/v1/brand/ai/products")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"domain\": \"<string>\",\n \"maxProducts\": 6,\n \"maxAgeMs\": 604800000,\n \"tags\": [\n \"production\",\n \"team-alpha\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.context.dev/v1/brand/ai/products")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"domain\": \"<string>\",\n \"maxProducts\": 6,\n \"maxAgeMs\": 604800000,\n \"tags\": [\n \"production\",\n \"team-alpha\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"cache_metadata": {
"status": "hit",
"age_ms": 1
},
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"partial": true,
"products": [
{
"name": "<string>",
"description": "<string>",
"features": [
"<string>"
],
"target_audience": [
"<string>"
],
"tags": [
"<string>"
],
"images": [
"<string>"
],
"sku": "<string>",
"price": 123,
"regular_price": 123,
"currency": "<string>",
"billing_frequency": "monthly",
"pricing_model": "per_seat",
"url": "<string>",
"category": "<string>",
"availability": "in_stock",
"dimensions": [
"<string>"
],
"image_url": "<string>"
}
],
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"message": "<string>",
"error_code": "INTERNAL_ERROR",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"error_code": "INTERNAL_ERROR",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"message": "<string>",
"error_code": "REQUEST_TIMEOUT",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"message": "<string>",
"error_code": "RATE_LIMITED",
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"message": "<string>",
"error_code": "INTERNAL_ERROR",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}Extract Products
Build a structured product catalog from any brand website — names, prices, images, and descriptions — without writing custom scrapers.
curl --request POST \
--url https://api.context.dev/v1/brand/ai/products \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"domain": "<string>",
"maxProducts": 6,
"maxAgeMs": 604800000,
"tags": [
"production",
"team-alpha"
]
}
'import requests
url = "https://api.context.dev/v1/brand/ai/products"
payload = {
"domain": "<string>",
"maxProducts": 6,
"maxAgeMs": 604800000,
"tags": ["production", "team-alpha"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
domain: '<string>',
maxProducts: 6,
maxAgeMs: 604800000,
tags: ['production', 'team-alpha']
})
};
fetch('https://api.context.dev/v1/brand/ai/products', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.context.dev/v1/brand/ai/products",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'domain' => '<string>',
'maxProducts' => 6,
'maxAgeMs' => 604800000,
'tags' => [
'production',
'team-alpha'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.context.dev/v1/brand/ai/products"
payload := strings.NewReader("{\n \"domain\": \"<string>\",\n \"maxProducts\": 6,\n \"maxAgeMs\": 604800000,\n \"tags\": [\n \"production\",\n \"team-alpha\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.context.dev/v1/brand/ai/products")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"domain\": \"<string>\",\n \"maxProducts\": 6,\n \"maxAgeMs\": 604800000,\n \"tags\": [\n \"production\",\n \"team-alpha\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.context.dev/v1/brand/ai/products")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"domain\": \"<string>\",\n \"maxProducts\": 6,\n \"maxAgeMs\": 604800000,\n \"tags\": [\n \"production\",\n \"team-alpha\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"cache_metadata": {
"status": "hit",
"age_ms": 1
},
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"partial": true,
"products": [
{
"name": "<string>",
"description": "<string>",
"features": [
"<string>"
],
"target_audience": [
"<string>"
],
"tags": [
"<string>"
],
"images": [
"<string>"
],
"sku": "<string>",
"price": 123,
"regular_price": 123,
"currency": "<string>",
"billing_frequency": "monthly",
"pricing_model": "per_seat",
"url": "<string>",
"category": "<string>",
"availability": "in_stock",
"dimensions": [
"<string>"
],
"image_url": "<string>"
}
],
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"message": "<string>",
"error_code": "INTERNAL_ERROR",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"error_code": "INTERNAL_ERROR",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"message": "<string>",
"error_code": "REQUEST_TIMEOUT",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"message": "<string>",
"error_code": "RATE_LIMITED",
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}{
"request_id": "3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91",
"message": "<string>",
"error_code": "INTERNAL_ERROR",
"key_metadata": {
"credits_consumed": 123,
"credits_remaining": 123
}
}Explicit deadlines and partial catalogs
UsetimeoutOpts to set a deadline. With behavior: "return-partial", an incomplete catalog can succeed with partial: true. With behavior: "fail", or when behavior is omitted, truncation returns an unbilled 408.
Legacy timeoutMS remains accepted with fail behavior. This replaces its earlier implicit partial success on this endpoint. Requests without an explicit timeout keep their existing best-effort behavior. See the migration guide.Authorizations
Bearer authentication header of the form Bearer <API_KEY>. Keys have full access by default.
Body
- By Domain
- By Direct URL
The domain name to analyze.
Maximum number of products to extract.
1 <= x <= 12Return a cached result if a prior scrape for the same parameters exists and is younger than this many milliseconds. Defaults to 7 days (604800000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh.
0 <= x <= 2592000000Optional request deadline and behavior on timeout. For GET requests, use timeoutOpts[milliseconds]=30000&timeoutOpts[behavior]=fail or a JSON-encoded timeoutOpts object.
Show child attributes
Show child attributes
Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.
201 - 50["production", "team-alpha"]
Response
Successful response
Cache outcome for this response. Composite responses are hits only when every cache-controlled fetch contributing to the output was a hit; age_ms is the oldest contributing hit.
Show child attributes
Show child attributes
Unique id of this API call, also sent in the X-Request-Id response header. Quote it when contacting support about a failed request.
"3f1c2a6e-8b4d-4c1e-9f0a-2d7b5e6c8a91"
True when timeoutOpts.behavior=return-partial returned the usable results collected before the deadline. Partial collections are not cached as complete results.
Array of products extracted from the website
Show child attributes
Show child attributes
Credit usage, included whenever a valid API key is provided.
Show child attributes
Show child attributes
Was this page helpful?