x402 Payments

In questa pagina

Il pacchetto @emdash-cms/x402 aggiunge il supporto al protocollo di pagamento x402 ai siti Astro renderizzati sul server. È un’integrazione Astro autonoma, quindi l’applicazione dei pagamenti non richiede EmDash. Quando il sito usa anche EmDash, un campo di contenuto può fornire il prezzo di ogni voce.

x402 è un protocollo di pagamento nativo di HTTP. Quando un client richiede una risorsa a pagamento senza aver pagato, il server risponde con 402 Payment Required e con istruzioni di pagamento leggibili da una macchina. Gli agenti e i browser che comprendono x402 possono completare automaticamente il pagamento e ritentare la richiesta.

Scegliere una modalità di applicazione

Usa l’applicazione normale quando ogni richiesta alla route deve presentare un pagamento valido. Questa modalità non dipende dai metadati della richiesta specifici di Cloudflare.

Usa la modalità solo bot quando il sito è in esecuzione su Cloudflare Workers con Bot Management attivo e devono pagare solo le richieste con punteggio basso. Il pacchetto legge request.cf.botManagement.score; quando quel valore è assente, tratta la richiesta come umana e salta l’applicazione. Non usare la modalità solo bot quando l’assenza di dati sui bot deve fallire in modo chiuso (fail closed).

hasPayment() offre un terzo comportamento, solo per la presentazione. Indica se la richiesta ha un’intestazione di pagamento, ma non verifica né regola il pagamento.

Installare il pacchetto

Installa il pacchetto con il tuo gestore di pacchetti:

pnpm

pnpm add @emdash-cms/x402

npm

npm install @emdash-cms/x402

yarn

yarn add @emdash-cms/x402

Configurare l’integrazione

Scegli un wallet, una rete e un facilitator che funzionino insieme. L’integrazione supporta per impostazione predefinita le reti Ethereum Virtual Machine (EVM), ma anche il facilitator deve supportare la rete e l’asset configurati. L’esempio seguente usa la mainnet di Base e impone il pagamento per ogni richiesta:

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",
		}),
	],
});

Aggiungi il riferimento ai tipi in modo che TypeScript conosca Astro.locals.x402:

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

Imporre il pagamento su una route

L’integrazione mette un enforcer su Astro.locals.x402. Chiama enforce() nel frontmatter della tua pagina per mettere il contenuto dietro un 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>

Il metodo enforce() restituisce una delle due cose seguenti:

  • Una Response (402) — il client deve pagare. Restituiscila direttamente.
  • Un EnforceResult — la richiesta deve proseguire. Il contenuto è stato pagato oppure l’applicazione è stata saltata (utente umano in modalità botOnly).

Attivare la modalità solo bot

Attiva botOnly nella configurazione dell’integrazione:

x402({
	payTo: "0xYourWalletAddress",
	network: "eip155:8453",
	defaultPrice: "$0.01",
	botOnly: true,
	botScoreThreshold: 30,
});

L’integrazione legge request.cf.botManagement.score di Cloudflare per classificare le richieste:

  • Punteggio inferiore alla soglia (30 per impostazione predefinita) -> trattato come bot, pagamento imposto
  • Punteggio pari o superiore alla soglia -> trattato come umano, applicazione saltata
  • Nessun dato di Bot Management (sviluppo locale, deployment non Cloudflare) -> trattato come umano

L’EnforceResult include un flag skipped, così puoi distinguere «non ha dovuto pagare» da «ha pagato»:

---
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)
---

Leggere un prezzo da EmDash

Quando usi EmDash, aggiungi un normale campo number alla collection per i prezzi per pagina e leggilo al momento della richiesta:

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

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

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

const { x402 } = Astro.locals;

// Use the price from the CMS, falling back only when it is absent.
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>

Verificare un’intestazione di pagamento senza imporre il pagamento

Usa hasPayment() per verificare se una richiesta include un’intestazione di pagamento senza controllarla né imporla. Può servire a cambiare un messaggio o un avviso di accesso, ma non deve mai sbloccare contenuti protetti:

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

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

{hasPaymentHeader ? (
  <p>Payment supplied. Verification is still required.</p>
) : (
  <p>This page requires payment.</p>
)}

Riferimento di configurazione

OpzioneTipoPredefinitoDescrizione
payTostringobbligatorioIndirizzo del wallet di destinazione
networkstringobbligatorioIdentificatore di rete CAIP-2 (ad es. eip155:8453)
defaultPricePrice—Prezzo predefinito, sovrascrivibile per pagina
facilitatorUrlstringhttps://x402.org/facilitatorURL del facilitator di pagamento
schemestring"exact"Schema di pagamento
maxTimeoutSecondsnumber60Timeout massimo per le firme di pagamento
evmbooleantrueAttiva il supporto alle reti Ethereum Virtual Machine
svmbooleanfalseAttiva il supporto alla Solana Virtual Machine (richiede @x402/svm)
botOnlybooleanfalseImpone il pagamento solo ai bot
botScoreThresholdnumber30Soglia del punteggio bot (1-99; più è basso, più è probabile che sia un bot)

Formato del prezzo

I prezzi possono essere specificati in diversi formati:

  • Stringa in dollari — "$0.10" (il prefisso $ viene rimosso e il valore viene passato così com’è)
  • Stringa numerica — "0.10"
  • Numero — 0.10
  • Oggetto — { amount: "100000", asset: "0x...", extra: {} } per indicare esplicitamente asset e importo

Identificatori di rete

CAIP-2 assegna identificatori inequivocabili alle reti blockchain, come eip155:8453 per la mainnet di Base. Usa l’identificatore esatto pubblicato dal facilitator. Il pacchetto accetta la famiglia eip155:* quando il supporto a EVM è attivo e la famiglia solana:* quando è attivo il supporto alla Solana Virtual Machine (SVM); questo non garantisce che un facilitator accetti ogni rete di quella famiglia.

Sovrascrivere una singola richiesta

Sovrascrivi i valori predefiniti della configurazione per una pagina specifica:

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
});

Attivare il supporto a Solana

Solana è opzionale. Installa @x402/svm e attivalo nella configurazione:

pnpm add @x402/svm

Imposta svm: true, usa l’identificatore CAIP-2 di Solana supportato dal facilitator e disattiva EVM se il sito accetta solo pagamenti Solana. Ad esempio, l’identificatore della mainnet di Solana usato da @x402/svm 2.8 è solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:

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

Flusso di una richiesta

  1. L’integrazione mette l’enforcer dei pagamenti su Astro.locals.x402 prima che la pagina venga eseguita.
  2. enforce() cerca un’intestazione payment-signature.
  3. Senza un’intestazione di pagamento, enforce() restituisce una risposta 402 Payment Required il cui corpo e la cui intestazione PAYMENT-REQUIRED descrivono il pagamento accettato.
  4. Con un pagamento corrispondente, il facilitator configurato lo verifica e lo regola.
  5. enforce() restituisce il pagatore e il risultato del regolamento. Chiama applyHeaders() in modo che la risposta della pagina includa la prova PAYMENT-RESPONSE del facilitator.