Profiles and consents

Consents — what to show the user

Only people who turned on participation themselves are added to the network. Add toggles with short explanations to your profile settings. Below are texts you can use as is; just change the app name.

“Show me in the Pereval network” — required

The toggle is off by default. Next to it, put a link to pereval.dating, which explains what the network is.

Show me to people from other apps Your profile (name, age, city, photos, bio) will be visible to users of other dating apps connected to the Pereval network. You chat with them right here in [Your app]. Your phone number and email are not sent to the network. The network receives coordinates from your app and stores rounded coordinates; other users do not receive coordinates. You can turn participation off at any time — new people from other apps won’t see you, and your chats stay. “Delete my data from the network” removes your profile and closes matches, but does not erase the other person’s chat history: it remains without your name and photos. Separate copies of messages may be retained to investigate reports.

“Open to chatting in other languages” — optional

Meet people who speak other languages Messages and profile bios can be translated automatically when the translation service is available. The original is always available; if translation fails, the original is shown.

“Worldwide” — optional

For people who want to meet someone from another city or country. Those who turn it on get the Worldwide feed (scope=world, see Feed) and appear in it themselves — but only to others who turned it on too. Offer it together with other languages: people from abroad usually speak a different one.

Meet people from other cities and countries Your feed gets a Worldwide tab — people from anywhere, no distance limit. Only people who turned it on too are there, and only they see you.

“Show distance to me” — optional

Off by default. Does not change the profile city. Other people’s cards get distance_km only if this person turned it on.

Show distance to me Others will see how many kilometres away you are. Your exact address is never shown.

Searching another city is a feed lat/lon parameter, not a city change on the profile (the city can still change only once a day).

What to send to the network

"consent": {
  "network": true,
  "cross_language": true,
  "world": false,
  "given_at": "2026-10-24T12:00:00Z",
  "text_version": "2026-10-24"
}
  • given_at — when the person actually turned on the toggle (store it on your side).
  • text_version — the version of the text they saw. Using the date the text changed works well. If the text changes substantively, ask for consent again and update the version.
  • Both values must be real. Uploading a user base without consent gets the platform disconnected — see the network rules.

Intents

intents says what the person is looking for. Two people meet in the feed only if they share an intent.

Value Intent
serious A serious relationship
casual Something casual
friendship Friendship, chatting
arrangement A relationship with a well-off partner

If omitted, it defaults to ["serious", "casual", "friendship"].

Relationships with a well-off partner

A separate, strictly opt-in category.

  • It’s enabled for your app when you join the network. Without that, profiles with arrangement are rejected (422).
  • arrangement_role is required: provider — ready to support a partner; seeker — looking for a well-off partner.
  • If two people share only arrangement, they see each other only with opposite roles.
  • The other person’s role is shown only to viewers who are in this category themselves.
  • Offering sex for money, price lists and “paid meetings” are forbidden in every category. A commercial report removes the member from the network at once.

User-facing text:

Looking for a relationship with a well-off partner / Ready to support a partner Only people who chose the opposite option will see you. This is about relationships, not services: offering paid meetings is forbidden and leads to a ban.

When to send a profile

Call PUT /v1/members/{external_id}:

  • when a person turns on participation in the network;
  • on any change to the profile, photos, preferences, city, languages or consents;
  • when a person has passed your photo verification — with verification or the network’s check.

The request is idempotent: sending the same profile again breaks nothing. Save the network_id from the response — it lets you recognize your user in other people’s feeds and avoid showing them to themselves.

The network translates the bio in the background, after the profile is saved. Until the translation is ready, other people’s feeds show the original.

First upload

When you connect, you may already have people who turned participation on. Send them in batches: PUT /v1/members, up to 100 profiles per request.

PUT /v1/members
{
  "items": [
    { "external_id": "user-123", "consent": { … }, "display_name": "Anna", … },
    { "external_id": "user-124", "consent": { … }, "display_name": "Olga", … }
  ]
}

