Aether

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:

  1. Logs the click for conversion tracking
  2. Redirects (HTTP 302) to the retailer's product page with affiliate tracking applied
  3. 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."