SDK for building on Stellar Snaps - payment links, transactions, wallet integration
npm install @stellar-snaps/sdkA complete SDK for building on Stellar Snaps technology. Create shareable payment links, build transactions, integrate wallets, and host your own snap endpoints.
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.
``bash`
npm install @stellar-snaps/sdkor
pnpm add @stellar-snaps/sdk
Peer dependencies (install if you use transaction building or Freighter):
@stellar/freighter-api, @stellar/stellar-sdk
- Shareable Snap API (createSnap, getSnap, listSnaps, deleteSnap) https://stellar-snaps.vercel.app
Calls the Stellar Snaps web app at by 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). Use baseUrl to point at your own deployment.
- SEP-0007 URIs (createPaymentSnap, createTransactionSnap, parseSnapUri) web+stellar:...
Pure logic, no network. Build or parse payment/transaction links.
- Transactions & Freighter (buildPaymentTransaction, signWithFreighter, submitTransaction, etc.) @stellar/freighter-api
Run in a browser with the Freighter extension installed. Uses and @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.
`typescript
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&...
`
`typescript
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', ... }
`
`typescript
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});`
}
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.
`typescript
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).
Create, fetch, list, and delete database-backed snaps—same behavior as the web dashboard. Uses https://stellar-snaps.vercel.app by default.
`typescript
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:
`typescript`
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:
`typescript
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 overlay
`
Create a discovery file to enable the browser extension to find your snaps:
`typescript
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.json
`
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' }).executeSnapPayment({ snap, amount })
- On "Pay" click: (browser only; requires Freighter).getTransactionUrl(result.hash, snap.network)
- Show success: .
3. Discovery file
- Host /.well-known/stellar-snap.json with rules mapping your snap path to your metadata API, e.g. pathPattern: "/s/*", apiPath: "/api/metadata/$1". Use createDiscoveryFile from 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 returned url (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.
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.
`typescript
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 SnapNotFoundError if the snap does not exist.SnapApiError
- Throws on 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 SnapNotFoundError if the snap does not exist.SnapUnauthorizedError
- Throws if the creator does not own the snap.SnapApiError
- Throws on other API errors.
#### Snap type
`typescript`
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.
`typescript`
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.
#### createPaymentSnap(options)
Creates a SEP-0007 payment URI.
`typescript`
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.
`typescript`
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.
`typescript`
const parsed = parseSnapUri('web+stellar:pay?destination=G...');
// => { type: 'pay', destination: 'G...', ... }
#### 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.
#### buildPaymentTransaction(options)
Builds a Stellar payment transaction and returns the XDR.
`typescript`
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.
`typescript`
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.
`typescript`
// 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.
#### getAccountSequence(publicKey, network)
Fetches the account's current sequence from Horizon (for building a transaction). Use in browser or Node; requires network access.
`typescript`
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).
`typescript`
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.
#### connectFreighter()
Connects to Freighter wallet and returns the user's public key and network.
`typescript`
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.
`typescript`
const result = await submitTransaction(signedXdr, 'public');
// => { hash: 'abc...', successful: true, ledger: 12345 }
#### createDiscoveryFile(options)
Creates a discovery file object for hosting at /.well-known/stellar-snap.json.
`typescript`
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.
`typescript`
matchUrlToRule('/pay/abc123', rules);
// => '/api/snap/abc123'
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 optional statusCode)
`typescript
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'
}
}
`
`typescript
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'
`
`typescript``
type Network = 'public' | 'testnet';
type MemoType = 'MEMO_TEXT' | 'MEMO_ID' | 'MEMO_HASH' | 'MEMO_RETURN';
MIT