Das Paket @emdash-cms/x402 ergänzt jede Astro-Site auf Cloudflare um Unterstützung für das x402-Zahlungsprotokoll. Es funktioniert eigenständig — ohne Abhängigkeit vom EmDash-Kern — und lässt sich gut mit CMS-Feldern von EmDash für preisliche Seiten kombinieren.
x402 ist ein HTTP-natives Zahlungsprotokoll. Fordert ein Client eine kostenpflichtige Ressource ohne Zahlung an, antwortet der Server mit 402 Payment Required und maschinenlesbaren Zahlungsanweisungen. Clients, die x402 verstehen (Agenten, Browser), können die Zahlung automatisch ausführen und die Anfrage wiederholen.
Wann einsetzen
Der häufigste Fall ist der Bot-only-Modus: KI-Agenten und Scraper zahlen für den Zugriff, menschliche Besucher lesen kostenlos. Dafür nutzt man Cloudflare Bot Management zur Unterscheidung.
Sie können Zahlungen auch für alle Besucher erzwingen oder nur prüfen, ob Zahlungs-Header vorhanden sind (bedingtes Rendering).
Installation
pnpm
pnpm add @emdash-cms/x402 npm
npm install @emdash-cms/x402 yarn
yarn add @emdash-cms/x402 Einrichtung
Fügen Sie die Integration in Ihre Astro-Konfiguration ein:
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,
}),
],
});
Ergänzen Sie die Typreferenz, damit TypeScript Astro.locals.x402 kennt:
/// <reference types="@emdash-cms/x402/locals" />
Grundlegende Nutzung
Die Integration stellt einen Enforcer unter Astro.locals.x402 bereit. Rufen Sie enforce() im Frontmatter Ihrer Seite auf, um Inhalte hinter Zahlung zu schützen:
---
const { x402 } = Astro.locals;
const result = await x402.enforce(Astro.request, {
price: "$0.05",
description: "Premium-Artikel",
});
// Ohne gültige Zahlung liefert enforce() eine 402-Response.
// Direkt zurückgeben, um dem Client Zahlungsanweisungen zu senden.
if (result instanceof Response) return result;
// Zahlung verifiziert (oder im botOnly-Modus übersprungen). Response-Header setzen
// für den Nachweis der Abwicklung.
x402.applyHeaders(result, Astro.response);
---
<article>
<h1>Premium-Inhalt</h1>
</article>
enforce() liefert entweder:
- eine
Response(402) — der Client muss zahlen; direkt zurückgeben. - ein
EnforceResult— die Anfrage soll fortgesetzt werden. Der Inhalt wurde bezahlt oder die Prüfung wurde übersprungen (Mensch im botOnly-Modus).
Bot-only-Modus
Ist botOnly true, liest die Integration request.cf.botManagement.score:
- Score unter dem Schwellenwert (Standard 30) → als Bot behandelt, Zahlung erzwungen
- Score ab Schwellenwert → als Mensch behandelt, Prüfung übersprungen
- Keine Bot-Management-Daten (lokale Entwicklung, kein CF) → als Mensch behandelt
EnforceResult enthält ein Flag skipped, um „musste nicht zahlen“ von „hat gezahlt“ zu unterscheiden:
---
const result = await x402.enforce(Astro.request, { price: "$0.01" });
if (result instanceof Response) return result;
x402.applyHeaders(result, Astro.response);
// result.paid — true, wenn Zahlung verifiziert
// result.skipped — true, wenn Prüfung übersprungen (Mensch im botOnly-Modus)
// result.payer — Wallet-Adresse des Zahlers (falls gezahlt)
---
Preise pro Seite mit EmDash
Mit EmDash können Sie ein number-Feld in der Sammlung für den Seitenpreis nutzen. Kein spezielles Schema nötig — ein normales CMS-Feld:
---
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { entry } = await getEmDashEntry("posts", slug);
if (!entry) return Astro.redirect("/404");
const { x402 } = Astro.locals;
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>
Zahlung prüfen ohne Erzwingen
Mit hasPayment() prüfen Sie, ob die Anfrage Zahlungs-Header enthält, ohne zu verifizieren oder zu erzwingen. Nützlich für bedingtes Rendering — unterschiedliche Inhalte für zahlende und nicht zahlende Besucher:
---
const { x402 } = Astro.locals;
const hasPaid = x402.hasPayment(Astro.request);
---
{hasPaid ? (
<p>Hier der vollständige Premium-Inhalt.</p>
) : (
<p>Abonnieren Sie für den vollen Artikel.</p>
)}
Konfigurationsreferenz
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
payTo | string | erforderlich | Ziel-Wallet-Adresse |
network | string | erforderlich | CAIP-2-Netzwerk-ID (z. B. eip155:8453) |
defaultPrice | Price | — | Standardpreis, pro Seite überschreibbar |
facilitatorUrl | string | https://x402.org/facilitator | URL des Payment-Facilitators |
scheme | string | "exact" | Zahlungsschema |
maxTimeoutSeconds | number | 60 | Maximale Gültigkeit der Zahlungssignatur |
evm | boolean | true | EVM-Ketten aktivieren |
svm | boolean | false | Solana aktivieren (benötigt @x402/svm) |
botOnly | boolean | false | Zahlung nur für Bots erzwingen |
botScoreThreshold | number | 30 | Bot-Score-Schwelle (1–99, niedriger = eher Bot) |
Preisformate
Preise können auf verschiedene Weise angegeben werden:
- Dollar-String —
"$0.10"(Präfix$wird entfernt, Wert wird weitergegeben) - Numerischer String —
"0.10" - Zahl —
0.10 - Objekt —
{ amount: "100000", asset: "0x...", extra: {} }für explizites Asset/Betrag
Netzwerk-IDs
Netzwerke nutzen das CAIP-2-Format:
| Netzwerk | Kennung |
|---|---|
| Base Mainnet | eip155:8453 |
| Base Sepolia | eip155:84532 |
| Ethereum | eip155:1 |
| Solana | solana:mainnet |
Optionen für enforce
Konfigurations-Defaults pro Seite überschreiben:
await x402.enforce(Astro.request, {
price: "$0.25",
payTo: "0xDifferentWallet",
network: "eip155:1",
description: "Artikel: Wie x402 funktioniert",
mimeType: "text/html",
});
Solana-Unterstützung
Solana ist optional. Installieren Sie @x402/svm und aktivieren Sie es in der Konfiguration:
pnpm add @x402/svm
x402({
payTo: "YourSolanaAddress",
network: "solana:mainnet",
svm: true,
evm: false,
});
Funktionsweise
- Die Integration
x402()registriert Middleware, die einen Enforcer erzeugt und unterAstro.locals.x402ablegt. - Die Konfiguration wird per Vite-Virtual-Modul (
virtual:x402/config) an die Middleware übergeben. - Bei
enforce()wird auf einenpayment-signature-Header der Anfrage geprüft. - Fehlt der Header, wird eine
402 Payment Required-Response mit Anweisungen im HeaderPAYMENT-REQUIREDzurückgegeben. - Ist der Header vorhanden, wird er über den Facilitator verifiziert und abgewickelt.
- Nach der Abwicklung setzt
applyHeaders()die HeaderPAYMENT-RESPONSEauf der Response.
Der Ressourcen-Server wird beim ersten Request lazy initialisiert und für die Worker-Laufzeit gecacht.