Feed, likes, matches

Feed

GET /v1/members/{external_id}/feed?limit=20 returns up to 50 profiles of people from other apps who are a good fit for your user (the rules are in How the network works).

How to mix with your own profiles

Alternating works well: your profile, a network profile, yours, network. This way the user sees more people nearby, and your own users don’t get lost.

What to show on the card

Mark the profile as coming from the Pereval network. Use a “From the Pereval network” label or a network badge with an explanation.

Field How to show it
bio_translated An “AI-translated” label and a “show original” link (bio_original)
photo_verified A verification badge — the same as for your verified users. the network computes the mark: the person’s app has an approved verification method and the photos are not newer than the check. verified_by: partner — their app verified them
distance_km “4 km”, if present: only for people who turned on show_distance
country Country (ISO 3166-1 code) — in Worldwide, instead of the distance: “Rome, Italy”
height_cm Height: “178 cm”, if the person specified it

Worldwide

The feed takes scope: nearby (default) or world. Worldwide ignores distance: people from any city and country, but only those who turned on the Worldwide consent (consent.world). The viewer needs it too — otherwise 409 world_consent_required. The other conditions — a shared language or both open to other languages, a shared intent, age — stay the same.

Show the two feeds with a “Nearby | Worldwide” switch rather than mixing them: someone looking for a date in their own city would drown in people from the other side of the world. A member with Worldwide still appears in regular nearby feeds. The 200 a day limit is shared by both feeds.

Filters

the feed takes the viewer’s filters — store them on your side and send them with every request:

Parameter What it does
radius_km The nearby radius, 1–300 km, 50 by default. Ignored with scope=world
verified_only=true Only profiles with photo_verified — the mark the network computes
height_min, height_max Height range, 120–230 cm. People who didn’t specify their height pass — otherwise a height filter would empty the feed
lat, lon Nearby search centre (both required). Does not change the viewer’s profile city
city, country Place name for the same-city fallback when a profile has no coordinates
age_min, age_max Narrows age. The intersection with the viewer’s profile range is used. An empty intersection is an empty page and 200. age_min greater than age_max in the query is 422
intent One intent from the viewer’s profile. Only people who have it remain. An intent the viewer does not have is 422
language An ISO 639-1 code. The person in the feed must speak it. A shared language, or both consents to other languages, still applies
gender Only the opposite of the viewer. The viewer’s own gender is 422

A filter does not widen the profile. Invalid values return 422.

If there are few profiles, consider widening radius_km yourself and telling the person: “If there are few profiles, the radius grows a little”.

Pages and the daily limit

The response includes next_cursor while the page may not be the last. The next request uses the same parameters and cursor. No cursor in the response means the pages are over. Repeating the request without cursor returns the same people.

A member gets at most 200 distinct people a day. Showing the same profiles again does not spend the limit. How many new people can still be shown is remaining_today:

{ "items": [ … ], "remaining_today": 180, "next_cursor": "…" }

Once the limit is used up, no new people appear until the next day (UTC), and people already shown today still come back. A dislike hides a profile for 30 days. A swipe app uses it for a skip. A search site does not use it to turn the page: pages use the cursor. Both starts are swipe app and search site.

Like

POST /v1/likes
{ "from": "user-123", "to": "1b9e…" }
  • {"matched": false} — the like is saved, and the other side received like.received.
  • {"matched": true, "match_id": "…"} — the like was mutual, and a match was created. Both platforms receive match.created.

You can’t like a user of your own app through the network (403) — do that in your app as usual.

  • You can only like someone your user could see. A block either way, the other environment (test vs live), or a hidden person 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 regular like to a super like sends like.received again, now with super.
  • While your user’s profile is in the network’s moderation, their likes are stored, but the other side gets like.received only after the profile passes. If it’s rejected, the likes already shown are withdrawn (like.withdrawn with rejected).

Super like

After explicit spending-account enrollment, a superlike order and X-Action-Ref are required even at zero RUB. Existing clients keep the legacy contract until enrollment. Five per day is a safety ceiling, not a free allowance. See network services.

POST /v1/likes
{ "from": "user-123", "to": "1b9e…", "super": true, "message": "Hi! Into hiking?" }

A special like the recipient sees right away, without a match. The message is optional, up to 200 characters, no contact details (phone, link, messenger handle — 422).

  • The recipient’s platform gets like.received with super: true, and the sender’s profile carries super_like: the message in the recipient’s language (message), the original (message_original), translated and scam signals (flags).
  • In the recipient’s feed and incoming likes this person comes first, with the same super_like. Show a super like clearly highlighted — the sender used a special action on it.
  • When a match happens, the super like message becomes the first message of the chat: the recipient’s platform gets it as a regular message.created, the sender’s platform shows it on its side itself.
  • 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 for them is up to you.

Changed my mind

After spending-account enrollment, a valid rewind-day and X-Action-Ref are required. Eligible rewinds have no commercial operation quota during the period. Rewind cannot resurrect erased matches or messages.

DELETE /v1/likes/1b9e…?from=user-123

Takes a like or super like back before it became a match; after a match — 409 matched (close the match instead). The recipient’s platform gets like.withdrawn and removes the like from “Liked you”. A skipped profile comes back with DELETE /v1/dislikes/{network_id}?from=… — it may appear in the feed again.

Dislike

POST /v1/dislikes
{ "from": "user-123", "to": "5c2a…" }

Send it when the person skipped a profile in a swipe app, or explicitly rejected one on a search site (“don’t show again”). Turning a search page and refreshing the grid are not dislikes: those use cursor. A disliked profile leaves the user’s feed for 30 days. The response is 204; the other side is not notified.

You can send a batch of up to 100 pairs:

POST /v1/dislikes
{
  "items": [
    { "from": "user-123", "to": "5c2a…" },
    { "from": "user-123", "to": "8d4f…" }
  ]
}

Incoming likes

The like.received event contains the profile of the person who sent the like (from), already in your user’s language. Show it under “Liked you”. A POST /v1/likes in return creates a match.

If events were lost, rebuild the list with:

GET /v1/members/{external_id}/likes?limit=50

It returns people who liked the member and are waiting for an answer — without mutual likes, dislikes and blocks, newest first:

{ "items": [ { "from": { "network_id": "…", "display_name": "Elena", … }, "liked_at": "2026-10-24T12:00:00Z" } ] }

Match

match.created is sent to both platforms — each with its own user in member and the other person’s profile in with. Create a conversation on your side and save the match_id ↔ your conversation mapping: messages, read receipts and closure will arrive by match_id.

If your user sent the like that made it mutual, the match_id arrives both in the like response and in the event — create the conversation idempotently (by match_id).

List of matches

GET /v1/members/{external_id}/matches returns open matches with the other people’s profiles. Use it for reconciliation and recovery after a failure; in normal operation, events are enough.

Parting ways

the network supports different ways to part — build your chat menu from them.

Delete the chat for your user only — the history is hidden for your user, the other person keeps it, the match stays; new messages flow as usual:

POST /v1/matches/{match_id}/clear
{ "as": "user-123" }

Close the match, keeping the history — both keep the chat, messaging is not possible (409 match_closed); the other side receives match.closed with reason: unmatched:

DELETE /v1/matches/{match_id}?by=user-123

Delete the pair for both — the match, messages and likes are deleted for both; the other side receives match.erased and removes the chat; they won’t appear in each other’s feeds for cooldown_days (0–365, 30 by default). Need “never” — block.

DELETE /v1/matches/{match_id}?by=user-123&erase=true&cooldown_days=30

If either of them reported the other, the network keeps a hidden copy of the deleted chat for 90 days to review reports.

A match is also closed if one of the two blocks the other (reason: blocked) or is removed from the network (reason: account_deleted or left_network, plus peer_deleted: true). In that case your user keeps the history — show “Account deleted” or “Left the network” instead of the name and photo.

Boost and incognito

See network services for optional modes, entitlements, privacy restrictions and receiving formats. No per-card impression callbacks are required.

Unclear? Ask a developer

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