Whisper Money

Search the documentation

Search pages and sections.

Achievements

A medal (an achievement) records a milestone you reached: a visit or saving streak, a net worth or savings rate level, transactions recorded, data kept tidy. Medals cover your whole account, not a space.

The example requests read your personal token from $WHISPER_MONEY_TOKEN: run export WHISPER_MONEY_TOKEN=wm_api_your_token_here before pasting them.

List achievements

GET /api/v1/achievements

The whole medal catalog, grouped into tracks, earned or not. On each track, the first medal you have not earned yet is next and comes named, often with how far along you are; the ones past it are locked and stay silhouettes, with no name, icon or figure. The catalog is small and fixed, so it is not paginated.

Scope: read. A personal token needs api:read; an OAuth token needs api:use.

Response

200

Field Type Description
data Achievements
data.currency string The currency the money milestones are set in: your account's currency when the medals have levels for it, USD otherwise.
data.unlocked integer How many medals you have earned.
data.total integer How many medals there are.
data.streak object or null Your saving streak as it stands: how many months in a row you have saved, from the last monthly report, and the first day of the first of them. It is a live figure, not a medal, and it can break. null with no streak running.
data.streak.months integer
data.streak.since string
data.latest object or null The medal you earned last, or null with none.
data.latest.name string or null
data.latest.achieved_on string
data.tracks array of AchievementTrack The tracks, each a ladder of medals.
data.tracks[].key string The track's key.
data.tracks[].label string The track's name.
data.tracks[].note string or null What the track has to explain about itself, or null.
data.tracks[].unlocked integer How many of its medals you have earned.
data.tracks[].medals array of Achievement Its medals, from the first rung up.
data.tracks[].medals[].key string The medal's key, unique in the catalog.
data.tracks[].medals[].rarity string How rare the medal is: common, uncommon, rare or epic.
data.tracks[].medals[].share number or null The percentage of Whisper Money users who hold it, or null while there are too few users to tell or nobody holds it yet.
data.tracks[].medals[].state "earned" | "next" | "locked" earned; next for the one rung of its track you are working towards; or locked for the ones past it.
data.tracks[].medals[].name string or null The medal's name. null on a locked medal, which stays a silhouette: only the next one is named.
data.tracks[].medals[].icon string or null The medal's pictogram, a Lucide icon name; null on a locked medal.
data.tracks[].medals[].figure object or null The milestone the medal stands for: its type (money, count, percent, months, weeks or days), its value (in minor units of currency for money) and that currency, null for the other types. null on a locked medal and on the ones that are an event with no number to them.
data.tracks[].medals[].figure.type string
data.tracks[].medals[].figure.value number
data.tracks[].medals[].figure.currency string or null
data.tracks[].medals[].reached object or null On an earned medal, what you had reached on the day, shaped like figure; null otherwise.
data.tracks[].medals[].reached.type string
data.tracks[].medals[].reached.value number
data.tracks[].medals[].reached.currency string or null
data.tracks[].medals[].achieved_on string (date) or null The day the medal was earned, or null.
data.tracks[].medals[].progress object or null On the next medal of the tracks whose figure is cheap to read, how far along you are: now against goal, and unlocking once you are past the goal but the medal still waits for the nightly check that awards it. null otherwise.
data.tracks[].medals[].progress.now integer
data.tracks[].medals[].progress.goal number
data.tracks[].medals[].progress.unlocking boolean

Example request

curl https://whisper.money/api/v1/achievements \
  -H "Authorization: Bearer $WHISPER_MONEY_TOKEN"

Example response

{
    "data": {
        "currency": "EUR",
        "unlocked": 12,
        "total": 59,
        "streak": {
            "months": 3,
            "since": "2026-07-01"
        },
        "latest": {
            "name": "First transaction",
            "achieved_on": "2026-03-02"
        },
        "tracks": [
            {
                "key": "transactions",
                "label": "Transactions recorded",
                "note": null,
                "unlocked": 1,
                "medals": [
                    {
                        "key": "transactions.2",
                        "rarity": "common",
                        "share": 42.5,
                        "state": "next",
                        "name": "50 transactions",
                        "icon": "ListChecks",
                        "figure": {
                            "type": "count",
                            "value": 50,
                            "currency": null
                        },
                        "reached": null,
                        "achieved_on": null,
                        "progress": {
                            "now": 23,
                            "goal": 50,
                            "unlocking": false
                        }
                    }
                ]
            }
        ]
    }
}

Errors

Status When
401 No bearer token, or one that is unknown, expired or revoked.
403 The token lacks the scope (insufficient_scope), the account has no Pro plan (plan_required, with a subscribe_url) or it is a shared demo account (shared_account).
429 The rate limit is exhausted. Wait the seconds in Retry-After.