OpenPermit Docs
Guides

Protect a Paid Seller Endpoint

Return payment challenges and verify paid retries with seller middleware.

Use the dashboard or API to create a seller profile for the organization.

Create a resource with method, path template, accepted payment methods, and canonical pricing.

Use Fetch or Hono middleware to protect the route.

import { createOpenPermitClient } from '@openpermit/sdk/client';
import { createSellerMiddleware } from '@openpermit/sdk/seller';

const openpermit = createOpenPermitClient({
	baseUrl: process.env.OPENPERMIT_API_URL!,
	apiKey: process.env.OPENPERMIT_SELLER_API_KEY!,
});

const requirePayment = createSellerMiddleware({
	client: openpermit,
	sellerId: process.env.OPENPERMIT_SELLER_ID!,
	resourceId: process.env.OPENPERMIT_RESOURCE_ID!,
	paymentMethod: 'x402',
});

export async function fetch(request: Request) {
	return requirePayment(request, async () => {
		return Response.json({ result: 'paid data' });
	});
}

If the request has no valid credential, middleware returns 402 Payment Required. If verification succeeds, your handler returns the protected resource.

You can also keep resource setup in code instead of the dashboard:

const requirePayment = createSellerMiddleware({
	client: openpermit,
	seller: {
		name: 'Example Data API',
		domain: 'api.example.com',
	},
	resource: {
		resourceId: 'quotes:v1',
		method: 'GET',
		pathTemplate: '/v1/quotes/{symbol}',
		acceptedPaymentMethods: ['x402'],
		pricing: { type: 'fixed', amount: '0.04', asset: 'USDC' },
	},
	paymentMethod: 'x402',
});

For per-request pricing, declare a dynamic resource and return a quote from middleware. OpenPermit validates the quote against the resource bounds and persists the resolved amount on the payment intent.

const requirePayment = createSellerMiddleware({
	client: openpermit,
	sellerId: process.env.OPENPERMIT_SELLER_ID!,
	resource: {
		resourceId: 'quotes:dynamic',
		sellerId: process.env.OPENPERMIT_SELLER_ID!,
		method: 'GET',
		pathTemplate: '/v1/quotes/{symbol}',
		acceptedPaymentMethods: ['x402'],
		pricing: { type: 'dynamic', asset: 'USDC', maxAmount: '0.25', displayAmount: '0.05' },
	},
	paymentMethod: 'x402',
	quote: async () => ({ amount: '0.08', expiresAt: new Date(Date.now() + 30_000).toISOString() }),
});