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
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
payTo | string | obbligatorio | Indirizzo del wallet di destinazione |
network | string | obbligatorio | Identificatore di rete CAIP-2 (ad es. eip155:8453) |
defaultPrice | Price | — | Prezzo predefinito, sovrascrivibile per pagina |
facilitatorUrl | string | https://x402.org/facilitator | URL del facilitator di pagamento |
scheme | string | "exact" | Schema di pagamento |
maxTimeoutSeconds | number | 60 | Timeout massimo per le firme di pagamento |
evm | boolean | true | Attiva il supporto alle reti Ethereum Virtual Machine |
svm | boolean | false | Attiva il supporto alla Solana Virtual Machine (richiede @x402/svm) |
botOnly | boolean | false | Impone il pagamento solo ai bot |
botScoreThreshold | number | 30 | Soglia 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
- L’integrazione mette l’enforcer dei pagamenti su
Astro.locals.x402prima che la pagina venga eseguita. enforce()cerca un’intestazionepayment-signature.- Senza un’intestazione di pagamento,
enforce()restituisce una risposta402 Payment Requiredil cui corpo e la cui intestazionePAYMENT-REQUIREDdescrivono il pagamento accettato. - Con un pagamento corrispondente, il facilitator configurato lo verifica e lo regola.
enforce()restituisce il pagatore e il risultato del regolamento. ChiamaapplyHeaders()in modo che la risposta della pagina includa la provaPAYMENT-RESPONSEdel facilitator.