List biggest gainers and losers
curl --request GET \
--url https://api.cromos.so/v1/cards/movers \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.cromos.so/v1/cards/movers"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.cromos.so/v1/cards/movers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cromos.so/v1/cards/movers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cromos.so/v1/cards/movers"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cromos.so/v1/cards/movers")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cromos.so/v1/cards/movers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": {
"items": [
{
"card_id": "sv06-155",
"name": "Lana's Aid",
"expansion_id": "sv06",
"number": "155",
"card_variant_id": 32484,
"printing": "reverse",
"start_cents": 119,
"end_cents": 351,
"change_cents": 232,
"change_bp": 19496,
"start_as_of": "2026-08-10",
"observed_on": "2026-08-18"
},
{
"card_id": "ecard2-13",
"name": "Exeggutor",
"expansion_id": "ecard2",
"number": "13",
"card_variant_id": 3013,
"printing": "reverse",
"start_cents": 5300,
"end_cents": 12915,
"change_cents": 7615,
"change_bp": 14368,
"start_as_of": "2026-08-10",
"observed_on": "2026-08-18"
},
{
"card_id": "ecard1-69",
"name": "Vileplume",
"expansion_id": "ecard1",
"number": "69",
"card_variant_id": 2763,
"printing": "reverse",
"start_cents": 1675,
"end_cents": 3904,
"change_cents": 2229,
"change_bp": 13307,
"start_as_of": "2026-07-31",
"observed_on": "2026-08-18"
}
],
"next_cursor": "eyJicCI6MTMzMDcsImlkIjoiZWNhcmQxLTY5In0"
},
"error": null
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}Cards
List biggest gainers and losers
Cards ranked by price movement over a window, gainers or losers.
GET
/
v1
/
cards
/
movers
List biggest gainers and losers
curl --request GET \
--url https://api.cromos.so/v1/cards/movers \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.cromos.so/v1/cards/movers"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.cromos.so/v1/cards/movers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cromos.so/v1/cards/movers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cromos.so/v1/cards/movers"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cromos.so/v1/cards/movers")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cromos.so/v1/cards/movers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": {
"items": [
{
"card_id": "sv06-155",
"name": "Lana's Aid",
"expansion_id": "sv06",
"number": "155",
"card_variant_id": 32484,
"printing": "reverse",
"start_cents": 119,
"end_cents": 351,
"change_cents": 232,
"change_bp": 19496,
"start_as_of": "2026-08-10",
"observed_on": "2026-08-18"
},
{
"card_id": "ecard2-13",
"name": "Exeggutor",
"expansion_id": "ecard2",
"number": "13",
"card_variant_id": 3013,
"printing": "reverse",
"start_cents": 5300,
"end_cents": 12915,
"change_cents": 7615,
"change_bp": 14368,
"start_as_of": "2026-08-10",
"observed_on": "2026-08-18"
},
{
"card_id": "ecard1-69",
"name": "Vileplume",
"expansion_id": "ecard1",
"number": "69",
"card_variant_id": 2763,
"printing": "reverse",
"start_cents": 1675,
"end_cents": 3904,
"change_cents": 2229,
"change_bp": 13307,
"start_as_of": "2026-07-31",
"observed_on": "2026-08-18"
}
],
"next_cursor": "eyJicCI6MTMzMDcsImlkIjoiZWNhcmQxLTY5In0"
},
"error": null
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"data": {},
"error": {
"code": "<string>",
"message": "<string>"
}
}Rows come back ordered by A different selection from
change_bp, biggest gainer first for direction=up and steepest drop
first for direction=down, paged by cursor exactly like List cards. Pass
expansion_id to rank inside one expansion instead of the whole catalog.
One row per card, and the printing depends on direction
A card can move differently on different printings. The gainers list names whichever printing rose most; the losers list, for the same card and the same window, names whichever printing fell most, and that can be a different printing entirely. A card whose holofoil rose while its reverse holofoil fell appears on both lists, each row naming the printing it is actually about. Read the printing off the row rather than assume the two lists agree on which piece of cardboard they mean.card_variant_id is what names it exactly: it matches an id in the card’s variants, from
Get a card or ?include=variants on List cards. printing is the
type axis alone, and one card can carry several printings that share a type, so matching on
that string can land on the wrong one.
What qualifies
The leaderboard ranks theungraded tier, which is the price of a raw copy, so a slab that
moved sharply does not push a card up this list.
A printing ranks only if it trades often enough for a movement to mean something, and only if it
was above a minimum price at the start of the window. A percentage measured on a handful of sales
a year says more about which two copies happened to change hands than about the market, so a
printing that thin is absent from both lists rather than at the top of one. The same applies at
the other end: a card that went from two cents to six is up 200% and is not news.
Read sales_volume on any printing from Get a card to see how many copies sold in
the trailing year. A card can therefore be absent here while still carrying prices.
Telling a held price from a stale one
A price is recorded only on the days it moved, so a printing that has held steady has no reading on most days.start_cents for a window is carried forward from the last day it was actually
observed, and start_as_of is that day. When start_as_of sits well before the window’s start,
change_bp is measured against a carried value rather than a fresh reading: a card untouched for
two months can still surface here, at a real percentage computed against an old price. Compare
start_as_of to the window to tell “held steady” from “not seen in a while.”
Windows need history behind them
A window is computable only once observations reach back across it, and the price history behind this leaderboard begins on 21.08.2026.30d therefore carries nothing until late September, and
an empty page for a wide window is an absence rather than a market that stopped moving. Narrower
windows fill in first.
A different selection from include=change
?include=change on List cards and Get a card reports change data
for a card too, but for a different printing: the one the card’s displayed price is read from, not
necessarily the one that moved most. A card can lead this leaderboard on one printing’s percentage
while its include=change figure, drawn from another, reads something smaller, or even moves the
other way. See Change on the card object.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Query Parameters
The period to measure over.
Available options:
1d, 7d, 30d up for biggest gainers, down for biggest losers.
Available options:
up, down Narrow the list to one expansion. An id that matches nothing is an empty page, not a 404.
How many rows to return. Defaults to 50 and stops at 200; a larger value is clamped, not rejected.
Required range:
1 <= x <= 200The next_cursor from the previous page. Omit it for the first page. A cursor this endpoint did not issue is ignored, and you get the first page back.