PiplyLLM Documentation

Complete guide to building AI-powered Solana applications

Introduction

PiplyLLM is a Solana-native LLM utility that enables developers to generate, enhance, and publish AI-generated content directly on the Solana blockchain.

Unlike traditional AI APIs that require complex API key management and external provider accounts, PiplyLLM uses wallet-first authentication powered by Solana. Users connect their wallet, sign requests, and interact with AI models—all without ever managing API keys.

Key Benefits
  • No API keys required for end users
  • Wallet-first authentication using Solana signatures
  • Sub-second latency with optimized relayer infrastructure
  • On-chain composability for metadata and verification
  • Built for Web3 meme coins, NFTs, and transaction memos

How PiplyLLM Works

PiplyLLM uses a relayer architecture to connect client applications with on-chain verification and off-chain inference capabilities.

Architecture Flow

1
Client SDK Request
User connects wallet and initiates generation
2
Wallet Signature
Request signed with user's Solana wallet
3
Piply Relayer
Verifies signature and queues inference job
4
Inference Node
Runs model and generates output
5
Response & Optional On-Chain Write
Returns result to client, optionally writes to Solana
On-Chain Composability

Generated content can be written to Solana programs for full composability. This enables use cases like:

  • NFT metadata generation and storage
  • Meme coin descriptions verified on-chain
  • Transaction memo explanations
  • DAO proposal summaries

Quick Start

Installation

npm install piply-sdk @solana/web3.js

Browser Usage (with Phantom Wallet)

import { PiplyClient } from "piply-sdk";
import { Connection } from "@solana/web3.js";

// Initialize the client
const piply = new PiplyClient({
  rpc: new Connection("https://api.mainnet-beta.solana.com"),
  network: "mainnet-beta",
  relayerUrl: "https://api.piplyllm.xyz",
});

// Connect wallet (Phantom example)
async function connectWallet() {
  if (window.solana) {
    await window.solana.connect();
    return window.solana.publicKey.toString();
  }
  throw new Error("Phantom wallet not found");
}

// Generate text
async function generateMemeDescription() {
  const wallet = await connectWallet();
  
  const response = await piply.generateText({
    model: "piply-compact-v1",
    prompt: "Generate a funny Solana meme coin description.",
    wallet: wallet,
    maxTokens: 100,
  });
  
  console.log(response.text);
  // Output: "SolMoon — Because Earth was too mainstream. 
  // We're taking your portfolio to the cosmos! 🚀🌙"
}

// Streaming example
async function streamGeneration() {
  const wallet = await connectWallet();
  
  const stream = await piply.streamGenerate({
    model: "piply-compact-v1",
    prompt: "List 5 meme-worthy taglines for PiplyCoin.",
    wallet: wallet,
  });
  
  stream.on("data", (chunk) => {
    console.log("Chunk:", chunk.text);
  });
  
  stream.on("end", () => {
    console.log("Stream complete!");
  });
  
  stream.on("error", (error) => {
    console.error("Error:", error);
  });
}

Node.js / Server-Side Usage

For server-side usage, you'll need a Piply API key (not an LLM provider key). Get yours at piplyllm.xyz/api

import { PiplyClient } from "piply-sdk";
import { Connection, Keypair } from "@solana/web3.js";

// Initialize with API key for server-side usage
const piply = new PiplyClient({
  rpc: new Connection(process.env.SOLANA_RPC_URL),
  network: "mainnet-beta",
  relayerUrl: "https://api.piplyllm.xyz",
  apiKey: process.env.PIPLY_API_KEY, // Your Piply API key
});

// Server-side generation
async function generateContent() {
  const response = await piply.generateText({
    model: "piply-compact-v1",
    prompt: "Generate a creative NFT description",
    maxTokens: 150,
  });
  
  return response.text;
}

// Batch processing example
async function batchGenerateDescriptions(prompts) {
  const results = await Promise.all(
    prompts.map(prompt =>
      piply.generateText({
        model: "piply-compact-v1",
        prompt: prompt,
        maxTokens: 100,
      })
    )
  );
  
  return results.map(r => r.text);
}

