Skip to main content
Before you start
  • A WHOOP membership, and a WHOOP developer account. The membership is the paid part. The developer account, at developer-dashboard.whoop.com, costs nothing.
  • A Team at WHOOP, if this is your first app. WHOOP asks a new developer account to create a Team before its first app. Any name will do, and the Team needs no other members.
  • A web address to give WHOOP as your privacy policy. WHOOP’s app form asks for one and will not take an empty field. You do not need a real privacy policy. WHOOP does not check the address: Postern’s own WHOOP app carries https://dummy.com/privacy.
  • Nothing to request from WHOOP. A new app serves up to 10 WHOOP members without approval. You are one of them. Approval is for an app you hand to other people.
  • About 10 minutes, in one sitting. Postern remembers a sign-in you started for 10 minutes, and lets you finish it once. Do not restart or update Postern while you work.
  • Postern started, with the Console open at http://localhost:8787. WHOOP sends you back to that address. Postern refuses a return under any other name, so finish the whole sign-in in that browser. No Postern yet? Install Postern. Postern on a computer with no screen? Open the Console over SSH first.
  • A password manager, open. WHOOP gives your app two values: a client ID and a client secret. Postern needs both — WHOOP refuses the sign-in without the secret. WHOOP shows the secret when it creates the app, then masks it. Copy it there and then.
1

Copy the redirect URI out of the Console

Open the Console at http://localhost:8787. In the left navigation, click Sources. On that page, click Add a source, then the Whoop tile.The left column carries the heading Register your app. Its second step reads Request the offline scope, and add this redirect URI:, with an address underneath.Click Copy beside that address. The button answers Copied.A redirect URI is the address the provider sends you back to after you approve. They match it exactly, character for character. On a stock install this one reads:
Copy it from the screen, not from this page. It stays correct if you ever change the Console port — the Console prints the address Postern will send, never one it worked out itself.The Console calls it a redirect URI. WHOOP’s form heads that section REDIRECT URLS. One address, two names.
The address is missing. Its place is empty, or it holds a sentence. Empty means Postern has not answered yet. A sentence is Postern’s own error message. Open a terminal on the machine Postern runs on. Go to the folder that holds docker-compose.yml. Run docker compose ps and wait until app reads healthy. Then reload the Console screen.
2

Create the app at WHOOP

Go to developer-dashboard.whoop.com and sign in with your WHOOP account. The signed-in page reads Your apps, with APPS, TEAM and DOCS across the top right.
The Console’s own first step names developer.whoop.com. That address is WHOOP’s documentation site. You create the app at developer-dashboard.whoop.com. Two addresses, one WHOOP.
If this is your first app, WHOOP asks you to create a Team before it opens the app form. Give the Team any name.Press CREATE NEW APP, top right. WHOOP opens a form titled New App.Fill the three sections at the top of that form:
  • NAME — type Postern. WHOOP’s note reads “App name displayed to the user in the OAuth flow.”, and the field shows App Name until you type.
  • LOGO — a .jpg or a .png. WHOOP’s note reads “Logo displayed to the user in the OAuth flow. This logo must be either .jpg or .png and will be displayed in 1:1 width/height pixel ratio.” You are the only person who ever sees it.
  • CONTACTS — type your own email address into Contact #1. The field shows contact@example.com until you type. WHOOP’s note reads “Contact emails for this app. Administrative communications from WHOOP concerning this app will be directed to these emails.”
