Skip to main content
QWED Logo

QWED-UCP

Deterministic Verification Middleware for Universal Commerce Protocol

Verify AI agent commerce before the money moves.

QWED-UCP sits between AI agents and payment processors — catching miscalculated totals,
invalid state transitions, and malformed checkouts before they hit production.

PyPI CI License Python 3.10+ Verified by QWED Snyk GitHub stars

Quick Start · The Guards · Integration · Trust Status · 📖 Docs


🚨 The Problem

AI agents (Gemini, ChatGPT, Claude) now generate e-commerce checkouts directly — cart totals, tax, discounts, refunds, fees. These agents hallucinate on math:

Scenario LLM Output Correct
10% off $99.99 "$10.00 discount" $9.999 → $10.00 ✅
8.25% tax on $100 "$8.00 tax" $8.25 ❌
$50 + $30 + $20 cart "$110.00 total" $100.00 ❌
Discount applied after tax Wrong order Math error ❌

QWED-UCP blocks these errors before they reach a payment processor.


✅ What QWED-UCP Is (and Isn't)

QWED-UCP IS:

  • Verification middleware that checks AI-generated UCP checkouts
  • Deterministic — uses Decimal math (no floating-point errors) and state-machine logic
  • Open source (Apache 2.0) — integrate into any e-commerce workflow
  • A safety layer — catches calculation errors and invalid state transitions before payment

QWED-UCP is NOT:

  • A shopping cart — use Shopify, WooCommerce, or Stripe for that
  • A payment processor — use Stripe, Adyen, or Square for that
  • A fraud detection system — use Sift, Signifyd, or Riskified for that
  • A replacement for e-commerce platforms — we just verify the math

Think of QWED-UCP as the "accountant" that reviews every AI checkout before payment.

Shopify builds carts. Stripe processes payments. QWED verifies the math.


🆚 How QWED-UCP Differs from E-Commerce Platforms

Aspect Shopify / Stripe / Adyen QWED-UCP
Purpose Build carts, process payments Verify calculations
Approach Trust AI outputs Deterministically verify AI outputs
Accuracy ~99% (edge cases fail) 100% deterministic
Tech Standard floating-point Decimal + JSON Schema
Integration Replace your stack Sits between AI and payment
Pricing Transaction fees Free (Apache 2.0)

Use Together

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   AI Agent   │ ──► │  QWED-UCP    │ ──► │    Stripe    │
│ (checkout)   │     │  (verifies)  │     │  (payment)   │
└──────────────┘     └──────────────┘     └──────────────┘

🛡️ The Guards

QWED-UCP ships 10 verification guards. UCPVerifier.verify_checkout() runs the 3 core guards as a fail-closed pipeline; the remaining 7 guards are available as standalone classes for manual or middleware use.

Core Guards (run by verify_checkout())

Guard Engine What It Verifies
Money Guard Decimal Cart totals against UCP formula: Total = Subtotal - Discount + Fulfillment + Tax + Fee
State Guard Manual state logic Checkout state machine (draft → ready → complete), rejects illegal transitions
Structure Guard JSON Schema UCP schema compliance (v1.0)

Standalone Guards

Guard Engine What It Verifies
Line Item Guard Decimal Item quantity × price = line total
Discount Guard Decimal Percentage and fixed discount calculations
Currency Guard Decimal Currency precision, $0.01 rounding, supported codes
Refund Guard Decimal Full/partial refund amounts, tax reversals
Tip Guard Decimal Pre/post-tax tip calculations, min/max bounds
Fee Guard Decimal Service fees, delivery fees, platform fees
Attestation Guard JWT (PyJWT) Context-bound attestation tokens with in-memory replay protection

🚀 Quick Start

Installation

pip install qwed-ucp

Verify a Checkout

from qwed_ucp import UCPVerifier

verifier = UCPVerifier()

checkout = {
    "currency": "USD",
    "totals": [
        {"type": "subtotal", "amount": 100.00},
        {"type": "tax", "amount": 8.25},
        {"type": "total", "amount": 108.25}
    ],
    "status": "ready_for_complete"
}

result = verifier.verify_checkout(checkout)

if result.verified:
    print("✅ Transaction verified — safe to process!")
else:
    print(f"❌ Verification failed: {result.error}")

verify_checkout() is always a full fail-closed trust verdict: it returns verified=True only when Money Guard, State Guard, and Structure Guard all pass.

Verify Totals Only

# Math-only check — does not verify state or schema
result = verifier.verify_totals_only(checkout)

⚠️ Do not treat verify_totals_only() as a final transaction verdict. It only runs the Money Guard and does not check state or schema validity.


📊 Interpreting Results

Shared Fields (all results)

Field Type Description
verified bool Convenience flag — True only when status == TrustStatus.VERIFIED
status TrustStatus Typed trust verdict — see Trust Status
error Optional[str] Error message when verification fails

Top-Level Only (UCPVerificationResult)

Field Type Description
engine str "QWED-Deterministic-v1"
guards list[GuardResult] Individual guard outcomes
verification_mode str "deterministic"

Branching on status (preferred)

from qwed_ucp import UCPVerifier, TrustStatus

verifier = UCPVerifier()
result = verifier.verify_checkout(checkout)

if result.status == TrustStatus.VERIFIED:
    proceed_to_payment(checkout)
elif result.status == TrustStatus.ENGINE_ERROR:
    page_operator("Verifier crashed — manual review required")
else:
    reject_transaction(f"Proof failed: {result.status}")

Aggregation

verify_checkout() propagates the most-severe guard status to the top level (fail-closed ordering):

Top-level status Triggered when
ENGINE_ERROR Any guard raised an exception
QUARANTINED A guard returned QUARANTINED (reserved)
FAILED A guard deterministically disproved the transaction
UNVERIFIABLE Most-severe guard status is UNVERIFIABLE
UNSUPPORTED Most-severe guard status is UNSUPPORTED
PARTIAL Most-severe guard status is PARTIAL
VERIFIED All guards passed

🔌 Integration

FastAPI Middleware

QWED-UCP ships a configurable FastAPI/Starlette middleware (requires Starlette, included with pip install qwed-ucp) that intercepts checkout requests and verifies them automatically:

from fastapi import FastAPI
from qwed_ucp.middleware.fastapi import QWEDUCPMiddleware

app = FastAPI()
app.add_middleware(QWEDUCPMiddleware)

The middleware:

  • Intercepts POST/PUT/PATCH to paths matching /checkout, /cart, /payment
  • Returns 422 Unprocessable Entity on verification failure (configurable)
  • Sets headers X-QWED-Verified, X-QWED-Guards-Passed, X-QWED-Error
  • Runs core guards (Money, State, Schema) plus optional advanced guards
  • Always fail-closed on empty body, malformed JSON, or non-dict payload

Configuration:

app.add_middleware(QWEDUCPMiddleware,
    block_on_failure=True,       # Block on verification failure (default)
    include_details=True,        # Include guard details in error response
    use_advanced_guards=True,    # Also run Line Items, Discount, Currency guards
    verify_paths=["/checkout"],  # Override default path list
    verify_methods=["POST"],     # Override default method list
)

A helper dependency is also available for manual injection:

from qwed_ucp.middleware.fastapi import create_verification_dependency

verify = create_verification_dependency()

@app.post("/checkout")
async def create_checkout(
    checkout: dict,
    verification = Depends(verify)
):
    if not verification["verified"]:
        raise HTTPException(422, verification["error"])
    ...

Express.js Middleware

QWED-UCP also ships an Express.js middleware:

const express = require('express');
const { createQWEDUCPMiddleware } = require('qwed-ucp');

const app = express();
app.use(express.json());
app.use(createQWEDUCPMiddleware());

app.post('/checkout', (req, res) => {
    res.json({ status: 'verified', checkout: req.body });
});

See examples/express_server.js for a complete example with rate limiting and security hardening.

Stripe

import stripe
from qwed_ucp import UCPVerifier

def create_payment_intent(ucp_checkout):
    verifier = UCPVerifier()
    result = verifier.verify_checkout(ucp_checkout)

    if not result.verified:
        raise ValueError(f"Checkout math error: {result.error}")

    total = next(
        (item["amount"] for item in ucp_checkout["totals"]
         if item["type"] == "total"),
        None
    )
    if total is None:
        raise ValueError("Missing required 'total' entry in checkout.totals")
    return stripe.PaymentIntent.create(
        amount=int(total * 100),
        currency=ucp_checkout["currency"].lower()
    )

CI/CD

# .github/workflows/verify-checkout.yml
name: Verify UCP Checkouts
on: [push]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: QWED-AI/qwed-ucp@v1
        with:
          test-script: tests/verify_checkouts.py

🔏 AttestationGuard

For environments that need cryptographic proof of verification:

from qwed_ucp import AttestationGuard, UCPVerifier
import uuid

attester = AttestationGuard(
    secret_key="your-256-bit-secret",
    allow_insecure=True     # Set False in production
)

verifier = UCPVerifier()
result = verifier.verify_checkout(checkout)

attestation = attester.sign_checkout(
    checkout=checkout,
    verification_result=result,      # Accepts UCPVerificationResult directly
    transaction_attempt_id=str(uuid.uuid4()),
    request_nonce=str(uuid.uuid4()),
    session_id="sess_abc123"
)

# attestation.token is a signed JWT

transaction_attempt_id and request_nonce are required for context binding and in-memory replay protection (not shared across replicas or restarts — use an external store for multi-instance deployment). Set QWED_ATTESTATION_SECRET env var instead of passing secret_key in code.


🏷️ Trust Status

QWED-UCP v0.3.0+ exposes a typed TrustStatus enum on every verification result, replacing the old verified: bool-only model:

State Meaning
VERIFIED Deterministic proof succeeded under supported conditions
FAILED Proof was attempted and disproved (e.g. totals mismatch)
UNVERIFIABLE Proof could not be established (e.g. missing proof basis)
UNSUPPORTED Input or state is outside supported semantics
PARTIAL Some checks ran, but no final verdict is justified
ENGINE_ERROR A verifier dependency or the runtime crashed
QUARANTINED Reserved for policy-level rejection

verified: bool is preserved as a backward-compatible derived field: result.verified == True only when result.status == TrustStatus.VERIFIED.


🔒 Security & Privacy

Your checkout data never leaves your machine.

Concern QWED-UCP Approach
Data Transmission No API calls, no cloud processing
Storage Nothing stored — pure computation
Dependencies Local-only (Decimal, JSON Schema, PyJWT, Starlette)
PCI Compliance No cardholder data processed

Perfect for: e-commerce with strict privacy requirements, transactions containing PII, PCI-DSS compliant environments.


🗺️ Roadmap

v0.3.0 (Current)

  • UCPVerifier with 3 core guards (Money, State, Structure)
  • All 10 guards shipped and tested
  • TrustStatus enum on every result
  • FastAPI middleware (fail-closed on unparseable bodies)
  • Express.js middleware
  • AttestationGuard with context-bound JWT + replay protection

In Progress

  • Multi-currency support (exchange rates)
  • Subscription/recurring payment validation
  • TypeScript/npm SDK

Planned

  • Shopify webhook integration
  • Stripe Checkout session verification
  • WooCommerce plugin
  • Real-time cart verification API

❓ FAQ

Is QWED-UCP free?

Yes! Apache 2.0 license. Use it in commercial products, modify it, distribute it — no restrictions.

Does it handle floating-point precision issues?

Yes! Uses Python's Decimal type with ROUND_HALF_UP to 2 decimal places. No 0.1 + 0.2 = 0.30000000000000004 issues.

What is the UCP total formula?

Total = Subtotal - Discount + Fulfillment + Tax + Fee

QWED-UCP's Money Guard verifies AI outputs against this formula exactly.

Can I use it without Google UCP?

Yes! The guards work with any JSON checkout format that has a totals array with type and amount fields.

How fast is verification?

Sub-millisecond to low milliseconds per checkout, depending on the guard set. The Decimal math engine is optimized for currency calculations.

Does QWED-UCP expose TrustStatus in the Python SDK?

Yes. qwed_ucp.TrustStatus is a 7-state enum on every result dataclass. The verified: bool field is preserved for backward compatibility.


🔗 Related QWED Packages

Package Purpose
qwed-verification Core verification engine
qwed-finance Banking & financial verification
qwed-legal Legal contract verification
qwed-infra Infrastructure-as-code verification
qwed-tax Tax compliance verification
qwed-mcp Claude Desktop MCP integration
qwed-open-responses OpenAI Responses API guards

🔗 Links

Resource Link
Universal Commerce Protocol ucp.dev
Google UCP Docs developers.google.com/merchant/ucp
QWED Documentation docs.qwedai.com
QWED-AI Organization github.com/QWED-AI

🧑‍💻 Development

From Source

git clone https://github.com/QWED-AI/qwed-ucp.git
cd qwed-ucp
pip install -e ".[dev]"

Running Tests

pytest tests/ -v                # All tests
pytest tests/ -v --cov=src/qwed_ucp --cov-report=html  # With coverage
pytest tests/test_money_guard.py -v  # Single guard

Linting

ruff check src/ tests/

📄 License

Apache 2.0 — See LICENSE


Built with ❤️ by QWED-AI

"AI agents shouldn't guess at math. QWED makes commerce verifiable."

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qwed_ucp-0.3.0.tar.gz (104.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qwed_ucp-0.3.0-py3-none-any.whl (41.8 kB view details)

Uploaded Python 3

File details

Details for the file qwed_ucp-0.3.0.tar.gz.

File metadata

  • Download URL: qwed_ucp-0.3.0.tar.gz
  • Upload date:
  • Size: 104.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for qwed_ucp-0.3.0.tar.gz
Algorithm Hash digest
SHA256 65abc2f0708c54f7c571b09675b821ac2f9f171acb7e024683e38f5cb0005ec6
MD5 dc205786b550c675d9c48ad8ba27ae9b
BLAKE2b-256 376ad1c19943e3a2d5d11942f7316821a5ec8521741e848a7e6c67c347d4b4bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for qwed_ucp-0.3.0.tar.gz:

Publisher: publish.yml on QWED-AI/qwed-ucp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qwed_ucp-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: qwed_ucp-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 41.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for qwed_ucp-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d0f771d1678484411fb308176a4ec98b35c7d1faa27882f0bde5e85326ee16f2
MD5 bed16715490ed17cf853aa03f6eb1a9e
BLAKE2b-256 3cc757aff4af078dadb7aef16aacf0995cd1f4f9dae3dd2f313c2cfdafc8c73e

See more details on using hashes here.

Provenance

The following attestation bundles were made for qwed_ucp-0.3.0-py3-none-any.whl:

Publisher: publish.yml on QWED-AI/qwed-ucp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page