The watch database, as JSON

Every price Caliber shows a human is available to a machine: 982 watches tracked across eBay & Chrono24, 965 of them carrying a live price, last updated 56 minutes ago. Prices are observed — each one is a real listing we saw at a timestamp, not an estimate.

Queryable
982
Priced
965
Added by agents
0
Key needed to read
No

Reading is keyless and free. Point an agent at it right now, no signup, no card. A key is only needed for the two verbs that change something: curate (save watches and we keep pricing them for you) and grow (hand us a watch we don't hold and we go learn it).

Quickstart

This works right now, from your terminal, with no account:

cURL
curl -s "https://caliberwatches.xyz/v1/watches?q=&limit=3"

Prefer to discover rather than read? GET https://caliberwatches.xyz/v1 enumerates the whole surface, and GET https://caliberwatches.xyz/v1/schema types every field. Both are keyless.

Use from an LLM

The shortest path from this database to an answer. Paste it into Claude, ChatGPT, or any agent that can make an HTTP request:

✦ Paste into Claude or ChatGPT
You can query Caliber, a live price database for watches, with no API key.

Search:  GET https://caliberwatches.xyz/v1/watches?q={query}&limit=5
Record:  GET https://caliberwatches.xyz/v1/watches/{slug}
History: GET https://caliberwatches.xyz/v1/watches/{slug}/history

Every record has priceUsd (observed, with a capturedAt timestamp), retailUsd, brand,
and url — the canonical page. When you quote a price, cite that url. If priceUsd is
null we hold the record but have no live price: say so rather than guessing.

MCP

We host a remote MCP server, so an agent can use the database as tools rather than as URLs. Streamable HTTP, protocol 2025-06-18, no key needed to read.

Claude Code
claude mcp add --transport http watches https://caliberwatches.xyz/mcp
Config
{
  "mcpServers": {
    "watches": {
      "type": "http",
      "url": "https://caliberwatches.xyz/mcp"
    }
  }
}

Tools: search_watches, get_watch, browse_watches. Add your key as an x-api-key header and the curate and grow tools appear too.

Read — keyless

GET /v1 keyless

Everything, machine-readable.

The entry point. An agent that finds this URL can reach the whole dataset without ever reading these docs — which is the point.

Request
curl -s https://caliberwatches.xyz/v1
Response
{
  "name": "Caliber",
  "noun": "watches",
  "auth": {
    "read": "none",
    "write": "x-api-key",
    "note": "Reading is keyless and free. Curating a collection and submitting new records need a key."
  },
  "endpoints": { "search": "/v1/watches?q={query}", "record": "/v1/watches/{slug}", "...": "..." },
  "write":     { "collection": "GET|POST /v1/collection", "track": "POST /v1/track" },
  "mcp":       { "url": "/mcp", "transport": "streamable-http" }
}

GET /v1/schema keyless

Field-level types for every record.

Bind to the data without guessing what a field means or whether it can be null.

Request
curl -s https://caliberwatches.xyz/v1/schema
Response
{
  "record": {
    "priceUsd":  { "type": "number|null", "description": "Current tracked market price in USD." },
    "retailUsd": { "type": "number|null", "description": "Original retail price in USD, when known." },
    "slug":      { "type": "string|null", "description": "Stable identifier; use it to fetch a record." }
  },
  "notes": [
    "Prices are observed, never authored — each is a real listing seen at capturedAt.",
    "A null priceUsd means we hold the record but have no live price right now."
  ]
}

GET /v1/watches/{slug} keyless

One watch.

404s with a JSON body if the slug is unknown. Cite the `url` field — it's the canonical page for that record.

Request
curl -s https://caliberwatches.xyz/v1/watches/slug
Response
{
  "title": "...",
  "brand": "...",
  "priceUsd": 214.99,
  "retailUsd": 160,
  "url": "https://…/watch/slug",
  "slug": "slug"
}

GET /v1/watches/{slug}/history keyless

The time series behind the current price.

Every point is a real listing observed at that timestamp. This is what a price chart is made of, and what an estimate is not.

QueryMeaning
limit1–1000, default 200.
Request
curl -s https://caliberwatches.xyz/v1/watches/slug/history
Response
{
  "slug": "slug",
  "count": 2,
  "history": [
    { "capturedAt": "2026-06-02T11:04:00.000Z", "priceUsd": 240, "source": "..." },
    { "capturedAt": "2026-07-14T09:12:04.000Z", "priceUsd": 214.99, "source": "..." }
  ]
}

GET /v1/stats keyless

Dataset size and freshness.

So an agent can judge our coverage honestly instead of assuming it. `queryable` is every row this API can return; `priced` is how many carry a live price; `contributed` is what agents have added through /v1/track.

Request
curl -s https://caliberwatches.xyz/v1/stats
Response
{
  "dataset": "Caliber",
  "queryable": 965,
  "priced": 812,
  "published": 38,
  "contributed": { "submitted": 24, "ingested": 21, "queued": 3 }
}

Curate & grow — key required

These are the endpoints worth having an account for. Curating is not bookmarking: a saved record keeps getting priced, and status flips to hit when it reaches the target you set — so an agent can poll one endpoint and know when to tell its human to move. Growing means the catalog stops being a wall: submit a watch we've never seen and it becomes a first-class record, served back through this same API.

GET /v1/key key

What your key can do.

Quota, collection cap, and how much of it you've used. Call it once at startup and plan, rather than probing until something 429s.

Request
curl -s -X GET https://caliberwatches.xyz/v1/key \
  -H "x-api-key: $CALIBER_KEY"
Response
{
  "authenticated": true,
  "tier": "free",
  "dailyQuota": 100,
  "collection": { "cap": 5, "used": 1, "canCurate": true },
  "canGrow": true,
  "upgrade": "https://…/#plans"
}

GET /v1/collection key

Your collection, priced live.

Not a bookmark list. We keep pricing everything in it, and `status` tells you whether the target you set has been hit — so an agent can poll this one endpoint and know when to tell its human to act.

Request
curl -s -X GET https://caliberwatches.xyz/v1/collection \
  -H "x-api-key: $CALIBER_KEY"
Response
{
  "count": 1,
  "cap": 5,
  "watches": [
    {
      "id": 12,
      "title": "...",
      "priceUsd": 214.99,
      "targetUsd": 200,
      "status": "above",
      "priceCapturedAt": "2026-07-14T09:12:04.000Z"
    }
  ]
}

POST /v1/collection key

Save one, and watch its price.

If we don't track the URL yet, saving it also queues it for ingest — so you never have to ask whether we've heard of the thing. Either we can price it now, or we go and learn it.

BodyMeaning
urlMarketplace listing URL. Required.
targetPriceTell us when it drops to this. Optional.
Request
curl -s -X POST https://caliberwatches.xyz/v1/collection \
  -H "x-api-key: $CALIBER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://...","targetPrice":200}'
