Search Flow
This guide describes a face search from the client's side: which calls to make, in what
order, what each response means, and where the credit is charged. For copy-paste curl
commands, see the Quickstart.
Overview
A search is asynchronous. The upload returns a searchId at once; the face search then runs
in the background. The client waits for
completed, shows the candidate matches, lets the user pick, and then reads the full
profiles.
Step 0 — Check the account
GET /users/me returns three fields that decide what the client may do next:
| Field | Meaning |
|---|---|
canSearch | false → the user must buy a plan before starting a new search. Treat only an explicit false as blocking. |
paymentStage | selection or results — which step charges the credit. Missing or null means selection. |
credits.available | Credits left to unlock results. |
Step 1 — Upload
POST /search/upload (multipart, field file) with a JPEG, PNG or HEIC photo.
| Response | Meaning |
|---|---|
200 {searchId, status: "processing", detectedFaces} | Search started. detectedFaces: 0 means no face was found. |
402 | Search limit reached: a user without a subscription has used the free searches. Upload never spends a credit. |
400 | No file, or the file is too large. |
Step 2 — Wait for the result
Poll GET /search/{searchId}/status every few seconds, or open
GET /search/{searchId}/status/stream, a Server-Sent Events stream that pushes the same
SearchStatusResponse object on every change.
status | Meaning | Next |
|---|---|---|
processing | The search is running. | Keep waiting. |
preview | An early partial result; thumbnail is set. | Keep waiting for completed. |
completed | Matches are ready. | Step 3. |
error | The search failed; see message. | Stop. |
Age restriction
If the status response has showAgeRestrictionPopup: true, show the user the age
restriction notice. After the user accepts, call
POST /search/{searchId}/age-restriction-consent (204). The notice is not shown again
for that search.
Step 3 — Matches
GET /search/{searchId}/matches returns candidates grouped by social network:
groups[]— one group per network (source), each with the first page of matches and anextCursorwhen there are more. Load the next page withGET /search/{searchId}/matches/{source}?cursor=<nextCursor>&limit=<n>.totalCount— matches across all networks;0means nothing was found.maxSelectable— the most matches the user may pick in step 4.
Match pictures are blurred and watermarked at this step. After selection this endpoint
returns 400; use the results endpoint instead.
Step 4 — Select
POST /search/{searchId}/select with {"matchIds": ["<id>", ...]} — the matches the user
picked, at most maxSelectable. An empty array means "none of these". Selection can be
made once per search.
| Response | Meaning |
|---|---|
200 | Selection saved. With paymentStage = selection, one credit was spent. |
402 | No credits available (paymentStage = selection only). The selection is rolled back; the user can buy credits and call select again. |
400 | Already selected, or more than maxSelectable IDs. |
Step 5 — Results
GET /search/{searchId}/results returns consensusName and profiles[] (source,
username, fullname, profilePicture, bio, profileUrl, isPrivate).
With paymentStage = results, the first call for a search spends the credit:
| Credits available | Already paid for this search | Response |
|---|---|---|
0 | no | 200, isBlurred: true — profile data is masked |
0 | yes | 200, full results |
> 0 | no | One credit is spent, 200, full results |
> 0 | yes | 200, full results — never charged twice |
This endpoint never returns 402. Calling it before step 4 returns 400.
Add ?getSocialprofiler=true to include the Social Profiler report once it is ready, or
call GET /search/{searchId}/socialprofiler (SSE: /socialprofiler/stream).
After the search
| Call | Purpose |
|---|---|
GET /search/history | Past searches, paginated with cursor and limit. |
GET /search/{searchId} | One search's details. |
DELETE /search/{searchId} | Remove a search from history. |
People can ask to be removed from Face2Social through the public opt-out form
(POST /optout). Removed profiles disappear from matches and results, including in
searches made earlier.