Tick all five read scopes below. Postern turns on the health sector only if WHOOP grants read:recovery, read:sleep or read:workout. Grant none of those three and Postern creates no connection at all — the Console can only report the connection it made.
Scroll down. Four more sections follow CONTACTS, in this order: PRIVACY POLICY, REDIRECT URLS, SCOPES, WEBHOOKS. This form prints every section heading in capitals. The app’s own screen prints the same names in ordinary case later, so match a section by what it asks for.PRIVACY POLICY — type any web address into the one field. WHOOP’s note reads “Link to your privacy policy. Users will be presented with this link in the OAuth flow.”, and the field shows https://example.com/privacy until you type. Nothing on screen marks the field required. Leave it empty and WHOOP will not create the app. You do not need a real privacy policy, and WHOOP does not check the address. Postern’s own WHOOP app carries https://dummy.com/privacy.REDIRECT URLS — paste the address you copied in step 1 into Redirect #1. Never type it by hand. The field shows https://myapp.com/callback until you paste. An ADD button below the field adds another redirect. Postern needs one, so leave ADD alone.WHOOP’s note here reads “Location to which the user is taken after logging in. A valid redirect URL will take the form of https://whoop.com or whoop://example.” Your address matches neither of those shapes. It starts http://, and WHOOP accepts it. Postern’s own WHOOP app is registered with that exact address, and it syncs today.SCOPES — six checkboxes, one per scope. WHOOP starts every one unticked. Tick the first five. Leave read:body_measurement unticked: Postern never asks for it.Scopes are permissions — the list of things your app may read. WHOOP’s own rule: “At least one scope must be specified to create an App.”offline is not one of the six, and there is no checkbox for it. Do not hunt for one. Postern asks WHOOP for offline on the sign-in request itself. The Console’s own step reads Request the offline scope, and add this redirect URI:. Postern makes that request. You register the address.offline is not data. It lets Postern renew the sign-in without you. Without it the connection dies the next day — WHOOP will not renew a token without it.WEBHOOKS — leave this section alone. Postern uses no webhooks. WHOOP renders no field here until you press ADD, so there is nothing to fill in.Press CREATE APP, at the bottom of the form. Until you change something on the form that button stays dim, and the line beneath it reads “Make a change to enable saving.”Your new app then sits under Your apps, and its card carries the app name and CLIENT ID.
3

Copy the client ID and the client secret

Copy the client secret into your password manager before you leave this screen. WHOOP shows the secret once, at creation. After that the app’s Credentials section prints Client Secret as a row of dots.
WHOOP hands the new app two values: a client ID and a client secret. Copy both into your password manager. Postern needs both in the next step.The client secret is a password. WHOOP’s own words: it should “never be logged or shared with anyone.”The client ID stays readable. Open the app from APPS, and Credentials prints Client ID in full. WHOOP’s own documentation says you can read both values later. That is true of the client ID only. The secret prints as dots.The same screen carries Status. WHOOP’s words there: “Apps can be used for development immediately with a limit of 10 WHOOP members. To launch your app to all WHOOP members, you must submit your app for approval.” You are the one member. Leave Request Approval alone.If you did not copy the secret. Nothing breaks on its own. A connection that already signed in carries on, because Postern holds the secret in the vault and renews the sign-in with it. You need the secret again only to sign in again.Look in your password manager first, then in the browser’s saved form entries.Then open the app at developer-dashboard.whoop.com and read the Credentials section. Nobody here has seen whether WHOOP offers a replacement secret there. If it does, take it, then paste the new pair into the Console.If it does not, register a second app and leave the first one alone. WHOOP’s own rule: “You can create up to 5 Apps.” Give the second app the same privacy policy address, the same redirect URL and the same five scopes. Copy its client ID and secret, then paste the pair into the Console.The first app holds the old sign-in until you finish. Do not delete it before then. Delete the app your connection runs on and the next sync stops.
4

Paste both halves into the Console and sign in

