> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://channel3.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://channel3.ferndocs.com/_mcp/server.

# SDK

## Installation

**`TypeScript`**

```bash title="TypeScript"
# npm
npm install @channel3/sdk

# yarn
yarn add @channel3/sdk

# pnpm
pnpm add @channel3/sdk
```

**`Python`**

```bash title="Python"
# pip
pip install channel3-sdk

# uv
uv add channel3-sdk
```

## Authentication

You can provide your API key using the `CHANNEL3_API_KEY` environment variable, or by passing it directly to the client.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

// Initialize with environment variable
const client = new Channel3();

// Or, initialize with API key directly
const clientWithKey = new Channel3({
  apiKey: "your_api_key_here",
});
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3, AsyncChannel3

# Initialize with environment variable
client = Channel3()

# Or, initialize with API key directly
client_with_key = Channel3(api_key="your_api_key_here")

# Async client
async_client = AsyncChannel3()
```

## Default locale

Set a default locale once on the client and it'll apply to every search and product detail call. Per-call values (e.g. `config.country` on search, `?country=` on product detail) override the client default.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3({
  country: "GB",
  currency: "GBP",
});

// Uses GB / GBP
await client.products.search({ query: "raincoat" });

// Override per-call (returns DE / EUR offers regardless of the client default)
await client.products.search({
  query: "raincoat",
  config: { country: "DE", currency: "EUR" },
});
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3(country="GB", currency="GBP")

client.products.search(query="raincoat")

client.products.search(
    query="raincoat",
    config={"country": "DE", "currency": "EUR"},
)
```

You can also set defaults via environment variables: `CHANNEL3_LANGUAGE`, `CHANNEL3_COUNTRY`, `CHANNEL3_CURRENCY`. Supported codes follow ISO 639-1 (language), ISO 3166-1 alpha-2 (country), and ISO 4217 (currency).

When only `country` is set, the server infers `currency` (e.g. `GB` → `GBP`) and `language` (e.g. `GB` → `en`). When all three are unset, defaults to `en` / `US` / `USD`.

## Usage

All top-level endpoints are available as properties on the client:

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.search({
    query: "organic cotton t-shirt",
  });
  console.log(response);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.products.search(
        query="organic cotton t-shirt"
    )
    print(response)

if __name__ == "__main__":
    main()
```

### Async Usage

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.search({
    query: "organic cotton t-shirt",
  });
  console.log(response);
}

main();
```

**`Python`**

```python title="Python"
import asyncio
from channel3_sdk import AsyncChannel3

client = AsyncChannel3()

async def main():
    response = await client.products.search(
        query="organic cotton t-shirt"
    )
    print(response)

if __name__ == "__main__":
    asyncio.run(main())
```

## Advanced Usage

### Search with filters

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.search({
    query: "running shoes",
    filters: {
      brand_ids: ["brand_id1", "brand_id2"],
      gender: "unisex",
      price: { min_price: 50.0, max_price: 150.0 },
      availability: ["InStock", "LimitedAvailability"],
    },
    limit: 20,
  });
  console.log(response);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.products.search(
        query="running shoes",
        filters={
            "availability": ["InStock"],
            "price": {"min_price": 10, "max_price": 50},
            "gender": "male",
        },
        limit=20,
    )
    print(response)

if __name__ == "__main__":
    main()
```

### Search with pagination

Use `next_page_token` from the response to fetch the next page of results.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const page1 = await client.products.search({
    query: "running shoes",
  });

  console.log("Page 1:", page1.products.length, "products");

  if (page1.next_page_token) {
    const page2 = await client.products.search({
      query: "running shoes",
      page_token: page1.next_page_token,
    });
    console.log("Page 2:", page2.products.length, "products");
  }
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    page1 = client.products.search(query="running shoes")

    print(f"Page 1: {len(page1.products)} products")

    if page1.next_page_token:
        page2 = client.products.search(
            query="running shoes",
            page_token=page1.next_page_token,
        )
        print(f"Page 2: {len(page2.products)} products")

if __name__ == "__main__":
    main()
```

