polarkey
v0.0.3
Published
A modular, edge-ready payment and API key management library bridging [Polar.sh](https://polar.sh) billing with [Unkey](https://unkey.com) API keys.
Readme
Payments SDK & Infrastructure
A modular, edge-ready payment and API key management library bridging Polar.sh billing with Unkey API keys.
Includes:
payments/api-key: Comprehensive API key management, RBAC, identities, credits, and rate limiting powered by Unkey.payments/polar-sh(andpayments/billing): Full billing operations with Polar.sh (products, checkouts, customer portal sessions, subscriptions, webhooks).payments/sdk: Framework-agnostic backend SDK bridging Polar and Unkey for automated lifecycle key provisioning, tier synchronizations, and subscription-backed access control.payments/hono: Edge-ready Hono router & middleware mounting API routes for checkouts, portal sessions, webhooks, key verification, and subscriptions.payments/client: Browser-ready frontend client SDK connecting to the Hono routes with standard Web APIs (fetch).payments/extension: Browser extension client SDK specifically tailored for Chrome/Firefox/Safari extensions with storage-backed key caching and tab launchers.
Installation
npm install payments @polar-sh/sdk @unkey/api honoModular Exports
Every functionality is modularized and exported in package.json:
{
"exports": {
".": "./dist/index.js",
"./api-key": "./dist/api-key/index.js",
"./polar-sh": "./dist/polar-sh/index.js",
"./billing": "./dist/billing/index.js",
"./sdk": "./dist/sdk/index.js",
"./hono": "./dist/hono/index.js",
"./client": "./dist/client/index.js",
"./extension": "./dist/extension/index.js"
}
}1. Unified Backend SDK (payments/sdk)
Orchestrates Unkey and Polar into an end-to-end payment management system:
import { PaymentsEngine } from 'payments/sdk';
import { ApiKey } from 'payments/api-key';
import { PolarBilling } from 'payments/polar-sh';
export const payments = new PaymentsEngine({
apiKey: new ApiKey('api_xxx', { rootKey: process.env.UNKEY_ROOT_KEY }),
billing: new PolarBilling({ accessToken: process.env.POLAR_ACCESS_TOKEN }),
webhookSecret: process.env.POLAR_WEBHOOK_SECRET,
tiers: [
{
productId: 'prod_pro_uuid',
tierName: 'pro',
roles: ['pro_user'],
permissions: ['api.read', 'api.write'],
rateLimit: { limit: 100, duration: 60000 },
credits: { initialCredits: 1000, refillAmount: 1000, refillInterval: 'monthly' }
}
],
onKeyProvisioned: async ({ key, keyId }, context) => {
console.log(`Provisioned key ${keyId} for user ${context.externalCustomerId}`);
}
});Key Capabilities
createCheckoutSession(options): Initiates checkout with attached user ID and tier metadata.createCustomerPortalSession(options): Generates a self-service customer portal session URL.handleWebhook(body, headers): Validates Polar signature and automatically provisions or updates keys uponorder.paidorsubscription.active.verifyApiKey(key, { requiredPermissions, checkSubscription }): Validates keys and ensures active subscription state.
2. Hono Middleware (payments/hono)
Mounts edge-ready routes onto your Hono API server:
import { Hono } from 'hono';
import { paymentsMiddleware } from 'payments/hono';
import { payments } from './payments.js';
const app = new Hono();
paymentsMiddleware({
engine: payments,
basePath: '/api/payments',
authenticateUser: async (c) => {
// Read session cookie or JWT
return { userId: 'user_123', email: '[email protected]' };
}
})(app);
export default app;Mounted Routes
POST /api/payments/checkout&GET /api/payments/checkout-> Create checkout session or redirectPOST /api/payments/portal&GET /api/payments/portal-> Create customer portal session or redirectPOST /api/payments/webhook-> Handle Polar webhooks with raw body verificationPOST /api/payments/verify&GET /api/payments/verify-> Verify API key and entitlementsGET /api/payments/subscriptions-> List user subscriptionsPOST /api/payments/keys-> Provision API key (protected)DELETE /api/payments/keys/:keyId-> Revoke API key (protected)
3. Browser Frontend SDK (payments/client)
Browser-ready client connecting to your Hono backend:
import { PaymentsClient } from 'payments/client';
const client = new PaymentsClient({
baseApiUrl: 'https://api.myapp.com/api/payments',
getAuthToken: async () => localStorage.getItem('auth_token')
});
// Create checkout and redirect
await client.redirectToCheckout({
products: ['prod_pro_uuid'],
successUrl: 'https://myapp.com/dashboard?checkout_id={CHECKOUT_ID}'
});
// Open customer portal
await client.openCustomerPortal();
// Verify key entitlements
const result = await client.verifyKey({ key: 'unkey_xxx' });
if (result.valid) {
console.log(`Welcome back! Remaining credits: ${result.credits}`);
}4. Browser Extension SDK (payments/extension)
Tailored for Chrome, Firefox, and Safari extensions with storage caching and tab launchers:
import { ExtensionPaymentsClient } from 'payments/extension';
const extClient = new ExtensionPaymentsClient({
baseApiUrl: 'https://api.myapp.com/api/payments',
storageArea: 'local',
cacheTtlMs: 5 * 60 * 1000 // Cache key verification for 5 mins
});
// Open checkout in a new browser tab
await extClient.launchCheckoutTab({
products: ['prod_pro_uuid']
});
// Cache-aware key check (uses browser.storage.local standard)
const verification = await extClient.getOrVerifyKey();
if (verification.valid) {
console.log(`Extension unlocked with tier ${verification.tier}`);
}
// Background script runtime listener (standard browser.runtime, with chrome.runtime fallback)
browser.runtime.onMessage.addListener(extClient.createMessageHandler());5. Standalone Polar Billing (payments/polar-sh)
Direct access to Polar resources and products:
import { PolarBilling, createPolarClient } from 'payments/polar-sh';
const billing = new PolarBilling({
accessToken: process.env.POLAR_ACCESS_TOKEN
});
// Create product
const product = await billing.createProduct({
name: 'Developer Plan',
recurring_interval: 'month',
prices: []
});
// Customer management
const customer = await billing.getCustomerByExternalId('usr_123');6. Standalone API Keys (payments/api-key)
Full Unkey v2 key, identity, and RBAC lifecycle:
import { ApiKey } from 'payments/api-key';
const keyManager = new ApiKey('api_id_xxx', {
rootKey: process.env.UNKEY_ROOT_KEY
});
const key = await keyManager.create({
name: 'prod-key',
roles: ['developer'],
ratelimits: [{ name: 'requests', limit: 100, duration: 60000 }]
});Verification & Testing
# Run unit tests
npm test
# Run TypeScript checks
npm run check
# Build distribution and lint package exports
npm run build