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 -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:
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 mcp add --transport http watches https://caliberwatches.xyz/mcp
{
"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.
curl -s https://caliberwatches.xyz/v1
{
"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.
curl -s https://caliberwatches.xyz/v1/schema
{
"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
keyless
Search and browse every watch we track.
Token-AND search across title, brand, watch reference and colorway. Priced records come first — an unpriced row is the least useful answer to "what does this cost". Also served at /v1/items, which is identical on every site in the fleet, so one client works against all of them.
| Query | Meaning |
|---|---|
q | Search text. Tokens are ANDed. |
brand | Exact brand match. |
source | Marketplace the row came from. |
priced | true — only records carrying a live price. |
limit | 1–100, default 20. |
offset | Paging offset. |
curl -s https://caliberwatches.xyz/v1/watches
{
"query": "example",
"total": 41,
"count": 1,
"watches": [
{
"title": "...",
"brand": "...",
"priceUsd": 214.99,
"retailUsd": 160,
"priceCapturedAt": "2026-07-14T09:12:04.000Z",
"source": "...",
"marketUrl": "https://...",
"url": "https://…/watch/slug",
"slug": "slug"
}
]
}
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.
curl -s https://caliberwatches.xyz/v1/watches/slug
{
"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.
| Query | Meaning |
|---|---|
limit | 1–1000, default 200. |
curl -s https://caliberwatches.xyz/v1/watches/slug/history
{
"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/trending
keyless
What's moving now.
| Query | Meaning |
|---|---|
limit | 1–100, default 6. |
curl -s https://caliberwatches.xyz/v1/trending
{ "count": 6, "watches": [ { "title": "...", "priceUsd": 214.99, "marketUrl": "https://..." } ] }
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.
curl -s https://caliberwatches.xyz/v1/stats
{
"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.
curl -s -X GET https://caliberwatches.xyz/v1/key \
-H "x-api-key: $CALIBER_KEY"
{
"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.
curl -s -X GET https://caliberwatches.xyz/v1/collection \
-H "x-api-key: $CALIBER_KEY"
{
"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.
| Body | Meaning |
|---|---|
url | Marketplace listing URL. Required. |
targetPrice | Tell us when it drops to this. Optional. |
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}'
{
"saved": { "id": 12, "url": "https://...", "targetUsd": 200 },
"tracking": "queued",
"ingesting": true,
"cap": 5,
"used": 1
}
DELETE
/v1/collection/{id}
key
Remove one.
curl -s -X DELETE https://caliberwatches.xyz/v1/collection/id \
-H "x-api-key: $CALIBER_KEY"
{ "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.
| Body | Meaning |
|---|---|
url | Marketplace listing URL. Required. |
curl -s -X POST https://caliberwatches.xyz/v1/track \
-H "x-api-key: $CALIBER_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://..."}'
{
"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.
| Query | Meaning |
|---|---|
url | The URL you submitted. |
curl -s https://caliberwatches.xyz/v1/track
{ "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:
x-api-key: sk_live_xxxxxxxxxxxxxxxxxxxx
# or
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx
| Plan | API calls / day | Collection cap | Grow |
|---|---|---|---|
| Keyless | Unlimited reads (fair-use) | — | — |
| Free account | 100 | 5 | Yes |
| Reseller | 10,000 | 200 | Yes |
| Mogul | 30,000 | 1,000 | Yes |
| Tycoon · Magnate | 100,000 · 300,000 | 5,000 · 20,000 | Yes |
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
| Code | Meaning |
|---|---|
400 | Bad input — the body says which field. |
401 | Write without a key, or an unknown/revoked key. |
403 | Valid key, but the plan can't do that yet. Carries upgrade: true. |
404 | Unknown slug, or deleting something that isn't yours. |
429 | Rate 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.