Each profile is validated on its own: one bad profile doesn’t block the rest. The response has a result for each one, in the same order:

{
  "items": [
    { "external_id": "user-123", "network_id": "6f1c2b4e-…" },
    { "external_id": "user-124", "error": { "code": "invalid", "message": "birth_year: members must be 18+" } }
  ]
}

Only people who turned participation on themselves: never upload your whole user base.

Profile requirements

Field Rule
display_name 1–50 characters. First name only, no last name or contacts
birth_year Age 18+
gender male or female; the network matches people of the opposite gender
age_min, age_max 18 ≤ age_min ≤ age_max
languages ISO 639-1 codes (two letters, otherwise 422), the first one is primary. The person speaks these languages, so the network never translates them for this person; everything else is translated into the primary one. Translation languages — GET /v1/languages, 38 languages
city Name and country, or coordinates. The network rounds coordinates to ~1 km, but it’s better to send the city center right away. The city can change once a day
bio Up to 1000 characters
photos 1–9 public https:// URLs. No watermarks with contacts. The network may cache photos
videos optional: up to 3 clips next to the photos, not instead of them. Each has url (MP4, up to 15 seconds) and poster (a still). Omit or [] to clear
verification how and when you checked that the person matches the photos — method, provider, verified_at. Details below; or by the network’s check: provider: "pereval" and check_id (below)
photo_verified Before 0.15 — a “verified” flag. Still accepted as a claim with an unspecified method at the time it arrives; send verification instead
height_cm optional: height in centimeters, 120–230. Don’t know it — leave it out
show_distance off by default: other people’s cards may show distance_km

A validation error returns 422 with the field in message, for example "birth_year: members must be 18+".

Photo verification

The “photo verified” badge in other apps’ feeds and the verified_only filter use the photo_verified mark, which the network computes. You send a claim — how and when you checked the person:

"verification": { "method": "selfie", "provider": "own", "verified_at": "2026-10-20T14:03:00Z" }
Field Value
method selfie — a photo selfie (e.g. with a gesture); video — a video selfie; liveness — an automated liveness check; document — an ID with a face match; in_person — met in person; other
provider Who did the check: a vendor (e.g. Sumsub) or own. Up to 60 characters
verified_at When the check passed. Not in the future

The mark counts if:

  1. The network has approved your verification method. Describe how you verify photos when you connect; the network reviews the method once. Until it is approved, your users’ marks don’t count in the network. Platforms connected before 0.15 were approved on upgrade.
  2. None of the current photos is newer than the check. The photos a person joins the network with are covered by a check made before you connected — you don’t need to re-verify your users. A photo added after the check switches the mark off until you send a newer verified_at. The network recognises the same picture under a new URL by its content.

Whether the mark counts and why is in the PUT /v1/members response:

{ "network_id": "…", "photo_verified": false, "verification": "photos_changed" }
verification Meaning
accepted The mark counts
none No claim
no_photos No photos
partner_not_approved The network hasn’t approved your verification method yet. Never happens for claims by the network’s check
photos_changed A photo is newer than the check: verify the person again and send a newer verified_at

The network re-checks a sample of verified people and those with fake signals: “fake” reports, the same photo on another person, generated images. If a platform’s marks fail the re-checks, the network stops counting them for all of its users.

Photo check by the network

No verification of your own? Use the network’s photo check. It’s free. The person takes it on a network page: agrees to the comparison, shows the requested gesture to the camera and takes a picture — with the camera only, not from the gallery. The network compares the picture with each profile photo and tells you the result for each photo. What to do with the result is up to you.

You don’t need to store pictures or facial data — you never get them. The person’s identity is not established from the picture and no facial features are stored. The picture is never shown to anyone: if the check passes, it is deleted right away; if it fails, it is kept for 24 hours so the person can dispute the result; if disputed, until the network moderator decides. The consent on the page names both you and the network: the network compares the photos on your behalf.

