stream402-sdk
v0.1.0
Published
Stream402 SDK - Integrate x402 payment protocol into your applications
Downloads
3
Maintainers
Readme
Stream402 SDK
A TypeScript SDK for integrating Stream402 payment protocol into your applications. Stream402 enables monetization of digital content using Solana payments via the x402 protocol.
Installation
npm install @stream402/sdkQuick Start
1. Discover an Asset
Check if an asset requires payment:
import { discover } from "@stream402/sdk";
const result = await discover("https://example.com/api/asset/123");
if (result.type === "free") {
// Asset is free, use the URL directly
console.log("Free asset:", result.url);
} else {
// Payment required
console.log("Payment required:", result.challenge);
console.log("Amount:", result.challenge.amount, result.challenge.currency);
}2. Pay and Fetch
Complete payment flow and get access to the resource:
import { payAndFetch } from "@stream402/sdk";
import { useWallet } from "@solana/wallet-adapter-react";
function MyComponent() {
const wallet = useWallet();
const handlePayAndFetch = async () => {
try {
const result = await payAndFetch(
"https://example.com/api/asset/123",
wallet
);
console.log("Download URL:", result.downloadUrl);
console.log("Expires at:", new Date(result.expiresAt));
// Use the download URL to access the resource
window.open(result.downloadUrl, "_blank");
} catch (error) {
console.error("Payment failed:", error);
}
};
return <button onClick={handlePayAndFetch}>Pay & Download</button>;
}3. Upload Asset
Upload an asset as a content provider:
import { uploadAsset } from "@stream402/sdk";
import { useWallet } from "@solana/wallet-adapter-react";
function UploadComponent() {
const wallet = useWallet();
const handleUpload = async (file: File) => {
try {
const result = await uploadAsset(
file,
{
title: "My Image",
price: 0.01, // USDC
tags: ["nature", "landscape"],
description: "A beautiful landscape image",
},
wallet
);
console.log("Asset uploaded:", result.assetId);
console.log("Asset URL:", result.url);
} catch (error) {
console.error("Upload failed:", error);
}
};
return (
<input
type="file"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) handleUpload(file);
}}
/>
);
}API Reference
discover(assetUrl: string): Promise<DiscoverResult>
Fetches an asset URL and returns either free access or a payment challenge.
Parameters:
assetUrl- Full URL to the asset (e.g.,"https://example.com/api/asset/123")
Returns:
{ type: "free", url: string }- Asset is free to access{ type: "payment_required", challenge: PaymentChallenge }- Payment required
Example:
const result = await discover("https://example.com/api/asset/123");payAndFetch(assetUrl: string, walletAdapter: WalletAdapter, connection?: Connection): Promise<PaymentResult>
Completes the full payment flow and returns the resource.
Parameters:
assetUrl- Full URL to the assetwalletAdapter- Solana wallet adapter from@solana/wallet-adapter-reactconnection- Optional Solana connection (defaults to devnet/mainnet based on challenge)
Returns:
{ accessToken: string, downloadUrl: string, expiresAt: number }
Example:
const result = await payAndFetch(assetUrl, wallet);
// Use result.downloadUrl to access the resourceuploadAsset(file: File, meta: AssetMetadata, walletAdapter?: WalletAdapter, baseUrl?: string): Promise<UploadResponse>
Uploads an asset to Stream402.
Parameters:
file- File to uploadmeta- Asset metadata:title: string- Asset titleprice: number | string- Price in USDCrecipient?: string- Recipient wallet address (optional, uses wallet if not provided)tags?: string[]- Tags for searchabilitydescription?: string- Asset description
walletAdapter- Optional wallet adapter (used for recipient if not provided)baseUrl- Optional base URL of Stream402 API (defaults to current origin)
Returns:
{ assetId: string, title: string, price: number, url: string, thumbnailUrl?: string }
Example:
const result = await uploadAsset(file, {
title: "My Image",
price: 0.01,
tags: ["nature"],
}, wallet);Types
PaymentChallenge
interface PaymentChallenge {
version: string;
network: string;
currency: string;
decimals: number;
amount: number;
mint: string;
recipient: string;
expiresAt: number;
assetId: string;
paymentRequestToken: string;
description?: string;
metadata?: Record<string, unknown>;
}PaymentResult
interface PaymentResult {
accessToken: string;
downloadUrl: string;
expiresAt: number;
}AssetMetadata
interface AssetMetadata {
title: string;
price: number | string;
recipient?: string;
tags?: string[];
description?: string;
}Examples
React Component Example
import React, { useState } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import { discover, payAndFetch } from "@stream402/sdk";
function AssetViewer({ assetUrl }: { assetUrl: string }) {
const wallet = useWallet();
const [status, setStatus] = useState<"loading" | "free" | "payment_required" | "paid">("loading");
const [downloadUrl, setDownloadUrl] = useState<string>("");
useEffect(() => {
checkAsset();
}, [assetUrl]);
const checkAsset = async () => {
try {
const result = await discover(assetUrl);
if (result.type === "free") {
setStatus("free");
setDownloadUrl(result.url);
} else {
setStatus("payment_required");
}
} catch (error) {
console.error("Failed to discover asset:", error);
}
};
const handlePay = async () => {
if (!wallet.connected) {
await wallet.connect();
}
try {
const result = await payAndFetch(assetUrl, wallet);
setStatus("paid");
setDownloadUrl(result.downloadUrl);
} catch (error) {
console.error("Payment failed:", error);
}
};
return (
<div>
{status === "loading" && <p>Loading...</p>}
{status === "free" && <a href={downloadUrl}>Download</a>}
{status === "payment_required" && (
<button onClick={handlePay}>Pay to Access</button>
)}
{status === "paid" && <a href={downloadUrl}>Download</a>}
</div>
);
}Node.js Example
import { discover, payAndFetch } from "@stream402/sdk";
import { Connection, Keypair } from "@solana/web3.js";
import { NodeWalletAdapter } from "@solana/wallet-adapter-wallets";
// Create a wallet adapter from a keypair
const keypair = Keypair.fromSecretKey(/* your secret key */);
const wallet = new NodeWalletAdapter(keypair);
const connection = new Connection("https://api.devnet.solana.com");
// Discover and pay
const result = await discover("https://example.com/api/asset/123");
if (result.type === "payment_required") {
const paymentResult = await payAndFetch(
"https://example.com/api/asset/123",
wallet,
connection
);
console.log("Download URL:", paymentResult.downloadUrl);
}Requirements
- Node.js 18+
- TypeScript 5+
- Solana wallet adapter (for payment functionality)
License
MIT
Support
For issues and questions, please visit Stream402 GitHub.
