agentscore-commerce 2.5.2__tar.gz → 2.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/CLAUDE.md +1 -1
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/PKG-INFO +3 -3
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/README.md +2 -2
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/__init__.py +9 -1
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/checkout.py +48 -1
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/__init__.py +4 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/payment_header.py +65 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/zero_settle.py +13 -4
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/quote_cache.py +84 -34
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/pyproject.toml +1 -1
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_checkout.py +4 -4
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout.py +70 -10
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_coverage_gaps.py +3 -1
- agentscore_commerce-2.5.4/tests/test_credential_precheck.py +135 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_dispatch.py +8 -2
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_quote_cache.py +44 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_seamless_helpers.py +128 -14
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/uv.lock +1 -1
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/dependabot.yml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/workflows/ci.yml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/workflows/publish.yml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.github/workflows/security.yml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/.gitignore +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/CODE_OF_CONDUCT.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/CONTRIBUTING.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/LICENSE +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/SECURITY.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/_headers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/_mppx_receipt.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/_redis.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/_warnings.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/gate.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/http_signature.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/jwks.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/request.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/types.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/aip/verify.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/api/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/accepted_methods.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/agent_instructions.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/agent_memory.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/body.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/how_to_pay.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/identity.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/pricing.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/receipt.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/respond_402.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/challenge/validation_error.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/checkout_compute_first.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/checkout_hooks.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/agentscore_content.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/bazaar.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/llms_txt.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/openapi.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/probe.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/redemption_md.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/robots_tag.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/skill_md.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/well_known.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/well_known_mpp.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/discovery/well_known_x402.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/errors.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/forwarded_proto.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/_denial.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/_response.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/a2a.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/address.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/aiohttp.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/cache.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/core.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/default_denied.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/django.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/fastapi.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/flask.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/middleware.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/policy.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/py.typed +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/sanic.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/sessions.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/signer.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/tokens.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/types.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/ucp.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/identity/ucp_jwks.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/_core.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/aiohttp.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/asgi.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/django.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/fastapi.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/flask.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/middleware/sanic.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/amounts.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/compose_rails.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/constants.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/default_rails.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/directive.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/dispatch.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/headers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/idempotency.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/lazy.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/mppx_failures.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/mppx_server.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/network_kind.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/networks.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/rail_spec.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/rails.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/settlement_override.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/signer.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/solana.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/usdc.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/wwwauthenticate.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/x402.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/x402_server.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/x402_settle.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/x402_validation.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/py.typed +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/mppx_stripe.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/pay_to_address.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/payment_intent.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/pi_cache.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/simulate_deposit.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/stripe_multichain/simulate_dispatch.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/README.md +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/api_provider.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/compliance_merchant.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/compute_first_merchant.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/identity_only.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/multi_rail_merchant.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/per_product_policy_merchant.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/signed_ucp_merchant.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/examples/stripe_multichain_merchant.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/lefthook.yml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/osv-scanner.toml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/ruff.toml +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/scripts/regenerate_cross_lang_fixtures.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/__init__.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/conftest.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-agentscore-gate-blocked.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-agentscore-gate-full.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-capability.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-emoji-keys.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-es256-rails.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-extras-int.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-int-boundary.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-minimal.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-multikey.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/node-unicode.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-agentscore-gate-blocked.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-agentscore-gate-full.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-capability.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-emoji-keys.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-es256-rails.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-extras-int.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-int-boundary.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-minimal.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-multikey.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/fixtures/cross-lang/py-unicode.json +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_a2a.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_a2a_jws_roundtrip.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_address.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_agent_memory_emitter.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aiohttp.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_adapters.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_agent_memory.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_gate.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_http_signature.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_jwks.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_presentation.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_request.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_types.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_aip_verify.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_amounts.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_api_reexport.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_cache.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_challenge.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_compute_first.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_compute_first_adapters.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_compute_first_ofac.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_compute_first_settle.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_signer_match.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_checkout_wallet_ofac_default.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_classify_orchestration_error.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_compose_rails.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_core.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_coverage_fillers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_default_denied.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_default_rails.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_default_read_only_on_denied.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_denial.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_discovery.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_django.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_extract_owner_scope.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_fastapi.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_flask.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_forwarded_proto.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_gate_quota_info.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_get_signer_verdict.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_idempotency_helper.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_integration.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_internal_helpers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_lifted_helpers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_load_ucp_signing_key_from_env.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_middleware.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_mppx_failures.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_mppx_receipt.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_network_kind.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_pay_to_address.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_directive.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_dispatch.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_handlers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_header.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_headers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_misc.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_servers.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_payment_signer.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_policy.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_pricing.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_public_surface.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_quote_cache_redis.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_rail_spec.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_rate_limit.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_redis_internal.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_response.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_robots_tag.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_sanic.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_sessions.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_signer_match.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_signer_verdict_request_scoped.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_simulate_dispatch.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_skill_md.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_solana.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_solana_mpp_rail_spec_post_init.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_stripe_multichain.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_tokens.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_ucp.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_ucp_cross_lang.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_ucp_jwks.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_validation_error.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_x402_settle_extra.py +0 -0
- {agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/tests/test_zero_settle.py +0 -0
|
@@ -8,7 +8,7 @@ Every helper is extracted from a real consumer, not speculated.
|
|
|
8
8
|
|
|
9
9
|
| Submodule | What it is |
|
|
10
10
|
|---|---|
|
|
11
|
-
| `agentscore_commerce` (top-level) | `Checkout` orchestrator (the 2.0 high-level surface): one config object + hooks (pre_validate, compute_pricing, mint_recipients, compose_mppx, on_settled, gate), auto-derived x402+pympp servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`, optional `discovery_probe` config for x402-crawler auto-routing. Plus `compute_first_checkout` — variable-cost pay-per-result helper (compute-first + exact-x402). Scope is exact-mode rails only (x402-exact Base, tempo/charge, solana/charge, Stripe SPT); does NOT use x402-upto (Permit2) or Settlement-Overrides — variable cost is captured by running the work pre-settle and emitting a 402 at the exact computed price. `create_quote_cache` — content-hash quote cache used by the compute-first helper (in-memory by default; pass `redis_url` for distributed deployments). `create_default_on_denied` — canonical `on_denied(reason)` factory matching `Checkout`'s gate hook (handles `wallet_signer_mismatch`, `wallet_not_trusted` unfixable fallback, `payment_required`, `token_expired`/`invalid_credential`/`api_error`); merchants pass `merchant_name` + `support_email` and override `wallet_not_trusted_message` / `payment_required_message` / `support_context` for vendor-specific copy. `has_payment_header` — discriminator that splits discovery legs (no payment credential → 402) from settle legs (`payment-signature` / `x-payment` / `Authorization: Payment <jwt>`); `has_x402_header` / `has_mppx_header` — granular dispatch helpers (x402 vs MPP credential present) for routes that branch on rail. `default_read_only_on_denied(reason)` — canonical `on_denied` for read-only resource gates (`GET /orders/:id`): collapses every denial to 401 `unauthorized` + `Cache-Control: no-store` while still spreading `denial_reason_to_body` so `agent_instructions` / `verify_url` ride through. Returns a `DefaultOnDeniedResult(body, status, headers)` dataclass; FastAPI / Flask / aiohttp / Sanic `on_denied` callbacks accept an optional 3-tuple `(body, status, headers)` — convert with `lambda req, reason: (r := default_read_only_on_denied(reason), (r.body, r.status, r.headers or {}))[1]` or a named wrapper. Django + ASGI middleware adapters return Response objects directly; construct `JsonResponse(r.body, status=r.status, headers=r.headers)` / `JSONResponse(content=r.body, status_code=r.status, headers=r.headers)`. `extract_owner_scope(headers) -> OwnerScope` — pull canonical owner identity from `X-Wallet-Address` / `X-Operator-Token` with safe token hashing; pair with a wallet-or-token-scoped resource query so plaintext tokens never leave the request. Plus factories: `pricing_result` (cents → typed `PricingResult`), `validation_response_{fastapi,flask,django,aiohttp,sanic}` (4xx envelope per framework) |
|
|
11
|
+
| `agentscore_commerce` (top-level) | `Checkout` orchestrator (the 2.0 high-level surface): one config object + hooks (pre_validate, compute_pricing, mint_recipients, compose_mppx, on_settled, gate), auto-derived x402+pympp servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`, optional `discovery_probe` config for x402-crawler auto-routing. Plus `compute_first_checkout` — variable-cost pay-per-result helper (compute-first + exact-x402). Scope is exact-mode rails only (x402-exact Base, tempo/charge, solana/charge, Stripe SPT); does NOT use x402-upto (Permit2) or Settlement-Overrides — variable cost is captured by running the work pre-settle and emitting a 402 at the exact computed price. `create_quote_cache` — content-hash quote cache used by the compute-first helper (in-memory by default; pass `redis_url` for distributed deployments). `create_result_cache` — the neutral primitive under it: keyed JSON-value cache with the same body-hash key builder; use it to cache any probe-leg result a Checkout-class merchant replays on the settle leg (e.g. a paid upstream call made in `pre_validate`). `create_default_on_denied` — canonical `on_denied(reason)` factory matching `Checkout`'s gate hook (handles `wallet_signer_mismatch`, `wallet_not_trusted` unfixable fallback, `payment_required`, `token_expired`/`invalid_credential`/`api_error`); merchants pass `merchant_name` + `support_email` and override `wallet_not_trusted_message` / `payment_required_message` / `support_context` for vendor-specific copy. `has_payment_header` — discriminator that splits discovery legs (no payment credential → 402) from settle legs (`payment-signature` / `x-payment` / `Authorization: Payment <jwt>`); `has_x402_header` / `has_mppx_header` — granular dispatch helpers (x402 vs MPP credential present) for routes that branch on rail. `malformed_payment_credential` — wire-shape gate for payment credentials (not base64 JSON, not token-shaped → reject); `Checkout` runs it before any merchant hook by default (`credential_pre_check=False` opts out). `default_read_only_on_denied(reason)` — canonical `on_denied` for read-only resource gates (`GET /orders/:id`): collapses every denial to 401 `unauthorized` + `Cache-Control: no-store` while still spreading `denial_reason_to_body` so `agent_instructions` / `verify_url` ride through. Returns a `DefaultOnDeniedResult(body, status, headers)` dataclass; FastAPI / Flask / aiohttp / Sanic `on_denied` callbacks accept an optional 3-tuple `(body, status, headers)` — convert with `lambda req, reason: (r := default_read_only_on_denied(reason), (r.body, r.status, r.headers or {}))[1]` or a named wrapper. Django + ASGI middleware adapters return Response objects directly; construct `JsonResponse(r.body, status=r.status, headers=r.headers)` / `JSONResponse(content=r.body, status_code=r.status, headers=r.headers)`. `extract_owner_scope(headers) -> OwnerScope` — pull canonical owner identity from `X-Wallet-Address` / `X-Operator-Token` with safe token hashing; pair with a wallet-or-token-scoped resource query so plaintext tokens never leave the request. Plus factories: `pricing_result` (cents → typed `PricingResult`), `validation_response_{fastapi,flask,django,aiohttp,sanic}` (4xx envelope per framework) |
|
|
12
12
|
| `agentscore_commerce.identity.{fastapi,flask,django,aiohttp,sanic,middleware}` | Trust gate middleware (KYC, age, sanctions on both account name and signer wallet, jurisdiction). Each adapter exports a conditional variant that wraps the gate so it fires only on settle legs (anonymous discovery flows through and gets a 402 with all rails): FastAPI / ASGI expose `ConditionalAgentScoreGate`, Django exposes `ConditionalAgentScoreMiddleware`, Flask + Sanic expose `conditional_agentscore_gate(app, ...)`, aiohttp exposes `conditional_agentscore_gate_middleware(...)`. Adapters export ONLY framework-specific surface (gate classes / fns, accessors, `capture_wallet`); shared helpers like `has_payment_header` / `denial_reason_to_body` import from their canonical home (`agentscore_commerce.payment` and `agentscore_commerce.identity` respectively). The Flask / Sanic `agentscore_gate(app, ...)` function accepts an optional `condition=` callable for inline gating (`AgentScoreGate.__init__` does not). |
|
|
13
13
|
| `agentscore_commerce.identity.policy` | Per-product compliance helpers: `PolicyBlock`, `build_gate_from_policy`, `run_gate_with_enforcement`, `shipping_country_allowed`, `shipping_state_allowed`, `validate_shipping_against_policy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss) |
|
|
14
14
|
| `agentscore_commerce.payment` | Networks/USDC/rails registries, paymentauth.org directive builders, `create_x402_server` (wraps `x402[evm]>=2.9` + `cdp-sdk` for `facilitator="coinbase"`; install via the `coinbase` extra), `build_x402_accepts_for_402` (build the 402's `accepts[]` from the registered scheme; derives the right `extra.name` per network), `build_default_checkout_rails(tempo=, x402_base=, solana_mpp=, stripe=)` (canonical 4-rail `rails` dict factory: merchants pass per-rail overrides instead of redeclaring the recipient sentinel + network/chain_id/token boilerplate. When a caller flips `network` without pinning `token` / `chain_id`, the underlying dataclass derives them from the network: Base Sepolia → Sepolia USDC + chain_id 84532, Solana devnet → devnet USDC mint. Explicit overrides always win. Solana's `network` field accepts both CAIP-2 (`solana:5eykt4UsFv8…` / `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) AND the raw `@solana/mpp` form (`mainnet-beta` / `devnet` / `localnet`)), `build_mppx_compose_rails(amount_usd=, tempo_recipient=, solana_recipient=, ...)` (per-call intent factory replacing the hand-rolled `[("tempo/charge", {...}), ("solana/charge", {...}), ("stripe/charge", {...})]` list; auto-handles USD→atomic conversion for Solana; auto-drops the `stripe/charge` rail with a one-time `logging.warning` when `amount_usd < 0.50` since Stripe's fixed ~$0.30 fee makes sub-50-cent charges unprofitable — many Stripe accounts also reject PI creation below the floor with `amount_too_small`; sub-50-cent APIs pass `include_stripe=False` explicitly to silence the warning), `process_x402_settle` (verify+settle in one call), `create_mppx_server` (wraps `pympp[server,tempo,stripe]>=0.6`), `is_evm_network`/`is_solana_network` (CAIP-2 discriminators that hide the `startswith("eip155:")` / `startswith("solana:")` prefix matching), `has_payment_header` (settle-leg vs discovery-leg discriminator), `parse_did_pkh_address` (parses ``did:pkh:<family>:<chain>:<addr>`` into a `PaymentSigner`), dispatch-by-network, signer extraction, WWW-Authenticate header, Settlement-Overrides header |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentscore-commerce
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.4
|
|
4
4
|
Summary: Agent commerce SDK for Python — identity middleware (FastAPI, Flask, Django, AIOHTTP, Sanic, ASGI) + payment helpers + 402 builders + discovery + Stripe multichain. The full merchant-side toolkit for AgentScore-powered agent commerce.
|
|
5
5
|
Project-URL: Homepage, https://www.agentscore.com
|
|
6
6
|
Project-URL: Repository, https://github.com/agentscore/python-commerce
|
|
@@ -72,10 +72,10 @@ pip install 'agentscore-commerce[fastapi,x402,coinbase]'
|
|
|
72
72
|
|
|
73
73
|
| Submodule | What it provides |
|
|
74
74
|
|---|---|
|
|
75
|
-
| `agentscore_commerce` (top-level) | `Checkout` orchestrator + `CheckoutContext` + `CheckoutGateConfig` + `CheckoutValidationError` + `DiscoveryProbeConfig` + `SettleOutcome` + `MppxComposeOutcome` + `PricingResult` (the 2.0 high-level surface: one config object, hooks for pre_validate/compute_pricing/on_settled/mint_recipients/compose_mppx, auto-derived x402+mppx servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`); `pricing_result` (factory: cents-denominated → typed `PricingResult` with embedded `PricingBlock`); `validation_response_{fastapi,flask,django,aiohttp,sanic}` (per-framework 4xx envelope wrappers); `make_mppx_compose_hook` (canonical pympp compose adapter). |
|
|
75
|
+
| `agentscore_commerce` (top-level) | `Checkout` orchestrator + `CheckoutContext` + `CheckoutGateConfig` + `CheckoutValidationError` + `DiscoveryProbeConfig` + `SettleOutcome` + `MppxComposeOutcome` + `PricingResult` (the 2.0 high-level surface: one config object, hooks for pre_validate/compute_pricing/on_settled/mint_recipients/compose_mppx, auto-derived x402+mppx servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`); `create_result_cache` (neutral keyed JSON-value cache with a stable body-hash key builder; cache a probe-leg result, e.g. a paid upstream call made in `pre_validate`, and replay it on the settle leg) plus the compute-first-shaped `create_quote_cache` built on it; `pricing_result` (factory: cents-denominated → typed `PricingResult` with embedded `PricingBlock`); `validation_response_{fastapi,flask,django,aiohttp,sanic}` (per-framework 4xx envelope wrappers); `make_mppx_compose_hook` (canonical pympp compose adapter). |
|
|
76
76
|
| `agentscore_commerce.identity.{fastapi,flask,django,aiohttp,sanic,middleware}` | Trust gate middleware: KYC, sanctions (account name + signer wallet), age, jurisdiction. `AgentScoreGate(...)` (or `agentscore_gate(app, ...)` on Flask/Sanic), `get_agentscore_data(...)`, `capture_wallet(...)`, `get_signer_verdict(...)`. The gate extracts the payment signer pre-evaluate and passes it to `/v1/assess`, so the API composes both wallet-binding (`signer_match`) and OFAC SDN wallet-address (`signer_sanctions`) verdicts on one round trip. |
|
|
77
77
|
| `agentscore_commerce.identity` (package level) | Re-exports the denial helpers: `denial_reason_status`, `denial_reason_to_body`, `build_signer_mismatch_body`, `build_contact_support_next_steps`, `verification_agent_instructions`, `is_fixable_denial`, `FIXABLE_DENIAL_REASONS`. The per-framework adapter modules also expose `get_gate_quota_info(request)` for surfacing X-RateLimit info from gate state. Also re-exports the per-product policy helpers: `PolicyBlock`, `GateResult`, `EnforcementMode`, `IdentityStatus`, `build_gate_from_policy`, `run_gate_with_enforcement`, `shipping_country_allowed`, `shipping_state_allowed`, `validate_shipping_against_policy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss), for multi-product merchants where each product carries its own compliance config: hard gate vs soft vs none, per-product shipping allowlists. Key + token helpers: `load_ucp_signing_key_from_env` (cached env-driven loader for the UCP signing key, reads `UCP_SIGNING_KEY_JWK_PRIVATE` JSON JWK, detects alg from shape, falls back to ephemeral when unset, sanitizes errors so key bytes never reach logs, concurrent-safe via `threading.Lock`; env-var names and `default_kid` / `default_alg` are overridable as kwargs); `hash_operator_token` (sha256 hex of plaintext `opc_...`, for merchants persisting `operator_token_id` to their own DB without ever storing the plaintext); `extract_owner_scope(headers) -> OwnerScope` (canonical owner-identity extractor for caller-scoped resource queries, reads `X-Wallet-Address` / `X-Operator-Token`, hashes the token so plaintext never leaves the request); `default_read_only_on_denied(reason)` (canonical `on_denied` for read-only resource gates: 401 + `Cache-Control: no-store` while still spreading `denial_reason_to_body`. Returns a `DefaultOnDeniedResult(body, status, headers)`; FastAPI / Flask / aiohttp / Sanic `on_denied` callbacks accept an optional 3-tuple `(body, status, headers)` to carry headers through; wrap with `lambda req, reason: (lambda r: (r.body, r.status, r.headers or {}))(default_read_only_on_denied(reason))`). |
|
|
78
|
-
| `agentscore_commerce.payment` | `networks`, `USDC`, `rails` registries; `payment_directive`, `build_payment_directive`, `www_authenticate_header`, `payment_required_header`, `alias_amount_fields` (opt-in v1↔v2 amount-field shim that adds both `amount` and `maxAmountRequired` to an entry. The 402 builders do NOT apply it by default, strict x402 v2 settlement matches the agent's echoed requirement by exact comparison, so an extra field the server's rebuilt requirement lacks breaks settle; use only when you know a client is hardcoded to read `maxAmountRequired`), `settlement_override_header`, `dispatch_settlement_by_network`, `extract_payment_signer` (accepts positional `x402_payment_header` AND/OR `authorization_header=` kwarg; recovers signer from x402 EIP-3009 `payload.authorization.from` OR MPP `Authorization: Payment <base64>` `did:pkh:eip155:<chain>:<addr>` / `did:pkh:solana:<genesis>:<addr>` source DID), `detect_rail_from_headers` (returns `"x402"` / `"mpp"` / `None` from inbound headers), `register_x402_schemes_v1_v2`; drop-in x402 helpers: `validate_x402_network_config` (boot-time guard), `verify_x402_request` (parse + validate inbound X-Payment), `process_x402_settle` (verify-then-settle with one call), `classify_x402_settle_result` (maps the tagged settle result to a recommended HTTP status / code / next_steps so merchants get a controlled envelope without coupling to facilitator-specific error text), `classify_orchestration_error` (same `ClassifiedX402Error` shape but for uncaught exceptions thrown elsewhere in the orchestration; returns `None` for unknown errors so merchants rethrow instead of swallowing); `zero_amount_carve_out` (skip CDP / pympp upstream verify+settle for $0 settles where the upstream rejects value=0 payloads; parses the credential, lifts signer + network, returns a `ZeroSettleResult` shaped identically to the success path so callers branch on rail, not on result shape); `usd_to_atomic` (Decimal-based USD → atomic int, ROUND_HALF_UP, for Tempo / Solana / Base USDC amount construction). |
|
|
78
|
+
| `agentscore_commerce.payment` | `networks`, `USDC`, `rails` registries; `payment_directive`, `build_payment_directive`, `www_authenticate_header`, `payment_required_header`, `alias_amount_fields` (opt-in v1↔v2 amount-field shim that adds both `amount` and `maxAmountRequired` to an entry. The 402 builders do NOT apply it by default, strict x402 v2 settlement matches the agent's echoed requirement by exact comparison, so an extra field the server's rebuilt requirement lacks breaks settle; use only when you know a client is hardcoded to read `maxAmountRequired`), `settlement_override_header`, `dispatch_settlement_by_network`, `extract_payment_signer` (accepts positional `x402_payment_header` AND/OR `authorization_header=` kwarg; recovers signer from x402 EIP-3009 `payload.authorization.from` OR MPP `Authorization: Payment <base64>` `did:pkh:eip155:<chain>:<addr>` / `did:pkh:solana:<genesis>:<addr>` source DID), `detect_rail_from_headers` (returns `"x402"` / `"mpp"` / `None` from inbound headers), `register_x402_schemes_v1_v2`; drop-in x402 helpers: `validate_x402_network_config` (boot-time guard), `verify_x402_request` (parse + validate inbound X-Payment), `process_x402_settle` (verify-then-settle with one call), `classify_x402_settle_result` (maps the tagged settle result to a recommended HTTP status / code / next_steps so merchants get a controlled envelope without coupling to facilitator-specific error text), `classify_orchestration_error` (same `ClassifiedX402Error` shape but for uncaught exceptions thrown elsewhere in the orchestration; returns `None` for unknown errors so merchants rethrow instead of swallowing); `zero_amount_carve_out` (skip CDP / pympp upstream verify+settle for $0 settles where the upstream rejects value=0 payloads, including credentials signed against a nonzero quote the merchant re-priced to $0 at settle; parses the credential, lifts signer + network, returns a `ZeroSettleResult` shaped identically to the success path so callers branch on rail, not on result shape), `malformed_payment_credential` (wire-shape gate: payment headers that are not base64 JSON and not token-shaped are rejected before merchant hooks run; `Checkout` applies it by default, opt out with `credential_pre_check=False`); `usd_to_atomic` (Decimal-based USD → atomic int, ROUND_HALF_UP, for Tempo / Solana / Base USDC amount construction). |
|
|
79
79
|
| `agentscore_commerce.discovery` | `is_discovery_probe_request`, `build_discovery_probe_response` (with optional `x402_sample` for x402-aware crawlers like `awal x402 details`), `sample_x402_accept_for_network` (USDC sample-accept builder for known CAIP-2 networks), `build_well_known_mpp`, `build_llms_txt` + `llms_txt_identity_section` + `llms_txt_payment_section` (compact + verbose modes), `build_skill_md` (Claude-Skill-compatible `/skill.md` agent-discovery manifest; strictly agent-facing data only, no internal posture), `build_redemption_skill_md` (delivery-neutral redemption-code template, printed mailers, emailed codes, API trial credits all covered; `endpoint_path`/`delivery_intro`/`body_shape`/`body_rules`/`extra_recovery_rows` overrides for non-goods shapes), `build_merchant_index_json` (canonical `/` discovery body), `standard_endpoint_descriptions(kind=)` (canonical method+path → description map for goods vs api merchants; optional `include_order_status_route` for goods), `build_success_next_steps` (universal Passport-active success block), `build_agentscore_onboarding_steps` (canonical skill.md onboarding for goods or API merchants), `agentscore_openapi_snippets`, `build_bazaar_discovery_payload`, `NoindexNonDiscoveryMiddleware` (ASGI middleware emitting `X-Robots-Tag: noindex` on every path except the agent-discovery surfaces; pure helpers `is_discovery_path` + `DEFAULT_DISCOVERY_PATHS` for non-ASGI frameworks). Plus the UCP/JWKS publish surface: `build_signed_ucp_response`, `build_signed_jwks_response`, `well_known_preflight_response`, `default_a2a_services`, `bootstrap_ucp_signing_key`, framework-neutral `SignedDiscoveryResponse` + per-framework wrappers `signed_response_{fastapi,flask,django,aiohttp,sanic}`. |
|
|
80
80
|
| `agentscore_commerce.challenge` | `build_402_body`, `build_accepted_methods`, `build_identity_metadata` (auto-attached by `Checkout` when an inbound `X-Wallet-Address` header is present), `build_how_to_pay`, `build_agent_instructions` (auto-emits per-rail `compatible_clients`: smoke-verified CLIs the agent should use; vendor override supported; pure helper `compatible_clients_by_rails(rails)` returns the same map for vendors building custom 402s), `build_pricing_block` (cents to dollar-string with optional shipping/tax), `first_encounter_agent_memory` (cross-merchant hint, returns the canonical block or `None` based on a per-merchant first-seen flag), `Receipt` + `ReceiptNextSteps` + `ProductInfo` + `ShippingAddress` (canonical 200-receipt dataclasses, universal across goods + API merchants); `respond_402`, a drop-in 402 emit that preserves pympp's `WWW-Authenticate` and layers x402's `PAYMENT-REQUIRED`. `build_validation_error`: structured 4xx body builder (`{error: {code, message}, required_fields?, example_body?, next_steps?, ...extra}`) so vendors compose body shapes by name instead of inlining at every validation site. |
|
|
81
81
|
| `agentscore_commerce.stripe_multichain` | `create_multichain_payment_intent` (returns `MultichainPaymentIntentResult(payment_intent_id, deposit_addresses)`; read `result.deposit_addresses[network]` directly), `create_pay_to_address_from_stripe_pi(authorization_header=, amount_cents=, stripe=, pi_cache=, networks=, static_recipients=, metadata=, order_id=, preferred_network=)`, per-order payTo resolver: on the settle leg, reuses the buyer's signed-against payTo from the MPP credential (after `pi_cache.has_address` check OR a `static_recipients` match, the static address is always-accepted because the merchant owns it); on the discovery leg, mints a fresh PI for the rails NOT covered by `static_recipients`, caches the merged map, registers static addresses with `pi_cache.cache_address` so verify-leg lookups pass. `mint_multichain_recipients(...same kwargs)`, structured variant returning `MintMultichainRecipientsResult(recipients, payment_intent_id, reused_from_credential)` for the full per-rail map (typical multi-rail merchant hook). Solana MPP requires a static recipient: pass `static_recipients={"solana": "<wallet>"}` and pre-fund its USDC ATA once from any external wallet. Rotating (per-order, Stripe-minted) Solana recipients do not settle, since the settlement transaction does not create the recipient's token account; the SDK logs a warning when one is minted. The static recipient is reused forever, each settle pays only the ~$0.001 per-tx fee, and this also sidesteps the per-call ATA rent (~$0.50 against MPP spec §13.6). `SolanaMppRailSpec.ata_creation_required` defaults to `True` (data-only; solana method registration through `create_mppx_server` is a follow-up, merchants building the solana method directly via `pympp` should pass the flag themselves to the charge factory). `simulate_crypto_deposit`; `create_pi_cache` (TTL'd PI / deposit-address cache, Redis-backed when `redis_url` set, in-memory otherwise), `simulate_deposit_if_test_mode` (gates on `sk_test_` and looks up the PI for you), `STRIPE_TEST_TX_HASH_SUCCESS` / `STRIPE_TEST_TX_HASH_FAILED` constants. Peer dep on `stripe`. |
|
|
@@ -24,10 +24,10 @@ pip install 'agentscore-commerce[fastapi,x402,coinbase]'
|
|
|
24
24
|
|
|
25
25
|
| Submodule | What it provides |
|
|
26
26
|
|---|---|
|
|
27
|
-
| `agentscore_commerce` (top-level) | `Checkout` orchestrator + `CheckoutContext` + `CheckoutGateConfig` + `CheckoutValidationError` + `DiscoveryProbeConfig` + `SettleOutcome` + `MppxComposeOutcome` + `PricingResult` (the 2.0 high-level surface: one config object, hooks for pre_validate/compute_pricing/on_settled/mint_recipients/compose_mppx, auto-derived x402+mppx servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`); `pricing_result` (factory: cents-denominated → typed `PricingResult` with embedded `PricingBlock`); `validation_response_{fastapi,flask,django,aiohttp,sanic}` (per-framework 4xx envelope wrappers); `make_mppx_compose_hook` (canonical pympp compose adapter). |
|
|
27
|
+
| `agentscore_commerce` (top-level) | `Checkout` orchestrator + `CheckoutContext` + `CheckoutGateConfig` + `CheckoutValidationError` + `DiscoveryProbeConfig` + `SettleOutcome` + `MppxComposeOutcome` + `PricingResult` (the 2.0 high-level surface: one config object, hooks for pre_validate/compute_pricing/on_settled/mint_recipients/compose_mppx, auto-derived x402+mppx servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`); `create_result_cache` (neutral keyed JSON-value cache with a stable body-hash key builder; cache a probe-leg result, e.g. a paid upstream call made in `pre_validate`, and replay it on the settle leg) plus the compute-first-shaped `create_quote_cache` built on it; `pricing_result` (factory: cents-denominated → typed `PricingResult` with embedded `PricingBlock`); `validation_response_{fastapi,flask,django,aiohttp,sanic}` (per-framework 4xx envelope wrappers); `make_mppx_compose_hook` (canonical pympp compose adapter). |
|
|
28
28
|
| `agentscore_commerce.identity.{fastapi,flask,django,aiohttp,sanic,middleware}` | Trust gate middleware: KYC, sanctions (account name + signer wallet), age, jurisdiction. `AgentScoreGate(...)` (or `agentscore_gate(app, ...)` on Flask/Sanic), `get_agentscore_data(...)`, `capture_wallet(...)`, `get_signer_verdict(...)`. The gate extracts the payment signer pre-evaluate and passes it to `/v1/assess`, so the API composes both wallet-binding (`signer_match`) and OFAC SDN wallet-address (`signer_sanctions`) verdicts on one round trip. |
|
|
29
29
|
| `agentscore_commerce.identity` (package level) | Re-exports the denial helpers: `denial_reason_status`, `denial_reason_to_body`, `build_signer_mismatch_body`, `build_contact_support_next_steps`, `verification_agent_instructions`, `is_fixable_denial`, `FIXABLE_DENIAL_REASONS`. The per-framework adapter modules also expose `get_gate_quota_info(request)` for surfacing X-RateLimit info from gate state. Also re-exports the per-product policy helpers: `PolicyBlock`, `GateResult`, `EnforcementMode`, `IdentityStatus`, `build_gate_from_policy`, `run_gate_with_enforcement`, `shipping_country_allowed`, `shipping_state_allowed`, `validate_shipping_against_policy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss), for multi-product merchants where each product carries its own compliance config: hard gate vs soft vs none, per-product shipping allowlists. Key + token helpers: `load_ucp_signing_key_from_env` (cached env-driven loader for the UCP signing key, reads `UCP_SIGNING_KEY_JWK_PRIVATE` JSON JWK, detects alg from shape, falls back to ephemeral when unset, sanitizes errors so key bytes never reach logs, concurrent-safe via `threading.Lock`; env-var names and `default_kid` / `default_alg` are overridable as kwargs); `hash_operator_token` (sha256 hex of plaintext `opc_...`, for merchants persisting `operator_token_id` to their own DB without ever storing the plaintext); `extract_owner_scope(headers) -> OwnerScope` (canonical owner-identity extractor for caller-scoped resource queries, reads `X-Wallet-Address` / `X-Operator-Token`, hashes the token so plaintext never leaves the request); `default_read_only_on_denied(reason)` (canonical `on_denied` for read-only resource gates: 401 + `Cache-Control: no-store` while still spreading `denial_reason_to_body`. Returns a `DefaultOnDeniedResult(body, status, headers)`; FastAPI / Flask / aiohttp / Sanic `on_denied` callbacks accept an optional 3-tuple `(body, status, headers)` to carry headers through; wrap with `lambda req, reason: (lambda r: (r.body, r.status, r.headers or {}))(default_read_only_on_denied(reason))`). |
|
|
30
|
-
| `agentscore_commerce.payment` | `networks`, `USDC`, `rails` registries; `payment_directive`, `build_payment_directive`, `www_authenticate_header`, `payment_required_header`, `alias_amount_fields` (opt-in v1↔v2 amount-field shim that adds both `amount` and `maxAmountRequired` to an entry. The 402 builders do NOT apply it by default, strict x402 v2 settlement matches the agent's echoed requirement by exact comparison, so an extra field the server's rebuilt requirement lacks breaks settle; use only when you know a client is hardcoded to read `maxAmountRequired`), `settlement_override_header`, `dispatch_settlement_by_network`, `extract_payment_signer` (accepts positional `x402_payment_header` AND/OR `authorization_header=` kwarg; recovers signer from x402 EIP-3009 `payload.authorization.from` OR MPP `Authorization: Payment <base64>` `did:pkh:eip155:<chain>:<addr>` / `did:pkh:solana:<genesis>:<addr>` source DID), `detect_rail_from_headers` (returns `"x402"` / `"mpp"` / `None` from inbound headers), `register_x402_schemes_v1_v2`; drop-in x402 helpers: `validate_x402_network_config` (boot-time guard), `verify_x402_request` (parse + validate inbound X-Payment), `process_x402_settle` (verify-then-settle with one call), `classify_x402_settle_result` (maps the tagged settle result to a recommended HTTP status / code / next_steps so merchants get a controlled envelope without coupling to facilitator-specific error text), `classify_orchestration_error` (same `ClassifiedX402Error` shape but for uncaught exceptions thrown elsewhere in the orchestration; returns `None` for unknown errors so merchants rethrow instead of swallowing); `zero_amount_carve_out` (skip CDP / pympp upstream verify+settle for $0 settles where the upstream rejects value=0 payloads; parses the credential, lifts signer + network, returns a `ZeroSettleResult` shaped identically to the success path so callers branch on rail, not on result shape); `usd_to_atomic` (Decimal-based USD → atomic int, ROUND_HALF_UP, for Tempo / Solana / Base USDC amount construction). |
|
|
30
|
+
| `agentscore_commerce.payment` | `networks`, `USDC`, `rails` registries; `payment_directive`, `build_payment_directive`, `www_authenticate_header`, `payment_required_header`, `alias_amount_fields` (opt-in v1↔v2 amount-field shim that adds both `amount` and `maxAmountRequired` to an entry. The 402 builders do NOT apply it by default, strict x402 v2 settlement matches the agent's echoed requirement by exact comparison, so an extra field the server's rebuilt requirement lacks breaks settle; use only when you know a client is hardcoded to read `maxAmountRequired`), `settlement_override_header`, `dispatch_settlement_by_network`, `extract_payment_signer` (accepts positional `x402_payment_header` AND/OR `authorization_header=` kwarg; recovers signer from x402 EIP-3009 `payload.authorization.from` OR MPP `Authorization: Payment <base64>` `did:pkh:eip155:<chain>:<addr>` / `did:pkh:solana:<genesis>:<addr>` source DID), `detect_rail_from_headers` (returns `"x402"` / `"mpp"` / `None` from inbound headers), `register_x402_schemes_v1_v2`; drop-in x402 helpers: `validate_x402_network_config` (boot-time guard), `verify_x402_request` (parse + validate inbound X-Payment), `process_x402_settle` (verify-then-settle with one call), `classify_x402_settle_result` (maps the tagged settle result to a recommended HTTP status / code / next_steps so merchants get a controlled envelope without coupling to facilitator-specific error text), `classify_orchestration_error` (same `ClassifiedX402Error` shape but for uncaught exceptions thrown elsewhere in the orchestration; returns `None` for unknown errors so merchants rethrow instead of swallowing); `zero_amount_carve_out` (skip CDP / pympp upstream verify+settle for $0 settles where the upstream rejects value=0 payloads, including credentials signed against a nonzero quote the merchant re-priced to $0 at settle; parses the credential, lifts signer + network, returns a `ZeroSettleResult` shaped identically to the success path so callers branch on rail, not on result shape), `malformed_payment_credential` (wire-shape gate: payment headers that are not base64 JSON and not token-shaped are rejected before merchant hooks run; `Checkout` applies it by default, opt out with `credential_pre_check=False`); `usd_to_atomic` (Decimal-based USD → atomic int, ROUND_HALF_UP, for Tempo / Solana / Base USDC amount construction). |
|
|
31
31
|
| `agentscore_commerce.discovery` | `is_discovery_probe_request`, `build_discovery_probe_response` (with optional `x402_sample` for x402-aware crawlers like `awal x402 details`), `sample_x402_accept_for_network` (USDC sample-accept builder for known CAIP-2 networks), `build_well_known_mpp`, `build_llms_txt` + `llms_txt_identity_section` + `llms_txt_payment_section` (compact + verbose modes), `build_skill_md` (Claude-Skill-compatible `/skill.md` agent-discovery manifest; strictly agent-facing data only, no internal posture), `build_redemption_skill_md` (delivery-neutral redemption-code template, printed mailers, emailed codes, API trial credits all covered; `endpoint_path`/`delivery_intro`/`body_shape`/`body_rules`/`extra_recovery_rows` overrides for non-goods shapes), `build_merchant_index_json` (canonical `/` discovery body), `standard_endpoint_descriptions(kind=)` (canonical method+path → description map for goods vs api merchants; optional `include_order_status_route` for goods), `build_success_next_steps` (universal Passport-active success block), `build_agentscore_onboarding_steps` (canonical skill.md onboarding for goods or API merchants), `agentscore_openapi_snippets`, `build_bazaar_discovery_payload`, `NoindexNonDiscoveryMiddleware` (ASGI middleware emitting `X-Robots-Tag: noindex` on every path except the agent-discovery surfaces; pure helpers `is_discovery_path` + `DEFAULT_DISCOVERY_PATHS` for non-ASGI frameworks). Plus the UCP/JWKS publish surface: `build_signed_ucp_response`, `build_signed_jwks_response`, `well_known_preflight_response`, `default_a2a_services`, `bootstrap_ucp_signing_key`, framework-neutral `SignedDiscoveryResponse` + per-framework wrappers `signed_response_{fastapi,flask,django,aiohttp,sanic}`. |
|
|
32
32
|
| `agentscore_commerce.challenge` | `build_402_body`, `build_accepted_methods`, `build_identity_metadata` (auto-attached by `Checkout` when an inbound `X-Wallet-Address` header is present), `build_how_to_pay`, `build_agent_instructions` (auto-emits per-rail `compatible_clients`: smoke-verified CLIs the agent should use; vendor override supported; pure helper `compatible_clients_by_rails(rails)` returns the same map for vendors building custom 402s), `build_pricing_block` (cents to dollar-string with optional shipping/tax), `first_encounter_agent_memory` (cross-merchant hint, returns the canonical block or `None` based on a per-merchant first-seen flag), `Receipt` + `ReceiptNextSteps` + `ProductInfo` + `ShippingAddress` (canonical 200-receipt dataclasses, universal across goods + API merchants); `respond_402`, a drop-in 402 emit that preserves pympp's `WWW-Authenticate` and layers x402's `PAYMENT-REQUIRED`. `build_validation_error`: structured 4xx body builder (`{error: {code, message}, required_fields?, example_body?, next_steps?, ...extra}`) so vendors compose body shapes by name instead of inlining at every validation site. |
|
|
33
33
|
| `agentscore_commerce.stripe_multichain` | `create_multichain_payment_intent` (returns `MultichainPaymentIntentResult(payment_intent_id, deposit_addresses)`; read `result.deposit_addresses[network]` directly), `create_pay_to_address_from_stripe_pi(authorization_header=, amount_cents=, stripe=, pi_cache=, networks=, static_recipients=, metadata=, order_id=, preferred_network=)`, per-order payTo resolver: on the settle leg, reuses the buyer's signed-against payTo from the MPP credential (after `pi_cache.has_address` check OR a `static_recipients` match, the static address is always-accepted because the merchant owns it); on the discovery leg, mints a fresh PI for the rails NOT covered by `static_recipients`, caches the merged map, registers static addresses with `pi_cache.cache_address` so verify-leg lookups pass. `mint_multichain_recipients(...same kwargs)`, structured variant returning `MintMultichainRecipientsResult(recipients, payment_intent_id, reused_from_credential)` for the full per-rail map (typical multi-rail merchant hook). Solana MPP requires a static recipient: pass `static_recipients={"solana": "<wallet>"}` and pre-fund its USDC ATA once from any external wallet. Rotating (per-order, Stripe-minted) Solana recipients do not settle, since the settlement transaction does not create the recipient's token account; the SDK logs a warning when one is minted. The static recipient is reused forever, each settle pays only the ~$0.001 per-tx fee, and this also sidesteps the per-call ATA rent (~$0.50 against MPP spec §13.6). `SolanaMppRailSpec.ata_creation_required` defaults to `True` (data-only; solana method registration through `create_mppx_server` is a follow-up, merchants building the solana method directly via `pympp` should pass the flag themselves to the charge factory). `simulate_crypto_deposit`; `create_pi_cache` (TTL'd PI / deposit-address cache, Redis-backed when `redis_url` set, in-memory otherwise), `simulate_deposit_if_test_mode` (gates on `sk_test_` and looks up the PI for you), `STRIPE_TEST_TX_HASH_SUCCESS` / `STRIPE_TEST_TX_HASH_FAILED` constants. Peer dep on `stripe`. |
|
|
@@ -145,7 +145,13 @@ from agentscore_commerce.payment import (
|
|
|
145
145
|
load_solana_fee_payer,
|
|
146
146
|
read_x402_payment_header,
|
|
147
147
|
)
|
|
148
|
-
from agentscore_commerce.quote_cache import
|
|
148
|
+
from agentscore_commerce.quote_cache import (
|
|
149
|
+
CachedQuote,
|
|
150
|
+
QuoteCache,
|
|
151
|
+
ResultCache,
|
|
152
|
+
create_quote_cache,
|
|
153
|
+
create_result_cache,
|
|
154
|
+
)
|
|
149
155
|
|
|
150
156
|
try:
|
|
151
157
|
__version__ = _pkg_version("agentscore-commerce")
|
|
@@ -208,6 +214,7 @@ __all__ = [
|
|
|
208
214
|
"PolicyResult",
|
|
209
215
|
"PricingResult",
|
|
210
216
|
"QuoteCache",
|
|
217
|
+
"ResultCache",
|
|
211
218
|
"SettleOutcome",
|
|
212
219
|
"SignerNetwork",
|
|
213
220
|
"SignerVerdict",
|
|
@@ -242,6 +249,7 @@ __all__ = [
|
|
|
242
249
|
"compute_first_checkout",
|
|
243
250
|
"create_default_on_denied",
|
|
244
251
|
"create_quote_cache",
|
|
252
|
+
"create_result_cache",
|
|
245
253
|
"default_read_only_on_denied",
|
|
246
254
|
"denial_reason_status",
|
|
247
255
|
"denial_reason_to_body",
|
|
@@ -90,7 +90,11 @@ from agentscore_commerce.errors import CheckoutValidationError
|
|
|
90
90
|
from agentscore_commerce.forwarded_proto import apply_forwarded_proto, read_forwarded_proto
|
|
91
91
|
from agentscore_commerce.payment.constants import STRIPE_MIN_CHARGE_USD
|
|
92
92
|
from agentscore_commerce.payment.mppx_failures import classify_mppx_failure
|
|
93
|
-
from agentscore_commerce.payment.payment_header import
|
|
93
|
+
from agentscore_commerce.payment.payment_header import (
|
|
94
|
+
has_mppx_header,
|
|
95
|
+
has_x402_header,
|
|
96
|
+
malformed_payment_credential,
|
|
97
|
+
)
|
|
94
98
|
from agentscore_commerce.payment.rail_spec import (
|
|
95
99
|
RecipientLike,
|
|
96
100
|
SolanaMppRailSpec,
|
|
@@ -752,6 +756,13 @@ class Checkout:
|
|
|
752
756
|
CDP facilitator and pympp's tempo intents both reject $0 settles outright;
|
|
753
757
|
this carve-out makes free-redemption flows work uniformly across rails.
|
|
754
758
|
Default ``False`` (every payment header attempts a real settle).
|
|
759
|
+
* ``credential_pre_check``; reject payment credentials that fail the cheap
|
|
760
|
+
wire-shape check (not base64 JSON, not a token-shaped value) BEFORE any
|
|
761
|
+
merchant hook runs, so junk headers never trigger ``pre_validate`` /
|
|
762
|
+
pricing / recipient minting / the gate's assess call. Shape only —
|
|
763
|
+
signature and payTo verification stay on the settle path. Default
|
|
764
|
+
``True``; set ``False`` for custom ``compose_mppx`` implementations that
|
|
765
|
+
accept non-standard credential encodings.
|
|
755
766
|
"""
|
|
756
767
|
|
|
757
768
|
def __init__(
|
|
@@ -776,6 +787,7 @@ class Checkout:
|
|
|
776
787
|
on_settled: OnSettledFn | None = None,
|
|
777
788
|
is_cached_address: IsCachedAddressFn | None = None,
|
|
778
789
|
zero_settle_carve_out: bool = False,
|
|
790
|
+
credential_pre_check: bool = True,
|
|
779
791
|
gate: CheckoutGateConfig | None = None,
|
|
780
792
|
discovery_extensions: dict[str, Any] | None = None,
|
|
781
793
|
resource_info: dict[str, Any] | None = None,
|
|
@@ -841,6 +853,7 @@ class Checkout:
|
|
|
841
853
|
self.on_settled = on_settled
|
|
842
854
|
self.is_cached_address = is_cached_address
|
|
843
855
|
self.zero_settle_carve_out = zero_settle_carve_out
|
|
856
|
+
self.credential_pre_check = credential_pre_check
|
|
844
857
|
self.gate = gate
|
|
845
858
|
# Lazily-built JWKS cache for AIP verification, shared across requests so issuer keys are
|
|
846
859
|
# fetched once and cached (per the verifier's hard 24h cap). Built on first AIT.
|
|
@@ -1048,6 +1061,40 @@ class Checkout:
|
|
|
1048
1061
|
settle_phase="discovery_probe",
|
|
1049
1062
|
)
|
|
1050
1063
|
|
|
1064
|
+
# Credential shape gate: runs BEFORE pre_validate / the identity gate /
|
|
1065
|
+
# pricing / recipient minting so a junk payment header cannot trigger
|
|
1066
|
+
# merchant hooks (which may do paid upstream work) or burn an assess
|
|
1067
|
+
# call. Shape only — real verification stays on the settle path, which
|
|
1068
|
+
# needs per-request state the hooks produce. Scoped to the credential
|
|
1069
|
+
# channels this Checkout actually dispatches on, so e.g. an x402 header
|
|
1070
|
+
# at a Tempo-only merchant keeps its current discovery-leg behavior.
|
|
1071
|
+
if self.credential_pre_check:
|
|
1072
|
+
malformed = malformed_payment_credential(request.headers)
|
|
1073
|
+
enforced = malformed is not None and (
|
|
1074
|
+
(self._x402_server_available() and self._x402_base_network is not None)
|
|
1075
|
+
if malformed.channel == "x402"
|
|
1076
|
+
else self.compose_mppx is not None
|
|
1077
|
+
)
|
|
1078
|
+
if enforced and malformed is not None:
|
|
1079
|
+
return CheckoutResult(
|
|
1080
|
+
status=400,
|
|
1081
|
+
body=build_validation_error(
|
|
1082
|
+
code="payment_proof_invalid",
|
|
1083
|
+
message=malformed.message,
|
|
1084
|
+
next_steps={
|
|
1085
|
+
"action": "regenerate_payment_credential",
|
|
1086
|
+
"user_message": (
|
|
1087
|
+
"The payment credential could not be decoded. "
|
|
1088
|
+
"Rebuild it from a fresh 402 challenge and retry."
|
|
1089
|
+
),
|
|
1090
|
+
},
|
|
1091
|
+
),
|
|
1092
|
+
headers={},
|
|
1093
|
+
reference_id=ctx.reference_id,
|
|
1094
|
+
settled=False,
|
|
1095
|
+
settle_phase="credential_malformed",
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1051
1098
|
# Pre-validate (optional): resolve merchant-specific per-request state
|
|
1052
1099
|
# (product lookup, code resolution, shipping checks, ...). May raise
|
|
1053
1100
|
# CheckoutValidationError to short-circuit with a 4xx; otherwise return
|
{agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/__init__.py
RENAMED
|
@@ -21,9 +21,11 @@ from agentscore_commerce.payment.mppx_server import MppxRailSpec, create_mppx_se
|
|
|
21
21
|
from agentscore_commerce.payment.network_kind import is_evm_network, is_solana_network
|
|
22
22
|
from agentscore_commerce.payment.networks import NetworkFamily, network_family, networks
|
|
23
23
|
from agentscore_commerce.payment.payment_header import (
|
|
24
|
+
MalformedPaymentCredential,
|
|
24
25
|
has_mppx_header,
|
|
25
26
|
has_payment_header,
|
|
26
27
|
has_x402_header,
|
|
28
|
+
malformed_payment_credential,
|
|
27
29
|
)
|
|
28
30
|
from agentscore_commerce.payment.rail_spec import (
|
|
29
31
|
RecipientLike,
|
|
@@ -95,6 +97,7 @@ __all__ = [
|
|
|
95
97
|
"X402_SUPPORTED_BASE_NETWORKS",
|
|
96
98
|
"ClassifiedX402Error",
|
|
97
99
|
"CustomScheme",
|
|
100
|
+
"MalformedPaymentCredential",
|
|
98
101
|
"MppxRailSpec",
|
|
99
102
|
"NetworkFamily",
|
|
100
103
|
"PaymentHeadersRail",
|
|
@@ -148,6 +151,7 @@ __all__ = [
|
|
|
148
151
|
"lazy_x402_server",
|
|
149
152
|
"load_solana_fee_payer",
|
|
150
153
|
"lookup_rail",
|
|
154
|
+
"malformed_payment_credential",
|
|
151
155
|
"network_family",
|
|
152
156
|
"networks",
|
|
153
157
|
"parse_did_pkh_address",
|
|
@@ -15,7 +15,12 @@ Three credential channels are checked:
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
import base64
|
|
19
|
+
import binascii
|
|
20
|
+
import json
|
|
21
|
+
import re
|
|
18
22
|
from collections.abc import Mapping
|
|
23
|
+
from dataclasses import dataclass
|
|
19
24
|
from typing import Any
|
|
20
25
|
|
|
21
26
|
|
|
@@ -94,3 +99,63 @@ def has_mppx_header(request_or_headers: Any) -> bool:
|
|
|
94
99
|
headers = _unwrap_headers(request_or_headers)
|
|
95
100
|
auth = _read_header(headers, "authorization")
|
|
96
101
|
return bool(isinstance(auth, str) and auth.startswith("Payment "))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
_JWT_SHAPE_RE = re.compile(r"^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _decodes_to_json_object(token: str) -> bool:
|
|
108
|
+
try:
|
|
109
|
+
padded = token + "=" * (-len(token) % 4)
|
|
110
|
+
try:
|
|
111
|
+
raw = base64.b64decode(padded, validate=False)
|
|
112
|
+
except (ValueError, binascii.Error):
|
|
113
|
+
raw = base64.urlsafe_b64decode(padded)
|
|
114
|
+
return isinstance(json.loads(raw.decode("utf-8")), dict)
|
|
115
|
+
except (ValueError, UnicodeDecodeError, binascii.Error):
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass(frozen=True)
|
|
120
|
+
class MalformedPaymentCredential:
|
|
121
|
+
"""Which credential channel carried the malformed value, and why."""
|
|
122
|
+
|
|
123
|
+
channel: str # "x402" | "mpp"
|
|
124
|
+
message: str
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def malformed_payment_credential(request_or_headers: Any) -> MalformedPaymentCredential | None:
|
|
128
|
+
"""Wire-shape gate for payment credentials, cheap enough to run before any merchant hook.
|
|
129
|
+
|
|
130
|
+
A request whose payment header cannot possibly be a credential (not
|
|
131
|
+
base64/base64url JSON, not a JWT-shaped token) is rejected up front, so junk
|
|
132
|
+
headers never trigger per-request hooks (``pre_validate``, pricing,
|
|
133
|
+
recipient minting) or the identity-gate API call.
|
|
134
|
+
|
|
135
|
+
This is deliberately a SHAPE check only. Signature verification, payTo
|
|
136
|
+
binding, and challenge validation stay where they are (the x402 validator
|
|
137
|
+
and the MPP settle path) — those need per-request state the hooks produce.
|
|
138
|
+
A well-formed-but-invalid credential still reaches the real validators and
|
|
139
|
+
fails there.
|
|
140
|
+
|
|
141
|
+
Returns ``None`` when every present credential channel is plausibly shaped
|
|
142
|
+
(or no payment header is present).
|
|
143
|
+
"""
|
|
144
|
+
headers = _unwrap_headers(request_or_headers)
|
|
145
|
+
x402_token = _read_header(headers, "payment-signature") or _read_header(headers, "x-payment")
|
|
146
|
+
if x402_token:
|
|
147
|
+
if not _decodes_to_json_object(x402_token):
|
|
148
|
+
return MalformedPaymentCredential(
|
|
149
|
+
channel="x402",
|
|
150
|
+
message="X-Payment header is not decodable base64 JSON.",
|
|
151
|
+
)
|
|
152
|
+
return None
|
|
153
|
+
auth = _read_header(headers, "authorization")
|
|
154
|
+
if isinstance(auth, str) and auth.startswith("Payment "):
|
|
155
|
+
token = auth[len("Payment ") :].strip()
|
|
156
|
+
if not token or (not _decodes_to_json_object(token) and not _JWT_SHAPE_RE.match(token)):
|
|
157
|
+
return MalformedPaymentCredential(
|
|
158
|
+
channel="mpp",
|
|
159
|
+
message=("Authorization: Payment credential is neither base64-encoded JSON nor a token-shaped value."),
|
|
160
|
+
)
|
|
161
|
+
return None
|
{agentscore_commerce-2.5.2 → agentscore_commerce-2.5.4}/agentscore_commerce/payment/zero_settle.py
RENAMED
|
@@ -2,16 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
CDP rejects EIP-3009 ``transferWithAuthorization`` with ``value=0`` as
|
|
4
4
|
``invalid_payload``; pympp's tempo intents accept only ``hash`` and
|
|
5
|
-
``transaction`` payload types
|
|
6
|
-
emits for $0 settles
|
|
7
|
-
|
|
5
|
+
``transaction`` payload types — the wallet-bound ``proof`` payload that the
|
|
6
|
+
mppx client emits for $0 settles (and that the mppx server verifies) has no
|
|
7
|
+
pympp counterpart yet. Both upstream verify+settle paths therefore fail when
|
|
8
|
+
the authorized amount is zero, so merchants that drop the settle to $0 in a
|
|
8
9
|
redemption-code flow need a way to skip verify+settle entirely while still
|
|
9
10
|
recovering the signer for wallet-capture attribution.
|
|
10
11
|
|
|
11
12
|
``zero_amount_carve_out`` is that path: parse the credential, lift the signer,
|
|
12
13
|
return ``ZeroSettleResult(signer_address, signer_network, tx_hash=None)``.
|
|
13
14
|
Identity is still authenticated by the merchant's gate above; the redemption
|
|
14
|
-
code is single-use; nothing on-chain to verify.
|
|
15
|
+
code is single-use; nothing on-chain to verify. The recovered signer block is
|
|
16
|
+
UNAUTHENTICATED (parse-only) on the MPP path — treat it as an attribution
|
|
17
|
+
hint, not a verified identity.
|
|
18
|
+
|
|
19
|
+
Known divergence from the Node SDK: node-commerce delegates $0 Tempo settles
|
|
20
|
+
to mppx's native zero-amount proof path (verified) and carves out only x402 +
|
|
21
|
+
Solana. This module keeps the Tempo carve-out because pympp has no proof
|
|
22
|
+
payload support; revisit when pympp ships it so both SDKs converge on
|
|
23
|
+
upstream verification.
|
|
15
24
|
"""
|
|
16
25
|
|
|
17
26
|
from __future__ import annotations
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
"""Short-TTL body-hash
|
|
1
|
+
"""Short-TTL body-hash caches.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
:func:`create_result_cache` is the neutral primitive: a keyed JSON-value cache
|
|
4
|
+
with a stable content-hash key builder. Use it to cache any per-request result
|
|
5
|
+
a merchant computes on the probe leg and replays on the settle leg — e.g. the
|
|
6
|
+
output of a paid upstream call made in a ``Checkout`` ``pre_validate`` hook, so
|
|
7
|
+
a payment retry (or a junk payment header) never pays upstream twice.
|
|
8
|
+
|
|
9
|
+
:func:`create_quote_cache` is the compute-first-flavored wrapper used by
|
|
10
|
+
``compute_first_checkout``: the cached value is a :class:`CachedQuote`
|
|
11
|
+
(``body`` / ``price_cents`` / ``recipients``). Standard x402-fetch retry
|
|
12
|
+
semantics resign the buyer's ORIGINAL request body — there's no ``result_id``
|
|
13
|
+
echo channel through the protocol — so both caches key by a stable
|
|
14
|
+
content-hash of the request body. Same body → same hash → same cache slot.
|
|
5
15
|
|
|
6
16
|
Default in-memory ``dict``; optional ``redis_url`` lazy-imports
|
|
7
17
|
``redis.asyncio`` for multi-instance deployments. ``redis`` is an optional
|
|
@@ -46,6 +56,16 @@ def _canonicalize(value: Any) -> Any:
|
|
|
46
56
|
return value
|
|
47
57
|
|
|
48
58
|
|
|
59
|
+
@dataclass
|
|
60
|
+
class ResultCache:
|
|
61
|
+
"""Async neutral result cache returned by :func:`create_result_cache`."""
|
|
62
|
+
|
|
63
|
+
body_hash_key: Any # (prefix: str, body: dict) -> str
|
|
64
|
+
read: Any # (key: str) -> Any | None
|
|
65
|
+
write: Any # (key: str, value: Any) -> None
|
|
66
|
+
clear: Any # () -> None
|
|
67
|
+
|
|
68
|
+
|
|
49
69
|
@dataclass
|
|
50
70
|
class QuoteCache:
|
|
51
71
|
"""Async quote cache returned by :func:`create_quote_cache`."""
|
|
@@ -56,20 +76,21 @@ class QuoteCache:
|
|
|
56
76
|
clear: Any # () -> None
|
|
57
77
|
|
|
58
78
|
|
|
59
|
-
def
|
|
79
|
+
def create_result_cache(
|
|
60
80
|
*,
|
|
61
81
|
ttl_ms: int = DEFAULT_TTL_MS,
|
|
62
82
|
redis_url: str | None = None,
|
|
63
|
-
key_prefix: str = "
|
|
64
|
-
) ->
|
|
65
|
-
"""Build a fresh
|
|
66
|
-
|
|
67
|
-
Each call owns its own state (memory dict + Redis client).
|
|
68
|
-
``redis_url`` for a Redis-backed
|
|
69
|
-
in-process only and replicas diverge under
|
|
83
|
+
key_prefix: str = "result:",
|
|
84
|
+
) -> ResultCache:
|
|
85
|
+
"""Build a fresh neutral result cache.
|
|
86
|
+
|
|
87
|
+
Each call owns its own state (memory dict + Redis client). Values must
|
|
88
|
+
survive ``json.dumps`` round-trips. Set ``redis_url`` for a Redis-backed
|
|
89
|
+
cache; otherwise the cache is in-process only and replicas diverge under
|
|
90
|
+
load.
|
|
70
91
|
"""
|
|
71
|
-
mem_state: dict[str, tuple[
|
|
72
|
-
_get_redis = memoized_redis(url=redis_url, label="
|
|
92
|
+
mem_state: dict[str, tuple[Any, float]] = {}
|
|
93
|
+
_get_redis = memoized_redis(url=redis_url, label="result-cache")
|
|
73
94
|
|
|
74
95
|
def _body_hash_key(prefix: str, body: dict[str, Any]) -> str:
|
|
75
96
|
canonical = json.dumps(_canonicalize(body), separators=(",", ":"))
|
|
@@ -82,40 +103,25 @@ def create_quote_cache(
|
|
|
82
103
|
if expires_at <= now:
|
|
83
104
|
del mem_state[k]
|
|
84
105
|
|
|
85
|
-
async def _read(key: str) ->
|
|
106
|
+
async def _read(key: str) -> Any | None:
|
|
86
107
|
r = await _get_redis()
|
|
87
108
|
if r is not None:
|
|
88
109
|
with contextlib.suppress(Exception):
|
|
89
110
|
raw = await r.get(f"{key_prefix}{key}")
|
|
90
111
|
if raw is None:
|
|
91
112
|
return None
|
|
92
|
-
|
|
93
|
-
return CachedQuote(
|
|
94
|
-
body=data["body"],
|
|
95
|
-
price_cents=data["price_cents"],
|
|
96
|
-
recipients=data.get("recipients", {}),
|
|
97
|
-
)
|
|
113
|
+
return json.loads(raw)
|
|
98
114
|
_evict_expired()
|
|
99
115
|
entry = mem_state.get(key)
|
|
100
116
|
return entry[0] if entry else None
|
|
101
117
|
|
|
102
|
-
async def _write(
|
|
103
|
-
key: str,
|
|
104
|
-
body: dict[str, Any],
|
|
105
|
-
price_cents: float,
|
|
106
|
-
*,
|
|
107
|
-
recipients: dict[str, str] | None = None,
|
|
108
|
-
) -> None:
|
|
109
|
-
cached = CachedQuote(body=body, price_cents=price_cents, recipients=recipients or {})
|
|
118
|
+
async def _write(key: str, value: Any) -> None:
|
|
110
119
|
r = await _get_redis()
|
|
111
120
|
if r is not None:
|
|
112
121
|
with contextlib.suppress(Exception):
|
|
113
|
-
|
|
114
|
-
{"body": cached.body, "price_cents": cached.price_cents, "recipients": cached.recipients}
|
|
115
|
-
)
|
|
116
|
-
await r.set(f"{key_prefix}{key}", payload, px=ttl_ms)
|
|
122
|
+
await r.set(f"{key_prefix}{key}", json.dumps(value), px=ttl_ms)
|
|
117
123
|
return
|
|
118
|
-
mem_state[key] = (
|
|
124
|
+
mem_state[key] = (value, time.monotonic() * 1000 + ttl_ms)
|
|
119
125
|
|
|
120
126
|
async def _clear() -> None:
|
|
121
127
|
mem_state.clear()
|
|
@@ -124,9 +130,53 @@ def create_quote_cache(
|
|
|
124
130
|
with contextlib.suppress(Exception):
|
|
125
131
|
await r.flushdb()
|
|
126
132
|
|
|
127
|
-
return
|
|
133
|
+
return ResultCache(
|
|
128
134
|
body_hash_key=_body_hash_key,
|
|
129
135
|
read=_read,
|
|
130
136
|
write=_write,
|
|
131
137
|
clear=_clear,
|
|
132
138
|
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def create_quote_cache(
|
|
142
|
+
*,
|
|
143
|
+
ttl_ms: int = DEFAULT_TTL_MS,
|
|
144
|
+
redis_url: str | None = None,
|
|
145
|
+
key_prefix: str = "quote:",
|
|
146
|
+
) -> QuoteCache:
|
|
147
|
+
"""Build a fresh quote cache (a result cache with the quote-shaped ``write``).
|
|
148
|
+
|
|
149
|
+
Each call owns its own state (memory dict + Redis client). Set
|
|
150
|
+
``redis_url`` for a Redis-backed cache; otherwise the cache is
|
|
151
|
+
in-process only and replicas diverge under load.
|
|
152
|
+
"""
|
|
153
|
+
cache = create_result_cache(ttl_ms=ttl_ms, redis_url=redis_url, key_prefix=key_prefix)
|
|
154
|
+
|
|
155
|
+
async def _read(key: str) -> CachedQuote | None:
|
|
156
|
+
data = await cache.read(key)
|
|
157
|
+
if data is None:
|
|
158
|
+
return None
|
|
159
|
+
return CachedQuote(
|
|
160
|
+
body=data["body"],
|
|
161
|
+
price_cents=data["price_cents"],
|
|
162
|
+
recipients=data.get("recipients", {}),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
async def _write(
|
|
166
|
+
key: str,
|
|
167
|
+
body: dict[str, Any],
|
|
168
|
+
price_cents: float,
|
|
169
|
+
*,
|
|
170
|
+
recipients: dict[str, str] | None = None,
|
|
171
|
+
) -> None:
|
|
172
|
+
await cache.write(
|
|
173
|
+
key,
|
|
174
|
+
{"body": body, "price_cents": price_cents, "recipients": recipients or {}},
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return QuoteCache(
|
|
178
|
+
body_hash_key=cache.body_hash_key,
|
|
179
|
+
read=_read,
|
|
180
|
+
write=_write,
|
|
181
|
+
clear=cache.clear,
|
|
182
|
+
)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentscore-commerce"
|
|
7
|
-
version = "2.5.
|
|
7
|
+
version = "2.5.4"
|
|
8
8
|
description = "Agent commerce SDK for Python — identity middleware (FastAPI, Flask, Django, AIOHTTP, Sanic, ASGI) + payment helpers + 402 builders + discovery + Stripe multichain. The full merchant-side toolkit for AgentScore-powered agent commerce."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -137,7 +137,7 @@ def _req(headers: dict[str, str]) -> CheckoutRequest:
|
|
|
137
137
|
return CheckoutRequest(
|
|
138
138
|
method="POST",
|
|
139
139
|
url=URL,
|
|
140
|
-
headers={"x-payment": "
|
|
140
|
+
headers={"x-payment": "eyJzdHViIjogdHJ1ZX0=", **headers},
|
|
141
141
|
body={"product_id": "p1", "quantity": 1},
|
|
142
142
|
)
|
|
143
143
|
|
|
@@ -608,7 +608,7 @@ class TestCheckoutAipRendererHonorsProblemJson:
|
|
|
608
608
|
async def test_edge_deny_renders_problem_json_through_fastapi_adapter(self) -> None:
|
|
609
609
|
checkout = _make_checkout(CheckoutGateConfig(api_key="as_test_key", require_kyc=True, aip=AIP))
|
|
610
610
|
request = _starlette_request(
|
|
611
|
-
{"x-payment": "
|
|
611
|
+
{"x-payment": "eyJzdHViIjogdHJ1ZX0=", "agent-identity": "eyJhbGciOiJFZERTQSJ9.e30.sig"}
|
|
612
612
|
)
|
|
613
613
|
resp = await checkout.handle_fastapi(request)
|
|
614
614
|
assert resp.status_code == 401
|
|
@@ -620,7 +620,7 @@ class TestCheckoutAipRendererHonorsProblemJson:
|
|
|
620
620
|
# The override is AIP-only: a missing-identity denial (no Agent-Identity header) through the
|
|
621
621
|
# same renderer must stay on the application/json default, untouched.
|
|
622
622
|
checkout = _make_checkout(CheckoutGateConfig(api_key="as_test_key", require_kyc=True, aip=AIP))
|
|
623
|
-
request = _starlette_request({"x-payment": "
|
|
623
|
+
request = _starlette_request({"x-payment": "eyJzdHViIjogdHJ1ZX0="})
|
|
624
624
|
resp = await checkout.handle_fastapi(request)
|
|
625
625
|
assert resp.media_type == "application/json"
|
|
626
626
|
body = json.loads(resp.body)
|
|
@@ -797,7 +797,7 @@ class TestCheckoutStaticGateEnforcement:
|
|
|
797
797
|
req = CheckoutRequest(
|
|
798
798
|
method="POST",
|
|
799
799
|
url=URL,
|
|
800
|
-
headers={"x-payment": "
|
|
800
|
+
headers={"x-payment": "eyJzdHViIjogdHJ1ZX0="},
|
|
801
801
|
body={"product_id": "p1", "quantity": 1},
|
|
802
802
|
raw=object(),
|
|
803
803
|
)
|