ShrimpCount AI

API Integration Guide

Integrate shrimp detection, counting, and weight estimation into your app. Send a photo, get back per-shrimp detections with segmentation masks, skeleton length, and estimated weight in grams.

Base URLhttps://shrimp-ai.durrowjones.com/apiLive Swagger playground

Authentication

POST /predict requires an API key sent in the X-API-Key header on every request. The key is configured server-side as API_KEY in backend/.env — ask the team operating this service for your key. Keep it on your server; never ship it to browsers or mobile clients.

http
X-API-Key: <your-api-key>

Health (GET /) and GET /backends need no key, so load balancers and uptime checks work unauthenticated.

POST/predict

Multipart upload of one image. Runs the local YOLOv8-seg model with Poly-Ridge weight estimation and returns detections for every shrimp (and calibration marker) found. For weight estimation the photo must contain the standard calibration marker and be shot top-down.

Query parameters

NameTypeDescription
capture_tilt_degnumberoptionalDevice tilt in degrees at capture time, from phone sensors. Adds a quality warning when past tolerance. Omit for plain uploads.

Body (multipart/form-data)

filefilerequiredThe image (JPEG/PNG). Content-Type must be an image type or the request is rejected with 400.

Response — 200 OK

count is the total number of detections including calibration markers — filter predictions by class_name === "shrimp" (or by weight_g != null) for shrimp-only counts. warnings carries non-fatal quality advisories (missing marker, high tilt). Fields like weight_g, length_mm, area_mm2 are null when the scale marker is not detected.

json
{
  "predictions": [
    {
      "x": 512.4, "y": 380.1,
      "width": 210.0, "height": 96.5,
      "confidence": 0.92,
      "class_name": "shrimp",
      "class_id": 0,
      "detection_id": "a1b2c3",
      "points": [{ "x": 410.0, "y": 350.2 }, ...],
      "skeleton_points": [{ "x": 415.1, "y": 372.0 }, ...],
      "length_mm": 84.3,
      "area_mm2": 612.7,
      "weight_g": 7.9,
      "scale_mm_per_px": 0.212
    }
  ],
  "count": 1,
  "class_counts": { "shrimp": 1 },
  "image_width": 3024,
  "image_height": 4032,
  "inference_time_ms": 842.5,
  "inference_type": "local_seg",
  "warnings": []
}

Examples

curl
curl -X POST "https://shrimp-ai.durrowjones.com/api/predict" \
  -H "X-API-Key: $SHRIMP_API_KEY" \
  -F "file=@shrimp_photo.jpg"
python
import os
import requests

API_URL = "https://shrimp-ai.durrowjones.com/api"
API_KEY = os.environ["SHRIMP_API_KEY"]

with open("shrimp_photo.jpg", "rb") as f:
    resp = requests.post(
        f"{API_URL}/predict",
        headers={"X-API-Key": API_KEY},
        files={"file": ("shrimp_photo.jpg", f, "image/jpeg")},
        timeout=60,
    )
resp.raise_for_status()
result = resp.json()

print(f"Shrimp count: {result['count']}")
for det in result["predictions"]:
    if det.get("weight_g") is not None:
        print(f"  {det['class_name']}: {det['weight_g']:.1f} g "
              f"({det['length_mm']:.0f} mm)")
typescript
const API_URL = "https://shrimp-ai.durrowjones.com/api";
const API_KEY = process.env.SHRIMP_API_KEY!; // keep server-side

async function countShrimp(image: File | Blob, filename: string) {
  const form = new FormData();
  form.append("file", image, filename);

  const res = await fetch(`${API_URL}/predict`, {
    method: "POST",
    headers: { "X-API-Key": API_KEY },
    body: form,
  });

  if (!res.ok) {
    const err = await res.json().catch(() => null);
    throw new Error(err?.detail ?? `HTTP ${res.status}`);
  }

  return res.json(); // PredictionResponse
}

Errors

StatusMeaning
400Not an image, or the backend rejected the input. See detail.
401Missing or invalid X-API-Key header.
503Server has no API_KEY configured, or the selected inference backend is unavailable.
500Unexpected failure while processing the image.

All errors are JSON: { "detail": "<message>" }