### Search with an image URL

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.search({
    image_url: "https://example.com/images/shoe.jpg",
  });
  console.log(response);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.products.search(
        image_url="https://example.com/images/shoe.jpg",
    )
    print(response)

if __name__ == "__main__":
    main()
```

### Search with a base64 image

**`TypeScript`**

```typescript title="TypeScript"
import fs from "node:fs";
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const b64 = fs.readFileSync("shoe.jpg").toString("base64");
  const response = await client.products.search({
    base64_image: b64,
  });
  console.log(response);
}

main();
```

**`Python`**

```python title="Python"
import base64
from channel3_sdk import Channel3

client = Channel3()

def main():
    with open("shoe.jpg", "rb") as f:
        b64 = base64.b64encode(f.read()).decode("utf-8")

    response = client.products.search(
        base64_image=b64,
    )
    print(response)

if __name__ == "__main__":
    main()
```

### Configure search behavior

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.search({
    query: "linen shirt",
    config: {
      keyword_search_only: true,
    },
  });
  console.log(response);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.products.search(
        query="linen shirt",
        config={"keyword_search_only": True},
    )
    print(response)

if __name__ == "__main__":
    main()
```

### Look up a product by URL

Pass any supported product page URL to `products.lookup` and get back the canonical `Product` from Channel3's catalog.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.lookup({
    url: "https://brand.com/products/linen-shirt",
  });
  console.log(response.product);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.products.lookup(
        url="https://brand.com/products/linen-shirt"
    )
    print(response.product)

if __name__ == "__main__":
    main()
```

### Find similar products

Given a canonical `product_id`, find the closest neighbors in the catalog. Add `filters` to narrow results.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.products.find_similar({
    product_id: "2yh8WH5",
    filters: {
      gender: "female",
      price: { max_price: 200 },
    },
    limit: 10,
  });
  console.log(response.products);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.products.find_similar(
        product_id="2yh8WH5",
        filters={
            "gender": "female",
            "price": {"max_price": 200},
        },
        limit=10,
    )
    print(response.products)

if __name__ == "__main__":
    main()
```

### Find brands by name

Search the brand catalog by free-text query. Returns brands ordered by relevance.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const response = await client.brands.search({ query: "lululemon" });
  console.log(response.brands);
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    response = client.brands.search(query="lululemon")
    print(response.brands)

if __name__ == "__main__":
    main()
```

### Browse the brand catalog

Cursor-paginated. Pass `next_cursor` from the response back as `cursor` to fetch the next page.

**`TypeScript`**

```typescript title="TypeScript"
import { Channel3 } from "@channel3/sdk";

const client = new Channel3();

async function main() {
  const page1 = await client.brands.list({ limit: 50 });
  console.log("Page 1:", page1.items.map(b => b.name));

  if (page1.next_cursor) {
    const page2 = await client.brands.list({
      limit: 50,
      cursor: page1.next_cursor,
    });
    console.log("Page 2:", page2.items.map(b => b.name));
  }
}

main();
```

**`Python`**

```python title="Python"
from channel3_sdk import Channel3

client = Channel3()

def main():
    page1 = client.brands.list(limit=50)
    print("Page 1:", [b.name for b in page1.items])

    if page1.next_cursor:
        page2 = client.brands.list(limit=50, cursor=page1.next_cursor)
        print("Page 2:", [b.name for b in page2.items])

if __name__ == "__main__":
    main()
```

## Available resources

| Resource        | Description                                         |
| --------------- | --------------------------------------------------- |
| `products`      | Search, image search, similar, lookup, retrieve     |
| `brands`        | List, search, and get brand details                 |
| `categories`    | List, search, and get category details              |
| `priceTracking` | Start/stop tracking, view history and subscriptions |
| `websites`      | Resolve website URLs to IDs and commission rates    |