From 7ebff666975a9e0d2610cfd6a5d8f3159d40f8db Mon Sep 17 00:00:00 2001 From: Lenz Date: Mon, 17 Aug 2026 12:05:43 +0300 Subject: [PATCH] chore: point key links at /api-credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lenz.io renamed /api-integration to /api-credentials: the page holds API keys AND OAuth connected apps, and the old path read like an integration landing page rather than a credentials manager. Touches the runtime strings users actually see — the 401 remediation hint, the missing-key error, and the three webhook-secret errors — plus _dashboard_url(), which `lenz login` OPENS IN A BROWSER, so it is the one that would visibly take someone to a redirect. Not urgent for anyone already installed: lenz.io keeps a permanent 302 from the old path precisely because published versions of this package hard-code it and can never be updated. This just stops new releases pointing at a redirect. openapi.json is deliberately untouched — it is generated from the Lenz repo via `make regen`, so it picks the new wording up on the next regeneration rather than being hand-edited here. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016A7nD9KjjwujFHr17SBybh --- README.md | 6 +++--- examples/core/fastapi_webhook.py | 2 +- src/lenz_io/cli/commands.py | 2 +- src/lenz_io/client.py | 4 ++-- src/lenz_io/errors.py | 2 +- src/lenz_io/webhooks.py | 8 ++++---- tests/test_cli.py | 2 +- tests/test_client.py | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 18e1b98..c65ac76 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ pip install "lenz-io[cli]" # or into your current environment ``` ```bash -lenz login # paste an API key (free — get one at lenz.io/api-integration) +lenz login # paste an API key (free — get one at lenz.io/api-credentials) lenz extract "Einstein won the 1921 Nobel for relativity" # free, 1000/day lenz assess "The Great Wall is visible from space" # fast verdict lenz verify "Water boils at 90C at sea level" # full pipeline (~90s) @@ -122,7 +122,7 @@ for source in v.sources[:3]: The demo claim is pre-cached so this returns in ~1.5s. Your own claims hit the full pipeline (~60-90s) — use webhooks for production async flows. -> **Get your webhook secret here →** [lenz.io/api-integration](https://lenz.io/api-integration) +> **Get your webhook secret here →** [lenz.io/api-credentials](https://lenz.io/api-credentials) ## What you get on the client @@ -237,7 +237,7 @@ except LenzAuthError as exc: print(exc) # Unauthorized # Cause: Invalid api key - # Fix: Generate a new key at https://lenz.io/api-integration. + # Fix: Generate a new key at https://lenz.io/api-credentials. # Docs: https://lenz.io/docs/auth # Request ID: req_abc123 except LenzRateLimitError as exc: diff --git a/examples/core/fastapi_webhook.py b/examples/core/fastapi_webhook.py index 4d1aa12..f3ca7f7 100644 --- a/examples/core/fastapi_webhook.py +++ b/examples/core/fastapi_webhook.py @@ -10,7 +10,7 @@ uvicorn examples.core.fastapi_webhook:app --host 0.0.0.0 --port 8000 Then point your Lenz API key's webhook URL at https:///lenz-webhook -on the /api-integration page, or pass `webhook_url=...` on individual +on the /api-credentials page, or pass `webhook_url=...` on individual verify() calls. """ diff --git a/src/lenz_io/cli/commands.py b/src/lenz_io/cli/commands.py index 0231f9f..6bfd9d5 100644 --- a/src/lenz_io/cli/commands.py +++ b/src/lenz_io/cli/commands.py @@ -161,7 +161,7 @@ def work(client: Lenz) -> None: def _dashboard_url(base_url: str) -> str: parts = urlsplit(base_url) - return urlunsplit((parts.scheme, parts.netloc, "/api-integration", "", "")) + return urlunsplit((parts.scheme, parts.netloc, "/api-credentials", "", "")) def login(ctx: typer.Context) -> None: diff --git a/src/lenz_io/client.py b/src/lenz_io/client.py index c393003..9f15d58 100644 --- a/src/lenz_io/client.py +++ b/src/lenz_io/client.py @@ -289,7 +289,7 @@ class Lenz: The constructor accepts ``api_key=None`` so library endpoints work without authentication (sandbox path for developers exploring before sign-up). Auth-required methods on an un-keyed client raise - ``LenzAuthError`` with a link to ``/api-integration``. + ``LenzAuthError`` with a link to ``/api-credentials``. Reads ``LENZ_API_KEY`` from the environment if no key is passed. """ @@ -763,7 +763,7 @@ def _request( cause="This method requires authentication; no API key was provided.", fix=( "Pass api_key= to Lenz(), set LENZ_API_KEY env var, or get one at " - "https://lenz.io/api-integration. Library endpoints work without a key." + "https://lenz.io/api-credentials. Library endpoints work without a key." ), doc_url="https://lenz.io/docs/auth", ) diff --git a/src/lenz_io/errors.py b/src/lenz_io/errors.py index 752f8f9..d8dfb59 100644 --- a/src/lenz_io/errors.py +++ b/src/lenz_io/errors.py @@ -407,7 +407,7 @@ def _opt_int(value: Any) -> int | None: def _fix_hint_for(status_code: int) -> str: return { - 401: "Generate a new key at https://lenz.io/api-integration.", + 401: "Generate a new key at https://lenz.io/api-credentials.", 403: "This key doesn't have access to that resource.", 402: "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", 422: "Check the request body against the OpenAPI spec.", diff --git a/src/lenz_io/webhooks.py b/src/lenz_io/webhooks.py index 63cedca..27f4045 100644 --- a/src/lenz_io/webhooks.py +++ b/src/lenz_io/webhooks.py @@ -21,7 +21,7 @@ ``replay_window_seconds`` (default 300s / 5 minutes). Customers MUST register the same secret with us via the -``/api-integration`` page. Rotating the secret on Lenz's side invalidates +``/api-credentials`` page. Rotating the secret on Lenz's side invalidates old deliveries. """ @@ -63,7 +63,7 @@ def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool: raise LenzWebhookSignatureError( message="Missing webhook signature", cause=f"No {SIGNATURE_HEADER} header on the request.", - fix="Inspect the webhook delivery in /api-integration to confirm the secret is set.", + fix="Inspect the webhook delivery in /api-credentials to confirm the secret is set.", doc_url="https://lenz.io/docs/webhooks", ) if not isinstance(raw_body, (bytes, bytearray)): @@ -79,7 +79,7 @@ def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool: raise LenzWebhookSignatureError( message="Webhook signature mismatch", cause="HMAC of the raw body using your secret does not match X-Lenz-Signature.", - fix="Verify the secret in /api-integration matches the one you configured here.", + fix="Verify the secret in /api-credentials matches the one you configured here.", doc_url="https://lenz.io/docs/webhooks", ) return True @@ -214,7 +214,7 @@ def __init__( replay_window_seconds: int = DEFAULT_REPLAY_WINDOW_SECONDS, ) -> None: if not secret: - raise ValueError("LenzWebhooks requires a non-empty secret. Get it from /api-integration.") + raise ValueError("LenzWebhooks requires a non-empty secret. Get it from /api-credentials.") self._secret = secret self._replay_window = replay_window_seconds diff --git a/tests/test_cli.py b/tests/test_cli.py index 026e3ca..6813db7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1146,7 +1146,7 @@ def test_login_json_no_key_points_to_dashboard(): assert result.exit_code == 0 payload = json.loads(result.stdout) assert payload["status"] == "no_key" - assert "api-integration" in payload["dashboard"] + assert "api-credentials" in payload["dashboard"] def test_login_write_failure_is_friendly(monkeypatch): diff --git a/tests/test_client.py b/tests/test_client.py index c0746bd..49315ed 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -61,7 +61,7 @@ def test_library_list_omits_curated_and_verdict_when_default(self, unauth_client def test_auth_required_method_without_key_raises_with_clear_message(self, unauth_client): with pytest.raises(LenzAuthError) as ei: unauth_client.verifications.list() - assert "/api-integration" in str(ei.value) + assert "/api-credentials" in str(ei.value) def test_api_key_armed_methods(self, client): with respx.mock(base_url=DEFAULT_BASE) as r: