From 439568d30792d4e205944666ebae43005314b657 Mon Sep 17 00:00:00 2001 From: zacchua-stripe Date: Wed, 16 Sep 2026 17:15:36 -0700 Subject: [PATCH 1/3] Add option to suppress Stripe notices (#1909) * Add option to suppress Stripe notices Committed-By-Agent: codex Co-authored-by: codex * Add changelog entry for notice suppression Committed-By-Agent: codex Co-authored-by: codex * Clarify Stripe notice suppression instructions Committed-By-Agent: codex Co-authored-by: codex --------- Co-authored-by: codex --- ...chua_add-stripe-suppress-notices.change.md | 7 +++ stripe/_api_requestor.py | 27 +++++++-- tests/test_api_requestor.py | 55 ++++++++++++++++++- 3 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 .hark/changes/2026-09-15_zacchua_add-stripe-suppress-notices.change.md diff --git a/.hark/changes/2026-09-15_zacchua_add-stripe-suppress-notices.change.md b/.hark/changes/2026-09-15_zacchua_add-stripe-suppress-notices.change.md new file mode 100644 index 000000000..40261bc43 --- /dev/null +++ b/.hark/changes/2026-09-15_zacchua_add-stripe-suppress-notices.change.md @@ -0,0 +1,7 @@ +--- +title: Allow suppressing Stripe notices +pr_url: https://github.com/stripe/stripe-python/pull/1909 +semver_level: minor +--- + +Set the `STRIPE_SUPPRESS_NOTICES` environment variable to `true` to suppress Stripe notices in test and sandbox environments when not running under a detected AI agent. Notices remain enabled by default and continue to be shown to AI agents. diff --git a/stripe/_api_requestor.py b/stripe/_api_requestor.py index e0f22186d..37f2011db 100644 --- a/stripe/_api_requestor.py +++ b/stripe/_api_requestor.py @@ -72,12 +72,31 @@ _default_proxy: Optional[str] = None -def _maybe_emit_stripe_notice(rheaders: Mapping[str, str]) -> None: +def _maybe_emit_stripe_notice( + rheaders: Mapping[str, str], + environ: Optional[Mapping[str, str]] = None, +) -> None: notice = rheaders.get("Stripe-Notice") - if notice: - import warnings + if not notice: + return + + environ = os.environ if environ is None else environ + ai_agent = _APIRequestor._detect_ai_agent(environ) + if ( + not ai_agent + and environ.get("STRIPE_SUPPRESS_NOTICES", "").lower() == "true" + ): + return + + if not ai_agent: + notice += ( + "\nTo suppress Stripe notices in test and sandbox environments, " + "set the STRIPE_SUPPRESS_NOTICES environment variable to true." + ) + + import warnings - warnings.warn(notice) + warnings.warn(notice) def is_v2_delete_resp(method: str, api_mode: ApiMode) -> bool: diff --git a/tests/test_api_requestor.py b/tests/test_api_requestor.py index c49803c46..744930ed9 100644 --- a/tests/test_api_requestor.py +++ b/tests/test_api_requestor.py @@ -11,7 +11,11 @@ import stripe import io -from stripe._api_requestor import _api_encode, _APIRequestor +from stripe._api_requestor import ( + _api_encode, + _APIRequestor, + _maybe_emit_stripe_notice, +) from stripe._customer import Customer from stripe._request_options import RequestOptions from stripe._requestor_options import ( @@ -1077,6 +1081,55 @@ def test_stripe_notice_header_emits_warning( with pytest.warns(UserWarning, match="test notice value"): requestor.request("get", self.v1_path, {}, base_address="api") + def test_stripe_notice_tells_humans_how_to_suppress_notices(self): + with pytest.warns(UserWarning) as warning: + _maybe_emit_stripe_notice( + {"Stripe-Notice": "test notice value"}, {} + ) + + assert str(warning[0].message) == ( + "test notice value\n" + "To suppress Stripe notices in test and sandbox environments, " + "set the STRIPE_SUPPRESS_NOTICES environment variable to true." + ) + + @pytest.mark.parametrize("suppression_value", ["true", "TRUE"]) + def test_stripe_notice_can_be_suppressed_for_humans( + self, suppression_value + ): + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("error") + _maybe_emit_stripe_notice( + {"Stripe-Notice": "test notice value"}, + {"STRIPE_SUPPRESS_NOTICES": suppression_value}, + ) + + @pytest.mark.parametrize( + "suppression_value", ["", "false", "1", "invalid"] + ) + def test_stripe_notice_is_not_suppressed_for_other_values( + self, suppression_value + ): + with pytest.warns(UserWarning): + _maybe_emit_stripe_notice( + {"Stripe-Notice": "test notice value"}, + {"STRIPE_SUPPRESS_NOTICES": suppression_value}, + ) + + def test_stripe_notice_is_not_suppressed_for_ai_agents(self): + with pytest.warns(UserWarning) as warning: + _maybe_emit_stripe_notice( + {"Stripe-Notice": "test notice value"}, + { + "STRIPE_SUPPRESS_NOTICES": "true", + "CODEX_SANDBOX": "1", + }, + ) + + assert str(warning[0].message) == "test notice value" + @pytest.mark.anyio async def test_stripe_notice_header_emits_warning_async( self, requestor, http_client_mock From 329c70233d07db9176d36b2792cb7c432a7ffb7b Mon Sep 17 00:00:00 2001 From: zacchua-stripe Date: Thu, 17 Sep 2026 11:30:49 -0700 Subject: [PATCH 2/3] Fix event handler account scoping (#1911) * Fix event handler account scoping Committed-By-Agent: codex Co-authored-by: codex * Add PR URL to changefile Committed-By-Agent: codex Co-authored-by: codex --------- Co-authored-by: codex --- ...16_zacchua_fix-event-handler-account-scoping.change.md | 8 ++++++++ stripe/_stripe_client.py | 1 - tests/test_event_notification_handler.py | 6 +++++- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .hark/changes/2026-09-16_zacchua_fix-event-handler-account-scoping.change.md diff --git a/.hark/changes/2026-09-16_zacchua_fix-event-handler-account-scoping.change.md b/.hark/changes/2026-09-16_zacchua_fix-event-handler-account-scoping.change.md new file mode 100644 index 000000000..c8cc29ced --- /dev/null +++ b/.hark/changes/2026-09-16_zacchua_fix-event-handler-account-scoping.change.md @@ -0,0 +1,8 @@ +--- +title: Fix account scoping for event notification handler callback clients +pr_url: https://github.com/stripe/stripe-python/pull/1911 +semver_level: patch +--- + +- Fix callback clients to use the event's Stripe context and preserve the original client's non-account configuration. +- Fix API errors when using an event notification handler with a client configured with a Stripe account. diff --git a/stripe/_stripe_client.py b/stripe/_stripe_client.py index f2c01b076..1db63f0c1 100644 --- a/stripe/_stripe_client.py +++ b/stripe/_stripe_client.py @@ -353,7 +353,6 @@ def with_stripe_context( """ return StripeClient( api_key=self._requestor.api_key, # type: ignore - stripe_account=self._requestor._options.stripe_account, stripe_context=stripe_context, stripe_version=self._requestor._options.stripe_version, base_addresses=self._requestor._options.base_addresses, diff --git a/tests/test_event_notification_handler.py b/tests/test_event_notification_handler.py index c47460589..74dad1855 100644 --- a/tests/test_event_notification_handler.py +++ b/tests/test_event_notification_handler.py @@ -29,6 +29,7 @@ class TestEventNotificationHandler: def stripe_client(self, http_client_mock: HTTPClientMock) -> StripeClient: return StripeClient( api_key="sk_test_1234", + stripe_account="acct_123", stripe_context=StripeContext.parse("original_context_123"), http_client=http_client_mock.get_mock_http_client(), ) @@ -249,12 +250,14 @@ def test_handler_uses_event_stripe_context( ) -> None: """Test that the handler receives a client with stripe_context from the event""" received_context: Optional[StripeContext | str] = None + received_account: Optional[str] = None def handler( event: V1BillingMeterErrorReportTriggeredEventNotification, client: StripeClient, ) -> None: - nonlocal received_context + nonlocal received_account, received_context + received_account = client._requestor._options.stripe_account received_context = client._requestor._options.stripe_context event_handler.on_v1_billing_meter_error_report_triggered(handler) @@ -268,6 +271,7 @@ def handler( event_handler.handle(v1_billing_meter_payload, sig_header) assert str(received_context) == "event_context_456" + assert received_account is None def test_stripe_context_restored_after_handler_success( self, From c9e2faf0d5dd0d6020fb49f5e8f03e4e7873655d Mon Sep 17 00:00:00 2001 From: jar-stripe Date: Tue, 22 Sep 2026 16:23:38 -0700 Subject: [PATCH 3/3] Document Stripe notice suppression (#1923) Committed-By-Agent: goose Orbit-Session-Id: d60d503e-7c8a-4aa0-89d1-37cc435afc02 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 8b40fd997..f851cec19 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,10 @@ There are a few options for enabling it: logging.getLogger('stripe').setLevel(logging.DEBUG) ``` +### Suppressing Stripe notices + +The SDK may print notices from Stripe that it receives in the `Stripe-Notice` header. These notices are always printed when the SDK runs in an agent environment. For API calls to test accounts or sandboxes, notices are also printed when the SDK runs outside an agent environment. To suppress notices when the SDK runs outside an agent environment, set the `STRIPE_SUPPRESS_NOTICES` environment variable to `true` before running your integration. + ### Accessing response code and headers You can access the HTTP response code and headers using the `last_response` property of the returned resource.