@stellar-snaps/sdk
v0.3.3
Published
SDK for building on Stellar Snaps - payment links, transactions, wallet integration
Maintainers
Readme
@stellar-snaps/sdk
A complete SDK for building on Stellar Snaps technology. Create shareable payment links, build transactions, integrate wallets, and host your own snap endpoints.
What is Stellar Snaps?
Stellar Snaps lets you create shareable payment links for the Stellar blockchain - like Venmo/PayPal request links, but for crypto. Share links on Twitter, Discord, or your website, and recipients can pay with one click using their Freighter wallet.
Installation
npm install @stellar-snaps/sdk
# or
pnpm add @stellar-snaps/sdkPeer dependencies (install if you use transaction building or Freighter):@stellar/freighter-api, @stellar/stellar-sdk
How it works
Shareable Snap API (
createSnap,getSnap,listSnaps,deleteSnap)
Calls the Stellar Snaps web app athttps://stellar-snaps.vercel.appby default. Snaps are stored there; you get back shareable URLs (e.g.https://stellar-snaps.vercel.app/s/abc123). Works in Node.js and browser (CORS is enabled on the API). UsebaseUrlto point at your own deployment.SEP-0007 URIs (
createPaymentSnap,createTransactionSnap,parseSnapUri)
Pure logic, no network. Build or parseweb+stellar:...payment/transaction links.Transactions & Freighter (
buildPaymentTransaction,signWithFreighter,submitTransaction, etc.)
Run in a browser with the Freighter extension installed. Uses@stellar/freighter-apiand@stellar/stellar-sdk.
So: install the package, use the Shareable Snap API from any environment; use Freighter-related APIs only in a browser with Freighter installed.
Quick Start
1. Create a Payment Link
import { createPaymentSnap } from '@stellar-snaps/sdk';
const { uri } = createPaymentSnap({
destination: 'GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOUJ3DTJE4QRK764',
amount: '10',
assetCode: 'USDC',
assetIssuer: 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
memo: 'Coffee payment',
network: 'public',
});
console.log(uri);
// => web+stellar:pay?destination=GDQP2K...&amount=10&asset_code=USDC&...2. Parse a Payment Link
import { parseSnapUri } from '@stellar-snaps/sdk';
const parsed = parseSnapUri('web+stellar:pay?destination=GDQP2K...&amount=10');
console.log(parsed);
// => { type: 'pay', destination: 'GDQP2K...', amount: '10', ... }3. Build and Sign a Transaction
import {
connectFreighter,
buildPaymentTransaction,
signWithFreighter,
submitTransaction,
} from '@stellar-snaps/sdk';
// Connect to user's wallet
const { publicKey, network } = await connectFreighter();
// Build the transaction
const xdr = buildPaymentTransaction({
source: publicKey,
sequence: '123456789', // Get from Horizon API
destination: 'GBZX...',
amount: '10',
asset: { code: 'XLM' },
network: 'public',
});
// Sign with Freighter (opens popup)
const signedXdr = await signWithFreighter(xdr, 'public');
// Submit to Stellar network
const result = await submitTransaction(signedXdr, 'public');
if (result.successful) {
console.log(`Success! Hash: ${result.hash}`);
}4. Payment flow (payment route like the web app)
Implement a payment route (e.g. /s/[id]) with the same behavior as stellar-snaps.vercel.app: fetch the snap, then run the full pay flow (Freighter connect → build tx → sign → submit) in one call.
import { getSnap, executeSnapPayment, getTransactionUrl } from '@stellar-snaps/sdk';
// On your /s/[id] page: load snap, then on "Pay" click:
const snap = await getSnap(id, { baseUrl: 'https://your-app.com' });
const amount = snap.amount ?? userEnteredAmount;
const result = await executeSnapPayment({ snap, amount });
if (result.successful) {
const explorerUrl = getTransactionUrl(result.hash, snap.network as 'public' | 'testnet');
console.log('Paid! View:', explorerUrl);
}getAccountSequence(publicKey, network)– Fetches account sequence from Horizon (for building a transaction).executeSnapPayment({ snap, amount })– Full flow: connect Freighter, build payment tx, sign with Freighter, submit. Same behavior as the web app’s “Pay with Stellar” button. Browser only (requires Freighter).
5. Create Shareable Snaps (Web App API)
Create, fetch, list, and delete database-backed snaps—same behavior as the web dashboard. Uses https://stellar-snaps.vercel.app by default.
import { createSnap, getSnap, listSnaps, deleteSnap } from '@stellar-snaps/sdk';
// Create a snap (stores on server, returns shareable URL)
const { url, snap } = await createSnap({
creator: 'GCNZMNUTQ5UMQ5QL0FUAW3CUADWB...',
title: 'Buy me a coffee',
destination: 'GCNZMNUTQ5UMQ5QL0FUAW3CUADWB...',
amount: '5',
network: 'testnet',
});
console.log(url);
// => https://stellar-snaps.vercel.app/s/u8oYHLhl
// Fetch a snap by ID
const fetchedSnap = await getSnap('u8oYHLhl');
// List all snaps for a creator
const snaps = await listSnaps('GCNZMNUTQ5UMQ5QL0FUAW3CUADWB...');
// Delete a snap (requires creator address)
await deleteSnap('u8oYHLhl', 'GCNZMNUTQ5UMQ5QL0FUAW3CUADWB...');Use baseUrl to point at your own Stellar Snaps instance:
const { url } = await createSnap({
creator: 'G...',
title: 'Test',
destination: 'G...',
baseUrl: 'https://your-stellar-snaps.vercel.app',
});Show the same modal overlay as the web app (browser only): open the snap URL in a modal so users can pay without leaving your page:
import { createSnap, openSnapModal, closeSnapModal } from '@stellar-snaps/sdk';
const { url } = await createSnap({ creator: 'G...', title: 'Tip', destination: 'G...' });
openSnapModal(url, {
width: 420,
height: 560,
onClose: () => console.log('Modal closed'),
});
// User sees the same payment UI as stellar-snaps.vercel.app/s/xxx in an overlay6. Host Your Own Snap Endpoints
Create a discovery file to enable the browser extension to find your snaps:
import { createDiscoveryFile } from '@stellar-snaps/sdk';
const discovery = createDiscoveryFile({
name: 'My Payment App',
description: 'Accept Stellar payments',
rules: [
{ pathPattern: '/pay/*', apiPath: '/api/snap/$1' },
],
});
// Save as: public/.well-known/stellar-snap.json7. Build your own project (full flow)
Everything in the stellar-snaps web app can be built in your own project using only this SDK. Use the same APIs and flows so creators can create snaps, share URLs, and payers can pay from your domain.
1. Backend (your server or serverless)
| Endpoint | Purpose | SDK usage |
|----------|---------|-----------|
| POST /api/snaps | Create snap, return { id, ... } | Store snap in your DB; return id. Use validateSnapInput, createSnapObject, generateSnapId from SDK. |
| GET /api/snap/[id] | Get full snap | Return snap from DB. |
| GET /api/metadata/[id] | Snap metadata for extension | Same as above; return flat object: id, title, destination, amount, assetCode, assetIssuer, memo, memoType, network. |
| POST /api/build-tx | Build XDR for extension | buildPaymentXdrFromPayload(req.body) → return { xdr }. Extension calls this when user clicks "Pay with Stellar" on your snap links. |
| DELETE /api/snaps?id=...&creator=... | Delete snap | Optional; enforce creator ownership. |
2. Payment page (e.g. /s/[id])
- Load snap:
getSnap(id, { baseUrl: 'https://your-app.com' }). - On "Pay" click:
executeSnapPayment({ snap, amount })(browser only; requires Freighter). - Show success:
getTransactionUrl(result.hash, snap.network).
3. Discovery file
- Host
/.well-known/stellar-snap.jsonwith rules mapping your snap path to your metadata API, e.g.pathPattern: "/s/*",apiPath: "/api/metadata/$1". UsecreateDiscoveryFilefrom the SDK.
4. Extension and registry
- Add your domain to the Stellar Snaps registry (or the registry your extension uses) so the extension shows snap cards for links to your domain.
5. Create snap from your app
- Call
createSnap({ creator, title, destination, ..., baseUrl: 'https://your-app.com' })from the SDK; use the returnedurl(e.g.https://your-app.com/s/abc123) as the shareable link.
End-to-end: create snap (SDK + your API) → share URL → payer opens /s/[id] (your payment page using executeSnapPayment) or payer sees link on Twitter → extension fetches metadata and build-tx from your API → pay with Stellar. All of this works in your own project using only the library.
API Reference
Shareable Snap API (Web App)
These functions mirror the Stellar Snaps web app API. Use them to create and manage snaps that are stored on a server and get shareable URLs.
createSnap(options)
Creates a snap on the server and returns the shareable URL.
interface CreateSnapOptions {
creator: string; // Creator's Stellar address (required)
title: string; // Display title (required)
destination: string; // Payment destination (required)
description?: string;
amount?: string; // Omit for open amount
assetCode?: string; // Default: 'XLM'
assetIssuer?: string; // Required for non-XLM
memo?: string;
memoType?: MemoType;
network?: 'public' | 'testnet'; // Default: 'testnet'
imageUrl?: string;
baseUrl?: string; // Default: 'https://stellar-snaps.vercel.app'
}
interface CreateSnapResult {
id: string;
url: string; // Full shareable URL
snap: Snap;
}getSnap(id, options?)
Fetches a snap by ID. Uses GET /api/snap/[id].
- Throws
SnapNotFoundErrorif the snap does not exist. - Throws
SnapApiErroron other API errors.
listSnaps(creator, options?)
Lists all snaps for a creator. Uses GET /api/snaps?creator=....
deleteSnap(id, creator, options?)
Deletes a snap. Requires the creator's address (ownership). Uses DELETE /api/snaps?id=...&creator=....
- Throws
SnapNotFoundErrorif the snap does not exist. - Throws
SnapUnauthorizedErrorif the creator does not own the snap. - Throws
SnapApiErroron other API errors.
Snap type
interface Snap {
id: string;
creator?: string; // Omitted in GET /api/snap/[id] response
title: string;
description?: string | null;
destination: string;
amount?: string | null;
assetCode: string;
assetIssuer?: string | null;
memo?: string | null;
memoType?: string;
network: string;
imageUrl?: string | null;
createdAt?: string;
updatedAt?: string;
}openSnapModal(snapUrl, options?)
Opens a snap URL in a full-screen modal overlay (iframe). Same payment UI as opening the link on the Stellar Snaps web app. Browser only; no-op in Node.
interface OpenSnapModalOptions {
width?: number; // Default: 420
height?: number; // Default: 560
onClose?: () => void;
}closeSnapModal()
Closes the snap modal if one is open. Safe to call anytime.
SEP-0007 URI Functions
createPaymentSnap(options)
Creates a SEP-0007 payment URI.
interface PaymentSnapOptions {
destination: string; // Recipient's Stellar address
amount?: string; // Amount to send
assetCode?: string; // Asset code (default: XLM)
assetIssuer?: string; // Asset issuer (required for non-XLM)
memo?: string; // Transaction memo
memoType?: MemoType; // Memo type (default: MEMO_TEXT)
message?: string; // Human-readable message (max 300 chars)
network?: 'public' | 'testnet';
callback?: string; // Callback URL after signing
}createTransactionSnap(options)
Creates a SEP-0007 transaction URI for arbitrary transactions.
interface TransactionSnapOptions {
xdr: string; // Transaction XDR
network?: 'public' | 'testnet';
message?: string; // Human-readable message
callback?: string; // Callback URL
pubkey?: string; // Required signer's public key
}parseSnapUri(uri)
Parses a SEP-0007 URI back into an object.
const parsed = parseSnapUri('web+stellar:pay?destination=G...');
// => { type: 'pay', destination: 'G...', ... }Validation Functions
isValidStellarAddress(address)
Returns true if the address is a valid Stellar public key (56 chars, starts with 'G').
isValidAssetCode(code)
Returns true if the code is a valid asset code (1-12 alphanumeric chars).
isValidAmount(amount)
Returns true if the amount is a positive number string.
Transaction Building
buildPaymentTransaction(options)
Builds a Stellar payment transaction and returns the XDR.
interface BuildPaymentOptions {
source: string; // Payer's address
sequence: string; // Account sequence number
destination: string; // Recipient's address
amount: string; // Amount to send
asset?: {
code: string;
issuer?: string;
};
memo?: {
type: MemoType;
value: string;
};
network: 'public' | 'testnet';
timeout?: number; // Default: 180 seconds
}createAsset(code, issuer?)
Creates a Stellar Asset object.
const xlm = createAsset('XLM');
const usdc = createAsset('USDC', 'GA5ZS...');buildPaymentXdrFromPayload(payload)
Builds payment XDR from the same payload the browser extension sends to POST /api/build-tx. Use in your server handler so the extension can build transactions when users click "Pay with Stellar" on your snap links.
// In your POST /api/build-tx handler:
const xdr = buildPaymentXdrFromPayload(req.body);
res.json({ xdr });Payload: { source, sequence, destination, amount, assetCode?, assetIssuer?, memo?, memoType?, network? }. Returns the transaction XDR string.
Payment Flow (Web App–Style Pay-with-Snap)
getAccountSequence(publicKey, network)
Fetches the account's current sequence from Horizon (for building a transaction). Use in browser or Node; requires network access.
const sequence = await getAccountSequence(publicKey, 'testnet');executeSnapPayment(options)
Runs the full payment flow for a snap: connect Freighter, build payment transaction, sign with Freighter, submit to the network. Same behavior as the web app's "Pay with Stellar" button on /s/[id]. Browser only (requires Freighter).
const result = await executeSnapPayment({
snap: await getSnap(id, { baseUrl: 'https://your-app.com' }),
amount: '10',
});
// => { hash: '...', successful: true, ledger?: number }Use this to implement a payment route (e.g. /s/[id]) with the same functionality as stellar-snaps.vercel.app.
Freighter Wallet Integration
connectFreighter()
Connects to Freighter wallet and returns the user's public key and network.
const { publicKey, network } = await connectFreighter();isFreighterConnected()
Returns true if Freighter is installed and the user has granted access.
getFreighterNetwork()
Returns the current network from Freighter ('public' or 'testnet').
signWithFreighter(xdr, network)
Signs a transaction XDR using Freighter. Opens a popup for user approval.
submitTransaction(signedXdr, network)
Submits a signed transaction to the Stellar network.
const result = await submitTransaction(signedXdr, 'public');
// => { hash: 'abc...', successful: true, ledger: 12345 }Discovery Files
createDiscoveryFile(options)
Creates a discovery file object for hosting at /.well-known/stellar-snap.json.
interface CreateDiscoveryFileOptions {
name: string;
description?: string;
icon?: string;
rules: Array<{
pathPattern: string; // URL pattern, e.g., "/pay/*"
apiPath: string; // API path, e.g., "/api/snap/$1"
}>;
}validateDiscoveryFile(file)
Type guard that validates if an object is a valid discovery file.
matchUrlToRule(pathname, rules)
Matches a URL path against rules and returns the API path.
matchUrlToRule('/pay/abc123', rules);
// => '/api/snap/abc123'Error Classes
All errors extend StellarSnapError with a code property for programmatic handling:
InvalidAddressError- Invalid Stellar addressInvalidAmountError- Invalid amountInvalidAssetError- Invalid asset configurationInvalidUriError- Invalid SEP-0007 URISnapNotFoundError- Snap not found (404 from API)SnapUnauthorizedError- Not authorized to perform action (e.g. delete another user's snap)SnapApiError- Stellar Snaps API returned an error (includes optionalstatusCode)
try {
createPaymentSnap({ destination: 'invalid' });
} catch (error) {
if (error instanceof InvalidAddressError) {
console.log(error.code); // 'INVALID_ADDRESS'
}
}
try {
const snap = await getSnap('missing-id');
} catch (error) {
if (error instanceof SnapNotFoundError) {
console.log(error.code); // 'SNAP_NOT_FOUND'
}
}Constants
import { NETWORK_PASSPHRASES, HORIZON_URLS } from '@stellar-snaps/sdk';
NETWORK_PASSPHRASES.public; // 'Public Global Stellar Network ; September 2015'
NETWORK_PASSPHRASES.testnet; // 'Test SDF Network ; September 2015'
HORIZON_URLS.public; // 'https://horizon.stellar.org'
HORIZON_URLS.testnet; // 'https://horizon-testnet.stellar.org'Types
type Network = 'public' | 'testnet';
type MemoType = 'MEMO_TEXT' | 'MEMO_ID' | 'MEMO_HASH' | 'MEMO_RETURN';License
MIT
