# Using the CardSight AI API - Marketplace Search (Free-Text Title)

## Overview
Search currently active marketplace listings by free-text listing title when you don't have a card ID. This is a fuzzy search over listing titles that returns a **flat, relevance-ranked list spanning many cards** — active auctions and Buy It Now listings, each with a direct link to buy. Results may include listings our AI **isn't confident in matching to a canonical card** — useful for surfacing those listings, or sellers who use unusual titles. Each result carries the canonical card it matched (when our AI is confident) and grade context for graded listings.

This differs from the single-card marketplace endpoint (`GET /v1/marketplace/{card_id}`), which returns a nested `raw`/`graded` structure for one known card. Use marketplace search when you only have text (a player's name, year, and set) rather than a UUID. It is the active-listings counterpart to Pricing Search (`GET /v1/pricing/search`), which covers completed/historical sales.

## Endpoint Details
- **Method**: GET
- **URL**: `https://api.cardsight.ai/v1/marketplace/search`
- **Authentication**: API Key required (X-Api-Key header)

## Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| q | string | Yes | Free-text search over marketplace listing titles. 3–300 characters. |
| listing_type | string | No | Filter by listing type: "auction" (auctions), "fixed" (buy-it-now), or "both" (default). |
| limit | integer | No | Maximum number of records to return. Default 100, hard cap 500. |

> Note: unlike Pricing Search, marketplace search has **no `period` parameter** — these are live listings, not historical sales.

## Using the CardSight AI SDK (Recommended)

### Node.js / TypeScript
```typescript
import { CardSightAI } from 'cardsightai'

const client = new CardSightAI({ apiKey: 'your-api-key' })

// Search active listings by listing title — no card ID needed
const response = await client.marketplace.search({
  q: 'Ken Griffey Jr 1989 Upper Deck', // Required, 3–300 characters
  listing_type: 'both',                 // Optional: auction, fixed, both
  limit: 25,                            // Optional: default 100, max 500
})

// Always check for errors
if (response.error) {
  console.error('Error:', response.error)
} else {
  const data = response.data

  console.log(`Found ${data.meta.total_records} active listings`)

  for (const listing of data.results) {
    console.log(`$${listing.price ?? 'N/A'} - ${listing.title} (${listing.source})`)
    if (listing.url) console.log(`  ${listing.url}`)
    if (listing.bid_count) console.log(`  Bids: ${listing.bid_count}`)
    if (listing.condition) console.log(`  Condition: ${listing.condition}`)

    // matched_card is present only when the listing was matched to a canonical card
    if (listing.matched_card) {
      console.log(`  ${listing.matched_card.name} - ${listing.matched_card.set.release}`)
    }
    // grade is present only for graded listings
    if (listing.grade) {
      console.log(`  ${listing.grade.company_name} ${listing.grade.grade_value}`)
    }
  }

  // Breakdown by data source
  for (const source of data.meta.sources) {
    console.log(`${source.source}: ${source.count}`)
  }
}
```

### Python
```python
from cardsightai import CardSightAI

client = CardSightAI(api_key='your-api-key')

response = client.marketplace.search(
    q='Ken Griffey Jr 1989 Upper Deck',
    listing_type='both',
    limit=25
)

print(f"Found {response.meta.total_records} active listings")

for listing in response.results:
    print(f"  ${listing.price}: {listing.title}")
    if listing.bid_count:
        print(f"    Bids: {listing.bid_count}")
    if listing.matched_card:
        print(f"    {listing.matched_card.name} - {listing.matched_card.set.release}")
```

## Direct API Call (cURL)
```bash
curl -X GET "https://api.cardsight.ai/v1/marketplace/search?q=ken%20griffey%20jr%201989%20upper%20deck&listing_type=both" \
  -H "X-Api-Key: your-api-key"
```

## Example Response
```json
{
  "query": {
    "q": "ken griffey jr 1989 upper deck",
    "listing_type": "both",
    "limit": 25,
    "as_of_date": "2026-06-30"
  },
  "results": [
    {
      "title": "1989 Upper Deck #1 Ken Griffey Jr RC Rookie PSA 10",
      "price": 1399.99,
      "source": "ebay",
      "listing_type": "fixed",
      "url": "https://www.ebay.com/itm/...",
      "image_url": "https://i.ebayimg.com/...",
      "condition": "Graded",
      "end_date": "2026-07-05T00:00:00Z",
      "bid_count": null,
      "parallel_id": null,
      "parallel_name": null,
      "matched_card": {
        "card_id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Ken Griffey Jr.",
        "number": "1",
        "set": {
          "set_id": "550e8400-e29b-41d4-a716-446655440002",
          "name": "Base Set",
          "year": "1989",
          "release": "1989 Upper Deck"
        }
      },
      "grade": {
        "grade_id": "550e8400-e29b-41d4-a716-446655440030",
        "grade_value": "10",
        "company_name": "PSA",
        "company_id": "550e8400-e29b-41d4-a716-446655440020"
      }
    },
    {
      "title": "Griffey 1989 UD rookie raw auction no reserve",
      "price": 25.50,
      "source": "ebay",
      "listing_type": "auction",
      "url": "https://www.ebay.com/itm/...",
      "image_url": null,
      "condition": "Ungraded",
      "end_date": "2026-07-02T00:00:00Z",
      "bid_count": 7,
      "parallel_id": null,
      "parallel_name": null
    }
  ],
  "meta": {
    "sources": [{ "source": "ebay", "count": 18 }],
    "total_records": 18
  }
}
```

> Note: in the second result, `matched_card` and `grade` are **absent** — the listing was found by title, but our AI isn't confident in matching it to a canonical card. Always check for their presence before reading them.

## Response Fields

### Top-Level Response

| Field | Type | Description |
|-------|------|-------------|
| query | object | Echo of the query parameters that were applied |
| results | array | Flat list of matched active listings, ranked by title relevance. Spans multiple cards and may include unmatched listings. |
| meta | object | Response metadata |

### Query Echo Object

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| q | string | Yes | Search query applied |
| listing_type | string | Yes | Listing type filter applied |
| limit | integer | No | Result limit applied |
| as_of_date | string | Yes | Date the data was retrieved |

### Marketplace Search Record Object

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | Yes | Listing title |
| source | string | Yes | Marketplace source (e.g., "ebay") |
| price | number | No | Current price or starting bid in USD |
| listing_type | string | No | "auction", "fixed" (buy-it-now), or "search" (a marketplace search link record) |
| url | string | No | URL to the listing |
| image_url | string | No | Primary image URL |
| condition | string | No | Condition description from seller |
| end_date | string | No | Listing end date in ISO 8601 format |
| bid_count | integer | No | Number of bids (auctions only) |
| parallel_id | UUID | No | Parallel variant UUID. Null for base card listings. |
| parallel_name | string | No | Parallel variant name. Null for base card listings. |
| matched_card | object | No | Canonical card this listing matched. **Omitted when the listing is unmatched.** |
| grade | object | No | Grade context for graded listings. **Omitted for ungraded listings.** |

### Matched Card Object (matched_card)

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| card_id | UUID | Yes | Card UUID — use this to call other endpoints (single-card marketplace, pricing, population, etc.) |
| name | string | Yes | Card name/subject |
| number | string | No | Card number in set |
| set | object | Yes | Set context: set_id, name, year, release |

### Grade Object (grade)

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| grade_id | UUID | Yes | Grade UUID |
| grade_value | string | Yes | Grade value (e.g., "10", "9.5") |
| company_name | string | Yes | Grading company name (e.g., "PSA") |
| company_id | UUID | Yes | Grading company UUID |

### Meta Object

| Field | Type | Description |
|-------|------|-------------|
| sources | array | Breakdown by data source (each item: source name + count) |
| total_records | number | Total records returned |

## Common Use Cases
- Find what's for sale right now when you have a card's name/year/set as text but not its UUID
- Show users where to buy a card, searched straight from a plain-text box
- Surface active listings our AI isn't confident in matching, or sellers using unusual titles
- Compare current asking prices and live auction bids across many listings at once
- Bridge text → catalog: read `matched_card.card_id` to then call the single-card marketplace, pricing, or population endpoints

## Tips for AI Assistants
- **Working with IDs:** The `matched_card.card_id` returned here (and other release/set/card UUIDs) let you look up catalog entities and chain calls together. Caching them briefly to fulfill a user's request is expected and fine — it's why the image and other free endpoints exist. If you need to save cards for the long term, add them to a **list or collection**: those are your own stable resources, purpose-built for holding cards. If you need a bulk or offline copy of catalog data, reach out to us at `support@cardsight.ai` so we can help with your use case.
- The SDK returns `{ data, error }` — always check for errors first
- `q` is **required** and must be 3–300 characters
- There is **no `period` parameter** — these are live listings, not historical sales (that's Pricing Search)
- Results are a **flat list spanning multiple cards**, ranked by title relevance — this is NOT scoped to one card like `GET /v1/marketplace/{card_id}`
- The date field is **`end_date`** (when the listing ends), not `date`
- `price` is optional/nullable here — handle the `null` case (for auctions it may be the starting bid)
- `listing_type` may be `"auction"`, `"fixed"`, or `"search"` (a marketplace search-link record) — handle all three
- `bid_count` is present for auctions; `condition` is the seller's stated condition
- `matched_card` and `grade` are **omitted** when not applicable — always check for their presence first
- `limit` defaults to 100 and is capped at 500
- Use `matched_card.card_id` to pivot from a text search into the precise single-card marketplace/pricing/population endpoints
- Coverage is expanding — as our AI grows more confident over time, more listings will match to canonical cards automatically
- Currently in beta for Baseball, with additional sports coming soon
