FaceCard Docs
API reference

POST /v1/match

Sign a user in by matching face descriptors against the app's enrolled users.

POST /v1/match

Compares 1 to 3 descriptors with the templates enrolled in your app. On a match, the owner of the matched template is signed in and receives a user token.

Credential: publishable key, from an allowed Origin.

Request body

{
  "challenge_id": "ch_...",
  "descriptors": [[0.012, -0.044, "... 128 floats in total"]],
  "liveness": { "score": 0.93, "checks": ["blink", "motion"] }
}
FieldTypeRules
challenge_idstringA fresh challenge.
descriptorsarray1 to 3 arrays, each exactly 128 finite floats.
livenessobjectAdvisory browser result.
curl -X POST https://api.facecard.dev/v1/match \
  -H "X-FaceCard-Key: fc_pk_live_xxx" \
  -H "Origin: https://app.example.com" \
  -H "Content-Type: application/json" \
  -d @match.json

Response

200 OK

{
  "user": {
    "id": "usr_...",
    "email": "ada@example.com",
    "name": "Ada",
    "created_at": "2026-10-14T12:00:00.000Z"
  },
  "token": "<jwt>",
  "expires_at": "2026-10-14T13:00:00.000Z",
  "confidence": 0.91
}

confidence is between 0.0 and 1.0. Matching rules (threshold and margin) are explained in Matching.

No match

401 Unauthorized

{ "error": { "code": "no_match", "message": "No matching face was found." } }

The message is generic on purpose. It never includes an email or any candidate data.

Errors

StatusCodeWhen
400invalid_requestMalformed body, wrong descriptor count or length.
400challenge_invalidThe challenge is missing, expired, already used or from another app.
401unauthorizedMissing or invalid key.
401no_matchNo candidate passed the threshold and margin.
403origin_not_allowedThe Origin is not on the allow list.
429rate_limitedMore than 30 requests a minute from this IP.
429plan_limit_reachedOver the monthly auth limit. A match that reaches face matching counts as one auth, success or failure.

On this page