> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qwedai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Express.js middleware

> Add QWED-UCP middleware to Express.js apps for automatic checkout verification. npm installation, configuration, and TypeScript support included.

Add automatic verification to your Express.js UCP merchant server.

***

## Installation

Copy the middleware file from the GitHub repository:

```bash theme={null}
# Clone or download
curl -O https://raw.githubusercontent.com/QWED-AI/qwed-ucp/main/middleware/express/qwed-ucp-middleware.js
```

***

## Basic usage

```javascript theme={null}
const express = require('express');
const { createQWEDUCPMiddleware } = require('./qwed-ucp-middleware');

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

// Add middleware
app.use(createQWEDUCPMiddleware());

app.post('/checkout-sessions', (req, res) => {
  // If we get here, checkout is already verified!
  res.status(201).json({ status: 'created' });
});

app.listen(8182);
```

***

## Configuration options

```javascript theme={null}
const middleware = createQWEDUCPMiddleware({
  verifyPaths: ['/checkout-sessions', '/checkout'],
  verifyMethods: ['POST', 'PUT', 'PATCH'],
  blockOnFailure: true,
  onVerified: (result, req) => {
    console.log(`✅ Verified: ${result.guardsPassed} guards passed`);
  },
  onFailed: (result, req) => {
    console.log(`❌ Failed: ${result.error}`);
  }
});

app.use(middleware);
```

***

## Response headers

| Header                 | Value            | Description                       |
| ---------------------- | ---------------- | --------------------------------- |
| `X-QWED-Verified`      | `true` / `false` | Verification result               |
| `X-QWED-Guards-Passed` | `4`              | Number of guards passed           |
| `X-QWED-Error`         | Error message    | Only on failure or internal error |

***

## Fail-closed on internal verification errors

If a guard raises an unexpected exception mid-verification, the middleware refuses to forward the request. Instead of calling `next()` and letting an unverified payload through, it responds with `HTTP 500`, `X-QWED-Verified: false`, `X-QWED-Error`, and `code: "INTERNAL_VERIFICATION_ERROR"`:

```json theme={null}
{
  "error": "QWED-UCP Verification Failed",
  "message": "Internal verification error: verification could not be completed",
  "code": "INTERNAL_VERIFICATION_ERROR"
}
```

The exception detail is logged server-side but not returned to the client, so raw error messages, stack traces, and file paths stay out of the response. Treat a `500` from a `/checkout-sessions` route the same as a `422` — the request has **not** been verified and must not be settled.

***

## Fail-closed on unparseable bodies

On a protected path and method, the middleware refuses to forward requests it cannot verify. Empty bodies and bodies that don't decode to a JSON object are rejected with `422`, `X-QWED-Verified: false`, and `code: "UNPARSEABLE_REQUEST"` before your handler runs:

```json theme={null}
{
  "error": "QWED-UCP Verification Failed",
  "message": "Empty or non-JSON request body: cannot verify unparseable payload",
  "code": "UNPARSEABLE_REQUEST"
}
```

<Note>
  Make sure `express.json()` is registered before `createQWEDUCPMiddleware()` so the middleware sees the parsed body. Send checkout payloads as `application/json` with a JSON object at the top level; arrays, primitives, and form-encoded bodies fail closed.
</Note>

***

## Error response

When verification fails:

```json theme={null}
{
  "error": "QWED-UCP Verification Failed",
  "message": "Total mismatch: calculated 98.25, declared 100.00",
  "code": "VERIFICATION_FAILED",
  "details": [
    {"guard": "Currency Guard", "verified": true, "error": null},
    {"guard": "Money Guard", "verified": false, "error": "Total mismatch..."}
  ]
}
```

***

## Available guards (JavaScript)

The Express.js middleware includes local JavaScript implementations:

```javascript theme={null}
const {
  verifyCurrency,
  verifyTotalsMath,
  verifyState,
  verifyLineItems
} = require('./qwed-ucp-middleware');

// Use individually
const result = verifyCurrency({ currency: 'USD' });
console.log(result.verified); // true
```

***

## Complete example

```javascript theme={null}
const express = require('express');
const { createQWEDUCPMiddleware } = require('./qwed-ucp-middleware');

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

// QWED-UCP middleware
app.use(createQWEDUCPMiddleware({
  blockOnFailure: true,
  onVerified: (result) => console.log('✅ QWED Verified'),
  onFailed: (result) => console.log('❌ QWED Failed:', result.error)
}));

// In-memory store
const checkouts = new Map();
let counter = 1;

app.post('/checkout-sessions', (req, res) => {
  const { currency = 'USD', line_items = [] } = req.body;
  
  const subtotal = line_items.reduce((sum, item) => {
    return sum + (item.price * (item.quantity || 1));
  }, 0);
  
  const tax = Math.round(subtotal * 0.0825 * 100) / 100;
  const total = Math.round((subtotal + tax) * 100) / 100;
  
  const checkout = {
    id: `checkout_${counter++}`,
    currency,
    line_items,
    totals: [
      { type: 'subtotal', amount: subtotal },
      { type: 'tax', amount: tax },
      { type: 'total', amount: total }
    ]
  };
  
  checkouts.set(checkout.id, checkout);
  res.status(201).json(checkout);
});

app.listen(8182, () => {
  console.log('🚀 UCP Merchant running on http://localhost:8182');
  console.log('✅ QWED-UCP verification ENABLED');
});
```
