Roam Moon Cloud

AI services

Integrate PPE detection

Send a photo of a scene and get back who is wearing what protective equipment, with a bounding box for every person and every item found.

Choose an endpoint

All three routes accept the same request and return the same response shape. Only which equipment types count toward compliance changes.

EndpointChecks for
POST /v1/ai/ppe-detection/detectFace and head coverings together. A person is compliant only when they wear both.
POST /v1/ai/ppe-detection/detect-maskFace coverings only.
POST /v1/ai/ppe-detection/detect-helmetHead coverings only, such as helmets and hard hats.

Request

Send multipart/form-data with one image:

FieldMeaning
imageimage is required. JPEG or PNG, up to 5 MB. Up to 15 people are scored.

Examples

This example calls the general endpoint; the other two are identical requests against a different URL.

curl -X POST https://core.roammoon.com/v1/ai/ppe-detection/detect \
  -H "X-API-Key: rm_live_YOUR_KEY" \
  -F "image=@site-entrance.jpg"

Response

Returns one entry per person found, each with its own bounding box and the equipment detected on it:

JSON
{
  "requiredEquipmentTypes": ["FACE_COVER", "HEAD_COVER"],
  "persons": [
    {
      "id": 0,
      "confidence": 99.8,
      "boundingBox": { "left": 0.12, "top": 0.05, "width": 0.31, "height": 0.62 },
      "compliant": true,
      "bodyParts": [
        {
          "name": "FACE",
          "confidence": 99.9,
          "equipment": [
            {
              "type": "FACE_COVER",
              "confidence": 98.5,
              "boundingBox": { "left": 0.18, "top": 0.09, "width": 0.14, "height": 0.11 },
              "covers": true,
              "coversConfidence": 99.1
            }
          ]
        }
      ]
    }
  ]
}
When nobody is in the photo

persons is an empty array. That is still a successful call and is still charged, because the API did its job and there was simply nobody to report on.

JSON
{
  "requiredEquipmentTypes": ["FACE_COVER"],
  "persons": []
}

Fields that matter

FieldMeaning
personsOne entry per person Rekognition found in the image, in no particular order.
persons[].complianttrue when this person wears every equipment type the endpoint checked for, false when at least one is missing, null when it could not be determined, most often because an item's own detection confidence fell under the platform's configured minimum, even though the item still appears in bodyParts.
persons[].bodyPartsFace and head, shown only when Rekognition actually located that body part.
bodyParts[].equipmentThe protective items detected on that body part.
equipment[].coversWhether the item actually covers the body part it was found near. A mask pulled down around the chin is still detected, but covers is false.
boundingBoxA fraction of the image's own width and height, 0–1, measured from the top-left corner. Draw it yourself on top of the image you already have, since this API never burns boxes into the image.

Billing

10 credits are charged only when a detection succeeds and a result is returned, on any of the three endpoints. Every failure is refunded, whether the image was rejected or the service itself could not complete the request.

The charge policy is charge-on-success: credit is reserved when the request is accepted and only committed once processing succeeds. A failure refunds the reservation.

Getting good results

  • Use the whole scene, not a per-person crop, since bounding boxes are relative to the image you send, so cropping tighter just shrinks what the model has to work with.
  • Distant or heavily occluded people are the most common cause of a missing or indeterminate compliant value. Get the camera closer or increase resolution before assuming the equipment isn't there.
  • This is equipment detection, not a safety certification. Treat it as a first pass that flags what to check, and keep a human in the loop before it drives an access or disciplinary decision.

Errors

Every error uses the same shape. Branch on code, not on message, because messages can change.

JSON
{
  "error": {
    "code": "INVALID_PPE_DETECTION_REQUEST",
    "message": "The \"image\" field must be an image file."
  }
}
HTTPCodeWhat to do
401API_KEY_REQUIREDThe X-API-Key header is missing.
401API_KEY_INVALIDThe key is wrong, disabled or expired. Check it or create a new one.
403API_KEY_FORBIDDENThe key is not permitted to use this service.
400INVALID_PPE_DETECTION_REQUESTThe "image" field is missing, empty, or Rekognition could not process it. No credit is charged.
402CREDIT_LIMIT_EXCEEDEDThe period's credits are exhausted. Upgrade or wait for the next period.
413IMAGE_TOO_LARGEThe image exceeds 5 MB. Compress or resize it.
415UNSUPPORTED_IMAGE_TYPEOnly JPEG and PNG are supported.
429RATE_LIMIT_EXCEEDEDPer-minute request limit exceeded. Slow down.
429PPE_DETECTION_SERVICE_BUSYThe detection service is saturated. Retry after a few seconds.
502PPE_DETECTION_UPSTREAM_ERRORThe PPE detection model could not complete the request. Retryable.
503PPE_DETECTION_SERVICE_MISCONFIGUREDThe service is not configured correctly. This is an operator problem, not something a retry fixes.

Retrying safely

429 and 502 are retryable, so use exponential backoff. Other errors return the same result on retry. Only a successful detection is charged, so retrying after a failure costs nothing extra. The exception is a network timeout: if the first attempt actually succeeded, the retry is charged as a second call.