Справочник API
Сгенерировано из закреплённой спецификации OpenAPI 1.0.0. Это релизный контракт, не подтверждение версии публичного API: перед включением возможностей проверьте GET /v1/capabilities своего контура. Описания запросов — на английском, как в спецификации. openapi.yaml · llms-full.txt
Первый стабильный контракт API 1.0.0, включая дополнительные услуги. Исходный коммит Net: da2b28b41924. Версии релизов Site и Via независимы от версии контракта API.
Для подтверждения заказа, даже нулевого, нужен отдельный X-Commerce-Key. Подключение рабочего партнёра явное; до него сохраняется старый контракт суперлайков и отмен. Услуги и порядок подключения
Доступ
| Адрес | https://api.pereval.dating — для тестового и боевого контуров, контур определяет ключ |
| Авторизация | Authorization: Bearer <api_key> — только с вашего сервера |
| Формат | JSON, UTF-8, время RFC 3339 UTC |
| Ошибки | {"error": "<code>", "message": "…"} — все коды |
| Лимит | 600 запросов в минуту на площадку; лента — 200 анкет на участника в сутки |
Участники
Push, update and remove your users' network profiles.
Add or update members in a batch
PUT/v1/members
Up to 100 members per request, each validated on its own — one bad profile doesn't block the rest. Use it for the first upload of users who turned the network on.
curl -X PUT 'https://api.pereval.dating/v1/members' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"external_id": "string",
"consent": {
"network": true,
"cross_language": false,
"world": false,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "string"
},
"display_name": "string",
"birth_year": 1,
"gender": "male",
"age_min": 18,
"age_max": 1,
"languages": [
"string"
],
"city": {
"name": "string",
"country": "string",
"lat": 1.5,
"lon": 1.5
},
"bio": "string",
"photos": [
"https://example.com/photo.jpg"
],
"videos": [
{
"url": "https://example.com/photo.jpg",
"poster": "https://example.com/photo.jpg"
}
],
"photo_verified": false,
"verification": {
"method": "selfie",
"provider": "string",
"verified_at": "2026-10-24T12:00:00Z",
"check_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
},
"intents": [
"serious",
"casual",
"friendship"
],
"arrangement_role": "provider",
"last_active_at": "2026-10-24T12:00:00Z",
"height_cm": 120,
"show_distance": false
}
]
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/members');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'items' => [[
'external_id' => 'string',
'consent' => [
'network' => true,
'cross_language' => false,
'world' => false,
'given_at' => '2026-10-24T12:00:00Z',
'text_version' => 'string',
],
'display_name' => 'string',
'birth_year' => 1,
'gender' => 'male',
'age_min' => 18,
'age_max' => 1,
'languages' => ['string'],
'city' => [
'name' => 'string',
'country' => 'string',
'lat' => 1.5,
'lon' => 1.5,
],
'bio' => 'string',
'photos' => ['https://example.com/photo.jpg'],
'videos' => [[
'url' => 'https://example.com/photo.jpg',
'poster' => 'https://example.com/photo.jpg',
]],
'photo_verified' => false,
'verification' => [
'method' => 'selfie',
'provider' => 'string',
'verified_at' => '2026-10-24T12:00:00Z',
'check_id' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
],
'intents' => ['serious', 'casual', 'friendship'],
'arrangement_role' => 'provider',
'last_active_at' => '2026-10-24T12:00:00Z',
'height_cm' => 120,
'show_distance' => false,
]],
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.put(
"https://api.pereval.dating/v1/members",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"items": [
{
"external_id": "string",
"consent": {
"network": True,
"cross_language": False,
"world": False,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "string"
},
"display_name": "string",
"birth_year": 1,
"gender": "male",
"age_min": 18,
"age_max": 1,
"languages": [
"string"
],
"city": {
"name": "string",
"country": "string",
"lat": 1.5,
"lon": 1.5
},
"bio": "string",
"photos": [
"https://example.com/photo.jpg"
],
"videos": [
{
"url": "https://example.com/photo.jpg",
"poster": "https://example.com/photo.jpg"
}
],
"photo_verified": False,
"verification": {
"method": "selfie",
"provider": "string",
"verified_at": "2026-10-24T12:00:00Z",
"check_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
},
"intents": [
"serious",
"casual",
"friendship"
],
"arrangement_role": "provider",
"last_active_at": "2026-10-24T12:00:00Z",
"height_cm": 120,
"show_distance": False
}
]
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"items": [
{
"external_id": "string",
"consent": {
"network": true,
"cross_language": false,
"world": false,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "string"
},
"display_name": "string",
"birth_year": 1,
"gender": "male",
"age_min": 18,
"age_max": 1,
"languages": [
"string"
],
"city": {
"name": "string",
"country": "string",
"lat": 1.5,
"lon": 1.5
},
"bio": "string",
"photos": [
"https://example.com/photo.jpg"
],
"videos": [
{
"url": "https://example.com/photo.jpg",
"poster": "https://example.com/photo.jpg"
}
],
"photo_verified": false,
"verification": {
"method": "selfie",
"provider": "string",
"verified_at": "2026-10-24T12:00:00Z",
"check_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
},
"intents": [
"serious",
"casual",
"friendship"
],
"arrangement_role": "provider",
"last_active_at": "2026-10-24T12:00:00Z",
"height_cm": 120,
"show_distance": false
}
]
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"items": [
{
"external_id": "string",
"consent": {
"network": true,
"cross_language": false,
"world": false,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "string"
},
"display_name": "string",
"birth_year": 1,
"gender": "male",
"age_min": 18,
"age_max": 1,
"languages": [
"string"
],
"city": {
"name": "string",
"country": "string",
"lat": 1.5,
"lon": 1.5
},
"bio": "string",
"photos": [
"https://example.com/photo.jpg"
],
"videos": [
{
"url": "https://example.com/photo.jpg",
"poster": "https://example.com/photo.jpg"
}
],
"photo_verified": false,
"verification": {
"method": "selfie",
"provider": "string",
"verified_at": "2026-10-24T12:00:00Z",
"check_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
},
"intents": [
"serious",
"casual",
"friendship"
],
"arrangement_role": "provider",
"last_active_at": "2026-10-24T12:00:00Z",
"height_cm": 120,
"show_distance": false
}
]
}`)
req, _ := http.NewRequestWithContext(ctx, "PUT", "https://api.pereval.dating/v1/members", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| itemsобязательно object[] | 1–100 items |
| external_idобязательно string | Your user id · 1–128 chars |
| consentобязательно object | |
| networkобязательно boolean | The user enabled "show me in the network". false hides the member (see the upsert) instead of being rejected |
| cross_language boolean | The user agreed to chat with people speaking other languages (machine translation) · default false |
| world boolean | The user wants to meet people from other cities and countries — the scope=world feed. Opt-in only, off by default · default false |
| given_atобязательно string (date-time) | When the user actually turned it on |
| text_versionобязательно string | Version of the consent text the user saw, e.g. its date |
| display_nameобязательно string | 1–50 chars |
| birth_yearобязательно integer | Members must be 18+ |
| genderобязательно "male" | "female" | Matches are always of the opposite gender; there is no "seeking" field (ignored if sent) |
| age_minобязательно integer | ≥ 18 |
| age_maxобязательно integer | |
| languagesобязательно string[] | First is the main language: profiles and messages are translated into it. Languages listed here are never
translated for this member. Translation languages — GET /v1/languages (38 in v0.8); other ISO 639-1 codes
are accepted, names such as Russian are rejected with 422.
· ≥ 1 items |
| cityобязательно object | Name or coordinates required. Can change once a day. |
| name string | |
| country string | ISO 3166-1 alpha-2 |
| lat number | |
| lon number | |
| bio string | ≤ 1000 chars |
| photosобязательно string (uri)[] | Public HTTPS URLs; 1–9 while visible, may be empty while hidden · ≤ 9 items |
| videos object[] | Short clips shown on the card next to photos, not instead of them. Omit or send [] to clear.
production rejects all nonempty video input with 422 until frame moderation exists.
Inspect the videos capability; the following format is for isolated development only.
Each clip is an MP4 up to 15 seconds and 20 MB, plus a poster image. The file stays on your host.
There is no mute flag: the viewing app starts clips silent and has one switch for every clip.
Posters are moderated like photos. A clip that is not an MP4, is longer, or cannot be downloaded
rejects the profile (video_invalid, video_too_long, video_unavailable).
· ≤ 3 items |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verified boolean | Before 0.15 — "you verified the person matches the photos". Still accepted: without verification it is a claim
with an unspecified method made when the network receives it. Send verification instead.
· default false |
| verification object | How and when you checked that the person matches their photos. The network turns it into the
photo_verified mark that other apps see, if (1) the network has approved your verification method — describe it
when you connect, the network reviews it once — and (2) none of the current photos is newer than verified_at.
Photos the person joins the network with are covered by an earlier check too; a photo added later switches the
mark off until you send a newer verified_at. The same picture under a new URL is recognised by its content.
The network re-checks a sample of verified people and those with fake signals (reports, the same photo on another
person, generated images); if your marks fail, the network stops counting them for all your users.
Omit (and photo_verified: false) — no claim.
— or a claim by the network's photo check: {"provider": "pereval", "check_id": "…"}. The network
verifies that the check is yours, has passed and covers all current photos (each with a match or no_face
verdict, at least one match, recognised by URL or content); then the mark counts even if your own method isn't
approved, and verified_at is the time of the check. method and verified_at are then ignored.
|
| method "selfie" | "video" | "liveness" | "document" | "in_person" | "other" | 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 |
| provider string | Who did the check: a vendor (e.g. Sumsub), own, or pereval — the network's photo check (with check_id) · ≤ 60 chars |
| verified_at string (date-time) | When the check passed. Not in the future. |
| check_id string (uuid) | id of a passed photo-check session of yours, less than 60 days from original creation. An expired/deleted reference returns 422 invalid; do not retry it or automatically create a replacement check. Omit a stale reference on subsequent upserts. Already accepted verification of unchanged photos is independent of case material retention; expiry does not approve any new photos. |
| intents "serious" | "casual" | "friendship" | "arrangement"[] | What the member is looking for. Two members are matched only if they share an intent.
arrangement — a relationship with a well-off partner — is opt-in only, requires your app to have the category
enabled, and requires arrangement_role. Members whose only shared intent is arrangement are matched only
with the opposite role. Offering money for sex is forbidden in every category.
· default ["serious","casual","friendship"] |
| arrangement_role "provider" | "seeker" | With the arrangement intent: provider — ready to support a partner; seeker — looking for a well-off partner |
| last_active_at string (date-time) | |
| height_cm integer | Height in cm · 120–230 |
| show_distance boolean | Others may see distance_km to this person. Off by default. Does not change the city. · default false |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| external_idобязательно string | |
| network_id string (uuid) | Present when stored |
| photo_verified boolean | Whether the verification mark counts — see the single upsert |
| verification "accepted" | "none" | "no_photos" | "partner_not_approved" | "photos_changed" | Why the verification mark counts or not: accepted; none — no claim; no_photos;
partner_not_approved — the network hasn't approved your verification method yet (never for claims by the network's
photo check, ); photos_changed — a photo is
newer than verified_at: check the person again and send a newer verified_at.
|
| error object | Present when this item was rejected |
| code "invalid" | "location_change_limited" | |
| message string |
message says which fieldAdd or update a member
PUT/v1/members/{external_id}
Idempotent upsert by external_id. Call it when a user opts in and whenever their profile, photos,
preferences or consents change.
Hidden members. consent.network: false hides the member instead of removing them: the same
network_id, matches, conversations, dislikes and blocks stay; the member is not in anyone's feed and gets no feed
(409 member_hidden); they can only like back someone who already liked them (that is a match), no super likes.
Messages in existing matches flow both ways. Photos are optional while hidden. Send consent.network: true again
and the member is visible with all their history. Use this when the user turns the network off; use DELETE only
to erase their network data (an explicit "delete my data from the network" or account deletion).
Coordinates are rounded to 0.01° (~1 km) by the network; send city-level precision anyway.
The city may change once a day: a new city (or a move over 50 km) sooner than 24 h after the previous change
returns 409 location_change_limited. The bio's language is detected by the network; the bio is translated
on demand into the main languages of members who are reading the feed.
Moderation. A new profile, or one with changed photos, name or bio, is checked before it
appears in feeds — usually within seconds. Explicit photos, insults or obscenity, contact details (phone, link,
messenger handle) and photos that cannot be downloaded are not allowed. On rejection you get member.rejected
with the reason; 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.
curl -X PUT 'https://api.pereval.dating/v1/members/user-123' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"consent": {
"network": true,
"cross_language": true,
"world": false,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "2026-10-24"
},
"display_name": "Anna",
"birth_year": 1994,
"gender": "female",
"age_min": 28,
"age_max": 40,
"languages": [
"ru",
"en"
],
"city": {
"name": "Moscow",
"country": "RU",
"lat": 55.75,
"lon": 37.62
},
"bio": "Hiking, jazz and good coffee",
"photos": [
"https://cdn.example-dating.app/u/123/1.jpg"
],
"photo_verified": true,
"height_cm": 168
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'consent' => [
'network' => true,
'cross_language' => true,
'world' => false,
'given_at' => '2026-10-24T12:00:00Z',
'text_version' => '2026-10-24',
],
'display_name' => 'Anna',
'birth_year' => 1994,
'gender' => 'female',
'age_min' => 28,
'age_max' => 40,
'languages' => ['ru', 'en'],
'city' => [
'name' => 'Moscow',
'country' => 'RU',
'lat' => 55.75,
'lon' => 37.62,
],
'bio' => 'Hiking, jazz and good coffee',
'photos' => ['https://cdn.example-dating.app/u/123/1.jpg'],
'photo_verified' => true,
'height_cm' => 168,
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.put(
"https://api.pereval.dating/v1/members/user-123",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"consent": {
"network": True,
"cross_language": True,
"world": False,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "2026-10-24"
},
"display_name": "Anna",
"birth_year": 1994,
"gender": "female",
"age_min": 28,
"age_max": 40,
"languages": [
"ru",
"en"
],
"city": {
"name": "Moscow",
"country": "RU",
"lat": 55.75,
"lon": 37.62
},
"bio": "Hiking, jazz and good coffee",
"photos": [
"https://cdn.example-dating.app/u/123/1.jpg"
],
"photo_verified": True,
"height_cm": 168
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"consent": {
"network": true,
"cross_language": true,
"world": false,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "2026-10-24"
},
"display_name": "Anna",
"birth_year": 1994,
"gender": "female",
"age_min": 28,
"age_max": 40,
"languages": [
"ru",
"en"
],
"city": {
"name": "Moscow",
"country": "RU",
"lat": 55.75,
"lon": 37.62
},
"bio": "Hiking, jazz and good coffee",
"photos": [
"https://cdn.example-dating.app/u/123/1.jpg"
],
"photo_verified": true,
"height_cm": 168
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"consent": {
"network": true,
"cross_language": true,
"world": false,
"given_at": "2026-10-24T12:00:00Z",
"text_version": "2026-10-24"
},
"display_name": "Anna",
"birth_year": 1994,
"gender": "female",
"age_min": 28,
"age_max": 40,
"languages": [
"ru",
"en"
],
"city": {
"name": "Moscow",
"country": "RU",
"lat": 55.75,
"lon": 37.62
},
"bio": "Hiking, jazz and good coffee",
"photos": [
"https://cdn.example-dating.app/u/123/1.jpg"
],
"photo_verified": true,
"height_cm": 168
}`)
req, _ := http.NewRequestWithContext(ctx, "PUT", "https://api.pereval.dating/v1/members/user-123", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
Тело запроса
| Поле | Описание |
|---|---|
| consentобязательно object | |
| networkобязательно boolean | The user enabled "show me in the network". false hides the member (see the upsert) instead of being rejected |
| cross_language boolean | The user agreed to chat with people speaking other languages (machine translation) · default false |
| world boolean | The user wants to meet people from other cities and countries — the scope=world feed. Opt-in only, off by default · default false |
| given_atобязательно string (date-time) | When the user actually turned it on |
| text_versionобязательно string | Version of the consent text the user saw, e.g. its date |
| display_nameобязательно string | 1–50 chars |
| birth_yearобязательно integer | Members must be 18+ |
| genderобязательно "male" | "female" | Matches are always of the opposite gender; there is no "seeking" field (ignored if sent) |
| age_minобязательно integer | ≥ 18 |
| age_maxобязательно integer | |
| languagesобязательно string[] | First is the main language: profiles and messages are translated into it. Languages listed here are never
translated for this member. Translation languages — GET /v1/languages (38 in v0.8); other ISO 639-1 codes
are accepted, names such as Russian are rejected with 422.
· ≥ 1 items |
| cityобязательно object | Name or coordinates required. Can change once a day. |
| name string | |
| country string | ISO 3166-1 alpha-2 |
| lat number | |
| lon number | |
| bio string | ≤ 1000 chars |
| photosобязательно string (uri)[] | Public HTTPS URLs; 1–9 while visible, may be empty while hidden · ≤ 9 items |
| videos object[] | Short clips shown on the card next to photos, not instead of them. Omit or send [] to clear.
production rejects all nonempty video input with 422 until frame moderation exists.
Inspect the videos capability; the following format is for isolated development only.
Each clip is an MP4 up to 15 seconds and 20 MB, plus a poster image. The file stays on your host.
There is no mute flag: the viewing app starts clips silent and has one switch for every clip.
Posters are moderated like photos. A clip that is not an MP4, is longer, or cannot be downloaded
rejects the profile (video_invalid, video_too_long, video_unavailable).
· ≤ 3 items |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verified boolean | Before 0.15 — "you verified the person matches the photos". Still accepted: without verification it is a claim
with an unspecified method made when the network receives it. Send verification instead.
· default false |
| verification object | How and when you checked that the person matches their photos. The network turns it into the
photo_verified mark that other apps see, if (1) the network has approved your verification method — describe it
when you connect, the network reviews it once — and (2) none of the current photos is newer than verified_at.
Photos the person joins the network with are covered by an earlier check too; a photo added later switches the
mark off until you send a newer verified_at. The same picture under a new URL is recognised by its content.
The network re-checks a sample of verified people and those with fake signals (reports, the same photo on another
person, generated images); if your marks fail, the network stops counting them for all your users.
Omit (and photo_verified: false) — no claim.
— or a claim by the network's photo check: {"provider": "pereval", "check_id": "…"}. The network
verifies that the check is yours, has passed and covers all current photos (each with a match or no_face
verdict, at least one match, recognised by URL or content); then the mark counts even if your own method isn't
approved, and verified_at is the time of the check. method and verified_at are then ignored.
|
| method "selfie" | "video" | "liveness" | "document" | "in_person" | "other" | 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 |
| provider string | Who did the check: a vendor (e.g. Sumsub), own, or pereval — the network's photo check (with check_id) · ≤ 60 chars |
| verified_at string (date-time) | When the check passed. Not in the future. |
| check_id string (uuid) | id of a passed photo-check session of yours, less than 60 days from original creation. An expired/deleted reference returns 422 invalid; do not retry it or automatically create a replacement check. Omit a stale reference on subsequent upserts. Already accepted verification of unchanged photos is independent of case material retention; expiry does not approve any new photos. |
| intents "serious" | "casual" | "friendship" | "arrangement"[] | What the member is looking for. Two members are matched only if they share an intent.
arrangement — a relationship with a well-off partner — is opt-in only, requires your app to have the category
enabled, and requires arrangement_role. Members whose only shared intent is arrangement are matched only
with the opposite role. Offering money for sex is forbidden in every category.
· default ["serious","casual","friendship"] |
| arrangement_role "provider" | "seeker" | With the arrangement intent: provider — ready to support a partner; seeker — looking for a well-off partner |
| last_active_at string (date-time) | |
| height_cm integer | Height in cm · 120–230 |
| show_distance boolean | Others may see distance_km to this person. Off by default. Does not change the city. · default false |
Ответы
| Поле | Описание |
|---|---|
| network_idобязательно string (uuid) | The member's id in the network. Stable across updates. |
| photo_verified boolean | Whether the verification mark counts: other apps see it and verified_only keeps the person |
| verification "accepted" | "none" | "no_photos" | "partner_not_approved" | "photos_changed" | Why the verification mark counts or not: accepted; none — no claim; no_photos;
partner_not_approved — the network hasn't approved your verification method yet (never for claims by the network's
photo check, ); photos_changed — a photo is
newer than verified_at: check the person again and send a newer verified_at.
|
location_change_limited — the city can change once a daymessage says which fieldErase a member from the network
DELETE/v1/members/{external_id}
Call when the user deletes their account or asks to delete their data from the network (to just turn the network
off, send consent.network: false — see the upsert). Their open matches are closed: the other platforms get
match.closed with reason (account_deleted or left_network) and peer_deleted: true — show the chat as
"Account deleted" / "Left the network", read-only. the messages stay with the other person (like Telegram);
the profile (name, photos, bio, city), likes, dislikes and blocks are erased. If the user comes back, it is a new member.
curl -X DELETE 'https://api.pereval.dating/v1/members/user-123' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.delete(
"https://api.pereval.dating/v1/members/user-123",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/members/user-123", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);req, _ := http.NewRequestWithContext(ctx, "DELETE", "https://api.pereval.dating/v1/members/user-123", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
| reason query · "left_network" | "account_deleted" | account_deleted or left_network (default) — goes to the other side in match.closed |
Ответы
The user is deleting their account (can restore within 30 days)
POST/v1/members/{external_id}/deactivate
Deferred account deletion: the member disappears from feeds and "liked you", their matches are frozen —
the other platforms get match.frozen and should show "Account deleted"; nobody can write (409 match_frozen).
Nothing is erased. Call /restore if the user comes back, or DELETE /v1/members/{external_id}?reason=account_deleted
when the 30 days are over; if you don't, the network erases the member itself after 30 days.
curl -X POST 'https://api.pereval.dating/v1/members/user-123/deactivate' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/deactivate');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/members/user-123/deactivate",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/members/user-123/deactivate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/members/user-123/deactivate", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
Ответы
Bring back a member the network hid after reports
POST/v1/members/{external_id}/reinstate
Your moderator reviewed the reports (member.reported) and found nothing wrong. The open reports are closed,
the member is back in feeds and their frozen matches resume (match.unfrozen to the other platforms).
A member who is deleting their account can't be reinstated (403).
curl -X POST 'https://api.pereval.dating/v1/members/user-123/reinstate' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/reinstate');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/members/user-123/reinstate",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/members/user-123/reinstate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/members/user-123/reinstate", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
Ответы
The user restored their account
POST/v1/members/{external_id}/restore
Everything is back as it was; the frozen matches resume (match.unfrozen to the other platforms).
curl -X POST 'https://api.pereval.dating/v1/members/user-123/restore' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/restore');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/members/user-123/restore",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/members/user-123/restore", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/members/user-123/restore", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
Ответы
Mark a member as active now
POST/v1/members/{external_id}/active
Feeds prefer recently active people and hide those inactive for 30+ days. For many users use POST /v1/activity.
curl -X POST 'https://api.pereval.dating/v1/members/user-123/active' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/active');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/members/user-123/active",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/members/user-123/active", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/members/user-123/active", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
Ответы
Mark many members as active
POST/v1/activity
Up to 1000 external ids — e.g. everyone who opened the app in the last few minutes. Unknown ids are skipped.
curl -X POST 'https://api.pereval.dating/v1/activity' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_ids": [
"string"
]
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/activity');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'external_ids' => ['string'],
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/activity",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"external_ids": [
"string"
]
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/activity", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"external_ids": [
"string"
]
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"external_ids": [
"string"
]
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/activity", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| external_idsобязательно string[] | 1–1000 items |
Ответы
| Поле | Описание |
|---|---|
| updated integer |
message says which fieldЛента
People from other apps who fit your user.
People from other apps for this member
GET/v1/members/{external_id}/feed
Members of other platforms only (you show your own users yourself). A candidate appears when:
opposite gender; each one's age is inside the other's range; within 50 km or radius_km
(or the same city and country when coordinates are missing); they share a language, or both consented
to cross-language chat; they share an intent; active in the last 30 days; not liked, not disliked in the last
30 days; no block either way. Most recently active first.
Filters only narrow what the viewer's profile already allows. age_min/age_max intersect the viewer's
range (an empty intersection is an empty feed and 200, not an error; age_min > age_max in the query is 422).
intent must be one of the viewer's intents, or 422. language is an ISO 639-1 code and still requires a shared
language or both consents to cross-language chat. gender, if sent, must be the opposite of the viewer, or 422.
Pages use cursor from the previous response's next_cursor. The same request without cursor returns the same
people. A member sees at most 200 distinct new people a day (UTC) — remaining_today. Repeating people already
shown today does not spend it. At zero, new people stop and people already shown today still come back.
A dislike hides a profile for 30 days; it is not how you turn the page.
A member hidden after reports or deleting their account gets no feed (403).
bio is translated into the viewer's main language when the viewer doesn't speak its language —
show the "translated" mark and let the user see bio_original. Translations are made on demand: the first
time a profile is shown to someone with a new main language it may come in the original (bio_translated: false),
and later feeds carry the translation.
scope=world drops the distance condition: people from any city and country, but only those with
consent.world. The viewer needs that consent too, otherwise 409 world_consent_required. Language and intent
conditions still apply. The 200 a day limit is shared by both scopes. Show the city and country on the card.
Viewer filters: radius_km widens or narrows the nearby search (ignored with scope=world);
verified_only=true keeps only photo_verified profiles (— marks the network counts, see verification); height_min/height_max keep people within that height —
people who didn't specify their height still pass, so a height filter never empties the feed by itself.
Store your users' filters yourself and send them with every request.
lat+lon (and optional city/country) search nearby around that point instead of the viewer's
profile city — the profile city does not change. distance_km is present only when that person turned on
show_distance.
curl -X GET 'https://api.pereval.dating/v1/members/user-123/feed' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "X-Feed-Request-Ref: $PEREVAL_FEED_REQUEST_REF"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/feed');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'X-Feed-Request-Ref: ' . getenv('PEREVAL_FEED_REQUEST_REF'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/members/user-123/feed",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}", "X-Feed-Request-Ref": os.environ['PEREVAL_FEED_REQUEST_REF']},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123/feed", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"X-Feed-Request-Ref": process.env.PEREVAL_FEED_REQUEST_REF,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/members/user-123/feed", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("X-Feed-Request-Ref", os.Getenv("PEREVAL_FEED_REQUEST_REF"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
| X-Feed-Request-Ref header · string | Logical search reference for opt-in boost delivery; preserve across retries/pages, change for a new search. |
| limit query · integer | |
| scope query · "nearby" | "world" | |
| radius_km query · integer | Search radius for scope=nearby |
| verified_only query · boolean | Only people with photo_verified |
| height_min query · integer | Minimum height, cm; people without a height pass |
| height_max query · integer | Maximum height, cm, not less than height_min; people without a height pass |
| lat query · number | Search centre latitude for scope=nearby; requires lon. Does not change the viewer's city. |
| lon query · number | Search centre longitude for scope=nearby; requires lat |
| city query · string | Place name for the same-city fallback when a profile has no coordinates |
| country query · string | ISO 3166-1 alpha-2 with city |
| age_min query · integer | Narrows the viewer's age range. Empty intersection with the profile returns an empty feed, not 422. |
| age_max query · integer | Narrows the viewer's age range. Must be ≥ age_min when both are set. |
| intent query · "serious" | "casual" | "friendship" | "arrangement" | One intent from the viewer's profile. Candidates must have it too. |
| language query · string | ISO 639-1. Candidates must list it. Does not bypass the shared-language rule. |
| gender query · "male" | "female" | Must be the opposite of the viewer. |
| cursor query · string | Opaque next page, from the previous next_cursor. Invalid cursor is 422. |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| network_idобязательно string (uuid) | |
| partnerобязательно object | |
| id string (uuid) | |
| name string | Name of the platform where the person registered. |
| display_nameобязательно string | |
| ageобязательно integer | |
| genderобязательно "male" | "female" | |
| cityобязательно string | |
| country string | ISO 3166-1 alpha-2 |
| distance_km integer | only if this person turned on show_distance. Kilometres from the search centre (viewer's city, or lat/lon) |
| languagesобязательно string[] | |
| bioобязательно string | In the viewer's main language when the viewer doesn't speak the original |
| bio_original string | |
| bio_translatedобязательно boolean | Show a "translated" mark when true |
| photosобязательно string (uri)[] | |
| videos object[] | but disabled in the production executable pending frame moderation. Absent when videos capability is false. |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verifiedобязательно boolean | The person's app verified they match the photos, and the network counts it |
| verified_by "partner" | Who verified the photos: partner — the person's app, with a method approved by the network |
| intentsобязательно string[] | |
| arrangement_role string | Shown only to viewers who have the arrangement intent themselves |
| height_cm integer | Absent when the person didn't specify it |
| super_like object | This person sent the viewer a super like (feed, incoming likes, like.received) |
| message string | In the viewer's main language when they don't speak the original |
| message_original string | |
| translated boolean | |
| lang string | |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
| remaining_todayобязательно integer | How many new people this member can still be shown today (UTC). Repeats do not decrease it. |
| next_cursor string | Pass as cursor for the next page. Absent on the last page. |
world_consent_required — scope=world for a member without consent.world; member_hidden — the member is hidden (consent.network: false)message says which fieldЛайки и мэтчи
Likes and dislikes across apps; a mutual like creates a match that opens chat.
Like a member of another app
POST/v1/likes
The liked member's platform gets like.received. If the like is mutual a match is created and both
platforms get match.created. Liking a member of your own app through the network is not allowed (403).
- You can only like someone your user could see: a block either way, the other environment (test vs live),
or a hidden member who hasn't liked your user →
404, as if the profile didn't exist. - A repeated like changes nothing and sends no event; upgrading a like to a super like sends
like.receivedagain. - While your user's profile is in moderation, their likes are stored but the recipient gets
like.receivedonly after the profile passes; if it is rejected, shown likes are withdrawn (like.withdrawn,rejected).
Super like: super: true with an optional message (up to 200 characters, no contact details —
422). The recipient sees it right away, before any match: like.received has super: true and the sender's
profile carries super_like with the message in the recipient's language; in the feed and in incoming likes such
a person comes first. Show it clearly highlighted. When a match happens, the message becomes the first message of
the chat (message.created to the recipient's platform). At most 5 super likes a day per member — then
429 super_like_limit; a regular like upgraded to a super like counts too. How many your users get (and
whether they pay) is up to you.
curl -X POST 'https://api.pereval.dating/v1/likes' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "X-Action-Ref: $PEREVAL_ACTION_REF" \
-H "Content-Type: application/json" \
-d '{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"super": false,
"message": "string"
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/likes');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'X-Action-Ref: ' . getenv('PEREVAL_ACTION_REF'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => 'string',
'to' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
'super' => false,
'message' => 'string',
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/likes",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}", "X-Action-Ref": os.environ['PEREVAL_ACTION_REF']},
json={
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"super": False,
"message": "string"
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/likes", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"X-Action-Ref": process.env.PEREVAL_ACTION_REF,
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"super": false,
"message": "string"
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"super": false,
"message": "string"
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/likes", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("X-Action-Ref", os.Getenv("PEREVAL_ACTION_REF"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| X-Action-Ref header · string | Required for superlikes after commerce enrollment, including zero-price entitlements. Same reference only for the same action payload. |
Тело запроса
| Поле | Описание |
|---|---|
| fromобязательно string | Your user's external_id |
| toобязательно string (uuid) | network_id from the feed |
| super boolean | default false |
| message string | Super like only: shown before the match, becomes the first message after it · ≤ 200 chars |
Ответы
| Поле | Описание |
|---|---|
| matchedобязательно boolean | |
| match_id string (uuid) | Present when matched |
member_hidden — a hidden member can only like back someone who liked them, without a super likemessage says which fieldsuper_like_limit — more than 5 super likes in 24 hTake a like (or super like) back before it became a match
DELETE/v1/likes/{network_id}
The liked member's platform gets like.withdrawn. After a match — 409 matched; close the match instead.
curl -X DELETE 'https://api.pereval.dating/v1/likes/{network_id}?from=VALUE' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "X-Action-Ref: $PEREVAL_ACTION_REF"<?php
$ch = curl_init('https://api.pereval.dating/v1/likes/{network_id}?from=VALUE');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'X-Action-Ref: ' . getenv('PEREVAL_ACTION_REF'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.delete(
"https://api.pereval.dating/v1/likes/{network_id}?from=VALUE",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}", "X-Action-Ref": os.environ['PEREVAL_ACTION_REF']},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/likes/{network_id}?from=VALUE", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"X-Action-Ref": process.env.PEREVAL_ACTION_REF,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);req, _ := http.NewRequestWithContext(ctx, "DELETE", "https://api.pereval.dating/v1/likes/{network_id}?from=VALUE", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("X-Action-Ref", os.Getenv("PEREVAL_ACTION_REF"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| X-Action-Ref header · string | Required after commerce enrollment. Replays of the same undo must use the same reference. |
| network_idобязательно path · string (uuid) | |
| fromобязательно query · string | Your user's external_id |
Ответы
matched — the like already became a matchBring a skipped profile back
DELETE/v1/dislikes/{network_id}
Removes the dislike — the profile may appear in the feed again.
curl -X DELETE 'https://api.pereval.dating/v1/dislikes/{network_id}?from=VALUE' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "X-Action-Ref: $PEREVAL_ACTION_REF"<?php
$ch = curl_init('https://api.pereval.dating/v1/dislikes/{network_id}?from=VALUE');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'X-Action-Ref: ' . getenv('PEREVAL_ACTION_REF'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.delete(
"https://api.pereval.dating/v1/dislikes/{network_id}?from=VALUE",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}", "X-Action-Ref": os.environ['PEREVAL_ACTION_REF']},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/dislikes/{network_id}?from=VALUE", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"X-Action-Ref": process.env.PEREVAL_ACTION_REF,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);req, _ := http.NewRequestWithContext(ctx, "DELETE", "https://api.pereval.dating/v1/dislikes/{network_id}?from=VALUE", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("X-Action-Ref", os.Getenv("PEREVAL_ACTION_REF"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| X-Action-Ref header · string | Required after commerce enrollment. Replays of the same undo must use the same reference. |
| network_idобязательно path · string (uuid) | |
| fromобязательно query · string | Your user's external_id |
Ответы
Your user saw a profile and didn't like it
POST/v1/dislikes
Send it when your user swiped left or scrolled past a profile without liking. Only your app knows what the user actually saw, so the network never treats a served feed as seen. The profile leaves the user's feed for 30 days. One pair or a batch of up to 100.
curl -X POST 'https://api.pereval.dating/v1/dislikes' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": false
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/dislikes');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => 'string',
'to' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
'erase' => false,
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/dislikes",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": False
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/dislikes", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": false
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": false
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/dislikes", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| fromобязательно string | Your user's external_id |
| toобязательно string (uuid) | network_id from the feed |
| erase boolean | blocks only: delete the match, messages and likes for both · default false |
Ответы
Who liked this member and waits for an answer
GET/v1/members/{external_id}/likes
Without mutual likes, dislikes and blocks. Rebuilds "Liked you" when events were lost.
curl -X GET 'https://api.pereval.dating/v1/members/user-123/likes' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/likes');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/members/user-123/likes",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123/likes", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/members/user-123/likes", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
| limit query · integer |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| fromобязательно object | A member of another app as seen by your user. |
| network_idобязательно string (uuid) | |
| partnerобязательно object | |
| id string (uuid) | |
| name string | Name of the platform where the person registered. |
| display_nameобязательно string | |
| ageобязательно integer | |
| genderобязательно "male" | "female" | |
| cityобязательно string | |
| country string | ISO 3166-1 alpha-2 |
| distance_km integer | only if this person turned on show_distance. Kilometres from the search centre (viewer's city, or lat/lon) |
| languagesобязательно string[] | |
| bioобязательно string | In the viewer's main language when the viewer doesn't speak the original |
| bio_original string | |
| bio_translatedобязательно boolean | Show a "translated" mark when true |
| photosобязательно string (uri)[] | |
| videos object[] | but disabled in the production executable pending frame moderation. Absent when videos capability is false. |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verifiedобязательно boolean | The person's app verified they match the photos, and the network counts it |
| verified_by "partner" | Who verified the photos: partner — the person's app, with a method approved by the network |
| intentsобязательно string[] | |
| arrangement_role string | Shown only to viewers who have the arrangement intent themselves |
| height_cm integer | Absent when the person didn't specify it |
| super_like object | This person sent the viewer a super like (feed, incoming likes, like.received) |
| message string | In the viewer's main language when they don't speak the original |
| message_original string | |
| translated boolean | |
| lang string | |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
| liked_atобязательно string (date-time) |
Open matches of a member
GET/v1/members/{external_id}/matches
curl -X GET 'https://api.pereval.dating/v1/members/user-123/matches' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/matches');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/members/user-123/matches",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123/matches", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/members/user-123/matches", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string | Your user id. |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| match_idобязательно string (uuid) | |
| created_atобязательно string (date-time) | |
| withобязательно object | A member of another app as seen by your user. |
| network_idобязательно string (uuid) | |
| partnerобязательно object | |
| id string (uuid) | |
| name string | Name of the platform where the person registered. |
| display_nameобязательно string | |
| ageобязательно integer | |
| genderобязательно "male" | "female" | |
| cityобязательно string | |
| country string | ISO 3166-1 alpha-2 |
| distance_km integer | only if this person turned on show_distance. Kilometres from the search centre (viewer's city, or lat/lon) |
| languagesобязательно string[] | |
| bioобязательно string | In the viewer's main language when the viewer doesn't speak the original |
| bio_original string | |
| bio_translatedобязательно boolean | Show a "translated" mark when true |
| photosобязательно string (uri)[] | |
| videos object[] | but disabled in the production executable pending frame moderation. Absent when videos capability is false. |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verifiedобязательно boolean | The person's app verified they match the photos, and the network counts it |
| verified_by "partner" | Who verified the photos: partner — the person's app, with a method approved by the network |
| intentsобязательно string[] | |
| arrangement_role string | Shown only to viewers who have the arrangement intent themselves |
| height_cm integer | Absent when the person didn't specify it |
| super_like object | This person sent the viewer a super like (feed, incoming likes, like.received) |
| message string | In the viewer's main language when they don't speak the original |
| message_original string | |
| translated boolean | |
| lang string | |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
| frozen boolean | Omitted when false |
| freeze_reason "account_deleting" | "suspended" | "partner_suspended" | Present when frozen |
Close or erase a match (unmatch)
DELETE/v1/matches/{match_id}
Without erase the match is closed and both keep the history (match.closed, reason: unmatched).
With erase=true the match, its messages and both likes are deleted for both — the other platform gets
match.erased and should remove the chat; the two won't meet in each other's feeds for cooldown_days.
If either of them reported the other, a hidden copy of the chat is kept for moderation for 90 days.
To hide the history only for your user, use POST /v1/matches/{match_id}/clear.
curl -X DELETE 'https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10?by=user-123' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10?by=user-123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.delete(
"https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10?by=user-123",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10?by=user-123", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);req, _ := http.NewRequestWithContext(ctx, "DELETE", "https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10?by=user-123", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| match_idобязательно path · string (uuid) | |
| byобязательно query · string | external_id of your user who unmatches |
| erase query · boolean | Delete the match, messages and likes for both |
| cooldown_days query · integer | with erase. Days before they can see each other in the feed again; for "never" block instead |
Ответы
match.closed) or erased (match.erased)message says which fieldСообщения
Text chat inside a match, machine-translated when the recipient doesn't speak the sender's language.
Delete the chat history for one side
POST/v1/matches/{match_id}/clear
"Delete chat" for your user only: the history before now is no longer returned to them; the other person keeps everything, the match stays, and new messages go both ways as usual.
curl -X POST 'https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/clear' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"as": "string"
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/clear');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'as' => 'string',
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/clear",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"as": "string"
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/clear", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"as": "string"
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"as": "string"
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/clear", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| match_idобязательно path · string (uuid) |
Тело запроса
| Поле | Описание |
|---|---|
| asобязательно string | external_id of your user |
Ответы
Conversation history as seen by a member
GET/v1/matches/{match_id}/messages
Newest first by (created_at, id). Messages from the other side are in the viewer's language with the original
and scam flags; own messages carry read_at and, when supplied, client_message_id for retry reconciliation.
The before message must belong to this match. Closure preserves history; erasure removes it.
curl -X GET 'https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages?as=user-123' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages?as=user-123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages?as=user-123",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages?as=user-123", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages?as=user-123", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| match_idобязательно path · string (uuid) | |
| asобязательно query · string | external_id of the viewer |
| before query · string (uuid) | Message id — returns older messages (pagination cursor) |
| limit query · integer |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| idобязательно string (uuid) | |
| fromобязательно string | "me" for the viewer's own messages, otherwise the sender's network_id |
| client_message_id string | Author history/POST echo when supplied; also included in message.created for reconciliation |
| textобязательно string | |
| text_original string | |
| translatedобязательно boolean | |
| langобязательно string | |
| created_atобязательно string (date-time) | |
| suspicious boolean | Messages from the other side only |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
| read_at string (date-time) | Own messages only: when the other side read it |
Send a message
POST/v1/matches/{match_id}/messages
The network detects the language from the text; short replies ("ok", "haha", emoji) are attributed to one of
the sender's languages, the main one first. If the recipient doesn't speak it, the message is translated in the background
into the recipient's main language, and the recipient's platform gets message.created once the translation is ready.
If translation fails the message is still delivered in the original language (translated: false).
Cheap scam signals are checked: links, phone numbers and invitations to other messengers early in a chat,
talk about money, the same text sent to many people. The message is delivered anyway, with suspicious and flags,
so the recipient's app can show a warning. Members in their first 7 days can start at most 20 conversations a day
(429 first_messages_limit); replying in existing conversations is unlimited.
optional client_message_id is sender-scoped (not match-scoped), at most 128 UTF-8 bytes,
without surrounding whitespace. Repeating the same ID, match and trimmed text returns the original message,
including after match closure; changing match/text returns 409 idempotency_conflict.
Ownership/auth are checked before replay. A suspended platform key is never authorized by a replay.
After message retention or explicit match erasure, the original is no longer available: this is not a permanent
idempotency reservation. Persist the returned message ID; recover a timed-out response through author history.
curl -X POST 'https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "string",
"text": "string",
"client_message_id": "string"
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => 'string',
'text' => 'string',
'client_message_id' => 'string',
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"from": "string",
"text": "string",
"client_message_id": "string"
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": "string",
"text": "string",
"client_message_id": "string"
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"from": "string",
"text": "string",
"client_message_id": "string"
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/messages", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| match_idобязательно path · string (uuid) |
Тело запроса
| Поле | Описание |
|---|---|
| fromобязательно string | Sender's external_id |
| textобязательно string | 1–4000 chars |
| client_message_id string | Optional sender-scoped retry ID; maximum 128 UTF-8 bytes, no surrounding whitespace · 1–128 chars |
Ответы
| Поле | Описание |
|---|---|
| idобязательно string (uuid) | |
| fromобязательно string | "me" for the viewer's own messages, otherwise the sender's network_id |
| client_message_id string | Author history/POST echo when supplied; also included in message.created for reconciliation |
| textобязательно string | |
| text_original string | |
| translatedобязательно boolean | |
| langобязательно string | |
| created_atобязательно string (date-time) | |
| suspicious boolean | Messages from the other side only |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
| read_at string (date-time) | Own messages only: when the other side read it |
message says which fieldfirst_messages_limit — a new member started too many conversations today, or rate_limitedYour user read the conversation
POST/v1/matches/{match_id}/read
Marks the other side's messages up to up_to (inclusive) as read; the other platform gets message.read.
curl -X POST 'https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/read' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"as": "string",
"up_to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/read');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'as' => 'string',
'up_to' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/read",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"as": "string",
"up_to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/read", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"as": "string",
"up_to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"as": "string",
"up_to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44"
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/matches/7d2a0f4e-1b6c-4e8a-9f3d-5c1b2a7e9d10/read", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| match_idобязательно path · string (uuid) |
Тело запроса
| Поле | Описание |
|---|---|
| asобязательно string | external_id of the reader |
| up_toобязательно string (uuid) | Id of the last message read |
Ответы
Безопасность
Blocks and reports. Reports reach the reported member's platform; serious ones suspend the member network-wide.
Block a member
POST/v1/blocks
Both disappear from each other's feeds for good. Without erase an open match between them is closed (match.closed,
reason: blocked), the history stays. With erase: true the match, messages and likes are deleted for both
(match.erased, reason: blocked); if either reported the other, a hidden copy is kept for moderation for 90 days.
curl -X POST 'https://api.pereval.dating/v1/blocks' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": false
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/blocks');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => 'string',
'to' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
'erase' => false,
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/blocks",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": False
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/blocks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": false
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"erase": false
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/blocks", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| fromобязательно string | Your user's external_id |
| toобязательно string (uuid) | network_id from the feed |
| erase boolean | blocks only: delete the match, messages and likes for both · default false |
Ответы
Report a member
POST/v1/reports
The reported member's platform gets member.reported. A report with reason: underage or commercial, or reports from
3 different people, suspends the member from the network until review (member.suspended): they are out of feeds and
their matches are frozen (match.frozen with reason: suspended, 409 match_frozen for both). Their platform brings
them back with POST /v1/members/{external_id}/reinstate.
curl -X POST 'https://api.pereval.dating/v1/reports' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"reason": "fake",
"comment": "string"
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/reports');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => 'string',
'to' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
'reason' => 'fake',
'comment' => 'string',
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/reports",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"reason": "fake",
"comment": "string"
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/reports", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"reason": "fake",
"comment": "string"
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"from": "string",
"to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"reason": "fake",
"comment": "string"
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/reports", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| fromобязательно string | |
| toобязательно string (uuid) | |
| reasonобязательно "fake" | "scam" | "spam" | "offensive" | "underage" | "commercial" | "other" | commercial — offers sex for money; suspends the member at once |
| comment string | ≤ 1000 chars |
Ответы
message says which fieldЯзыки
Languages the network translates profiles and messages into.
Translation languages
GET/v1/languages
ISO 639-1 codes the network translates between. Members may list other ISO 639-1 codes in languages,
but a member whose main language is not in this list reads others in the original.
curl -X GET 'https://api.pereval.dating/v1/languages' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/languages');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/languages",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/languages", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/languages", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Ответы
| Поле | Описание |
|---|---|
| translatedобязательно string[] | ISO 639-1 codes |
Photo check
The network's photo check for platforms without their own: the person takes it on a network page (consent, a requested gesture, a camera picture); the network compares the picture with each profile photo.
Start a photo check
POST/v1/photo-checks
Creates a check session with the person's profile photos (the network downloads them right away) and returns the
url of the network's check page. Open it for the person — in the browser, a new tab or a webview with camera access;
it can't be embedded in an iframe. The link is valid for 30 minutes and allows up to 5 attempts. On the page the
person agrees to the comparison, shows the requested gesture and takes a picture with the camera; the network
compares it with each photo. The result comes as photo_check.updated (after each attempt, a dispute and the
moderator's decision) and in GET /v1/photo-checks/{id}; the page also posts
{type: "pereval.photo_check", status} to the window that opened it.
The picture is never shown to you or other people and no facial features are stored: it is deleted right after a passed check, kept for 24 hours after a failed one (so the person can dispute the result) and until the moderator's decision if disputed, but never beyond 60 days in the active database from original check creation, including unresolved disputes. Personal metadata, references and source photos are also subject to that absolute limit. Updates, appeals and disputes do not restart it; expiry never approves a photo or removes a sanction. Operators must review before expiry. Public access ends at the earlier public token expiry independently of retained evidence. The consent names your platform and the network, which compares photos on your behalf.
curl -X POST 'https://api.pereval.dating/v1/photo-checks' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"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"
}
]
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/photo-checks');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'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',
]],
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/photo-checks",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"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"
}
]
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/photo-checks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"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"
}
]
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"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"
}
]
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/photo-checks", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| refобязательно string | How you recognise the person in the result, usually their external_id · 1–200 chars |
| photosобязательно object[] | 1–9 items |
| id string | Your photo id, unique in the session; default — the position (1, 2, …) · ≤ 100 chars |
| urlобязательно string (uri) | Public HTTPS URL of a profile photo |
| lang "ru" | "en" | Language of the check page · default "en" |
| return_url string (uri) | Optional: the page's "Back" button · ≤ 500 chars |
Ответы
url for the person| Поле | Описание |
|---|---|
| idобязательно string (uuid) | |
| refобязательно string | |
| url string (uri) | Only in the POST reply: the check page to open for the person |
| statusобязательно "created" | "passed" | "partial" | "failed" | "disputed" | "resolved" | "expired" | created — not taken yet; passed — it's the person on every photo with a face; partial — some photos don't
look like the picture; failed — see reason; disputed — the person disputed, a network moderator decides
(usually within 24 hours); resolved — the moderator decided (note explains); expired — the link expired untaken.
|
| reason "no_match" | "no_face" | "many_faces" | "no_gesture" | "virtual_camera" | Why it failed |
| attemptsобязательно integer | Pictures taken (up to 5 per session) |
| expires_atобязательно string (date-time) | Until when the link allows attempts |
| checked_at string (date-time) | The last picture |
| dispute_until string (date-time) | Failed or partial: the person can dispute until then |
| disputed_at string (date-time) | |
| decided_at string (date-time) | The moderator's decision |
| note string | The moderator's explanation for the person |
| photosобязательно object[] | |
| idобязательно string | |
| urlобязательно string (uri) | |
| verdict "match" | "no_match" | "unsure" | "no_face" | match — the same person; no_match — doesn't look like them; unsure — couldn't compare reliably; no_face — no face, not counted. Absent — not compared yet |
| created_atобязательно string (date-time) |
message says which fieldphoto_check_limit — more than 10 checks for this person (ref) a day; or rate_limitedphoto_check_off — the comparison service is temporarily unavailable; retry laterPhoto check result
GET/v1/photo-checks/{id}
curl -X GET 'https://api.pereval.dating/v1/photo-checks/{id}' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/photo-checks/{id}');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/photo-checks/{id}",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/photo-checks/{id}", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/photo-checks/{id}", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| idобязательно path · string (uuid) |
Ответы
url)| Поле | Описание |
|---|---|
| idобязательно string (uuid) | |
| refобязательно string | |
| url string (uri) | Only in the POST reply: the check page to open for the person |
| statusобязательно "created" | "passed" | "partial" | "failed" | "disputed" | "resolved" | "expired" | created — not taken yet; passed — it's the person on every photo with a face; partial — some photos don't
look like the picture; failed — see reason; disputed — the person disputed, a network moderator decides
(usually within 24 hours); resolved — the moderator decided (note explains); expired — the link expired untaken.
|
| reason "no_match" | "no_face" | "many_faces" | "no_gesture" | "virtual_camera" | Why it failed |
| attemptsобязательно integer | Pictures taken (up to 5 per session) |
| expires_atобязательно string (date-time) | Until when the link allows attempts |
| checked_at string (date-time) | The last picture |
| dispute_until string (date-time) | Failed or partial: the person can dispute until then |
| disputed_at string (date-time) | |
| decided_at string (date-time) | The moderator's decision |
| note string | The moderator's explanation for the person |
| photosобязательно object[] | |
| idобязательно string | |
| urlобязательно string (uri) | |
| verdict "match" | "no_match" | "unsure" | "no_face" | match — the same person; no_match — doesn't look like them; unsure — couldn't compare reliably; no_face — no face, not counted. Absent — not compared yet |
| created_atобязательно string (date-time) |
Забор событий
Pull events yourself — for platforms without a webhook URL and for recovery after an outage.
Pull events
GET/v1/events
Events of your environment in seq order after the given cursor; pulled events count as delivered.
If your platform has no webhook URL, the network doesn't push — you pull. Events are kept for 7 days.
The data of each event is the same as in the webhook of that type.
curl -X GET 'https://api.pereval.dating/v1/events' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/events');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/events",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/events", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/events", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| after query · integer | next_after from the previous response (0 — from the oldest kept event) |
| limit query · integer |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| seqобязательно integer | |
| idобязательно string | |
| typeобязательно string | |
| created_atобязательно string (date-time) | |
| dataобязательно object | |
| next_afterобязательно integer | Pass as after next time |
MCP
Model Context Protocol JSON-RPC 2.0 for AI agents. Same Bearer key as REST. POST /mcp — methods initialize, tools/list, tools/call, ping. Protocol version 2024-11-05.
Model Context Protocol (JSON-RPC)
POST/mcp
Same API key as the REST API. Methods: initialize, tools/list, tools/call, ping.
Tools: upsert_member, get_feed, like, dislike, send_message, list_events, list_languages.
A tools/call result is JSON in result.content[].text. RPC errors use JSON-RPC error;
tool failures set isError: true and keep HTTP 200. Missing key — HTTP 401.
curl -X POST 'https://api.pereval.dating/mcp' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": {},
"method": "tools/list",
"params": {}
}'<?php
$ch = curl_init('https://api.pereval.dating/mcp');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'jsonrpc' => '2.0',
'id' => [
],
'method' => 'tools/list',
'params' => [
],
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/mcp",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"jsonrpc": "2.0",
"id": {},
"method": "tools/list",
"params": {}
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/mcp", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"jsonrpc": "2.0",
"id": {},
"method": "tools/list",
"params": {}
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);body := []byte(`{
"jsonrpc": "2.0",
"id": {},
"method": "tools/list",
"params": {}
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/mcp", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| jsonrpcобязательно "2.0" | |
| id object | number, string or null (null = notification, no response) |
| methodобязательно string | |
| params object |
Ответы
Дополнительные услуги
Current own boost and remaining time; voluntary cancellation is not supported
GET/v1/members/{external_id}/boost
curl -X GET 'https://api.pereval.dating/v1/members/user-123/boost' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/boost');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/members/user-123/boost",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123/boost", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/members/user-123/boost", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string |
Ответы
| Поле | Описание |
|---|---|
| generationобязательно string (uuid) | |
| stateобязательно "active" | "paused" | "completed" | |
| started_atобязательно string (date-time) | |
| remaining_msобязательно integer | ≥ 0 |
| api_placementsобязательно integer | ≥ 0 |
Declare receiving support independently of purchases
PUT/v1/commerce/delivery
curl -X PUT 'https://api.pereval.dating/v1/commerce/delivery' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "swipe",
"enabled": true
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/commerce/delivery');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'format' => 'swipe',
'enabled' => true,
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.put(
"https://api.pereval.dating/v1/commerce/delivery",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"format": "swipe",
"enabled": True
},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/v1/commerce/delivery", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"format": "swipe",
"enabled": true
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);body := []byte(`{
"format": "swipe",
"enabled": true
}`)
req, _ := http.NewRequestWithContext(ctx, "PUT", "https://api.pereval.dating/v1/commerce/delivery", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| formatобязательно "swipe" | "search" | "none" | |
| enabledобязательно boolean |
Ответы
Catalog in the enrolled account currency
GET/v1/commerce/catalog
curl -X GET 'https://api.pereval.dating/v1/commerce/catalog' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/commerce/catalog');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/commerce/catalog",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/commerce/catalog", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/commerce/catalog", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Ответы
| Поле | Описание |
|---|---|
| currencyобязательно "TEST" | "RUB" | |
| test_onlyобязательно boolean | |
| itemsобязательно object[] | |
| skuобязательно string | |
| capabilityобязательно "superlike" | "rewind" | "incognito" | "boost" | |
| unitобязательно "action" | "minute" | "day" | |
| unit_priceобязательно integer (int64) | ≥ 0 |
| min_quantityобязательно integer | ≥ 1 |
| max_quantityобязательно integer | ≥ 1 |
| fulfillment_readyобязательно boolean | |
| versionобязательно integer | ≥ 1 |
| currencyобязательно "TEST" | "RUB" |
TEST credits or zero-only RUB balance
GET/v1/commerce/balance
curl -X GET 'https://api.pereval.dating/v1/commerce/balance' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/commerce/balance');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/commerce/balance",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/commerce/balance", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/commerce/balance", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Ответы
| Поле | Описание |
|---|---|
| currencyобязательно "TEST" | "RUB" | |
| test_onlyобязательно boolean | |
| balanceобязательно integer (int64) | ≥ 0 |
Create a five-minute price snapshot; no debit
POST/v1/commerce/quotes
curl -X POST 'https://api.pereval.dating/v1/commerce/quotes' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"member": "string",
"sku": "string",
"quantity": 1
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/commerce/quotes');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'member' => 'string',
'sku' => 'string',
'quantity' => 1,
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/commerce/quotes",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"member": "string",
"sku": "string",
"quantity": 1
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/commerce/quotes", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"member": "string",
"sku": "string",
"quantity": 1
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"member": "string",
"sku": "string",
"quantity": 1
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/commerce/quotes", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| memberобязательно string | 1–256 chars |
| skuобязательно string | 1–80 chars |
| quantityобязательно integer | 1–1000000 |
Ответы
| Поле | Описание |
|---|---|
| idобязательно string (uuid) | |
| member_idобязательно string (uuid) | |
| skuобязательно string | |
| capabilityобязательно string | |
| unitобязательно string | |
| quantityобязательно integer | ≥ 1 |
| unit_priceобязательно integer (int64) | ≥ 0 |
| totalобязательно integer (int64) | ≥ 0 |
| catalog_versionобязательно integer | |
| expires_atобязательно string (date-time) | |
| currencyобязательно "TEST" | "RUB" |
Atomically purchase entitlement; durable replay by external_order_ref
POST/v1/commerce/orders
curl -X POST 'https://api.pereval.dating/v1/commerce/orders' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "X-Commerce-Key: $PEREVAL_COMMERCE_KEY" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"external_order_ref": "string"
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/commerce/orders');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'X-Commerce-Key: ' . getenv('PEREVAL_COMMERCE_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'quote_id' => '6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44',
'external_order_ref' => 'string',
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.post(
"https://api.pereval.dating/v1/commerce/orders",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}", "X-Commerce-Key": os.environ['PEREVAL_COMMERCE_KEY']},
json={
"quote_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"external_order_ref": "string"
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/commerce/orders", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"X-Commerce-Key": process.env.PEREVAL_COMMERCE_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"quote_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"external_order_ref": "string"
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"quote_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"external_order_ref": "string"
}`)
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pereval.dating/v1/commerce/orders", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("X-Commerce-Key", os.Getenv("PEREVAL_COMMERCE_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Тело запроса
| Поле | Описание |
|---|---|
| quote_idобязательно string (uuid) | |
| external_order_refобязательно string | 1–128 chars |
Ответы
| Поле | Описание |
|---|---|
| idобязательно string (uuid) | |
| external_order_refобязательно string | |
| quote_idобязательно string (uuid) | |
| totalобязательно integer (int64) | ≥ 0 |
| created_atобязательно string (date-time) | |
| currencyобязательно "TEST" | "RUB" | |
| grant_idобязательно string (uuid) | |
| valid_fromобязательно string (date-time) | |
| valid_untilобязательно string,null (date-time) |
List own subject entitlements
GET/v1/members/{external_id}/entitlements
curl -X GET 'https://api.pereval.dating/v1/members/user-123/entitlements' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/entitlements');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/members/user-123/entitlements",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123/entitlements", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/members/user-123/entitlements", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string |
Ответы
| Поле | Описание |
|---|---|
| itemsобязательно object[] | |
| idобязательно string (uuid) | |
| capabilityобязательно string | |
| quantityобязательно integer | ≥ 1 |
| usedобязательно integer (int64) | ≥ 0 |
| valid_fromобязательно string (date-time) | |
| valid_untilобязательно string,null (date-time) | |
| revoked_atобязательно string,null (date-time) |
Explicitly enable incognito with a valid right or freely disable it
PUT/v1/members/{external_id}/incognito
curl -X PUT 'https://api.pereval.dating/v1/members/user-123/incognito' \
-H "Authorization: Bearer $PEREVAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true
}'<?php
$ch = curl_init('https://api.pereval.dating/v1/members/user-123/incognito');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'enabled' => true,
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.put(
"https://api.pereval.dating/v1/members/user-123/incognito",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
json={
"enabled": True
},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/members/user-123/incognito", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"enabled": true
}),
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();body := []byte(`{
"enabled": true
}`)
req, _ := http.NewRequestWithContext(ctx, "PUT", "https://api.pereval.dating/v1/members/user-123/incognito", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Параметры
| external_idобязательно path · string |
Тело запроса
| Поле | Описание |
|---|---|
| enabledобязательно boolean |
Ответы
| Поле | Описание |
|---|---|
| enabledобязательно boolean |
Прочее
Process liveness
GET/healthz
curl -X GET 'https://api.pereval.dating/healthz' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/healthz');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/healthz",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/healthz", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/healthz", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Ответы
Database readiness, not a check of external moderation or AI availability
GET/readyz
curl -X GET 'https://api.pereval.dating/readyz' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/readyz');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/readyz",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()const res = await fetch("https://api.pereval.dating/readyz", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/readyz", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Ответы
Runtime protocol and feature configuration
GET/v1/capabilities
curl -X GET 'https://api.pereval.dating/v1/capabilities' \
-H "Authorization: Bearer $PEREVAL_API_KEY"<?php
$ch = curl_init('https://api.pereval.dating/v1/capabilities');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('PEREVAL_API_KEY'),
],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status >= 400) {
throw new RuntimeException("Pereval $status: $response");
}
$data = json_decode($response, true);import os, requests
resp = requests.get(
"https://api.pereval.dating/v1/capabilities",
headers={"Authorization": f"Bearer {os.environ['PEREVAL_API_KEY']}"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()const res = await fetch("https://api.pereval.dating/v1/capabilities", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PEREVAL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`Pereval ${res.status}: ${await res.text()}`);
const data = await res.json();req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.pereval.dating/v1/capabilities", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PEREVAL_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("pereval %d: %s", resp.StatusCode, b)
}Ответы
| Поле | Описание |
|---|---|
| protocol_versionобязательно "1.0.0" | |
| productionобязательно boolean | |
| commerce_enabledобязательно boolean | Full network commerce is enabled; does not imply this partner is enrolled |
| commerce_live_zero_onlyобязательно boolean | Live checkout accepts zero RUB only; no monetary payment processor |
| commerce_pilotобязательно boolean | TEST-only development pilot; false in production |
| client_message_idобязательно true | |
| videosобязательно boolean | False in the production executable |
| photo_checksобязательно boolean | Facecheck URL is configured |
| profile_moderationобязательно boolean | Profile moderation is configured |
События (вебхуки)
Every webhook is a POST with this envelope. Headers: X-Network-Signature: sha256=<hex> — HMAC-SHA256 of the
raw body with your signing secret (verify it, constant-time compare); X-Network-Event: <type>.
Reply 2xx quickly. Non-2xx or timeout (10 s) → retries after 10 s, 1 min, 5 min, 30 min, 2 h, 6 h, then daily
for up to 3 days. Deliveries may repeat — dedupe by id. Order holds unless a delivery is retried.
Without a webhook URL, pull the same events with GET /v1/events.
Проверка подписи и приём — в разделе «Вебхуки»
boost.started
Boost started
Durable boost lifecycle event, not a human impression. Reconcile current state with the member boost endpoint.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "boost.started",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"generation": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"remaining_ms": 0
}
}data
| Поле | Описание |
|---|---|
| memberобязательно string | Your member external_id |
| generationобязательно string (uuid) | |
| remaining_msобязательно integer | ≥ 0 |
boost.extended
Boost extended
Durable boost lifecycle event, not a human impression. Reconcile current state with the member boost endpoint.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "boost.extended",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"generation": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"remaining_ms": 0
}
}data
| Поле | Описание |
|---|---|
| memberобязательно string | Your member external_id |
| generationобязательно string (uuid) | |
| remaining_msобязательно integer | ≥ 0 |
boost.paused
Boost paused
Durable boost lifecycle event, not a human impression. Reconcile current state with the member boost endpoint.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "boost.paused",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"generation": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"remaining_ms": 0
}
}data
| Поле | Описание |
|---|---|
| memberобязательно string | Your member external_id |
| generationобязательно string (uuid) | |
| remaining_msобязательно integer | ≥ 0 |
boost.resumed
Boost resumed
Durable boost lifecycle event, not a human impression. Reconcile current state with the member boost endpoint.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "boost.resumed",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"generation": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"remaining_ms": 0
}
}data
| Поле | Описание |
|---|---|
| memberобязательно string | Your member external_id |
| generationобязательно string (uuid) | |
| remaining_msобязательно integer | ≥ 0 |
boost.completed
Boost completed
Durable boost lifecycle event, not a human impression. Reconcile current state with the member boost endpoint.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "boost.completed",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"generation": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"remaining_ms": 0
}
}data
| Поле | Описание |
|---|---|
| memberобязательно string | Your member external_id |
| generationобязательно string (uuid) | |
| remaining_msобязательно integer | ≥ 0 |
like.received
Someone from another app liked your user
Show it as an incoming like. Liking back via POST /v1/likes creates a match.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "like.received",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"to": "string",
"from": {
"network_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"partner": {
"id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"name": "string"
},
"display_name": "string",
"age": 1,
"gender": "male",
"city": "string",
"country": "string",
"distance_km": 1,
"languages": [
"string"
],
"bio": "string",
"bio_original": "string",
"bio_translated": true,
"photos": [
"https://example.com/photo.jpg"
],
"videos": [
{
"url": "https://example.com/photo.jpg",
"poster": "https://example.com/photo.jpg"
}
],
"photo_verified": true,
"verified_by": "partner",
"intents": [
"string"
],
"arrangement_role": "string",
"height_cm": 1,
"super_like": {
"message": "string",
"message_original": "string",
"translated": true,
"lang": "string",
"flags": [
"link"
]
}
},
"super": true
}
}data
| Поле | Описание |
|---|---|
| toобязательно string | Your user's external_id |
| fromобязательно object | A member of another app as seen by your user. |
| network_idобязательно string (uuid) | |
| partnerобязательно object | |
| id string (uuid) | |
| name string | Name of the platform where the person registered. |
| display_nameобязательно string | |
| ageобязательно integer | |
| genderобязательно "male" | "female" | |
| cityобязательно string | |
| country string | ISO 3166-1 alpha-2 |
| distance_km integer | only if this person turned on show_distance. Kilometres from the search centre (viewer's city, or lat/lon) |
| languagesобязательно string[] | |
| bioобязательно string | In the viewer's main language when the viewer doesn't speak the original |
| bio_original string | |
| bio_translatedобязательно boolean | Show a "translated" mark when true |
| photosобязательно string (uri)[] | |
| videos object[] | but disabled in the production executable pending frame moderation. Absent when videos capability is false. |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verifiedобязательно boolean | The person's app verified they match the photos, and the network counts it |
| verified_by "partner" | Who verified the photos: partner — the person's app, with a method approved by the network |
| intentsобязательно string[] | |
| arrangement_role string | Shown only to viewers who have the arrangement intent themselves |
| height_cm integer | Absent when the person didn't specify it |
| super_like object | This person sent the viewer a super like (feed, incoming likes, like.received) |
| message string | In the viewer's main language when they don't speak the original |
| message_original string | |
| translated boolean | |
| lang string | |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
| super boolean | A super like: from.super_like has the message |
like.withdrawn
A like your user hasn't answered is gone
Remove it from your user's incoming likes. it also comes when the person who liked is no longer available —
deleting their account, hidden after reports, their profile rejected by moderation, or removed from the network
(reason). If they come back (restored, reinstated, profile fixed), your user gets like.received again.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "like.withdrawn",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"to": "string",
"from": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"reason": "unliked"
}
}data
| Поле | Описание |
|---|---|
| toобязательно string | Your user's external_id |
| fromобязательно string (uuid) | network_id of the person who took the like back |
| reason "unliked" | "account_deleting" | "suspended" | "rejected" | "account_deleted" | "left_network" | unliked — they took the like back themselves |
match.created
A match was created
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "match.created",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"member": "string",
"with": {
"network_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"partner": {
"id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"name": "string"
},
"display_name": "string",
"age": 1,
"gender": "male",
"city": "string",
"country": "string",
"distance_km": 1,
"languages": [
"string"
],
"bio": "string",
"bio_original": "string",
"bio_translated": true,
"photos": [
"https://example.com/photo.jpg"
],
"videos": [
{
"url": "https://example.com/photo.jpg",
"poster": "https://example.com/photo.jpg"
}
],
"photo_verified": true,
"verified_by": "partner",
"intents": [
"string"
],
"arrangement_role": "string",
"height_cm": 1,
"super_like": {
"message": "string",
"message_original": "string",
"translated": true,
"lang": "string",
"flags": [
"link"
]
}
}
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| memberобязательно string | Your user's external_id |
| withобязательно object | A member of another app as seen by your user. |
| network_idобязательно string (uuid) | |
| partnerобязательно object | |
| id string (uuid) | |
| name string | Name of the platform where the person registered. |
| display_nameобязательно string | |
| ageобязательно integer | |
| genderобязательно "male" | "female" | |
| cityобязательно string | |
| country string | ISO 3166-1 alpha-2 |
| distance_km integer | only if this person turned on show_distance. Kilometres from the search centre (viewer's city, or lat/lon) |
| languagesобязательно string[] | |
| bioобязательно string | In the viewer's main language when the viewer doesn't speak the original |
| bio_original string | |
| bio_translatedобязательно boolean | Show a "translated" mark when true |
| photosобязательно string (uri)[] | |
| videos object[] | but disabled in the production executable pending frame moderation. Absent when videos capability is false. |
| urlобязательно string (uri) | Public MP4, at most 15 seconds and 20 MB |
| posterобязательно string (uri) | Still frame. Shown before playback and by apps that do not play video. Moderated like a photo |
| photo_verifiedобязательно boolean | The person's app verified they match the photos, and the network counts it |
| verified_by "partner" | Who verified the photos: partner — the person's app, with a method approved by the network |
| intentsобязательно string[] | |
| arrangement_role string | Shown only to viewers who have the arrangement intent themselves |
| height_cm integer | Absent when the person didn't specify it |
| super_like object | This person sent the viewer a super like (feed, incoming likes, like.received) |
| message string | In the viewer's main language when they don't speak the original |
| message_original string | |
| translated boolean | |
| lang string | |
| flags "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
message.created
A new message for your user
Show a warning when suspicious is true — flags say why.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "message.created",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"to": "string",
"message": {
"id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"from": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"client_message_id": "string",
"text": "string",
"text_original": "string",
"translated": true,
"lang": "string",
"created_at": "2026-10-24T12:00:00Z",
"suspicious": true,
"flags": [
"link"
]
}
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| toобязательно string | Your user's external_id |
| messageобязательно object | |
| idобязательно string (uuid) | Use it as up_to in markRead |
| fromобязательно string (uuid) | Sender's network_id |
| client_message_id string | Sender-scoped retry ID when supplied; deduplicate incoming messages by message.id |
| textобязательно string | In your user's language when translated |
| text_original string | |
| translatedобязательно boolean | |
| langобязательно string | Language of text |
| created_atобязательно string (date-time) | |
| suspiciousобязательно boolean | |
| flagsобязательно "link" | "phone" | "messenger" | "money" | "mass_text"[] | Scam signals: link, phone, messenger (early in a chat), money, mass_text (the same text in several matches, only together with another signal ) |
message.read
The other side read your user's messages
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "message.read",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"member": "string",
"by": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"up_to": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"read_at": "2026-10-24T12:00:00Z"
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| memberобязательно string | Your user's external_id (the author) |
| byобязательно string (uuid) | network_id of the reader |
| up_toобязательно string (uuid) | Messages up to this one (inclusive) are read |
| read_atобязательно string (date-time) |
match.closed
A match of your user was closed by the other side
Make the chat read-only; the history stays. With peer_deleted: true (the other person deleted their account or their
network data) also replace their name and photo with "Account deleted" / "Left the network".
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "match.closed",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"member": "string",
"reason": "unmatched",
"peer_deleted": true
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| memberобязательно string | |
| reasonобязательно "unmatched" | "blocked" | "left_network" | "account_deleted" | |
| peer_deleted boolean | The other person is gone from the network: their profile is erased |
match.erased
A match of your user was erased by the other side
The other side deleted the pair (or blocked with erase) — remove the chat and its history on your side.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "match.erased",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"member": "string",
"reason": "unmatched"
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| memberобязательно string | Your user's external_id |
| reasonобязательно "unmatched" | "blocked" |
match.frozen
The other person is deleting their account or was hidden after reports
The chat is read-only (409 match_frozen). reason: account_deleting — show "Account deleted";
it may come back with match.unfrozen (restored within 30 days) or end with match.closed + peer_deleted.
suspended — the network hid them after reports; show "Account unavailable" until match.unfrozen (their platform
reinstated them) or match.closed.
partner_suspended means either platform is suspended. Restore messaging only after an unfreeze
or a fresh bootstrap confirming frozen: false; another independent freeze may remain.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "match.frozen",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"member": "string",
"reason": "account_deleting"
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| memberобязательно string | Your user's external_id |
| reason "account_deleting" | "suspended" | "partner_suspended" | partner_suspended |
match.unfrozen
The other person restored their account or was reinstated after reports
The chat is back as it was — their name, photo and messaging.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "match.unfrozen",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"match_id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"member": "string"
}
}data
| Поле | Описание |
|---|---|
| match_idобязательно string (uuid) | |
| memberобязательно string | Your user's external_id |
member.reported
Your user was reported by someone from another app
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "member.reported",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"reason": "string",
"comment": "string"
}
}data
| Поле | Описание |
|---|---|
| member string | |
| reason string | |
| comment string |
member.suspended
Your user was hidden from the network pending review
After a report with underage or commercial, or reports from 3 different people. Their matches are frozen until you
review the reports: block the user in your app or bring them back with POST /v1/members/{external_id}/reinstate.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "member.suspended",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"reason": "string"
}
}data
| Поле | Описание |
|---|---|
| member string | |
| reason string |
member.rejected
Your user's profile did not pass the network's moderation
The profile is hidden from feeds and cannot like until you send a corrected one.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "member.rejected",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"member": "string",
"reason": "photo_nudity",
"photo": "https://example.com/photo.jpg",
"video": "https://example.com/photo.jpg"
}
}data
| Поле | Описание |
|---|---|
| memberобязательно string | |
| reasonобязательно "photo_nudity" | "offensive_text" | "contact_info" | "photo_unavailable" | "video_invalid" | "video_too_long" | "video_unavailable" | |
| photo string (uri) | The photo or poster that did not pass (photo_* reasons) |
| video string (uri) | The clip that did not pass (video_* reasons) |
photo_check.updated
A new result of a photo check
After each attempt, when the person disputes the result and when the network moderator decides — go by the latest.
Passed (passed or resolved with the photos matched) — you may claim verification: {provider: "pereval", check_id}.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "photo_check.updated",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"id": "6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"ref": "string",
"url": "https://example.com/photo.jpg",
"status": "created",
"reason": "no_match",
"attempts": 1,
"expires_at": "2026-10-24T12:00:00Z",
"checked_at": "2026-10-24T12:00:00Z",
"dispute_until": "2026-10-24T12:00:00Z",
"disputed_at": "2026-10-24T12:00:00Z",
"decided_at": "2026-10-24T12:00:00Z",
"note": "string",
"photos": [
{
"id": "string",
"url": "https://example.com/photo.jpg",
"verdict": "match"
}
],
"created_at": "2026-10-24T12:00:00Z"
}
}data
| Поле | Описание |
|---|---|
| idобязательно string (uuid) | |
| refобязательно string | |
| url string (uri) | Only in the POST reply: the check page to open for the person |
| statusобязательно "created" | "passed" | "partial" | "failed" | "disputed" | "resolved" | "expired" | created — not taken yet; passed — it's the person on every photo with a face; partial — some photos don't
look like the picture; failed — see reason; disputed — the person disputed, a network moderator decides
(usually within 24 hours); resolved — the moderator decided (note explains); expired — the link expired untaken.
|
| reason "no_match" | "no_face" | "many_faces" | "no_gesture" | "virtual_camera" | Why it failed |
| attemptsобязательно integer | Pictures taken (up to 5 per session) |
| expires_atобязательно string (date-time) | Until when the link allows attempts |
| checked_at string (date-time) | The last picture |
| dispute_until string (date-time) | Failed or partial: the person can dispute until then |
| disputed_at string (date-time) | |
| decided_at string (date-time) | The moderator's decision |
| note string | The moderator's explanation for the person |
| photosобязательно object[] | |
| idобязательно string | |
| urlобязательно string (uri) | |
| verdict "match" | "no_match" | "unsure" | "no_face" | match — the same person; no_match — doesn't look like them; unsure — couldn't compare reliably; no_face — no face, not counted. Absent — not compared yet |
| created_atобязательно string (date-time) |
ping
Test event from the dashboard
Sent when you click "Send a test event" in the dashboard. Reply 2xx — this checks the URL and the signature.
{
"id": "evt_6f1c2b4e-8a3d-4c55-9b1e-2f0a7d9c1e44",
"type": "ping",
"created_at": "2026-10-24T12:00:00Z",
"data": {
"message": "string"
}
}data
| Поле | Описание |
|---|---|
| message string |