Express Middleware
createAIOTPaymentRoutes returns an Express Router that mounts four routes under the /aiot-pay/* prefix. Under the hood it instantiates an AIOTShopifyClient and wires it to the routes, so one call configures the whole payment flow.
What it mounts
| Method | Path | Purpose |
|---|---|---|
POST | /aiot-pay/checkout | Create a new checkout session from a cart |
GET | /aiot-pay/status/:sessionId | Poll session state for the frontend |
POST | /aiot-pay/complete | Settle a signed payment |
GET | /aiot-pay/pay/:sessionId | Serve the self-contained payment page HTML |
Basic usage
import express from 'express'
import { createAIOTPaymentRoutes } from '@aiot/shopify-x402/middleware/express'
const app = express()
app.use(express.json())
app.use(
createAIOTPaymentRoutes({
aiotApiKey: process.env.AIOT_API_KEY!,
merchantWallet: process.env.MERCHANT_WALLET!,
shopifyAccessToken: process.env.SHOPIFY_ACCESS_TOKEN ?? '',
shopifyStoreDomain: process.env.SHOPIFY_STORE_DOMAIN ?? '',
chainId: 97,
callbackUrl: 'https://mystore.example/thanks'
})
)
app.listen(3000)Config
AIOTPaymentRoutesConfig extends AIOTShopifyClientConfig with one extra field:
| Name | Type | Description |
|---|---|---|
paymentPageOptions | PaymentPageOptions | Customize the rendered payment page (title, testnet badge). |
All other fields (API key, wallet, Shopify creds, session store) come from AIOTShopifyClientConfig β see the SDK client guide for the full table.
Route behavior
POST /aiot-pay/checkout
Creates a checkout and returns the session payload.
POST /aiot-pay/checkout
Content-Type: application/json
{
"items": [
{ "title": "Pro plan", "price": "29.99", "quantity": 1 }
],
"currency": "usd"
}Response: the CreateCheckoutResult object (sessionId, paymentPageUrl, usdcAmount, fiatTotal, expiresAt).
Validation:
itemsmust be a non-empty array; returns400otherwise.- Any
AIOTErroris serialized as{ error, code }with the appropriate status code.
GET /aiot-pay/status/:sessionId
Returns a slimmed-down view of the session β id, status, amounts, expiry, and the paymentResult object if completed. Returns 404 if no session matches.
POST /aiot-pay/complete
Accepts { sessionId, payment, eip7702Auth? } and calls client.completePayment under the hood. Returns the PaymentResult on success. On a CheckoutExpiredError returns 410 Gone; on a PaymentFailedError returns 402 Payment Required.
GET /aiot-pay/pay/:sessionId
Serves the self-contained HTML payment page. If the session is already completed, redirects to callbackUrl if configured, otherwise shows βPayment already completed.β Expired sessions return 410.
Error handling
All routes funnel through a shared handleError function:
CheckoutExpiredErrorβ410 { error }AIOTErrorβerr.statusCode { error, code }- Anything else β
500 { error: 'Internal server error' }(the underlying error is logged)
The middleware uses console.error for unexpected errors. In production,
pass a custom logger to AIOTShopifyClientConfig and wire it to your
observability stack so you can trace failures across the
settle β Shopify call chain.
Customizing the payment page
Pass paymentPageOptions:
createAIOTPaymentRoutes({
// ...,
paymentPageOptions: {
title: 'Pay with Crypto β Store',
testnet: true // shows the "BSC Testnet" badge
}
})See the checkout page guide for the full options list.
Related
- SDK client β the underlying class
- Checkout page β the page rendered by
GET /aiot-pay/pay/:sessionId - Error handling
- API Reference β createAIOTPaymentRoutes