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.
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 thatA payment processor— use Stripe, Adyen, or Square for thatA fraud detection system— use Sift, Signifyd, or Riskified for thatA 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/PATCHto paths matching/checkout,/cart,/payment - Returns
422 Unprocessable Entityon 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65abc2f0708c54f7c571b09675b821ac2f9f171acb7e024683e38f5cb0005ec6
|
|
| MD5 |
dc205786b550c675d9c48ad8ba27ae9b
|
|
| BLAKE2b-256 |
376ad1c19943e3a2d5d11942f7316821a5ec8521741e848a7e6c67c347d4b4bd
|
Provenance
The following attestation bundles were made for qwed_ucp-0.3.0.tar.gz:
Publisher:
publish.yml on QWED-AI/qwed-ucp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qwed_ucp-0.3.0.tar.gz -
Subject digest:
65abc2f0708c54f7c571b09675b821ac2f9f171acb7e024683e38f5cb0005ec6 - Sigstore transparency entry: 2205179247
- Sigstore integration time:
-
Permalink:
QWED-AI/qwed-ucp@361afee6d45370d8d2f0d13eeac47890ee1222c5 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/QWED-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@361afee6d45370d8d2f0d13eeac47890ee1222c5 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0f771d1678484411fb308176a4ec98b35c7d1faa27882f0bde5e85326ee16f2
|
|
| MD5 |
bed16715490ed17cf853aa03f6eb1a9e
|
|
| BLAKE2b-256 |
3cc757aff4af078dadb7aef16aacf0995cd1f4f9dae3dd2f313c2cfdafc8c73e
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qwed_ucp-0.3.0-py3-none-any.whl -
Subject digest:
d0f771d1678484411fb308176a4ec98b35c7d1faa27882f0bde5e85326ee16f2 - Sigstore transparency entry: 2205179255
- Sigstore integration time:
-
Permalink:
QWED-AI/qwed-ucp@361afee6d45370d8d2f0d13eeac47890ee1222c5 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/QWED-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@361afee6d45370d8d2f0d13eeac47890ee1222c5 -
Trigger Event:
release
-
Statement type: