---
title: "Get Alert Matches"
method: GET
path: "/api/alerts/{alert_id}/cars"
tags: ["Vehicle Alerts"]
---

# Get Alert Matches

`GET /api/alerts/{alert_id}/cars`

## Request

- Base URL: `https://pegarex.com.br` (the document declares no server; this is the origin it was published from)
- URL: `https://pegarex.com.br/api/alerts/{alert_id}/cars`
- Auth: HTTP bearer

The NEW arrivals recorded against this alert — not everything on the site
that happens to fit it — one page at a time, unseen ones first.

This deliberately reads alert_matches rather than re-querying car_listings.
An alert answers "what showed up since I asked?", so a listing only appears
here once a sync has brought it in and a matcher has recorded it against this
alert; the full standing inventory is one click away behind the search page's
own filters ("Ver na busca" in the UI), newest listings first.

A freshly-created alert is therefore empty until the next sync runs, which is
intended — the empty state says so.

LIFETIME: a match stays until the user has seen it, at most 7 days from
matched_at (expires_at, set at insert). The nightly digest deletes expired
rows and seen+emailed rows once their car is past the matcher's 48h window
(deleting sooner would let the matcher re-insert them); the expires_at
filter here keeps the list honest in between, and expires_at rides along so
the UI can count down.

ORDER: cars not seen before this visit first, then cars seen on a previous
visit (the UI shows those darker, marked "visto"). "Before this visit" is
decided by `visit`, a server timestamp: the first page (no cursor) takes
NOW() and returns it; the client sends it back on later pages, and /read
stamps read_at on the same clock — so a car marked seen DURING the visit
never jumps to the end mid-session and pages don't shift as they are read.
Within each group: newest sync batch first, then the digest email's order
(first_seen_at DESC, car_id DESC), so the cars an email lists are the first
ones here. Every part of the key is load-bearing: one sync stamps its whole
batch with a single matched_at (9,874 cars in one production batch), and
those shared only 1,184 distinct first_seen_at values, so car_id is what
makes the order total.

PAGINATION is keyset over that 4-part key, not OFFSET: a sync can insert or
expire matches while someone is paging, and an offset would then repeat or
skip cars. `total` and `unread_total` come with the first page only.

## Path parameters

- `alert_id` string, uuid, required

## Query parameters

- `cursor` string, nullable
- `visit` string, nullable

## Response `200`

Successful Response

- unknown

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/pegarex/apis/pegarex-api.md) · [All operations](https://skmtc.dev/pegarex/apis/pegarex-api/llms.txt) · [OpenAPI document](https://skmtc.dev/pegarex/apis/pegarex-api/revisions/8c789c9bd72d?raw)
