Valuations

Get price estimates for cars, wristwatches, and rings. Send a category and attributes; optionally include a fileId from Vision to trigger enrichment first.

Simplest request — no image:

POST
/v1/valuations
{
  "category": "wristwatch",
  "attributes": {
    "brand": "Rolex"
  }
}

Response (200):

{
  "success": true,
  "predictionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "valuation": {
    "currency": "SEK",
    "priceEstimate": 85000,
    "confidence": 0.5,
    "range": { "low": 50000, "high": 150000 }
  },
  "category": "wristwatch",
  "attributes": { "brand": "Rolex" },
  "metadata": { "timestamp": "...", "creditUsed": 1 }
}

More attributes (e.g. model, reference number) give a tighter range and higher confidence.

Request body

FieldTypeRequiredDescription
categorystringYes"car" | "wristwatch" | "ring" (see GET /v1/categories).
attributesobjectYesCategory-specific attributes. See Attributes.
fileIdstringNoFrom POST /v1/vision. Triggers enrichment unless options.skipEnrich is true.
optionsobjectNoSee Valuation options.

Valuation options

All fields are optional. Omit options to use defaults.

OptionTypeDefaultDescription
skipEnrichbooleanfalseSkip enrichment even when fileId is provided.
asOfstring | numbertodayPoint-in-time valuation. ISO 8601, date-only, or epoch seconds.
modelstringlatestPin a specific internal model version (e.g. "watch-v3.2.1").
marketstringserver defaultMarket region, e.g. "SE", "US", "EU".
currencystringserver defaultISO 4217 code (e.g. "SEK", "USD").
confidenceFloornumberSuppress results below this confidence (0–1).

Example with options:

{
  "category": "wristwatch",
  "attributes": {
    "brand": "Rolex",
    "model": "Submariner",
    "referenceNumber": "116610LN"
  },
  "options": {
    "currency": "SEK",
    "market": "SE",
    "asOf": "2025-01-15"
  }
}

Examples by category

Wristwatch — minimal (brand only)

{
  "category": "wristwatch",
  "attributes": {
    "brand": "Rolex"
  }
}

Response (200):

{
  "success": true,
  "predictionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "valuation": {
    "currency": "SEK",
    "priceEstimate": 85000,
    "confidence": 0.5,
    "range": { "low": 50000, "high": 150000 }
  },
  "category": "wristwatch",
  "attributes": { "brand": "Rolex" },
  "metadata": { "timestamp": "2025-03-06T12:00:00.000Z", "asOf": "2025-03-06", "creditUsed": 1 }
}

Wristwatch — full attributes

More attributes yield a tighter estimate.

{
  "category": "wristwatch",
  "attributes": {
    "brand": "Rolex",
    "model": "Submariner",
    "referenceNumber": "116610LN",
    "strap": "steel",
    "case": "steel",
    "bezel": "steel",
    "movement": "automatic",
    "dialColor": "black",
    "caseDiameter": 41,
    "condition": "very_good",
    "box": true,
    "papers": true
  }
}

Response (200):

{
  "success": true,
  "predictionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "valuation": {
    "currency": "SEK",
    "priceEstimate": 125000,
    "confidence": 0.88,
    "range": { "low": 110000, "high": 140000 }
  },
  "category": "wristwatch",
  "attributes": { "..." : "..." },
  "metadata": { "timestamp": "...", "asOf": "2025-03-06", "creditUsed": 1 }
}

Car — full attributes

{
  "category": "car",
  "attributes": {
    "licensePlate": "ABC123",
    "brand": "Volvo",
    "model": "XC60",
    "yearOfManufacture": 2020,
    "odometerReading": 45000,
    "fuelType": "Plug-in Hybrid (PHEV)",
    "drive": "AWD",
    "gearbox": "Automatic",
    "enginePower": 340,
    "color": "black",
    "additionalWheelset": false
  }
}

Response has the same shape; valuation.currency is "SEK".

Ring

{
  "category": "ring",
  "attributes": {
    "style": "solitairering",
    "engraving": false,
    "material": "white gold",
    "materialPurity": "18k",
    "weight": 4.2,
    "condition": "excellent",
    "diamondCarat": 0.5
  }
}

Examples by flow

Flow A: Valuate with enrichment (image first)

The API enriches missing attributes from the image, then values the item.

curl -X POST https://api.gemmai.io/v1/vision \
  -H "Content-Type: application/json" \
  -d '{"imageUrl": "https://example.com/watch.jpg"}'
# Response: { "fileId": "f47ac10b-...", ... }

The server loads vision data for the fileId, runs enrichment, then values the enriched attributes.

Flow B: Valuate without image (attributes only)

{
  "category": "wristwatch",
  "attributes": {
    "brand": "Rolex",
    "model": "Submariner",
    "referenceNumber": "116610LN",
    "strap": "steel",
    "movement": "automatic",
    "dialColor": "black",
    "condition": "very_good"
  }
}

Flow C: Valuate with image but skip enrichment

You have a fileId but want to value using only the attributes you send (e.g. user already confirmed them).

{
  "category": "wristwatch",
  "attributes": {
    "brand": "Rolex",
    "model": "Submariner",
    "referenceNumber": "116610LN"
  },
  "fileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "options": { "skipEnrich": true }
}

Retrieving a valuation

Use the predictionId from a create response to fetch it later.

GET
/v1/valuations/{id}
curl https://api.gemmai.io/v1/valuations/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "X-API-Key: <your-api-key>"

Response (404):

{ "error": "Valuation not found" }

Timeline and similar sales

Timeline:

GET /v1/valuations/{id}/timeline
{
  "period": { "from": "2025-01-01T00:00:00.000Z", "to": "2025-03-06T00:00:00.000Z" },
  "difference": { "percentageChange": 0.02, "absoluteChange": 2500 },
  "timeline": [
    {
      "date": "2025-03-06T12:00:00.000Z",
      "priceEstimate": 125000,
      "confidence": 0.88,
      "range": { "low": 110000, "high": 140000 }
    }
  ]
}

Similar sales:

GET /v1/valuations/{id}/similar-sales?limit=20&offset=0
{
  "results": [
    {
      "title": "...",
      "price": { "currency": "SEK", "amount": 118000 },
      "attributes": { "..." : "..." }
    }
  ],
  "total": 42
}

Error handling

400 — Validation error:

{
  "success": false,
  "details": {
    "brand": ["Required"],
    "referenceNumber": ["Invalid value"]
  },
  "metadata": { "timestamp": "...", "creditUsed": 0 }
}

404 — Valuation not found:

{ "error": "Valuation not found" }

500 — Server error:

{ "error": "Something went wrong" }

Was this page helpful?