AIOT Payment x402 is in public beta. Install the skill for your AI agent.
GuidesFor DevelopersExpress Middleware

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

MethodPathPurpose
POST/aiot-pay/checkoutCreate a new checkout session from a cart
GET/aiot-pay/status/:sessionIdPoll session state for the frontend
POST/aiot-pay/completeSettle a signed payment
GET/aiot-pay/pay/:sessionIdServe 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:

NameTypeDescription
paymentPageOptionsPaymentPageOptionsCustomize 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:

  • items must be a non-empty array; returns 400 otherwise.
  • Any AIOTError is 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)
Warning

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.