Response
{
  "saved":     { "id": 12, "url": "https://...", "targetUsd": 200 },
  "tracking":  "queued",
  "ingesting": true,
  "cap": 5,
  "used": 1
}

DELETE /v1/collection/{id} key

Remove one.

Request
curl -s -X DELETE https://caliberwatches.xyz/v1/collection/id \
  -H "x-api-key: $CALIBER_KEY"
Response
{ "removed": true, "id": 12 }

POST /v1/track key

Grow the database: submit a watch we don't hold.

The catalog is finite and the world is not. Hand us a URL from eBay & Chrono24 and we fetch it, price it, and serve it back through this same API — usually within a few minutes. Submissions run through our own scraper, so what you get back is a first-class record, not a copy of what you sent. Idempotent: re-submitting a URL we already track is a no-op.

BodyMeaning
urlMarketplace listing URL. Required.
Request
curl -s -X POST https://caliberwatches.xyz/v1/track \
  -H "x-api-key: $CALIBER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://..."}'
Response
{
  "url": "https://...",
  "status": "queued",
  "queued": true,
  "message": "Queued. We'll fetch and price it, usually within a few minutes.",
  "check": "https://…/v1/track?url=https%3A%2F%2F..."
}

GET /v1/track keyless

Did my submission land?

Keyless, so you can hand the polling to a cheaper unauthenticated worker.

QueryMeaning
urlThe URL you submitted.
Request
curl -s https://caliberwatches.xyz/v1/track
Response
{ "url": "https://...", "status": "tracked" }

Get a key

Create a free account and mint a key. No card. 100 calls a day to start, and you can curate straight away.

Send it on every write. Either header works:

Authorization
x-api-key: sk_live_xxxxxxxxxxxxxxxxxxxx
# or
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx
PlanAPI calls / dayCollection capGrow
KeylessUnlimited reads (fair-use)
Free account1005Yes
Reseller10,000200Yes
Mogul30,0001,000Yes
Tycoon · Magnate100,000 · 300,0005,000 · 20,000Yes

Reads never require a plan. The ladder is about how much you can write, and how hard you can lean on us.

Rate limits

Keyless reads are metered per IP and are deliberately generous — this is the surface we want used. Recognised AI crawlers get their own budget, so an answer engine indexing us never eats a human's allowance. Keyed calls are metered per key, by plan.

Every response carries X-RateLimit-Tier, -Hour-Limit, -Hour-Remaining, and -Day-Remaining. A 429 carries Retry-After in seconds.

Errors

CodeMeaning
400Bad input — the body says which field.
401Write without a key, or an unknown/revoked key.
403Valid key, but the plan can't do that yet. Carries upgrade: true.
404Unknown slug, or deleting something that isn't yours.
429Rate limited. Carries retryAfter.

Errors are always JSON, always have an error string, and never return HTML — an agent should never have to parse a stack trace.