x402 Payments

Nesta página

O pacote @emdash-cms/x402 adiciona suporte ao protocolo de pagamento x402 a qualquer site Astro no Cloudflare. Ele é executado como uma integração Astro independente e combina com os campos CMS do EmDash para preços por página quando você usa o EmDash.

x402 é um protocolo de pagamento nativo HTTP. Quando um cliente solicita um recurso pago sem pagamento, o servidor responde com 402 Payment Required e instruções de pagamento legíveis por máquina. Agentes e navegadores que entendem x402 podem completar o pagamento automaticamente e tentar novamente a solicitação.

Quando usar isto

O caso de uso mais comum é o modo somente bots: cobre de agentes de IA e scrapers pelo acesso ao conteúdo enquanto permite que visitantes humanos leiam gratuitamente. Isso usa o Cloudflare Bot Management para distinguir bots de humanos.

Você também pode impor pagamento para todos os visitantes, ou verificar cabeçalhos de pagamento sem impor (renderização condicional).

Instalação

Instale o pacote com seu gerenciador de pacotes:

pnpm

pnpm add @emdash-cms/x402

npm

npm install @emdash-cms/x402

yarn

yarn add @emdash-cms/x402

Configuração

Adicione a integração à sua configuração Astro:

import { defineConfig } from "astro/config";
import { x402 } from "@emdash-cms/x402";

export default defineConfig({
	integrations: [
		x402({
			payTo: "0xYourWalletAddress",
			network: "eip155:8453", // Base mainnet
			defaultPrice: "$0.01",
			botOnly: true,
			botScoreThreshold: 30,
		}),
	],
});

Adicione a referência de tipo para que o TypeScript conheça Astro.locals.x402:

/// <reference types="@emdash-cms/x402/locals" />

Uso básico

A integração coloca um enforcer em Astro.locals.x402. Chame enforce() no frontmatter da sua página para proteger conteúdo atrás de pagamento:

---
const { x402 } = Astro.locals;

const result = await x402.enforce(Astro.request, {
  price: "$0.05",
  description: "Premium article",
});

// If the request has no valid payment, enforce() returns a 402 Response.
// Return it directly to send payment instructions to the client.
if (result instanceof Response) return result;

// Payment verified (or skipped in botOnly mode). Apply response headers
// so the client gets settlement proof.
x402.applyHeaders(result, Astro.response);
---

<article>
  <h1>Premium content</h1>
</article>

O método enforce() retorna:

  • Uma Response (402) — o cliente precisa pagar. Retorne-a diretamente.
  • Um EnforceResult — a solicitação deve prosseguir. O conteúdo foi pago, ou a imposição foi pulada (humano no modo botOnly).

Modo somente bots

Quando botOnly é true, a integração lê request.cf.botManagement.score para classificar solicitações:

  • Pontuação abaixo do limiar (padrão 30) -> tratado como bot, pagamento imposto
  • Pontuação no limiar ou acima -> tratado como humano, imposição pulada
  • Sem dados de gerenciamento de bots (dev local, implantação não-CF) -> tratado como humano

O EnforceResult inclui uma flag skipped para que você possa distinguir “não precisou pagar” de “pagou”:

---
const result = await x402.enforce(Astro.request, { price: "$0.01" });
if (result instanceof Response) return result;

x402.applyHeaders(result, Astro.response);

// result.paid    — true if payment was verified
// result.skipped — true if enforcement was skipped (human in botOnly mode)
// result.payer   — wallet address of payer (if paid)
---

Preços por página com EmDash

Ao usar o EmDash, adicione um campo number regular à sua coleção para preços por página e leia-o no momento da solicitação:

---
import { getEmDashEntry } from "emdash";

const { slug } = Astro.params;
const { entry } = await getEmDashEntry("posts", slug);

if (!entry) return Astro.redirect("/404");

const { x402 } = Astro.locals;

// Use the price from the CMS, falling back to a default
const result = await x402.enforce(Astro.request, {
  price: entry.data.price || "$0.01",
  description: entry.data.title,
});
if (result instanceof Response) return result;

x402.applyHeaders(result, Astro.response);
---

<article>
  <h1>{entry.data.title}</h1>
</article>

Verificar pagamento sem impor

Use hasPayment() para verificar se uma solicitação inclui cabeçalhos de pagamento sem verificar ou impor. Isso é útil para renderização condicional — mostrar conteúdo diferente para visitantes pagantes vs não pagantes:

---
const { x402 } = Astro.locals;

const hasPaid = x402.hasPayment(Astro.request);
---

{hasPaid ? (
  <p>Full premium content here.</p>
) : (
  <p>Subscribe for the full article.</p>
)}

Referência de configuração

OpçãoTipoPadrãoDescrição
payTostringobrigatórioEndereço da carteira de destino
networkstringobrigatórioIdentificador de rede CAIP-2 (ex: eip155:8453)
defaultPricePricePreço padrão, substituível por página
facilitatorUrlstringhttps://x402.org/facilitatorURL do facilitador de pagamento
schemestring"exact"Esquema de pagamento
maxTimeoutSecondsnumber60Timeout máximo para assinaturas de pagamento
evmbooleantrueHabilitar suporte de cadeia EVM
svmbooleanfalseHabilitar suporte de cadeia Solana (requer @x402/svm)
botOnlybooleanfalseImpor pagamento apenas para bots
botScoreThresholdnumber30Limiar de pontuação de bot (1-99, menor = mais provável ser bot)

Formato de preço

Os preços podem ser especificados em vários formatos:

  • String de dólar"$0.10" (o prefixo $ é removido, o valor é passado como está)
  • String numérica"0.10"
  • Número0.10
  • Objeto{ amount: "100000", asset: "0x...", extra: {} } para ativo/valor explícito

Identificadores de rede

As redes usam o formato CAIP-2:

RedeIdentificador
Base mainneteip155:8453
Base Sepoliaeip155:84532
Ethereumeip155:1
Solanasolana:mainnet

Opções de Enforce

Substitua os padrões de configuração para uma página específica:

await x402.enforce(Astro.request, {
	price: "$0.25", // Override price
	payTo: "0xDifferentWallet", // Override wallet
	network: "eip155:1", // Override network
	description: "Article: How x402 Works", // Resource description
	mimeType: "text/html", // MIME type hint
});

Suporte Solana

Solana é opt-in. Instale @x402/svm e habilite-o na configuração:

pnpm add @x402/svm

Defina a rede para um identificador Solana e desabilite EVM se você usar apenas Solana:

x402({
	payTo: "YourSolanaAddress",
	network: "solana:mainnet",
	svm: true,
	evm: false, // Disable EVM if only using Solana
});

Como funciona

  1. A integração x402() registra middleware que cria um enforcer e o coloca em Astro.locals.x402
  2. A configuração é passada para o middleware via um módulo virtual Vite (virtual:x402/config)
  3. Quando enforce() é chamado, ele verifica um cabeçalho payment-signature na solicitação
  4. Se nenhum cabeçalho de pagamento estiver presente, uma resposta 402 Payment Required é retornada com instruções de pagamento no cabeçalho PAYMENT-REQUIRED
  5. Se um cabeçalho de pagamento estiver presente, ele é verificado através do serviço facilitador e liquidado
  6. Após a liquidação, os cabeçalhos PAYMENT-RESPONSE são definidos na resposta via applyHeaders()

O servidor de recursos é inicializado preguiçosamente na primeira solicitação e armazenado em cache pela vida útil do worker.