1. Create a session — from your server, with your API key:

POST /v1/photo-checks
{
  "ref": "u_123",
  "lang": "en",
  "return_url": "https://your.app/verified",
  "photos": [
    { "id": "ph1", "url": "https://cdn.your.app/ph1.jpg" },
    { "id": "ph2", "url": "https://cdn.your.app/ph2.jpg" }
  ]
}
Field Meaning
ref How you will recognise the person in the result, usually their external_id. 1–200 characters
photos 1–9 profile photos — public https URLs. id is your photo identifier, the position by default. The network downloads the photos right away
lang Page language: ru or en
return_url Optional: an https address for the “Back” button at the end of the check

Reply 201 — the session, with the check page url and expires_at. At most 10 sessions per person a day (429 photo_check_limit); the comparison service is unavailable — 503 photo_check_off, retry later.

2. Open the url for the person — in the browser, a new tab or your app’s in-app window (a webview with camera access). The link is valid for 30 minutes and allows up to 5 attempts. The page can’t be embedded in an iframe on your site. Besides the event, the page passes the result to the window that opened it: postMessage({ type: "pereval.photo_check", status }).

3. The result comes as a photo_check.updated event — after each attempt, when the person disputes the result and when the moderator decides; go by the latest one. The same is in GET /v1/photo-checks/{id}:

{
  "id": "…", "ref": "u_123", "status": "partial", "attempts": 1,
  "checked_at": "2026-10-30T09:14:00Z", "dispute_until": "2026-10-31T09:14:00Z",
  "photos": [
    { "id": "ph1", "url": "https://cdn.your.app/ph1.jpg", "verdict": "match" },
    { "id": "ph2", "url": "https://cdn.your.app/ph2.jpg", "verdict": "no_match" }
  ]
}
status Meaning
created The person hasn’t taken the check yet
passed It’s them on every photo with a face
partial Some photos don’t look like the picture
failed Didn’t pass; why — in reason: no_match (no photo looks like them), no_face, many_faces, no_gesture (gesture not recognised), virtual_camera
disputed The person disputed the result; a network moderator decides — usually within 24 hours
resolved The moderator decided: the per-photo result is theirs, note is an explanation for the person
expired The link expired and the person never took the check

Per-photo verdict: match — the same person; no_match — doesn’t look like them; unsure — couldn’t compare reliably; no_face — no face, not counted.

4. The mark in the network. Once the check has passed (passed or resolved), send a claim that refers to it:

"verification": { "provider": "pereval", "check_id": "…" }

The network verifies that the check is yours, has passed and that all current profile photos were in it with a match or no_face verdict, at least one match. A photo is recognised by its URL or its content. Then the mark counts even if the network hasn’t approved your own verification method yet, and verified_at is the time of the check. Otherwise — 422 with the reason. A new photo after the check switches the mark off as before: take the person through the check again.

Changing the city

The city can change once a day. If you send a new city, or a location more than 50 km away, sooner than 24 hours after the previous change, the network returns 409 location_change_limited. Moving around within the city is not limited.

The profile is not updated in that case. Tell the person they can change the city in a day, and send the other changes with the previous city.

Photos

The network shows photos from your URLs. Requirements:

  • URLs are accessible without authentication and don’t expire (or update the profile when the URLs change);
  • EXIF metadata is stripped from the files — it can contain location;
  • the first photo is the main one and shows the face clearly.

Video

Production video is disabled until frame moderation exists. Check GET /v1/capabilities: when videos: false, nonempty videos is rejected. The following describes the protocol format, not a promise of availability in the live environment.

A short clip on the card, next to the photos. Photos stay required: face checks use them, and an app that does not play video still has a card.

