Skip to content

feat: add card/delegation guard-rails to Python SDK#147

Merged
aaitor merged 5 commits intomainfrom
feat/payment-guardrails
Mar 9, 2026
Merged

feat: add card/delegation guard-rails to Python SDK#147
aaitor merged 5 commits intomainfrom
feat/payment-guardrails

Conversation

@aaitor
Copy link
Member

@aaitor aaitor commented Mar 3, 2026

Summary

  • Add card_id and delegation_id fields to CardDelegationConfig for reusing existing delegations and targeting specific cards
  • Make provider_payment_method_id, spending_limit_cents, duration_secs optional
  • Add DelegationSummary model and list_delegations() method to DelegationAPI

Related

Test plan

  • Run poetry run pytest tests/unit/ to verify unit tests pass
  • Run poetry run black --check payments_py/ to verify formatting
  • Test list_delegations() against staging
  • Test get_x402_access_token with delegation_id against staging

🤖 Generated with Claude Code

Add `card_id` and `delegation_id` fields to CardDelegationConfig for
reusing existing delegations and targeting specific cards. Add
`DelegationSummary` model and `list_delegations()` method to
DelegationAPI.

Refs: nevermined-io/internal#882

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aaitor
Copy link
Member Author

aaitor commented Mar 3, 2026

@aaitor aaitor marked this pull request as ready for review March 3, 2026 14:01
@aaitor aaitor requested a review from a team as a code owner March 3, 2026 14:01
Copilot AI review requested due to automatic review settings March 3, 2026 14:01
@aaitor aaitor requested a review from a team as a code owner March 3, 2026 14:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Python X402 card-delegation support to allow reusing existing cards/delegations when generating access tokens, and adds an API method to list existing delegations from the backend.

Changes:

  • Expanded CardDelegationConfig to support card_id / delegation_id reuse paths and made the “new delegation” fields optional.
  • Added DelegationSummary plus DelegationAPI.list_delegations() for retrieving existing delegations.
  • Re-exported DelegationSummary from the payments_py.x402 module.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
payments_py/x402/types.py Extends CardDelegationConfig for delegation/card reuse and relaxes required fields.
payments_py/x402/delegation_api.py Adds DelegationSummary model and list_delegations() API call.
payments_py/x402/__init__.py Exposes DelegationSummary via module exports.
Comments suppressed due to low confidence (1)

payments_py/x402/delegation_api.py:9

  • Any and Dict are imported but not used in this module. Removing unused imports helps avoid lint failures and keeps the public surface clean.
from typing import Any, Dict, List, Optional

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +113 to +116
def list_delegations(self) -> List[DelegationSummary]:
"""
List the user's existing card delegations.

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list_delegations() and DelegationSummary are new behavior, but there are existing unit tests for list_payment_methods() in this repo and no corresponding coverage for delegations. Please add unit tests that mock the GET call and assert successful parsing and HTTP error handling for list_delegations().

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +274 to +278
To reuse an existing delegation supply ``delegation_id``.
To reuse an existing card (PaymentMethod entity) supply ``card_id``.
When creating a brand-new delegation provide ``provider_payment_method_id``,
``spending_limit_cents``, and ``duration_secs``.

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CardDelegationConfig now documents that certain fields are required for “brand-new” delegations, but the model allows constructing/sending an empty delegationConfig (all fields optional). This makes it easy for callers to create invalid configs that only fail at the backend. Consider adding a Pydantic model_validator to enforce valid combinations (e.g., either delegation_id is set, or card_id is set, or provider_payment_method_id+spending_limit_cents+duration_secs are set), and clarify in the docstring which additional fields are required when using card_id.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Copy link
Contributor

Copilot AI commented Mar 3, 2026

@aaitor I've opened a new pull request, #148, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Mar 3, 2026

@aaitor I've opened a new pull request, #149, to work on those changes. Once the pull request is ready, I'll request review from you.

aaitor added 4 commits March 6, 2026 12:30
The test_non_blocking_execution_with_polling test was failing because the
final settle_called.wait(timeout=10.0) blocked for 10 seconds without
making any requests to the TestClient, starving the ASGI event loop of
ticks needed to run the background settlement task.

Fix: increase polling iterations from 5 to 50 and keep driving the event
loop throughout the entire wait period instead of doing a single long
blocking wait at the end.
The settle_permissions call in the streaming A2A handler was hanging
forever when the staging backend was slow/unresponsive, causing e2e
test timeouts.

Add a default (10s connect, 30s read) timeout to both
get_backend_http_options and get_public_http_options so all HTTP
requests fail fast instead of blocking indefinitely.
@aaitor aaitor merged commit 5dd398e into main Mar 9, 2026
3 checks passed
@aaitor aaitor deleted the feat/payment-guardrails branch March 9, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants