Once you’ve created policies in the Developer Portal, you can fetch their
details programmatically. This guide shows the current package choices for
policy reads and how to retrieve policy information through the REST API and
TypeScript clients.
This page covers the portal-facing clients
@swig-wallet/api and @swig-wallet/developer. For the
primary prepare-first Swig Developer SDK, see
What the Developer SDK Does.
Treat @swig-wallet/developer as the legacy SDK for new
integrations. The current @swig-wallet/developer-sdk package is
optimized for prepared wallet operations. It does expose
swig.wallets.getPolicy(policyId), but it returns raw policy
metadata rather than the richer helper surface from the legacy SDK.
Prerequisites
Before fetching policies, ensure you have:
- An API key created in the Developer Portal
- A policy created that you want to fetch
- The policy ID (visible in the portal’s policy details)
Choose the Right Package
API SDK
Current SDK
Legacy SDK
npm install @swig-wallet/api
# or
bun add @swig-wallet/api
npm install @swig-wallet/developer-sdk
# or
bun add @swig-wallet/developer-sdk
npm install @swig-wallet/developer
# or
bun add @swig-wallet/developer
Fetching a Policy
Using the REST API
Make a GET request to the policies endpoint:
curl -X GET "https://dashboard.onswig.com/api/v1/policies/{policyId}" \
-H "Authorization: Bearer sk_your_api_key"
Replace {policyId} with your actual policy ID (e.g., clx1234567890abcdef).
Example Response:
{
"id": "clx1234567890abcdef",
"name": "user-wallet-policy",
"description": "Standard user wallet with transfer limits",
"authority": {
"type": "Ed25519",
"publicKey": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
},
"actions": [
{ "type": "SolLimit", "amount": "1000000000" },
{ "type": "TokenLimit", "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": "1000000" }
]
}
Using a Portal Client
import { SwigApiClient } from '@swig-wallet/api';
// Initialize the client
const client = new SwigApiClient({
apiKey: 'sk_your_api_key',
portalUrl: 'https://dashboard.onswig.com',
});
// Fetch a policy
async function getPolicy(policyId: string) {
const { data: policy, error } = await client.policies.get(policyId);
if (error) {
console.error(`Error fetching policy: ${error.message}`);
console.error(`Error code: ${error.code}, Status: ${error.status}`);
return null;
}
console.log('Policy:', policy.name);
console.log('Description:', policy.description);
if (policy.authority) {
console.log('Authority Type:', policy.authority.type);
console.log('Authority Key:', policy.authority.publicKey);
} else {
console.log('Authority: Not configured (provide at wallet creation)');
}
console.log('Actions:', policy.actions.map(a => a.type).join(', '));
return policy;
}
// Usage
const policy = await getPolicy('clx1234567890abcdef');
import { SwigClient, SwigError } from '@swig-wallet/developer';
// Initialize the client
const client = new SwigClient({
apiKey: 'sk_your_api_key',
baseUrl: 'https://dashboard.onswig.com',
});
// Fetch a policy
async function getPolicy(policyId: string) {
try {
const policy = await client.getPolicy(policyId);
console.log('Policy:', policy.name);
// Rich authority methods
if (policy.authority) {
console.log('Authority Type:', policy.authority.type);
if (policy.authority.isSession()) {
console.log('Session Duration:', policy.authority.maxDurationSlots, 'slots');
}
if (policy.authority.isEd25519()) {
console.log('Using Ed25519 signature scheme');
}
}
// Rich action query methods
if (policy.actions.canSpendSol(1_000_000_000n)) {
console.log('Can spend up to 1 SOL');
}
const solLimit = policy.actions.solSpendLimit();
if (solLimit) {
console.log('SOL limit:', solLimit, 'lamports');
}
if (policy.actions.canUseProgram('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')) {
console.log('Can interact with Token program');
}
return policy;
} catch (error) {
if (error instanceof SwigError) {
console.error(`Error: ${error.code} - ${error.message}`);
}
return null;
}
}
// Usage
const policy = await getPolicy('clx1234567890abcdef');
If You’re Already Using the Current SDK
If your app already uses @swig-wallet/developer-sdk for prepared wallet
operations, you can read the same raw policy metadata the SDK uses during
wallet creation and recovery flows:
import { SwigClient } from '@swig-wallet/developer-sdk/server/typescript';
const swig = new SwigClient({
apiKey: process.env.SWIG_API_KEY!,
network: 'devnet',
});
const policy = await swig.wallets.getPolicy('clx1234567890abcdef');
console.log(policy.name);
console.log(policy.guardianEnabled);
console.log(policy.guardianDelaySeconds);
console.log(policy.actions);
Use this when policy lookup is part of a prepared-wallet flow. For standalone
policy inspection, prefer @swig-wallet/api. For richer helper methods around
actions and authorities, use the legacy @swig-wallet/developer client.
Package Fit
| Package | Primary job | Policy surface |
|---|
@swig-wallet/api | Raw portal endpoint access | client.policies.get() returns raw policy JSON |
@swig-wallet/developer-sdk | Prepared wallet operations | swig.wallets.getPolicy() returns raw policy metadata used by hosted flows |
@swig-wallet/developer (legacy) | Existing rich portal integrations | client.getPolicy() returns richer helper types and query methods |
If you are starting fresh and only need to fetch policies, prefer
@swig-wallet/api. If you are starting fresh and need hosted
wallet operations, use @swig-wallet/developer-sdk and treat
policy reads as a supporting detail rather than the primary interface.
Response Types
Policy
interface Policy {
/** Unique policy ID */
id: string;
/** Policy name */
name: string;
/** Optional description */
description: string | null;
/** Authority configuration (signer) - null if not configured */
authority: AuthorityConfig | null;
/** Action configurations (permissions) */
actions: ActionConfig[];
}
Authority Configuration
The authority field can be one of several types:
type AuthorityConfig =
| { type: 'Ed25519'; publicKey: string }
| { type: 'Ed25519Session'; publicKey: string; maxDurationSlots: string }
| { type: 'Secp256k1'; publicKey: string }
| { type: 'Secp256k1Session'; publicKey: string; maxDurationSlots: string }
| { type: 'Secp256r1'; publicKey: string }
| { type: 'Secp256r1Session'; publicKey: string; maxDurationSlots: string };
Action Configuration
The actions array contains one or more action configurations:
type ActionConfig =
// General permissions
| { type: 'All' }
| { type: 'AllButManageAuthority' }
| { type: 'ManageAuthority' }
// SOL transfer limits
| { type: 'SolLimit'; amount: string }
| { type: 'SolRecurringLimit'; recurringAmount: string; window: string }
| { type: 'SolDestinationLimit'; amount: string; destination: string }
| { type: 'SolRecurringDestinationLimit'; recurringAmount: string; window: string; destination: string }
// Token transfer limits
| { type: 'TokenLimit'; mint: string; amount: string }
| { type: 'TokenRecurringLimit'; mint: string; recurringAmount: string; window: string }
| { type: 'TokenDestinationLimit'; mint: string; amount: string; destination: string }
| { type: 'TokenRecurringDestinationLimit'; mint: string; recurringAmount: string; window: string; destination: string }
// Program access
| { type: 'Program'; programId: string }
| { type: 'ProgramAll' }
| { type: 'ProgramCurated' }
// Staking
| { type: 'StakeLimit'; amount: string }
| { type: 'StakeRecurringLimit'; recurringAmount: string; window: string }
| { type: 'StakeAll' }
// Sub-accounts
| { type: 'SubAccount' };
Error Handling
import { SwigApiClient, ApiError } from '@swig-wallet/api';
const client = new SwigApiClient({
apiKey: 'sk_your_api_key',
});
const { data, error } = await client.policies.get('invalid-policy-id');
if (error) {
// ApiError properties:
// - message: Human-readable error message
// - code: Error code string (e.g., 'NOT_FOUND', 'UNAUTHORIZED')
// - status: HTTP status code
// - details: Additional error context (if available)
switch (error.code) {
case 'NOT_FOUND':
console.log('Policy does not exist');
break;
case 'UNAUTHORIZED':
console.log('Invalid or expired API key');
break;
default:
console.log(`Unexpected error: ${error.message}`);
}
}
import { SwigClient, SwigError } from '@swig-wallet/developer';
const client = new SwigClient({
apiKey: 'sk_your_api_key',
baseUrl: 'https://dashboard.onswig.com',
});
try {
const policy = await client.getPolicy('invalid-policy-id');
} catch (error) {
if (error instanceof SwigError) {
// SwigError properties:
// - message: Human-readable error message
// - code: Error code string (e.g., 'POLICY_NOT_FOUND')
// - statusCode: HTTP status code
// - response: Raw response data (if available)
switch (error.code) {
case 'POLICY_NOT_FOUND':
console.log('Policy does not exist');
break;
case 'UNAUTHORIZED':
console.log('Invalid or expired API key');
break;
default:
console.log(`Unexpected error: ${error.message}`);
}
}
}
Common Errors
| Status | Code | Meaning |
|---|
| 401 | UNAUTHORIZED | Invalid or missing API key |
| 403 | FORBIDDEN | API key doesn’t have access to this policy |
| 404 | NOT_FOUND / POLICY_NOT_FOUND | Policy ID doesn’t exist |
| 500 | INTERNAL_ERROR | Server error, try again later |
Retry Configuration
Both SDKs support automatic retries for transient failures:
const client = new SwigApiClient({
apiKey: 'sk_your_api_key',
portalUrl: 'https://dashboard.onswig.com',
retry: {
maxRetries: 3, // Number of retry attempts
retryDelay: 1000, // Initial delay in milliseconds
backoffMultiplier: 2, // Exponential backoff multiplier
},
});
const client = new SwigClient({
apiKey: 'sk_your_api_key',
baseUrl: 'https://dashboard.onswig.com',
retryOptions: {
maxRetries: 3,
retryDelay: 1000,
backoffMultiplier: 2,
},
});
With these settings, retries occur at: 1s, 2s, 4s (exponential backoff).
Both SDKs only retry on 5xx server errors and network failures. Client errors (4xx) are not retried.
Complete Example
import { SwigApiClient } from '@swig-wallet/api';
async function main() {
const client = new SwigApiClient({
apiKey: process.env.SWIG_API_KEY!,
portalUrl: 'https://dashboard.onswig.com',
retry: { maxRetries: 3, retryDelay: 1000 },
});
const policyId = 'your-policy-id';
const { data: policy, error } = await client.policies.get(policyId);
if (error) {
console.error('Failed to fetch policy:', error.message);
process.exit(1);
}
console.log('=== Policy Details ===');
console.log(`ID: ${policy.id}`);
console.log(`Name: ${policy.name}`);
console.log(`Description: ${policy.description ?? 'None'}`);
console.log('\n=== Authority ===');
if (policy.authority) {
console.log(`Type: ${policy.authority.type}`);
console.log(`Public Key: ${policy.authority.publicKey}`);
} else {
console.log('No authority configured');
}
console.log('\n=== Actions ===');
for (const action of policy.actions) {
console.log(`- ${action.type}`);
}
}
main();
import { SwigClient, SwigError } from '@swig-wallet/developer';
async function main() {
const client = new SwigClient({
apiKey: process.env.SWIG_API_KEY!,
baseUrl: 'https://dashboard.onswig.com',
retryOptions: { maxRetries: 3, retryDelay: 1000 },
});
try {
const policy = await client.getPolicy('your-policy-id');
console.log('=== Policy Details ===');
console.log(`ID: ${policy.id}`);
console.log(`Name: ${policy.name}`);
console.log('\n=== Authority ===');
if (policy.authority) {
console.log(`Type: ${policy.authority.type}`);
console.log(`Is Session: ${policy.authority.isSession()}`);
console.log(`Is Ed25519: ${policy.authority.isEd25519()}`);
} else {
console.log('No authority configured');
}
console.log('\n=== Permissions ===');
console.log(`Is Root: ${policy.actions.isRoot()}`);
console.log(`Can Manage Authority: ${policy.actions.canManageAuthority()}`);
const solLimit = policy.actions.solSpendLimit();
console.log(`SOL Limit: ${solLimit ? `${solLimit} lamports` : 'None'}`);
} catch (error) {
if (error instanceof SwigError) {
console.error('Failed to fetch policy:', error.message);
process.exit(1);
}
throw error;
}
}
main();
Next Steps
Now that you can fetch policies, learn how to create Swig wallets using those policies.