API Reference
Complete endpoint documentation for the Aether API. All endpoints return data conforming to the Aether product schema.
Base URL
https://api.aethergraph.io/v1 All endpoints are versioned. Breaking changes will receive a new version number; additive changes (new optional fields, new endpoints) will not.
Common parameters
These parameters are available on all list endpoints (search products, list categories, list merchants).
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 10 | Results per page. Range: 1–50. |
cursor | string | — | Opaque cursor for pagination. Returned in meta.next_cursor. |
fields | string | — | Comma-separated list of additional fields to include. |
currency | string | GBP | ISO 4217 currency code for price fields. |
Field selection
Responses return a compact set of fields by default to minimise token usage for AI agents. Use the fields parameter to request additional data.
Default fields (always returned):
id, name, brand, price, availability, condition, merchant.name, purchase_url, images.primary, category.aether
Optional fields (request via fields parameter):
description, identifiers, attributes, specs, images.additional, merchant.id, merchant.network, source_id, source_url, category.source, category.google_category_id, freshness
Example:
GET /v1/products?q=headphones&fields=identifiers,attributes,freshness Endpoints
Search products
GET /v1/products Search and filter products across all integrated merchants. This is the primary endpoint for most agent workflows.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Yes* | Free-text search query. Searched against product name, brand, and description. |
category | string | Yes* | Filter by Aether category slug (e.g. headphones, laptops). |
brand | string | No | Filter by brand name. Case-insensitive. |
min_price | number | No | Minimum price in the specified currency. Inclusive. |
max_price | number | No | Maximum price in the specified currency. Inclusive. |
in_stock | boolean | No | If true, only return products with availability: "in_stock". Default: true. |
condition | string | No | Filter by condition: new, refurbished, or used. Default: all. |
merchant | string | No | Filter by merchant name or ID. |
gtin | string | No | Filter by GTIN/EAN/UPC. Returns all merchant listings for that specific product. |
sort | string | No | Sort order. Default: relevance. |
*At least one of q or category is required.
Sort options:
| Value | Description |
|---|---|
relevance | Best match to search query (default) |
price_asc | Cheapest first |
price_desc | Most expensive first |
name_asc | Alphabetical A–Z |
newest | Most recently updated in feed |
Example requests:
# Find Samsung phones under £500, cheapest first
GET /v1/products?q=samsung&category=smartphones&max_price=500&sort=price_asc
# In-stock AirPods
GET /v1/products?q=airpods&in_stock=true
# Refurbished laptops under £400
GET /v1/products?category=laptops&condition=refurbished&max_price=400&sort=price_asc
# All merchants' listings for a specific product by GTIN
GET /v1/products?gtin=8806095360850&sort=price_asc Example response:
{
"status": "ok",
"count": 3,
"total": 47,
"data": [
{
"id": "aeth-curry-720702",
"name": "Samsung Galaxy S25 Ultra 256GB Titanium Black",
"brand": "Samsung",
"price": {
"amount": 949.00,
"currency": "GBP",
"sale_price": 949.00,
"sale_active": true
},
"availability": "in_stock",
"condition": "new",
"merchant": {
"name": "Currys"
},
"purchase_url": "https://api.aethergraph.io/r/aeth-curry-720702",
"images": {
"primary": "https://media.currys.co.uk/i/curyspcworld/..."
},
"category": {
"aether": ["electronics", "smartphones"]
}
}
],
"meta": {
"query_time_ms": 38,
"next_cursor": "eyJvZmZzZXQiOjEwfQ==",
"has_more": true,
"freshness_oldest": "2026-03-05T06:00:00Z",
"freshness_newest": "2026-03-06T08:30:00Z"
}
} Get product detail
GET /v1/products/{id}
Returns full details for a single product. All fields are returned — the fields parameter is not needed.
Example request:
GET /v1/products/aeth-curry-720702 Example response:
{
"status": "ok",
"data": {
"id": "aeth-curry-720702",
"source_id": "720702",
"source": "awin",
"merchant": {
"id": "awin-1234",
"name": "Currys",
"network": "awin"
},
"name": "Samsung Galaxy S25 Ultra 256GB Titanium Black",
"description": "Samsung Galaxy S25 Ultra with 256GB storage, Titanium Black. Features a 6.9-inch display...",
"category": {
"aether": ["electronics", "smartphones"],
"source": "Electronics > Mobile Phones > Smartphones",
"google_category_id": "267"
},
"price": {
"amount": 949.00,
"currency": "GBP",
"sale_price": 949.00,
"sale_active": true
},
"availability": "in_stock",
"condition": "new",
"brand": "Samsung",
"identifiers": {
"gtin": "8806095360850",
"mpn": "SM-S938BZKDEUB"
},
"images": {
"primary": "https://media.currys.co.uk/i/curyspcworld/...",
"additional": []
},
"purchase_url": "https://api.aethergraph.io/r/aeth-curry-720702",
"source_url": "https://www.currys.co.uk/products/...",
"attributes": {
"color": "Titanium Black",
"size": "256GB"
},
"specs": {},
"freshness": {
"feed_updated": "2026-03-06T06:00:00Z",
"last_checked": "2026-03-06T08:30:00Z"
}
},
"meta": {
"query_time_ms": 5
}
} Compare prices
GET /v1/compare/{gtin} The highest-value endpoint. Given a GTIN (EAN/UPC barcode number), returns every merchant's listing for that exact product, sorted by price. This is Aether's core proposition: answering "where's the cheapest place to buy this specific product?"
Results are always sorted by price ascending. Out-of-stock listings appear at the end.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
condition | string | No | Filter by condition: new, refurbished, or used. Default: all. |
in_stock | boolean | No | Only show in-stock listings. Default: true. |
Example request:
GET /v1/compare/8806095360850 Example response:
{
"status": "ok",
"product_name": "Samsung Galaxy S25 Ultra 256GB Titanium Black",
"gtin": "8806095360850",
"brand": "Samsung",
"listing_count": 4,
"data": [
{
"id": "aeth-ao-88291",
"merchant": { "name": "AO.com" },
"price": { "amount": 929.00, "currency": "GBP", "sale_active": false },
"availability": "in_stock",
"condition": "new",
"purchase_url": "https://api.aethergraph.io/r/aeth-ao-88291",
"freshness": { "feed_updated": "2026-03-06T04:00:00Z" }
},
{
"id": "aeth-curry-720702",
"merchant": { "name": "Currys" },
"price": { "amount": 949.00, "currency": "GBP", "sale_active": true },
"availability": "in_stock",
"condition": "new",
"purchase_url": "https://api.aethergraph.io/r/aeth-curry-720702",
"freshness": { "feed_updated": "2026-03-06T06:00:00Z" }
},
{
"id": "aeth-jl-445512",
"merchant": { "name": "John Lewis" },
"price": { "amount": 1099.00, "currency": "GBP", "sale_active": false },
"availability": "in_stock",
"condition": "new",
"purchase_url": "https://api.aethergraph.io/r/aeth-jl-445512",
"freshness": { "feed_updated": "2026-03-05T22:00:00Z" }
},
{
"id": "aeth-argos-991823",
"merchant": { "name": "Argos" },
"price": { "amount": 1099.00, "currency": "GBP", "sale_active": false },
"availability": "out_of_stock",
"condition": "new",
"purchase_url": "https://api.aethergraph.io/r/aeth-argos-991823",
"freshness": { "feed_updated": "2026-03-06T02:00:00Z" }
}
],
"meta": {
"query_time_ms": 12,
"price_range": { "min": 929.00, "max": 1099.00, "currency": "GBP" },
"in_stock_count": 3
}
} List categories
GET /v1/categories
Returns the Aether category taxonomy. Use this to discover what product categories are available and their slugs for the category parameter on the search endpoint.
Categories are two levels deep: a parent and its children.
Example response:
{
"status": "ok",
"data": [
{
"slug": "electronics",
"name": "Electronics",
"product_count": 48230,
"children": [
{ "slug": "smartphones", "name": "Smartphones", "product_count": 3841 },
{ "slug": "laptops", "name": "Laptops", "product_count": 5672 },
{ "slug": "headphones", "name": "Headphones & Earbuds", "product_count": 2918 },
{ "slug": "tablets", "name": "Tablets", "product_count": 1205 },
{ "slug": "monitors", "name": "Monitors", "product_count": 1842 },
{ "slug": "webcams", "name": "Webcams", "product_count": 437 },
{ "slug": "keyboards", "name": "Keyboards & Peripherals", "product_count": 2105 }
]
}
]
} List merchants
GET /v1/merchants Returns all integrated merchants. Useful for filtering searches by merchant or presenting merchant options to users.
Example response:
{
"status": "ok",
"data": [
{
"id": "awin-1234",
"name": "Currys",
"network": "awin",
"categories": ["electronics"],
"product_count": 12450
},
{
"id": "awin-5678",
"name": "John Lewis",
"network": "awin",
"categories": ["electronics"],
"product_count": 8920
}
]
} Redirect (purchase link)
GET /r/{product_id} This is not a data endpoint. It's the redirect that handles affiliate tracking when a user clicks a purchase link.
When called, it:
- Logs the click for conversion tracking
- Redirects (HTTP 302) to the retailer's product page with affiliate tracking applied
- Returns in under 100ms
This endpoint sits at /r/, not under /v1/, because it's user-facing. Purchase links need to be fast, short, and permanent — they should never break due to API versioning.
You do not need to call this endpoint directly. The purchase_url field in every product response already points here. Present it to users as a clickable link.
Pagination
Aether uses cursor-based pagination, not offset-based. Cursors are opaque strings — treat them as tokens, not values to decode.
Cursor pagination is more stable than offset pagination. If products are added or removed between page requests, offset-based pagination can skip results or show duplicates. Cursors avoid this.
First page:
GET /v1/products?q=samsung&limit=10 Response includes:
{
"meta": {
"next_cursor": "eyJvZmZzZXQiOjEwfQ==",
"has_more": true
}
} Next page:
GET /v1/products?q=samsung&limit=10&cursor=eyJvZmZzZXQiOjEwfQ== When has_more is false, there are no more results.
Error handling
All errors return a consistent structure:
{
"status": "error",
"error": {
"code": "invalid_parameter",
"message": "Parameter 'max_price' must be a positive number",
"param": "max_price"
}
} Error codes:
| HTTP Status | Code | Description |
|---|---|---|
| 400 | invalid_parameter | A query parameter is malformed or out of range |
| 400 | missing_parameter | A required parameter is missing (e.g. neither q nor category provided) |
| 401 | unauthorized | Missing or invalid API key |
| 403 | rate_limited | Rate limit exceeded. Check the Retry-After header for when to retry. |
| 404 | not_found | Product or resource not found |
| 404 | category_not_found | Requested category slug does not exist |
| 500 | internal_error | Something went wrong on Aether's side |
| 503 | data_unavailable | An upstream data source is temporarily unavailable |
Data freshness
Product data comes from retailer feeds that are refreshed periodically, not in real time. Prices can change between the time Aether last checked and the time a user visits the retailer.
Every API response includes freshness metadata:
List responses include freshness_oldest and freshness_newest in the meta object, showing the age range of data in the result set.
Individual products include a freshness object (request with ?fields=freshness) containing feed_updated (when the merchant last updated their feed) and last_checked (when Aether last verified the data).
If your agent communicates with end users, consider surfacing freshness information when data is more than a few hours old — for example: "Prices checked 4 hours ago. The retailer's current price may differ."