---
title: "Auth Refresh Tier"
method: GET
path: "/api/auth/refresh-tier"
tags: ["auth", "billing"]
---

# Auth Refresh Tier

`GET /api/auth/refresh-tier`

## Request

- Base URL: `https://www.oxfordledge.com` (the document declares no server; this is the origin it was published from)
- URL: `https://www.oxfordledge.com/api/auth/refresh-tier`
- Auth: none declared

Re-read the user's tier from PG and refresh the session cookie.

CR-H5 (2026-04-30): After Stripe Checkout the webhook can take 2–5s to
update the user's tier. The frontend polls this endpoint (up to 10×, 1s
apart) until `tier` changes from the pre-checkout value, then dispatches
`ol-tier-refreshed` so TierGate re-evaluates gates without a page reload.

This is a read-only GET — no CSRF required (idempotent, no state change
on the server beyond reading PG). The session cookie is refreshed in-place
when the tier changes so subsequent /api/auth/me calls reflect the new tier
without the client needing a full logout/login cycle.

GET is exempt from validate_csrf per the auth-route convention: read-only
endpoints that carry no state mutation are guarded by require_auth (401)
rather than CSRF (403). See `auth_me` + `billing_trial_status` siblings
for prior art.

## Response `200`

Successful Response

- TierRefreshResponse: `GET /api/auth/refresh-tier` response. Used by the post-Stripe-Checkout polling loop in session-lifecycle.js to detect when the webhook has processed the upgrade and the user's tier has changed. Required fields: `tier` (the canonical tier string read fresh from PG `user_billing`, or `users.tier` as fallback) + `refreshed_at` (ISO-8601 UTC timestamp of this read — lets the poller compare against the pre-checkout tier to detect a change). Frontend `OLSessionLifecycle.pollTierRefresh()` calls this in a loop until `tier` changes from the pre-checkout value (or 10 attempts pass). On change, dispatches `ol-tier-refreshed` CustomEvent so TierGate and other listeners re-evaluate gates without a page reload.
  - `tier` string, required: Current tier from PG (`user_billing.tier` primary, `users.tier` fallback). One of 'free', 'plus_trial', 'plus', 'pro', 'professional', etc. Frontend polls until this value changes from the pre-checkout tier stored in OLSessionLifecycle.
  - `refreshedAt` string, required: ISO-8601 UTC timestamp of this tier read. Lets the poller distinguish a stale cached response from a fresh DB hit. Format: YYYY-MM-DDTHH:MM:SS.ffffffZ.

---

[API](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api.md) · [All operations](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/revisions/e832a1260f0b?raw)
