- JavaScript 100%
| examples | ||
| src | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| COMPLETION_SUMMARY.md | ||
| IMPLEMENTATION_GUIDE.md | ||
| package.json | ||
| QUICK_REFERENCE.md | ||
| README.md | ||
Pax8 API Integration Tool
A reusable Node.js API client for retrieving Pax8 subscription data with automatic caching, pagination handling, and enriched company/product information.
Features
✅ OAuth 2.0 Authentication - Secure token management with automatic caching and refresh
✅ Paginated Subscriptions Fetching - Automatically handles all pages of results
✅ Company & Product Lookups - Cached enrichment of subscription data with names
✅ Flexible Filtering - Filter subscriptions by company, product, status, billing term
✅ Subscription Summary - Extract Company, Product, Quantity, Next Renewal Date, Commitment Duration
✅ Error Handling - Comprehensive error messages for auth failures, rate limits, API errors
✅ Fully Tested - Jest unit tests for all modules with mocked API calls
Installation
-
Clone or download this repository
-
Install dependencies
npm install
- Set up environment variables
cp .env.example .env
- Add your Pax8 API credentials to
.env- Get credentials from https://app.pax8.com/integrations/credentials
- See
.env.examplefor required fields
Quick Start
Basic Usage
const Pax8Client = require('./src/pax8-client');
// Create client (loads credentials from .env)
const client = new Pax8Client();
// Get subscription summary with all required fields
const summary = await client.getSubscriptionSummary();
console.log(summary);
/* Output:
[
{
Company: 'Acme Corp',
Product: 'Microsoft 365 Business Standard',
Quantity: 50,
'Next Renewal Date': '2025-12-31',
'Commitment Duration': '3-Year'
},
...
]
*/
Get All Subscriptions (Enriched with Company & Product Names)
const enriched = await client.getAllSubscriptionsEnriched();
console.log(enriched);
Get Subscriptions for Specific Company
const companyId = 'f7fc273a-8d86-45c9-a26f-ffd42416adda';
const subs = await client.getCompanySubscriptions(companyId);
Filter Subscriptions
const summary = await client.getSubscriptionSummary({
companyId: 'company-uuid', // Optional: filter by company
productId: 'product-uuid', // Optional: filter by product
status: 'Active', // Optional: default is 'Active'
});
API Reference
Pax8Client
Main facade class combining all functionality.
Constructor
new Pax8Client(options)
Options:
clientId(string): Pax8 Client ID. Defaults toPAX8_CLIENT_IDenv var.clientSecret(string): Pax8 Client Secret. Defaults toPAX8_CLIENT_SECRETenv var.validateOnInit(boolean): Validate config on creation. Default:true.
Methods
getSubscriptionSummary(options)
Fetches subscriptions with Company, Product, Quantity, Next Renewal Date, and Commitment Duration.
Parameters:
{
status: 'Active', // Filter by status (optional, default: 'Active')
companyId: 'uuid', // Filter by company (optional)
productId: 'uuid', // Filter by product (optional)
fetchAll: true // Fetch all pages (optional, default: true)
}
Returns: Promise resolving to array of subscription summaries
Example:
const summary = await client.getSubscriptionSummary({
status: 'Active',
companyId: 'comp-123'
});
// Returns:
// [
// {
// Company: 'Acme Corp',
// Product: 'Cloud Suite',
// Quantity: 10,
// 'Next Renewal Date': '2025-12-31',
// 'Commitment Duration': '3-Year',
// _subscription: { id, status, billingTerm, price, ... }
// }
// ]
getAllSubscriptionsEnriched(options)
Fetches all subscriptions with company and product names added.
Parameters: Same as getSubscriptionSummary
Returns: Promise resolving to array of enriched subscription objects
getCompanySubscriptions(companyId, options)
Fetches subscriptions for a specific company.
Parameters:
companyId(string): Company UUIDoptions(Object): Query options (size, sort, etc.)
Returns: Promise resolving to array of subscriptions with product names
clearCaches()
Clears all internal caches (companies, products, tokens).
client.clearCaches();
getStatus()
Returns cache and token status information.
const status = client.getStatus();
// Returns:
// {
// token: { hasToken: true, isValid: true, expiresAt: '...' },
// companies: { cachedCompanies: 150, cacheValid: true, cacheAge: 5000 },
// products: { cachedProducts: 500, cacheValid: true, cacheAge: 5000 }
// }
Auth Module
Low-level authentication handling.
const auth = require('./src/pax8-client/auth');
// Get access token (cached automatically)
const token = await auth.getAccessToken(clientId, clientSecret);
// Check token validity
const status = auth.getTokenCacheStatus();
// Clear cache
auth.clearTokenCache();
Subscriptions Module
Direct access to subscription fetching.
const subs = require('./src/pax8-client/subscriptions');
// Get all subscriptions
const all = await subs.getAllSubscriptions(token);
// Get subscriptions for company
const byCompany = await subs.getSubscriptionsForCompany(token, 'comp-id');
// Get subscriptions for product
const byProduct = await subs.getSubscriptionsForProduct(token, 'prod-id');
// Get only active subscriptions
const active = await subs.getActiveSubscriptions(token);
Companies Module
Company lookup and caching.
const companies = require('./src/pax8-client/companies');
// Get all companies
const all = await companies.getAllCompanies(token);
// Get specific company
const company = await companies.getCompanyById(token, 'comp-id');
// Get company name
const name = await companies.getCompanyName(token, 'comp-id');
// Get company name map (companyId → name)
const map = await companies.getCompanyNameMap(token);
// { 'comp-1': 'Acme Corp', 'comp-2': 'Tech Inc', ... }
// Cache management
companies.clearCache();
const status = companies.getCacheStatus();
Products Module
Product lookup and caching.
const products = require('./src/pax8-client/products');
// Get all products
const all = await products.getAllProducts(token);
// Get specific product
const product = await products.getProductById(token, 'prod-id');
// Get product name
const name = await products.getProductName(token, 'prod-id');
// Get product name map (productId → name)
const map = await products.getProductNameMap(token);
// Cache management
products.clearCache();
const status = products.getCacheStatus();
Subscription Summary Data Format
The main output of getSubscriptionSummary() is an array of objects with these fields:
| Field | Type | Description |
|---|---|---|
Company |
string | Company name from Pax8 |
Product |
string | Product name from Pax8 |
Quantity |
number | Number of licenses/seats |
Next Renewal Date |
string | ISO date (YYYY-MM-DD) or 'N/A' |
Commitment Duration |
string | e.g., "3-Year", "Annual", "Monthly", or 'N/A' |
_subscription |
object | Original subscription data (hidden by default) |
Example Response
[
{
Company: 'Acme Corporation',
Product: 'Microsoft 365 Business Premium',
Quantity: 50,
'Next Renewal Date': '2026-05-15',
'Commitment Duration': '3-Year'
},
{
Company: 'Acme Corporation',
Product: 'Adobe Creative Cloud',
Quantity: 10,
'Next Renewal Date': '2024-12-31',
'Commitment Duration': 'Annual'
},
{
Company: 'TechStart Inc',
Product: 'Slack Workspace',
Quantity: 75,
'Next Renewal Date': 'N/A',
'Commitment Duration': 'Monthly'
}
]
Testing
Run the test suite:
npm test
Run tests in watch mode:
npm run test:watch
View coverage report:
npm test -- --coverage
Error Handling
The client provides detailed error messages:
Authentication Errors
try {
const client = new Pax8Client();
await client.getSubscriptionSummary();
} catch (error) {
if (error.message.includes('Missing required environment variables')) {
console.error('Set PAX8_CLIENT_ID and PAX8_CLIENT_SECRET in .env');
}
if (error.message.includes('authentication failed')) {
console.error('Invalid Pax8 credentials');
}
}
API Errors
try {
const summary = await client.getSubscriptionSummary();
} catch (error) {
if (error.message.includes('429')) {
console.error('Rate limit exceeded (1000 calls/minute)');
}
if (error.message.includes('401')) {
console.error('Unauthorized - check credentials');
}
if (error.message.includes('404')) {
console.error('Resource not found');
}
}
Caching
The client implements intelligent caching to minimize API calls:
- Token Cache: Access tokens are cached for 24 hours with automatic refresh 5 minutes before expiry
- Company Cache: Company names are cached for 1 hour
- Product Cache: Product names are cached for 1 hour
Clear caches manually when needed:
client.clearCaches();
Rate Limiting
Pax8 API allows 1000 successful requests per minute. The client automatically handles pagination but does not implement rate limiting. If you expect to exceed this limit:
- Implement exponential backoff for retries
- Use filtering to reduce data fetched
- Batch operations across multiple client instances
Performance Tips
-
Use filters to reduce data returned:
const summary = await client.getSubscriptionSummary({ status: 'Active', companyId: 'specific-company' }); -
Reuse the same client instance to benefit from caching:
const client = new Pax8Client(); const summary1 = await client.getSubscriptionSummary(); const summary2 = await client.getSubscriptionSummary(); // Uses cached companies/products -
Only fetch what you need:
// Get raw data without company/product enrichment for faster response const raw = await subscriptions.getAllSubscriptions(token);
Troubleshooting
Missing required environment variables
Solution: Copy .env.example to .env and fill in your credentials:
cp .env.example .env
# Edit .env with your Pax8 API credentials
authentication failed (401): Unauthorized
Solution: Verify your credentials:
- Log in to https://app.pax8.com
- Go to Settings > Integrations > API Keys
- Create a new API credential or verify existing one
- Update
.envfile
No subscriptions returned
Solution: Check filters and account status:
- Verify the account actually has subscriptions
- Try removing filters:
await client.getSubscriptionSummary({}) - Check subscription status: use
status: nullto include all (except the code defaults to 'Active')
Slow performance
Solution: Implement pagination:
// Instead of fetching all, get one page
const summary = await client.getSubscriptionSummary({
fetchAll: false // Only returns first page
});
API Documentation
For detailed Pax8 API documentation, visit:
Contributing
This is a read-only client library. For Pax8 API issues, contact: integrations@pax8.com
License
MIT
Support
For issues with this client:
- Check the error messages in Troubleshooting section
- Review the test suite in
tests/pax8-client.test.jsfor usage examples - Ensure all environment variables are set correctly
- Contact your Pax8 account representative for API credential issues