For your own scripts — anything where the OAuth dance is overkill. An API key is a single-credential bearer token that always acts as you.
When to use API keys vs OAuth
| Use API keys when | Use OAuth when |
|---|---|
| It's a personal script (cron job, jupyter notebook, weekend hack) | A multi-tenant integration that touches other users' data |
| The credential lives on a machine you control | The credential is shipped to end-user devices |
| You're OK with the token never expiring | You need users to revoke individually from their side |
API keys cannot grant
flights:delete. Use OAuth Authorization Code if you need destructive scopes.
Generating a key
- Sign in to https://we-fly.cloud.
- Open https://we-fly.cloud/developer → New API key.
- Pick a name, an expiration (1–365 days, or blank for no expiration), and the scopes you need.
- Copy the key (
wf_key_…) when it's revealed. It's shown once — if you lose it, revoke the key and generate a new one.
Using a key
curl https://we-fly.cloud/api/v1/flights \
-H "Authorization: Bearer ${WEFLY_API_KEY}"
Identical to using an OAuth access token. The same scope and rate-limit rules apply.
Revoking a key
/developer → click Revoke on the row. Effects are immediate;
subsequent requests with the revoked key return
401 invalid_token.
Revoking is irreversible. There's no "unrevoke" — generate a new key if you change your mind.
Best practices
- Store the key in a secrets manager, not in a checked-in
.envfile. If your CI logs leak, you don't want the key with them. - Set an expiration if the script's life is bounded (e.g., a one-off backfill).
- Use the narrowest scope set you can. If your script only reads,
don't tick
flights:write. - Rotate before they're compromised. A monthly rotation is a good default for production scripts.
Example: nightly export of new flights
import os, requests, json
from datetime import datetime, timezone
API = "https://we-fly.cloud/api/v1"
KEY = os.environ["WEFLY_API_KEY"]
HEAD = {"Authorization": f"Bearer {KEY}", "User-Agent": "nightly-export/1.0"}
def list_flights(page=1):
r = requests.get(f"{API}/flights", headers=HEAD, params={"page": page, "pageSize": 100})
r.raise_for_status()
return r.json()
def main():
all_flights = []
page = 1
while True:
body = list_flights(page)
all_flights += body["data"]
if page >= body["pagination"]["totalPages"]:
break
page += 1
with open("flights.json", "w") as f:
json.dump({"exportedAt": datetime.now(timezone.utc).isoformat(), "flights": all_flights}, f, indent=2)
main()