Developer
Step 3 of 7

Authentication

Every request to https://api.pff.com under /v1/ or /v2/ carries one credential in the Authorization header. There are two kinds. Both need a paid PFF Pro subscription, and the API treats them the same once it has checked them.

Browser sign-in API key
Best for Working at your own terminal Scripts, CI, notebooks, or any HTTP client
How you get it Your first restish pff command opens your browser Create one at pff.com/account/api-keys
What it looks like An OAuth token Restish stores for you in ~/.config/restish/tokens.cbor A string starting with ak_live_, shown once
How long it lasts Refreshed silently; restish pff logout ends it Until you revoke it on the same page
Where it works Restish, which runs the browser flow for you Restish, curl, and any language

If you only ever use the CLI interactively, you can skip straight to Log in. Everything else on this page is about API keys.

Get an API key

  1. Sign in at pff.com with the account that holds your PFF Pro subscription.
  2. Open Account → API Keys, or go straight to https://www.pff.com/account/api-keys.
  3. Create a key. It is shown once, so copy it now. It starts with ak_live_.
  4. Store it as PFF_API_KEY in your shell profile or your CI’s secret store. Never put it on a command line, in a repo, or in a chat message.

PFF+, free and Pro-trial accounts see an upgrade prompt on that page instead of a key manager. The CLI and API are part of paid PFF Pro only.

Revoking a key is the same page. Revocation takes effect within a minute: the API caches a successful key check for up to 60 seconds, so a request in that window may still succeed. Treat a key you no longer control as compromised and revoke it rather than waiting for it to fall out of use.

Send it

Whichever credential you hold, it travels the same way:

Authorization: Bearer <your API key or OAuth access token>

With curl or any HTTP client

whoami is the right first call. It costs nothing against your rate budget and tells you exactly what the API thinks of your credential.

export PFF_API_KEY=ak_live_...   # set it once, in your shell only

curl -s https://api.pff.com/v1/auth/whoami \
  -H "Authorization: Bearer $PFF_API_KEY"
{
  "external_id": "93482620-...",
  "email": "you@example.com",
  "tier": "pro",
  "entitled": true,
  "entitlement_reason": null,
  "credential": "api_key",
  "session_expires_at": null
}

entitled: true with credential: api_key means every data operation will work. From there, any path in the API reference:

# v1 — the Premium Stats reports: snake_case query parameters
curl -s 'https://api.pff.com/v1/facet/passing/summary?league=nfl&season=2025&franchise_id=26' \
  -H "Authorization: Bearer $PFF_API_KEY"

# v2 — PFF's team tables: camelCase query parameters, team by slug or franchise id
curl -s 'https://api.pff.com/v2/nfl/teams/los-angeles-rams/reports/passing?season=2025&weekGroup=REG' \
  -H "Authorization: Bearer $PFF_API_KEY"

# CSV instead of JSON: v1 takes export=true, v2 takes format=csv
curl -s 'https://api.pff.com/v1/facet/passing/summary?league=nfl&season=2025&export=true' \
  -H "Authorization: Bearer $PFF_API_KEY" -o passing-2025.csv
curl -s 'https://api.pff.com/v2/nfl/teams?season=2025&format=csv' \
  -H "Authorization: Bearer $PFF_API_KEY" -o teams-2025.csv

Three things worth knowing when you leave Restish behind:

  • Restish renames some parameters. The flag is not always the wire name: --franchise is franchise_id and --game is game_id on /v1, and /v2 uses camelCase such as weekGroup and weekTo. The OpenAPI document is the source of truth for the real names, and it is public — no credential needed.
  • Budgets are per account, not per key. Every account gets 100 reads and 20 exports per minute across every credential it holds. Each counted response carries x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset; going over answers 429 with a Retry-After. whoami and logout are never counted.
  • Every error is one JSON shape. {"error":{"code","message","request_id","details"}}. Branch on error.code and error.details.reason, never on the message text, and quote request_id when you write to support.

With Restish

Give Restish a second profile that reads the key from the environment, and pick it per command with -p ci. Your default profile keeps using browser sign-in, so both work side by side.

restish api set pff 'profiles.ci.credentials.pffApiKey.auth.type: bearer'
restish api set pff 'profiles.ci.credentials.pffApiKey.auth.params.token: env:PFF_API_KEY'

restish pff whoami -p ci                                  # credential: api_key
restish pff passing --league nfl --season 2025 -p ci -o json

Restish reads PFF_API_KEY when it sends the request, so the key never lands in restish.json or your shell history. The full recipe, including CSV in CI, is in Log in and Exporting.

When it fails

Every refusal names its reason in error.details.reason. Restish prints the message; with curl you will see the JSON.

Status and code details.reason What it means What to do
401 unauthorized missing No Authorization header Send Authorization: Bearer <key>
401 unauthorized malformed The header is not Bearer <credential> Check the header format and that the key was not truncated
401 unauthorized invalid_signature The credential could not be verified: a typo, a key from another environment, or one that was deleted Copy the key again, or create a new one
401 unauthorized revoked The key or sign-in was revoked, by you or by support Create a new key, or sign in again
401 unauthorized expired An OAuth token that could not be refreshed restish api auth logout pff, then run any command to sign in again
401 unauthorized wrong_token_type You sent a pff.com session token (a browser cookie) instead of an OAuth access token or API key Use an API key, or sign in through Restish
403 forbidden subscription_required The credential is valid but the account is PFF+ or free Upgrade to PFF Pro
403 forbidden trial The account is on a Pro trial; the CLI and API unlock when it converts Nothing to fix now
403 forbidden unlinked_account A Pro account not yet linked to a subscriber record Email contact@pff.com and quote the request_id
429 rate_limited verify_ip Too many unknown keys tried from one address in a minute Fix the key rather than retrying; wait for Retry-After
503 upstream_error — The identity provider did not answer Retry after Retry-After; nothing is wrong with your key

Next: Log in with your PFF account — the browser flow for interactive use, and the no-browser variant for SSH sessions.