Enrich
Given a category and either a fileId from Vision, a set of attributes, or both, Enrich returns normalized attributes plus per-field details: which values were derived and how confident the API is. When called without a fileId, Enrich normalizes and fills in missing attribute values based on the attributes you supply — no image required.
Simplest request — after getting a fileId from Vision:
{
"category": "wristwatch",
"fileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Response (200):
{
"normalizedAttributes": {
"brand": "Rolex",
"strap": "steel",
"dialColor": "black"
},
"candidates": [],
"enriched": [
{ "attribute": "strap", "value": "steel", "confidence": 0.9, "source": "VISUAL_MATCH" }
],
"confidence": 0.82,
"warnings": []
}
Pass normalizedAttributes directly to POST /v1/valuations as attributes, or show them to the user for editing first.
When to use Enrich
| Use case | Approach |
|---|---|
| You only have an image | Vision → Enrich → get suggested attributes |
| You want to show "what we detected" before valuing | Enrich → show normalizedAttributes and enriched → valuate |
| You want a valuation in one step | POST /v1/valuations with fileId; server enriches internally |
| You have all attributes and no image | Skip Enrich; call Valuations with attributes only |
fileId is optional. When provided it must come from a previous Vision upload — the client never sends raw images to Enrich, only the ID of an already-processed image. When omitted, Enrich works purely from the attributes you supply.
Prerequisites: vision and fileId
Upload an image:
{
"imageUrl": "https://example.com/photos/watch-front.jpg"
}
Response (200):
{
"fileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "completed",
"objects": [{ "type": "wristwatch" }],
"usage": { "creditUsed": 1 }
}
If the same image was processed before, the server returns a cached result (creditUsed: 0).
Request and response
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
category | string | Yes | "car" | "wristwatch" | "ring" (see GET /v1/categories). |
fileId | string | No | ID from POST /v1/vision. Required if no attributes are provided. |
attributes | object | No | Initial or partial attributes. Required if no fileId is provided. Enrichment merges them with derived values. |
Response (200):
{
"normalizedAttributes": { "..." : "..." },
"candidates": [ "..." ],
"enriched": [ "..." ],
"confidence": 0.92,
"warnings": [ "..." ]
}
Response fields explained
| Field | Description |
|---|---|
| normalizedAttributes | Merged result of your input + enriched values. Use directly as attributes in POST /v1/valuations. |
| enriched | Attributes that were derived (not only copied from input). Each item: attribute, value, confidence (0–1), source. |
| candidates | Possible values when the system is unsure. Same shape as enriched items. |
| confidence | Overall confidence (0–1) for the enrichment result. |
| warnings | Optional { "code": "...", "message": "..." } items (e.g. ambiguous options, conflicts). |
Enriched item shape:
{
"attribute": "strap",
"value": "steel",
"confidence": 0.95,
"source": "VISUAL_MATCH"
}
Examples by category
Wristwatch — image only
{
"category": "wristwatch",
"fileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Response (200):
{
"normalizedAttributes": {
"brand": "Rolex",
"model": "Submariner",
"strap": "steel",
"case": "steel",
"bezel": "steel",
"movement": "automatic",
"dialColor": "black",
"caseDiameter": 41
},
"candidates": [
{ "attribute": "referenceNumber", "value": "116610LN", "confidence": 0.75, "source": "watch-database" }
],
"enriched": [
{ "attribute": "strap", "value": "steel", "confidence": 0.9, "source": "VISUAL_MATCH" },
{ "attribute": "dialColor", "value": "black", "confidence": 0.85, "source": "VISUAL_MATCH" },
{ "attribute": "movement", "value": "automatic", "confidence": 0.7, "source": "MOST_POPULAR" }
],
"confidence": 0.82,
"warnings": [
{ "code": "AMBIGUOUS_OPTION", "message": "Multiple referenceNumber options available; send one to lock valuation range." }
]
}
Wristwatch — with initial attributes (brand + model)
Seeding brand and model lets enrichment narrow reference number and other fields more confidently.
{
"category": "wristwatch",
"fileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"attributes": {
"brand": "Rolex",
"model": "Submariner"
}
}
Response (200):
{
"normalizedAttributes": {
"brand": "Rolex",
"model": "Submariner",
"referenceNumber": "116610LN",
"strap": "steel",
"case": "steel",
"bezel": "steel",
"movement": "automatic",
"dialColor": "black",
"caseDiameter": 41
},
"candidates": [],
"enriched": [
{ "attribute": "referenceNumber", "value": "116610LN", "confidence": 0.92, "source": "WATCH_DATABASE" },
{ "attribute": "strap", "value": "steel", "confidence": 0.95, "source": "VISUAL_MATCH" }
],
"confidence": 0.91,
"warnings": []
}
Car — license plate from image
Vision detects the plate; Enrich calls the car registry to fill brand, model, color, year, mileage.
{
"category": "car",
"fileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"attributes": {}
}
Response (200):
{
"normalizedAttributes": {
"licensePlate": "ABC123",
"brand": "Volvo",
"model": "XC60",
"color": "black",
"yearOfManufacture": 2020,
"odometerReading": 52000
},
"candidates": [],
"enriched": [
{ "attribute": "brand", "value": "Volvo", "confidence": 1, "source": "car-registry" },
{ "attribute": "model", "value": "XC60", "confidence": 1, "source": "car-registry" }
],
"confidence": 1,
"warnings": []
}
Registry-sourced fields typically have confidence: 1. You may still need to supply fuelType, drive, gearbox, enginePower, and additionalWheelset for a full car valuation.
Using Enrich with Valuations
Pattern A: Enrich first, then valuate (two calls)
Use when you want to show the user the enriched attributes and let them edit before valuing.
RESP=$(curl -s -X POST https://api.gemmai.io/v1/vision \
-H "Content-Type: application/json" \
-d '{"imageUrl": "https://example.com/watch.jpg"}')
FILE_ID=$(echo "$RESP" | jq -r '.fileId')
Pattern B: Single valuate call (enrich inside)
Use when you want one round-trip and don't need to show enrichment details.
{
"category": "wristwatch",
"attributes": { "brand": "Rolex" },
"fileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
The server runs enrichment internally. The response contains the valuation and the attributes used after enrichment.
Warnings and confidence
confidence(0–1): Higher means the enriched attributes are more reliable. Low confidence often accompaniescandidatesorwarnings.AMBIGUOUS_OPTION: Several values are possible for a field; sending one narrows the valuation.CONFLICT_DERIVED: A value you sent conflicts with what was derived; consider showing both and letting the user choose.
Error handling
400 — Missing or invalid category:
{ "error": "category query param is required" }
400 — Invalid or missing fileId:
{ "error": "..." }
500 — Enrichment failed:
{ "error": "Enrichment failed" }
Typical causes: vision data missing for fileId, external service unavailable, or invalid category.