"videos": [
  {
    "url": "https://cdn.example/u/1.mp4",
    "poster": "https://cdn.example/u/1.jpg"
  }
]
  • Up to three clips. A repeated url is 422.
  • url is a public MP4, at most 15 seconds and 20 MB. The file stays on your host; the feed carries the link.
  • poster is a still. Apps show it before playback, and apps that cannot play video show it instead.
  • The protocol has no mute flag. A clip starts silent. One switch in the viewing app turns sound on for every clip, not a flag on each one.
  • The poster is moderated like a photo. The network downloads the file and reads its duration; it does not decode frames. Not an MP4 — video_invalid, longer than 15 seconds — video_too_long, could not be downloaded — video_unavailable. The clip URL arrives in video on member.rejected.

Moderation

A new profile, or one with changed photos, clips, name or bio, is checked by the network before it appears in feeds — usually within seconds. Not allowed:

  • explicit photos;
  • insults, threats, obscenity, offers of paid meetings;
  • contact details — phone, link, messenger handle: people chat inside the apps;
  • photos that cannot be downloaded (after several attempts).

If a profile does not pass, you get the member.rejected event with the reason: photo_nudity, offensive_text, contact_info, photo_unavailable, video_invalid, video_too_long or video_unavailable. A photo or poster URL is in photo; a clip URL is in video. The profile is hidden and cannot like until you send a corrected one; resending the same profile does not trigger a new check. Photos and text that already passed are not checked again.

It’s better to check profiles on your side first: it’s easier for a person to fix the profile right away than after the network rejects it.

Activity

The feed favors people who were online recently and hides those inactive for more than 30 days. Report activity with POST /v1/members/{id}/active — no more than once every few minutes per user. A profile PUT also updates activity.

With many users, a batch is easier — every few minutes, for everyone who opened the app in that time:

POST /v1/activity
{ "external_ids": ["user-123", "user-124", "user-125"] }

Up to 1000 ids per request. The response is {"updated": 3}: how many members were found and updated. Unknown ids are skipped.

Turning off: hide, don’t delete

When a person turns participation off, send the same profile with consent.network: false. The network hides them instead of deleting:

  • the record and network_id stay — matches, conversations, dislikes and blocks are kept;
  • they are in nobody’s feed and get no feed themselves (409 member_hidden);
  • they can only like back someone who already liked them — that is a match right away; no super likes (409 member_hidden);
  • conversations in existing matches go on both ways;
  • photos are optional while hidden — they may have deleted them all.

Turned it on again — send consent.network: true: the person is visible again, with their whole history. Turning it on and off any number of times never creates new profiles.

When a hidden person replies to someone from the network (writes in a conversation or likes back), offer to come back: “Show you in the network again?” with “Reply and rejoin the network” and “Just reply”. Rejoin only on that tap: it is consent to show the profile again.

Deferred account deletion

If your app gives 30 days to restore an account, tell the network that the person is “deleting”:

POST /v1/members/{external_id}/deactivate

The profile disappears from feeds and “liked you”, matches are frozen: the other people’s platforms get match.frozen — show “Account deleted”, messaging is blocked (409 match_frozen). Nothing is erased. They came back — POST /v1/members/{external_id}/restore: everything is as it was, the others get match.unfrozen. Didn’t come back within 30 days — delete them (DELETE below); if you don’t, the network erases them itself: personal data must be destroyed no later than 30 days after consent is withdrawn.

Deletion

Call DELETE /v1/members/{external_id}?reason=account_deleted when a person deletes their account with you; ?reason=left_network (the default) when they tap “Delete my data from the network”. The network:

  • closes their matches: the other side receives match.closed with that reason and peer_deleted: true;
  • the conversations stay with the other people, like in Telegram — show them without the name and photo: “Account deleted” / “Left the network”;
  • erases the profile (name, photos, bio, city), likes, dislikes and blocks.

If the person turns participation on again, it will be a new profile without the old matches.

Unclear? Ask a developer

Read the reply and continue the conversation on this site using the private link you receive after sending. Incoming email is not accepted.