Custom ecommerce integration
The Brand API lets you read your brand's published articles, download their media, and check for publication or retirement changes.
All requests use this base URL:
https://api.creatorgeo.ai/brand/2026-10Ask the Creator GEO team to enable custom ecommerce for your brand and confirm API access. Published means an approved article is available through the API; it does not mean the article is live on your storefront.
Authenticate
Section titled “Authenticate”Create a key in Settings → API keys and set it as the DELIVERY_API_KEY environment variable. The full key is shown only when you create it. Send it in every request:
Authorization: Bearer <DELIVERY_API_KEY>The key identifies your brand, so you do not need a brand ID. Keep it out of browser code, source control, and logs. Run the examples from your terminal or backend, with shell tracing turned off.
API examples
Section titled “API examples”Choose a language to fetch the first page of published articles. Each example makes one request and prints the response.
curl.
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# List available articles.curl --fail --max-time 30 \ -H "Authorization: Bearer $api_key" \ 'https://api.creatorgeo.ai/brand/2026-10/articles'Python 3.10+. Install with pip install requests.
import osimport requests
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key = os.environ["DELIVERY_API_KEY"]
# List available articles.response = requests.get( "https://api.creatorgeo.ai/brand/2026-10/articles", headers={"Authorization": f"Bearer {api_key}"}, timeout=30,)response.raise_for_status()
print(response.json())Node.js 18+; save as example.mjs.
// Your Creator GEO API key, stored in DELIVERY_API_KEY.const apiKey = process.env.DELIVERY_API_KEY;
// List available articles.const response = await fetch("https://api.creatorgeo.ai/brand/2026-10/articles", { headers: { Authorization: `Bearer ${apiKey}` }, signal: AbortSignal.timeout(30_000),});if (!response.ok) { throw new Error(`HTTP ${response.status}`);}
console.log(await response.json());Ruby 3.1+.
require 'net/http'require 'uri'
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key = ENV.fetch('DELIVERY_API_KEY')
# List available articles.url = URI('https://api.creatorgeo.ai/brand/2026-10/articles')request = Net::HTTP::Get.new(url)request['Authorization'] = "Bearer #{api_key}"
response = Net::HTTP.start( url.host, url.port, use_ssl: url.scheme == 'https', open_timeout: 30, read_timeout: 30) { |http| http.request(request) }response.value # Raise on an HTTP error.
puts response.bodyJDK 17+; save as Example.java.
import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.time.Duration;
public class Example { public static void main(String[] args) throws Exception { // Your Creator GEO API key, stored in DELIVERY_API_KEY. String apiKey = System.getenv("DELIVERY_API_KEY");
// List available articles. HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.creatorgeo.ai/brand/2026-10/articles")) .header("Authorization", "Bearer " + apiKey) .timeout(Duration.ofSeconds(30)) .GET() .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); }}Go 1.22+; save as example.go.
package main
import ( "fmt" "io" "net/http" "os" "time")
func main() { // Your Creator GEO API key, stored in DELIVERY_API_KEY. apiKey := os.Getenv("DELIVERY_API_KEY")
// List available articles. request, err := http.NewRequest(http.MethodGet, "https://api.creatorgeo.ai/brand/2026-10/articles", nil) if err != nil { panic(err) } request.Header.Set("Authorization", "Bearer " + apiKey)
client := &http.Client{Timeout: 30 * time.Second} response, err := client.Do(request) if err != nil { panic(err) } defer response.Body.Close()
body, err := io.ReadAll(response.Body) if err != nil { panic(err) }
fmt.Println(string(body))}The response contains article metadata and pagination cursors:
{ "articles": [ { "id": "10000000-0000-4000-8000-000000000001", "title": "A creator's guide to everyday layers", "version": 1, "published_at": "2026-10-01T12:00:00Z" } ], "next_cursor": null, "change_cursor": "opaque-synthetic-change-cursor"}Only currently published custom-ecommerce articles appear here. Drafts, retired articles, and articles delivered through Shopify are excluded.
Get the next page
Section titled “Get the next page”When next_cursor is not null, pass it as cursor in your next request. Replace the example value below with the cursor from your response.
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# Fetch the next page of articles.curl --fail --max-time 30 --get \ -H "Authorization: Bearer $api_key" \ --data-urlencode 'cursor=opaque-synthetic-list-cursor' \ 'https://api.creatorgeo.ai/brand/2026-10/articles'The default page size is 50. Add limit to request between 1 and 100 articles. Treat cursors as opaque values: pass them back unchanged using your client's query-parameter support.
Read an article
Section titled “Read an article”Use an article ID from the list response:
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# Fetch an article's content.curl --fail --max-time 30 \ -H "Authorization: Bearer $api_key" \ 'https://api.creatorgeo.ai/brand/2026-10/articles/10000000-0000-4000-8000-000000000001'The response includes body_html, head_title, meta_description, canonical_url, stylesheet, and a media list. It is the current approved snapshot. See the API reference for the complete response schema and examples in all six languages.
Download media
Section titled “Download media”Each media entry has a download_path. Add it to https://api.creatorgeo.ai and send the same authorization header:
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# Download a media file.curl --fail --max-time 30 \ -H "Authorization: Bearer $api_key" \ --output example-media.png \ 'https://api.creatorgeo.ai/brand/2026-10/articles/10000000-0000-4000-8000-000000000001/media/20000000000040008000000000000001'Use HEAD to read the headers without downloading the file:
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# Read media headers only.curl --fail --max-time 30 --head \ -H "Authorization: Bearer $api_key" \ 'https://api.creatorgeo.ai/brand/2026-10/articles/10000000-0000-4000-8000-000000000001/media/20000000000040008000000000000001'Media requests return 200 for the complete file. A single Range header can request part of a file, returning 206. Media requires the API key; the download URL is not a public storefront URL.
Check whether an article changed
Section titled “Check whether an article changed”Article responses include an ETag header. Send that value as If-None-Match on a later request:
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# Check a previously fetched article.curl --fail --max-time 30 --include \ -H "Authorization: Bearer $api_key" \ -H 'If-None-Match: "1111111111111111111111111111111111111111111111111111111111111111"' \ 'https://api.creatorgeo.ai/brand/2026-10/articles/10000000-0000-4000-8000-000000000001'Replace the example ETag with the one you received. A 304 Not Modified response has no body and lets you reuse your complete saved response. A 200 response contains the current article. Revoked keys and retired articles are still refused.
Read publication changes
Section titled “Read publication changes”Use the article list's change_cursor to request changes since that list began:
# Your Creator GEO API key, stored in DELIVERY_API_KEY.api_key="$DELIVERY_API_KEY"
# Fetch publication and retirement changes.curl --fail --max-time 30 --get \ -H "Authorization: Bearer $api_key" \ --data-urlencode 'cursor=opaque-synthetic-change-cursor' \ 'https://api.creatorgeo.ai/brand/2026-10/article-changes'The response contains a changes array, next_cursor, and change_cursor. Events arrive in increasing sequence order:
publishedidentifies an article whose current approved content you can fetch.retiredidentifies an article that is no longer available. Detail and media requests for it return410.
Follow next_cursor until it is null. After reading all pages, use change_cursor to request later changes. Omitting cursor reads from the beginning of the change history. The default page size is 100; limit accepts 1–500.
List cursors and change cursors are different; use each only with its own endpoint. An article missing from a list is not a retirement event.
Response codes
Section titled “Response codes”| Code | Meaning |
|---|---|
400 | Invalid limit or cursor. |
401 | Missing, invalid, or revoked API key. |
404 | Article or media is unavailable to this key. |
410 | The article has been retired. |
416 | Invalid or unsatisfiable media range. |
429 | Request limit reached; Retry-After gives the wait in seconds. |
5xx | Server error. Try the request again later. |
The current limit is 120 requests per minute per brand per API process, shared across the brand's keys and endpoints. All API responses use Cache-Control: private, no-store.
The /2026-10 path identifies the API contract version. Unsupported versions return 404 without a redirect or fallback. For every endpoint, parameter, and response field, see the Brand API reference or download the OpenAPI specification.