Roam Moon Cloud

AI services

Integrate face comparison

Send two face photos and get back whether they belong to the same person, with a similarity score.

Request

Send multipart/form-data with both images:

FieldMeaning
sourceImagesourceImage is required. JPEG or PNG, up to 5 MB. The reference face.
targetImagetargetImage is required. JPEG or PNG, up to 5 MB. Compared against every face found in this image.

Examples

curl -X POST https://core.roammoon.com/v1/ai/face-comparison/compare \
  -H "X-API-Key: rm_live_YOUR_KEY" \
  -F "sourceImage=@id-card.jpg" \
  -F "targetImage=@selfie.jpg"

Response

Returns whether the two faces belong to the same person:

JSON
{
  "isSamePerson": true,
  "similarity": 97.52
}
When no match is found

similarity is null rather than 0, because there was nothing to score, whether the target image has no matching face or no face at all. isSamePerson is false either way.

JSON
{
  "isSamePerson": false,
  "similarity": null
}

Fields that matter

FieldMeaning
isSamePersontrue once at least one face in targetImage matches sourceImage.
similarityThe highest match confidence found, 0–100. null when isSamePerson is false.

Billing

10 credits are charged only when the comparison succeeds and a result is returned. Every failure is refunded, whether the images were 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 accuracy

  • Well-lit, front-facing photos where the face is a meaningful part of the frame. Extreme angles and heavy shadow are the most common cause of missed matches.
  • sourceImage should contain exactly the face you are checking against, and if it has several faces, the largest one is used.
  • This is a probabilistic comparison, not identity verification. Treat a low-confidence result as inconclusive rather than a definitive no-match, and keep a human in the loop for anything that affects a person's rights or access.

Errors

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

JSON
{
  "error": {
    "code": "NO_FACE_DETECTED",
    "message": "No face was detected in one of the images."
  }
}
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_FACE_COMPARISON_REQUESTThe sourceImage or targetImage field is missing or empty. No credit is charged.
400NO_FACE_DETECTEDNo face was detected in one of the images. 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.
429FACE_COMPARISON_SERVICE_BUSYThe comparison service is saturated. Retry after a few seconds.
502FACE_COMPARISON_UPSTREAM_ERRORThe face comparison model could not complete the request. Retryable.
503FACE_COMPARISON_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 comparison 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.