Save Result On-Chain

Write generated content to a Solana program for verification and composability:

import { PiplyClient } from "piply-sdk";

async function generateAndSaveOnChain() {
  const wallet = await connectWallet();
  
  // Generate content
  const response = await piply.generateText({
    model: "piply-compact-v1",
    prompt: "Generate a meme coin tagline",
    wallet: wallet,
  });
  
  // Create transaction to store on-chain
  const tx = await piply.createOnchainMetadataTx({
    content: response.text,
    contentType: "text",
    wallet: wallet,
    metadata: {
      prompt: "Generate a meme coin tagline",
      model: "piply-compact-v1",
      timestamp: Date.now(),
    },
  });
  
  // Sign and send transaction
  if (window.solana) {
    const signed = await window.solana.signTransaction(tx);
    const signature = await piply.sendTransaction(signed);
    console.log("Saved on-chain:", signature);
  }
}

API Reference

PiplyClient(options)

Creates a new PiplyLLM client instance.

Parameters

rpc:Connection

Solana RPC connection instance

network:"mainnet-beta" | "devnet" | "testnet"

Solana network to use

relayerUrl:string

Piply relayer endpoint (default: https://api.piplyllm.xyz)

apiKey?:string

Optional API key for server-side usage

Example

const piply = new PiplyClient({ rpc: new Connection("https://api.mainnet-beta.solana.com"), network: "mainnet-beta", relayerUrl: "https://api.piplyllm.xyz", });

generateText(options)

Generates text completion based on a prompt.

Parameters

model:string

Model ID (e.g., "piply-compact-v1", "piply-creative-v1")

prompt:string

Input prompt for generation

wallet:string

Wallet public key (for client-side) or omit (for server-side with API key)

maxTokens?:number

Maximum tokens to generate (default: 256)

temperature?:number

Sampling temperature 0.0-2.0 (default: 0.7)

Returns

Promise<GenerateResponse>
text: string - Generated text
id: string - Request ID
usage: object - Token usage stats

Example

const response = await piply.generateText({ model: "piply-compact-v1", prompt: "Generate a Solana meme coin name and tagline", wallet: walletAddress, maxTokens: 100, temperature: 0.9, }); console.log(response.text);

streamGenerate(options)

Streams text generation in real-time for better UX.

Parameters

Same as generateText()

Returns

Promise<PiplyStream>
on("data", callback) - Chunk received
on("end", callback) - Stream complete
on("error", callback) - Error occurred

Example

const stream = await piply.streamGenerate({ model: "piply-compact-v1", prompt: "Write a short poem about Solana", wallet: walletAddress, }); let fullText = ""; stream.on("data", (chunk) => { fullText += chunk.text; updateUI(fullText); // Update UI in real-time }); stream.on("end", () => { console.log("Generation complete!"); }); stream.on("error", (error) => { console.error("Stream error:", error); });

createOnchainMetadataTx(options)

Creates a Solana transaction to store generated content on-chain.

Parameters

content:string

Content to store on-chain

contentType:"text" | "json" | "metadata"

Type of content

wallet:string

Wallet public key

metadata?:object

Additional metadata to store

Returns

Promise<Transaction>

getRequestStatus(requestId)

Checks the status of a generation request.

Parameters

requestId:string

Returns

Promise<RequestStatus>
status: "pending" | "processing" | "completed" | "failed"
result?: Generated text (if completed)

moderate(text)

Checks text content for safety and compliance.

Parameters

text:string

Returns

Promise<ModerationResult>
flagged: boolean
categories: string[]

Recipes & Use Cases

1. Meme Coin Metadata Generator

Generate creative names and descriptions for meme coins on Solana.

async function generateMemeCoin() {
  // Generate name
  const nameResponse = await piply.generateText({
    model: "piply-creative-v1",
    prompt: "Generate a funny and catchy Solana meme coin name",
    wallet: walletAddress,
    maxTokens: 20,
    temperature: 1.0,
  });
  
  // Generate description
  const descResponse = await piply.generateText({
    model: "piply-creative-v1",
    prompt: `Generate a hilarious description for a meme coin called "${nameResponse.text}"`,
    wallet: walletAddress,
    maxTokens: 100,
    temperature: 0.9,
  });
  
  return {
    name: nameResponse.text,
    description: descResponse.text,
  };
}

// Example output:
// {
//   name: "SolMoonDoge",
//   description: "The only coin that barks at the moon while riding Solana's lightning-fast rails. Much speed, very decentralized! 🐕🚀"
// }

2. NFT Description Batch Generator

Generate unique descriptions for NFT collections at scale.

async function batchGenerateNFTDescriptions(traits) {
  const descriptions = [];
  
  for (const trait of traits) {
    const stream = await piply.streamGenerate({
      model: "piply-compact-v1",
      prompt: `Generate a unique NFT description for a character with these traits: ${JSON.stringify(trait)}`,
      wallet: walletAddress,
      maxTokens: 150,
    });
    
    let description = "";
    
    await new Promise((resolve, reject) => {
      stream.on("data", (chunk) => {
        description += chunk.text;
      });
      
      stream.on("end", () => {
        descriptions.push({
          traits: trait,
          description: description,
        });
        resolve();
      });
      
      stream.on("error", reject);
    });
  }
  
  return descriptions;
}

// Usage
const nftTraits = [
  { background: "cosmic", accessory: "laser-eyes", rarity: "legendary" },
  { background: "neon-city", accessory: "headphones", rarity: "rare" },
  { background: "desert", accessory: "sunglasses", rarity: "common" },
];

const results = await batchGenerateNFTDescriptions(nftTraits);

3. Transaction Memo Explainer

Generate human-readable explanations for transaction memos.

async function explainTransaction(txSignature) {
  // Fetch transaction details
  const tx = await piply.rpc.getTransaction(txSignature);
  
  // Extract memo
  const memo = extractMemoFromTx(tx);
  
  // Generate explanation
  const response = await piply.generateText({
    model: "piply-compact-v1",
    prompt: `Explain this Solana transaction memo in simple terms: "${memo}"`,
    wallet: walletAddress,
    maxTokens: 100,
  });
  
  return response.text;
}

function extractMemoFromTx(tx) {
  // Extract memo from transaction instructions
  const memoInstruction = tx.transaction.message.instructions.find(
    ix => ix.programId.toString() === "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
  );
  
  if (memoInstruction) {
    return Buffer.from(memoInstruction.data, "base64").toString("utf-8");
  }
  
  return "No memo found";
}

// Example usage
const explanation = await explainTransaction("3w8Kj...");
// Output: "This transaction swapped 10 SOL for USDC on a decentralized exchange."

Security & Authentication

PiplyLLM uses a wallet-first authentication model that eliminates the need for traditional API keys and provides true Web3 integration.

How Authentication Works

1. Wallet Connection

Users connect their Solana wallet (Phantom, Solflare, etc.) to your application.

2. Request Signing

Each API request is signed with the user's wallet private key. The signature proves ownership without revealing the private key.

3. Relayer Verification

The Piply relayer verifies the signature against the wallet's public key before processing the inference request.

4. Rate Limiting per Wallet

Rate limits and usage quotas are tracked per wallet address, preventing abuse while maintaining user privacy.

Server-Side API Keys

For server-side usage (batch processing, background jobs, etc.), you can use a Piply API key instead of wallet signatures.

// Server-side with API key const piply = new PiplyClient({ rpc: new Connection(process.env.SOLANA_RPC_URL), network: "mainnet-beta", relayerUrl: "https://api.piplyllm.xyz", apiKey: process.env.PIPLY_API_KEY, // Get from piplyllm.xyz });

⚠️Never expose your Piply API key in client-side code. Use environment variables and keep keys secure.

Best Practices

1. Caching

Cache generated content to reduce costs and improve response times:

const cache = new Map(); async function getCachedGeneration(prompt) { if (cache.has(prompt)) { return cache.get(prompt); } const response = await piply.generateText({ model: "piply-compact-v1", prompt: prompt, wallet: walletAddress, }); cache.set(prompt, response.text); return response.text; }
2. Error Handling & Retries

Implement exponential backoff for transient errors:

async function generateWithRetry(options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await piply.generateText(options); } catch (error) { if (error.code === "RATE_LIMIT" || error.code === "TEMPORARY") { const delay = Math.pow(2, i) * 1000; // Exponential backoff await new Promise(resolve => setTimeout(resolve, delay)); continue; } throw error; // Re-throw non-retryable errors } } throw new Error("Max retries exceeded"); }
3. Content Moderation

Always moderate user-generated prompts and AI outputs:

async function safeGenerate(prompt) { // Check prompt const promptCheck = await piply.moderate(prompt); if (promptCheck.flagged) { throw new Error("Prompt violates content policy"); } // Generate content const response = await piply.generateText({ model: "piply-compact-v1", prompt: prompt, wallet: walletAddress, }); // Check output const outputCheck = await piply.moderate(response.text); if (outputCheck.flagged) { throw new Error("Generated content flagged"); } return response.text; }
4. Streaming for Better UX

Use streaming for long-running generations to provide real-time feedback:

function StreamingComponent() { const [text, setText] = useState(""); const [isGenerating, setIsGenerating] = useState(false); async function generate() { setIsGenerating(true); setText(""); const stream = await piply.streamGenerate({ model: "piply-compact-v1", prompt: "Write a detailed guide...", wallet: walletAddress, }); stream.on("data", (chunk) => { setText(prev => prev + chunk.text); }); stream.on("end", () => { setIsGenerating(false); }); } return ( <div> <button onClick={generate}>Generate</button> <div>{text}</div> {isGenerating && <Spinner />} </div> ); }
5. Cost Control

Monitor usage and set limits to control costs:

  • Use maxTokens to limit generation length
  • Implement client-side usage tracking and warnings
  • Cache frequently requested content
  • Use the compact model for simple tasks
  • Set per-wallet spending limits in the Piply dashboard

Pricing

Starter
Free
  • 10,000 tokens/month
  • Basic models
  • Wallet authentication
  • Community support
Get Started
Popular
Pro
$49/month
  • 500,000 tokens/month
  • All models including creative
  • Streaming support
  • Priority support
  • On-chain metadata
Upgrade to Pro
Enterprise
Custom
  • Unlimited tokens
  • Custom models
  • Dedicated infrastructure
  • 24/7 support
  • SLA guarantees
Contact Sales

Frequently Asked Questions

Do I need an LLM provider API key?

No! PiplyLLM handles all inference infrastructure. Your users authenticate with their Solana wallet, and you never need to manage API keys from providers. For server-side usage, you only need a Piply API key.

Which Solana wallets are supported?

PiplyLLM works with any Solana wallet that supports the standard wallet adapter protocol, including Phantom, Solflare, Backpack, Glow, and more.

How fast is inference?

PiplyLLM's relayer infrastructure provides sub-second response times for most requests. With streaming enabled, users see content appearing in real-time, typically starting within 200-500ms.

Can I store generated content on-chain?

Yes! Use the createOnchainMetadataTx() method to create a Solana transaction that stores generated content in a program account. This enables full composability with other Solana programs.

What models are available?

PiplyLLM currently offers two models:

  • piply-compact-v1 — Fast, efficient model for simple tasks
  • piply-creative-v1 — More creative model for meme generation and storytelling
Is content moderation built-in?

Yes. Use the moderate() method to check both input prompts and generated outputs for safety and compliance. We recommend always moderating user-generated content.

Can I use PiplyLLM on devnet?

Yes! Set network: "devnet" when initializing the client. Devnet usage is free for testing and development.

PiplyLLM

On-Chain LLM Utility for Solana

© 2025 PiplyLLM. All rights reserved.