Etsy API v3 Client

A modern, universal TypeScript/JavaScript client for the Etsy Open API v3 with full OAuth 2.0 PKCE authentication support. Works seamlessly in both browser and Node.js environments.
This repository is heavily based on the official Etsy OpenAPI specification (https://www.etsy.com/openapi/generated/oas/3.0.0.json), as referenced in Etsy's API documentation (https://developers.etsy.com/documentation/reference).
π Features
- Universal Compatibility: Works in browsers, Node.js, and Web Workers
- OAuth 2.0 PKCE Authentication: Full support for secure authentication flow
- TypeScript First: Complete type definitions with IntelliSense support
- Rate Limiting: Built-in request throttling to respect API limits
- Token Management: Automatic token refresh with configurable storage
- Caching: Optional response caching to improve performance
- Error Handling: Comprehensive error types for different failure scenarios
- Zero Dependencies: No external runtime dependencies
π¦ Installation
npm install @profplum700/etsy-v3-api-client
yarn add @profplum700/etsy-v3-api-client
pnpm add @profplum700/etsy-v3-api-client
π€ Connect an agent to your Etsy shop
The companion @profplum700/etsy-mcp-server package runs locally over stdio and exposes read-only shop, active-listing, and listing-inventory tools. It requires Node.js 24+, your own approved Etsy developer app, and an OS credential store. It does not use a hosted endpoint.
Register http://localhost:3030/oauth/redirect as the Etsy app callback if required, then run this in a local interactive terminal:
npx --yes @profplum700/etsy-mcp-server@latest setup
Enter your keystring and shared secret in the hidden terminal prompts, authorize only shops_r and listings_r in Etsy, then choose whether to add the server to your user-level Codex MCP configuration. For another stdio client, configure npx --yes @profplum700/etsy-mcp-server@latest serve as its launch command.
You can connect multiple shops without replacing earlier profiles. Run setup --reuse-app --manual-browser to reuse the saved developer app credentials, then open the printed authorization URL in the browser profile signed in to the shop you want to add. Use status to see saved shops and use <shop name or ID> to choose which one MCP tools query. disconnect removes only the active shop; disconnect --all removes every saved profile. Use remove-codex to remove the Codex entry without disconnecting any shop.
Prompt for an agent: βSet up the local Etsy MCP server. Do not ask me to paste Etsy credentials into chat or save them in a repository or environment file. Run the setup command in an interactive local terminal so I can enter them there; request only shops_r and listings_r, verify my shop, and offer the user-level Codex connection.β
π§ Quick Start
Basic Setup
import { EtsyClient, AuthHelper } from '@profplum700/etsy-v3-api-client';
// Create authentication helper
const authHelper = new AuthHelper({
keystring: 'your-api-key',
redirectUri: 'https://your-app.com/callback',
scopes: ['shops_r', 'listings_r']
});
// Get authorization URL
const authUrl = await authHelper.getAuthUrl();
console.log('Visit this URL to authorize:', authUrl);
// After user authorization, exchange code for tokens
const state = await authHelper.getState();
await authHelper.setAuthorizationCode('authorization-code-from-callback', state);
const tokens = await authHelper.getAccessToken();
// Create API client
const client = new EtsyClient({
keystring: 'your-api-key',
sharedSecret: 'your-shared-secret', // REQUIRED for v3 API compliance
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresAt: tokens.expires_at
});
// Make API calls
const user = await client.getUser();
console.log('User:', user);
Browser Usage
<script type="module">
import { EtsyClient, AuthHelper } from 'https://unpkg.com/@profplum700/etsy-v3-api-client/dist/browser.esm.js';
// Your code here...
</script>
Or using UMD:
<script src="https://unpkg.com/@profplum700/etsy-v3-api-client/dist/browser.umd.js"></script>
<script>
const { EtsyClient, AuthHelper } = EtsyApiClient;
// Your code here...
</script>
Node.js Usage
// CommonJS
const { EtsyClient, AuthHelper } = require('@profplum700/etsy-v3-api-client');
// ES Modules
import { EtsyClient, AuthHelper } from '@profplum700/etsy-v3-api-client';
π Authentication
OAuth 2.0 Flow
- Create AuthHelper with your app credentials
- Generate authorization URL for user to visit
- Handle callback with authorization code
- Exchange code for tokens
- Use tokens with EtsyClient
import { AuthHelper, ETSY_SCOPES } from '@profplum700/etsy-v3-api-client';
const authHelper = new AuthHelper({
keystring: 'your-api-key',
redirectUri: 'https://your-app.com/callback',
scopes: [
ETSY_SCOPES.SHOPS_READ,
ETSY_SCOPES.LISTINGS_READ,
ETSY_SCOPES.PROFILE_READ
]
});
// Step 1: Get authorization URL
const authUrl = await authHelper.getAuthUrl();
// Redirect user to authUrl
// Step 2: Handle callback (in your callback endpoint)
const { code, state } = getCallbackParams(); // Your implementation
const expectedState = await authHelper.getState();
if (state === expectedState) {
await authHelper.setAuthorizationCode(code, state);
const tokens = await authHelper.getAccessToken();
// Store tokens securely
}
Available Scopes
import { ETSY_SCOPES, COMMON_SCOPE_COMBINATIONS } from '@profplum700/etsy-v3-api-client';
// Individual scopes
const scopes = [
ETSY_SCOPES.SHOPS_READ,
ETSY_SCOPES.LISTINGS_WRITE,
ETSY_SCOPES.TRANSACTIONS_READ
];
// Pre-defined combinations
const readOnlyScopes = COMMON_SCOPE_COMBINATIONS.SHOP_READ_ONLY;
const managementScopes = COMMON_SCOPE_COMBINATIONS.SHOP_MANAGEMENT;
πͺ Client Usage
Creating a Client
import { EtsyClient } from '@profplum700/etsy-v3-api-client';
const client = new EtsyClient({
keystring: 'your-api-key',
sharedSecret: 'your-shared-secret', // Get this from Your Apps page on Etsy
accessToken: 'user-access-token',
refreshToken: 'user-refresh-token',
expiresAt: new Date('2024-12-31T23:59:59Z'),
// Optional configuration
rateLimiting: {
enabled: true,
maxRequestsPerSecond: 5,
maxRequestsPerDay: 5000 // Conservative local fallback; Etsy response headers report this app's actual quota
},
caching: {
enabled: true,
ttl: 300 // 5 minutes
}
});
Making API Calls
// Get current user
const user = await client.getUser();
// Get user's shops
const shops = await client.getUserShops();
// Get shop listings
const listings = await client.getListingsByShop('shop-id');
// Get specific listing
const listing = await client.getListing('listing-id');
// Search listings
const searchResults = await client.findAllListingsActive({
keywords: 'vintage',
taxonomy_id: 123,
limit: 25
});
Error Handling
import { EtsyApiError, EtsyAuthError, EtsyRateLimitError } from '@profplum700/etsy-v3-api-client';
try {
const user = await client.getUser();
} catch (error) {
if (error instanceof EtsyAuthError) {
// Handle authentication errors
console.error('Auth error:', error.message, error.code);
} else if (error instanceof EtsyRateLimitError) {
// Handle rate limiting
console.error('Rate limited. Retry after:', error.retryAfter);
} else if (error instanceof EtsyApiError) {
// Handle API errors
console.error('API error:', error.statusCode, error.message);
} else {
// Handle other errors
console.error('Unexpected error:', error);
}
}
πΎ Token Storage
Built-in Storage Options
The client provides several storage mechanisms:
import {
createDefaultTokenStorage,
LocalStorageTokenStorage,
SessionStorageTokenStorage,
FileTokenStorage,
MemoryTokenStorage
} from '@profplum700/etsy-v3-api-client';
// Automatic storage selection based on environment
const storage = createDefaultTokenStorage();
// Browser localStorage
const localStorage = new LocalStorageTokenStorage('etsy-tokens');
// Browser sessionStorage
const sessionStorage = new SessionStorageTokenStorage('etsy-tokens');
// Node.js file storage
const fileStorage = new FileTokenStorage('./tokens.json');
// In-memory storage (not persistent)
const memoryStorage = new MemoryTokenStorage();
// Use with client
const client = new EtsyClient(config, storage);
Custom Storage
import { TokenStorage } from '@profplum700/etsy-v3-api-client';
class CustomTokenStorage implements TokenStorage {
async save(tokens: EtsyTokens): Promise<void> {
// Your save implementation
}
async load(): Promise<EtsyTokens | null> {
// Your load implementation
}
async clear(): Promise<void> {
// Your clear implementation
}
}
π¦ Rate Limiting
The client includes built-in rate limiting to respect Etsy's API limits:
const client = new EtsyClient({
// ... other config
rateLimiting: {
enabled: true,