Il pacchetto @emdash-cms/x402 aggiunge il supporto per il protocollo di pagamento x402 a qualsiasi sito Astro su Cloudflare. Funziona come un’integrazione Astro standalone e si combina con i campi CMS di EmDash per la tariffazione per pagina quando usi EmDash.
x402 è un protocollo di pagamento nativo HTTP. Quando un client richiede una risorsa a pagamento senza pagamento, il server risponde con 402 Payment Required e istruzioni di pagamento leggibili dalla macchina. Gli agenti e i browser che comprendono x402 possono completare il pagamento automaticamente e riprovare la richiesta.
Quando usare questo
Il caso d’uso più comune è la modalità solo bot: addebita agli agenti IA e ai scraper l’accesso ai contenuti lasciando che i visitatori umani leggano gratuitamente. Questo utilizza Cloudflare Bot Management per distinguere i bot dagli umani.
Puoi anche imporre il pagamento per tutti i visitatori, o verificare gli header di pagamento senza imporre (rendering condizionale).
Installazione
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 Configurazione
Aggiungi l’integrazione alla tua configurazione 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,
}),
],
});
Aggiungi il riferimento di tipo in modo che TypeScript conosca Astro.locals.x402:
/// <reference types="@emdash-cms/x402/locals" />
Utilizzo di base
L’integrazione posiziona un enforcer su Astro.locals.x402. Chiama enforce() nel frontmatter della tua pagina per proteggere i contenuti dietro 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
Response(402) — il client deve pagare. Restituiscila direttamente. - Un
EnforceResult— la richiesta dovrebbe procedere. Il contenuto è stato pagato, o l’applicazione è stata saltata (umano in modalità botOnly).
Modalità solo bot
Quando botOnly è true, l’integrazione legge request.cf.botManagement.score per classificare le richieste:
- Punteggio sotto la soglia (predefinito 30) -> trattato come bot, pagamento imposto
- Punteggio sulla soglia o sopra -> trattato come umano, applicazione saltata
- Nessun dato di gestione bot (sviluppo locale, deployment non-CF) -> trattato come umano
Il EnforceResult include un flag skipped in modo che tu possa distinguere tra “non ha dovuto pagare” e “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)
---
Tariffazione per pagina con EmDash
Quando usi EmDash, aggiungi un campo number regolare alla tua collezione per la tariffazione 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.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>
Verificare il pagamento senza imporre
Usa hasPayment() per verificare se una richiesta include header di pagamento senza verificare o imporre. Questo è utile per il rendering condizionale — mostrare contenuti diversi ai visitatori paganti vs non paganti:
---
const { x402 } = Astro.locals;
const hasPaid = x402.hasPayment(Astro.request);
---
{hasPaid ? (
<p>Full premium content here.</p>
) : (
<p>Subscribe for the full article.</p>
)}
Riferimento di configurazione
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
payTo | string | richiesto | Indirizzo wallet di destinazione |
network | string | richiesto | Identificatore di rete CAIP-2 (es. eip155:8453) |
defaultPrice | Price | — | Prezzo predefinito, sovrascrivibile per pagina |
facilitatorUrl | string | https://x402.org/facilitator | URL del facilitatore di pagamento |
scheme | string | "exact" | Schema di pagamento |
maxTimeoutSeconds | number | 60 | Timeout massimo per le firme di pagamento |
evm | boolean | true | Abilita il supporto della chain EVM |
svm | boolean | false | Abilita il supporto della chain Solana (richiede @x402/svm) |
botOnly | boolean | false | Imponi il pagamento solo per i bot |
botScoreThreshold | number | 30 | Soglia di punteggio bot (1-99, più basso = più probabile che sia un bot) |
Formato del prezzo
I prezzi possono essere specificati in diversi formati:
- Stringa dollaro —
"$0.10"(il prefisso$viene rimosso, il valore viene passato così com’è) - Stringa numerica —
"0.10" - Numero —
0.10 - Oggetto —
{ amount: "100000", asset: "0x...", extra: {} }per importo/asset esplicito
Identificatori di rete
Le reti usano il formato CAIP-2:
| Rete | Identificatore |
|---|---|
| Base mainnet | eip155:8453 |
| Base Sepolia | eip155:84532 |
| Ethereum | eip155:1 |
| Solana | solana:mainnet |
Opzioni di Enforce
Sovrascrivi i valori predefiniti di 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
});
Supporto Solana
Solana è opt-in. Installa @x402/svm e abilitalo nella configurazione:
pnpm add @x402/svm
Imposta la rete su un identificatore Solana e disabilita EVM se usi solo Solana:
x402({
payTo: "YourSolanaAddress",
network: "solana:mainnet",
svm: true,
evm: false, // Disable EVM if only using Solana
});
Come funziona
- L’integrazione
x402()registra un middleware che crea un enforcer e lo posiziona suAstro.locals.x402 - La configurazione viene passata al middleware tramite un modulo virtuale Vite (
virtual:x402/config) - Quando viene chiamato
enforce(), controlla la presenza di un headerpayment-signaturesulla richiesta - Se non è presente alcun header di pagamento, viene restituita una risposta
402 Payment Requiredcon le istruzioni di pagamento nell’headerPAYMENT-REQUIRED - Se è presente un header di pagamento, viene verificato attraverso il servizio facilitatore e regolato
- Dopo la regolazione, gli header
PAYMENT-RESPONSEvengono impostati sulla risposta tramiteapplyHeaders()
Il server delle risorse viene inizializzato in modo lazy alla prima richiesta e memorizzato nella cache per la durata del worker.