API v1 (legacy)
v1 is maintained for existing integrations. New integrations should use v2. See Migrating from v1 to v2.
- Content type:
application/json - Authentication:
api-keyheader (Authentication) - v1's OpenAPI document (
/openapi.json,/docs) requires the API key.
Endpoints
| Method | Path | Model | Input | Status |
|---|---|---|---|---|
POST |
/invocations |
Latest model (bc-v1) |
Image only | Supported |
POST |
/invocations/bc-v1 |
bc-v1 |
Image only | Supported |
POST |
/invocations/bc-legacy |
Original mood model | Image or video | Deprecated (details) |
GET |
/ping |
— | — | Health check |
POST /invocations and POST /invocations/bc-v1
Both run the bc-v1 model on a single image and behave identically.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
threshold |
number | No | Threshold applied to the model's discomfort ("pain") probability. If omitted, the model default is used (currently 0.3). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
media_type |
string | No | Must be "image" (the default). "video" returns HTTP 400; any other value returns HTTP 422. |
media_data |
object | Yes | Container for the media |
media_data.image |
string | Yes in practice | Base64-encoded image. Standard base64 only, no data: prefix. If omitted, the request fails with success: false. |
media_data.video, media_data.frames_to_analyze, media_data.top_n_predictions |
— | No | Ignored by these endpoints (used only by the deprecated legacy endpoint) |
Example request
printf '{"media_type":"image","media_data":{"image":"%s"}}' "$(base64 < cat.jpg | tr -d '\n')" > v1_body.json
curl -X POST "$BASE_URL/invocations?threshold=0.3" \
-H "api-key: $API_KEY" \
-H "Content-Type: application/json" \
--data @v1_body.json
response = requests.post(
f"{BASE_URL}/invocations",
headers={"api-key": API_KEY},
params={"threshold": 0.3}, # optional
json={"media_type": "image", "media_data": {"image": image_b64}},
timeout=60,
)
result = response.json()
if result["success"]:
print(result["prediction"], result["probability"])
else:
print("No prediction:", result["message"])
v1 response schema
| Field | Type | Description |
|---|---|---|
mood_class |
integer | 1 = Unhappy (discomfort), 0 = Happy (comfort), -1 = no prediction |
prediction |
string | "Unhappy", "Happy", or "Unknown" |
probability |
number | Confidence in the predicted class (not the discomfort probability; see below). 0.0 when there's no prediction. |
threshold |
number | null | Threshold applied on success. On failures it is usually the threshold query parameter you sent (or null); don't rely on it when success is false. |
message |
string | "Success" or a description of why no prediction was made |
success |
boolean | true only when a prediction was made |
cat_quality |
number | null | Cat detector confidence (0.0–1.0), when available |
cat_detected |
boolean | true only when a cat was detected with confidence ≥ 0.69 |
additional_data |
object | null | Present on success, see below |
additional_data.input_dimensions |
string | Input size as "WIDTHxHEIGHT", e.g. "1028x1028" |
additional_data.detected_cat_dimensions |
string | Cropped cat size as "WIDTHxHEIGHT" |
additional_data.size_unit |
string | Always "pixels" |
additional_data.extraction_time |
number | Seconds spent detecting and cropping the cat |
additional_data.inference_time |
number | Seconds spent classifying |
additional_data.time_unit |
string | Always "seconds" |
additional_data.bounding_box_cat |
array | A list with one box { "x1", "y1", "x2", "y2" } (integer pixels, top-left origin) |
additional_data.model |
string | "BC-V1" |
version |
string | Fixed response-format date, "2023-11-22" |
inference_metadata |
object | null | { "version": "0.0.34", "build_number": "34" } on success; null on failures |
If a photo contains several cats, v1's
bounding_box_catmay not always correspond to the cat that was scored. v2 fixes this.
v1 response examples
Success
{
"mood_class": 1,
"prediction": "Unhappy",
"probability": 0.32395651936531067,
"threshold": 0.3,
"message": "Success",
"success": true,
"cat_quality": 0.9662923216819763,
"cat_detected": true,
"additional_data": {
"input_dimensions": "1028x1028",
"detected_cat_dimensions": "949x939",
"size_unit": "pixels",
"extraction_time": 0.7679755687713623,
"inference_time": 0.024747371673583984,
"time_unit": "seconds",
"bounding_box_cat": [ { "x1": 56, "y1": 74, "x2": 1005, "y2": 1013 } ],
"model": "BC-V1"
},
"version": "2023-11-22",
"inference_metadata": { "version": "0.0.34", "build_number": "34" }
}
Cat found but image quality too low (detector confidence between 0.5 and 0.69)
{
"mood_class": -1,
"prediction": "Unknown",
"probability": 0.0,
"threshold": null,
"message": "Cat image quality is too low",
"success": false,
"cat_quality": 0.6602507829666138,
"cat_detected": false,
"additional_data": null,
"version": "2023-11-22",
"inference_metadata": null
}
No cat detected
{
"mood_class": -1,
"prediction": "Unknown",
"probability": 0.0,
"threshold": null,
"message": "No cats detected",
"success": false,
"cat_quality": null,
"cat_detected": false,
"additional_data": null,
"version": "2023-11-22",
"inference_metadata": null
}
Understanding probability and threshold in v1
The model produces a discomfort ("pain") probability p between 0 and 1:
mood_class = 1("Unhappy") whenp > threshold, otherwisemood_class = 0("Happy").probabilityis the confidence in the returned class:- when
mood_class = 1:probability = p - when
mood_class = 0:probability = 1 − p
- when
So a result of Happy with probability: 0.9 means p = 0.1. To recover the discomfort probability from a v1 response:
p = result["probability"] if result["mood_class"] == 1 else 1 - result["probability"]
Don't compare probability directly with threshold. v2's prediction.score is p itself.
v1 errors
Most problems with v1 requests return HTTP 200 with success: false, mood_class: -1, and a message. Always check success.
| Situation | HTTP | Response |
|---|---|---|
| No cat found | 200 | success: false, message: "No cats detected" |
| Cat found with low confidence | 200 | success: false, message: "Cat image quality is too low", cat_quality set |
Image isn't a decodable image, or media_data.image missing |
200 | success: false, message: "Error loading image from base64 string" |
| Invalid base64 or other processing failure | 200 | success: false, message starting with "Error: " |
media_type: "video" on /invocations |
400 | {"detail": "The active model (bc-v1) only supports 'image' media type. For video analysis, use /invocations/bc-legacy."} |
media_type: "video" on /invocations/bc-v1 |
400 | {"detail": "BC-V1 endpoint only supports 'image' media type. For video analysis, use /invocations/bc-legacy."} |
| Missing or invalid API key | 401 | {"detail": "Invalid or missing API key"} |
Body missing media_data, media_type not "image"/"video", wrong types, or malformed JSON |
422 | Framework validation format: {"detail": [{"type": ..., "loc": [...], "msg": ..., ...}]}. May echo the submitted input. |
| Unexpected server error | 500 | Plain-text Internal Server Error |
| Platform overload, deploys, or timeouts | 429 / 502 / 503 / 504 | May not be JSON |
The retry guidance in Errors & retries applies to v1 as well.
Deprecated: POST /invocations/bc-legacy
Deprecated. Uses the original mood model and is not recommended for new or existing workloads. Pending: publish a removal date.
- Accepts
media_type: "image"or"video". - Image: same request as
POST /invocations(nothresholdparameter). The response has the same shape, withthresholdalwaysnull,additional_data.modelset to"BC-Legacy", andinference_metadataset tonull. - Video: send
media_data.video(base64-encoded MP4) with optionalframes_to_analyze(default20) andtop_n_predictions(default5). The response has the same top-level fields exceptthreshold.additional_datacontainsframes_extracted,top_n_predictions,input_dimensions,detected_cat_dimensions,total_extraction_time,total_prediction_time,bounding_box_cat,size_unit, andtime_unit. - Neither v1
bc-v1nor v2 supports video. For video, extract frames and send them as images to v2.
GET /ping
Health check. Requires the API key.
curl -H "api-key: $API_KEY" "$BASE_URL/ping"
{ "status": "healthy", "service": "sylvester-ml" }