Subjects
Enroll a reference face
PUT https://api.xipid.org/subjects/{id}/reference-face
Enrolls the face a selfie is matched to: one JPEG or PNG of at most 4 MB, in Base64, holding exactly one face, which replaces the face this brand enrolled before. Until the person accepts, it is held with the referral; once they have, it goes on file only where no face of their own is. XipID never sends it back: the subject shows when it was enrolled. With If-Match, it goes ahead only while the subject is as the brand last read it. The body may hold 6 MB, every other route's 1 MB.
Scope: any live key of the brand.
Limits: 1,000 requests a minute per key and 2,000 requests a minute per source address; every answer says what is left in X-RateLimit-Remaining, and a refusal when to come back in Retry-After.
Idempotency: repeating it does what it did, and no more.
Changes: 2026-09-26: added.
Parameters
idXipID's id for the subject.
If-MatchThe
ETagof the subject as the brand last read it, or a list of them: the change goes ahead only while the subject is as one says, and is refused412otherwise.Xip-VersionThe version to answer in; when absent, the version the brand's org is pinned to.
2026-09-26: The first version: challenges, subjects and events, and the signed outcome.
Body
image
{
"image": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA=="
}
Answers
200 OK
The subject, read back once the face went on file.
Its headers: X-Request-Id, Xip-Version, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, ETag.
idreferencestatusWhere the referral stands for the brand; the last three are final.
pending: Waiting on the person to accept.linked: The person accepted: the brand has their pairwise identifier and may challenge them.declined: The person declined. Final.expired: Unanswered for thirty days. Final.unlinked: The person took the brand's access back. Final.
pairwise_idlinked_atinvite_urldisplay_namechanneltypeThe channel the brand referred the person by.
phone: A phone number.email: An email address.
to_masked
scopesattributeWhat the scope lets the brand do with the person.
presence: Ask them to confirm it is really them, by a challenge.name: See their name.date_of_birth: See their date of birth.email: See their email address.phone: See their phone number.address: See their address.tier: See their verification tier.ssn_match: Check that a Social Security number the brand holds is theirs.
purpose
reference_faceenrolled_at
created_atupdated_at
{
"id": "01JD2R2B4D6F8H0J2K4M6N8P0Q",
"reference": "acct_4417",
"status": "linked",
"pairwise_id": "Vb3kQ9xR2mTz7LpW4nYc8d",
"linked_at": "2026-11-18T15:42:55.020Z",
"display_name": "Sam Rivera",
"channel": {
"type": "phone",
"to_masked": "+1 ••• ••• 0142"
},
"scopes": [
{
"attribute": "presence",
"purpose": "wire_approval"
}
],
"reference_face": {
"enrolled_at": "2026-11-18T16:01:13.668Z"
},
"created_at": "2026-11-18T15:20:07.311Z",
"updated_at": "2026-11-18T16:01:13.668Z"
}
Errors
json_invalid, 400: The request body is not valid JSON.parameter_missing, 400: The request lacks a required parameter.parameter_invalid, 400: The request contains invalid parameters.parameter_unknown, 400: The request contains a parameter this route does not take.version_invalid, 400: Xip-Version names no released version of this API.authentication_required, 401: Authentication is required.authentication_failed, 401: The credential is invalid, expired or revoked.insufficient_scope, 403: The credential does not allow this operation.resource_not_found, 404: No such resource.resource_conflict, 409: The resource's state conflicts with the request; read it again.reference_face_on_file, 409: The person has a face on file that this brand did not enroll, and it stays.precondition_failed, 412: If-Match does not match the resource's current ETag.content_too_large, 413: The request body is larger than this route accepts.media_type_unsupported, 415: This route does not accept that Content-Type.reference_face_unusable, 422: The image cannot be a reference face.rate_limit_exceeded, 429: Too many requests; try again later.internal_error, 500: Something went wrong on our side.upstream_error, 502: A service XipID depends on failed.service_unavailable, 503: The service is temporarily unavailable.upstream_timeout, 504: A service XipID depends on did not answer in time.