Go back to Console → Sources → Add a sourceWhoop. The right column carries the heading Configure the app.Paste the client ID into Client ID. Paste the client secret into Client secret. Leave the secret empty and the Console sends nothing. The field answers Whoop is a confidential client — paste the client secret too, or the sign-in will be refused.
Sign in on WHOOP’s page with the WHOOP account that wears the strap. A different WHOOP account connects, looks healthy, and holds no data.
Press Save & sign in with Whoop. Postern stores both values encrypted, then sends you to WHOOP’s consent page. Approve there. WHOOP returns you to the Console’s Sources page, and a message reads WHOOP connected — Health. After this, the secret leaves your machine only to renew the sign-in.The new row reads Awaiting first sync until the first poll runs. It then reads Syncing…, with a count of the rows so far on that first sync only.
You land back on the Console’s Whoop screen, which reads Whoop did not complete the sign-in. with a code beneath it in mono. The code is WHOOP’s own. Three causes: you declined, the app at WHOOP is set up wrong, or the client secret does not match the client ID. Correct the app at WHOOP, or re-paste the pair, then press Save & sign in with Whoop again.
A bare page reads {"error":"invalid or expired state"} at the callback address, instead of the Console. You took longer than 10 minutes, restarted Postern part-way, or opened the callback link a second time. Postern stored nothing, and you lost nothing. Go back to Console → Sources → Add a sourceWhoop and press Save & sign in with Whoop again.
5

Set how often Postern checks

Optional. Postern asks WHOOP for new data on a schedule, and you set it. Console → Sources → click the WHOOP row. Under Controls, Poll cadence offers 15m, 30m, 1h, 6h, 12h and 1d. WHOOP starts at 6h. 15m is the floor, and Postern clamps a faster value to it.The first sync fetches the last 30 days, so it takes longer than the syncs after it. Each later sync re-reads the last 3 days, so a night WHOOP scored late still lands.Press Sync now on the same page to sync at once, rather than at the next poll.Your app’s own screen prints WHOOP’s budget under Rate Limits: API Minute Rate Limit 100 and API Day Rate Limit 10000. A 15m poll is nowhere near either. Postern uses no webhooks, so Webhook URLs on that screen stays at No webhooks configured.

Confirm it works

  • Console → Sources lists one WHOOP row, under Health.
  • That row carries no label at all. There is no healthy badge in this Console.
  • Open the WHOOP row: Samples cached reads a number above 0.
  • Last synced shows a time, and Next poll shows one.
  • Console → Add a sourceWhoop now reads Whoop is already connected. Signing in again replaces the stored app and re-runs consent — it won’t create a second connection., with a checkbox Yes — replace the stored app and re-run consent. and a button Reconnect Whoop.

If something went wrong

What you have now

One health connection, on a credential you own. It carries recovery, sleep, day-strain, workouts and day-cycles. Any agent you have granted the health sector can answer from it. You grant on the key, not here — connect an agent. WHOOP fills three kinds of row: sleep sessions, workouts and health samples. Recovery and the day-cycle both land in samples, and the Console’s Samples cached counts all three kinds together. An agent asks for the samples by name: recovery_score · resting_heart_rate · hrv_rmssd · spo2 · skin_temperature · day_strain · day_average_heart_rate · day_max_heart_rate · day_kilojoule spo2 and skin_temperature come from the 4.0 strap only. On a 3.0 strap they stay empty. day_kilojoule stays in kilojoules, while Postern converts workout energy to kcal. A night WHOOP has not scored yet produces no rows at all. It appears on a later sync. WHOOP is read-only. There is nothing here for an agent to act on — WHOOP offers no actions, and Postern refuses to run one. What you carry from here: the WHOOP membership, and the app registration at WHOOP. Delete that app, or let the sign-in lapse, and the next sync stops. Disconnect in the Console. Postern then deletes the access token, the refresh token and the client secret from the vault. It also marks the connection and its credential revoked. The connection’s page then reads This connection was removed — its credential is gone from the vault. Syncing will not resume on its own; re-add the source to start a new connection. Your synced rows stay. To reconnect, paste the client ID and secret again.

Next

Connect an agent

An agent key, shown once · a few minutes, plus a restart of the client you connect · nothing opened to the internet, unless the client is claude.ai or ChatGPT.

Connect Apple Health

Health Auto Export on your iPhone · about 10 minutes · push, not pull. The Console’s own WHOOP screen names it: recovery, sleep and day-strain, alongside Apple Health.