npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@netiva-ai/sdk

v0.0.6

Published

Official Node.js SDK for Netiva

Readme

@netiva-ai/sdk

Official Node.js SDK for Netiva.

Installation

npm install @netiva-ai/sdk

Quick Start

import { Netiva } from '@netiva-ai/sdk'

const netiva = new Netiva({
  workspaceId: process.env.NETIVA_WORKSPACE_ID!,
  apiKey: process.env.NETIVA_API_KEY!,  // Format: nsk_xxx
})

Customers

// Create with metadata (store your internal IDs for mapping)
const customer = await netiva.customers.create({
  email: '[email protected]',
  firstName: 'John',
  lastName: 'Doe',
  metadata: {
    userUid: 'your-internal-user-id',
    organizationUid: 'your-internal-org-id',
  },
})
// Returns: { id, email, firstName, lastName, metadata }

// Get customer
const found = await netiva.customers.get(customer.id)

// List customers
const { data, meta } = await netiva.customers.list({ search: 'john', page: 1, limit: 25 })

// Update customer
const updated = await netiva.customers.update(customer.id, { firstName: 'Jane' })

// Delete customer
await netiva.customers.delete(customer.id)

// List organizations a customer belongs to
const orgs = await netiva.customers.listOrganizations(customer.id)
// Returns: Organization[] - all orgs where the customer is a member

Organizations

// Create with metadata
const org = await netiva.organizations.create({
  name: 'Acme Corp',
  domain: 'acme-corp',  // slug/key
  metadata: {
    organizationUid: 'your-internal-org-id',
  },
})
// Returns: { id, name, domain, metadata }

// Get organization
const found = await netiva.organizations.get(org.id)

// List organizations
const { data } = await netiva.organizations.list()

// Update organization
const updated = await netiva.organizations.update(org.id, { name: 'Acme Inc' })

// Delete organization
await netiva.organizations.delete(org.id)

// Add member to organization
await netiva.organizations.addMember(org.id, {
  customerId: customer.id,
  role: 'admin',  // or 'member'
})

// Remove member
await netiva.organizations.removeMember(org.id, customer.id)

Add-ons

Manage add-ons (fixed, quantity-based, or metered) for organization subscriptions:

// List all available add-ons for the workspace
const { addons } = await netiva.addons.list()
// Returns: { addons: [{ id, name, description, type, unitLabel, prices, ... }] }

// List active add-ons for an organization
const { addons: orgAddons } = await netiva.addons.listForOrganization(org.id)
// Returns: { addons: [{ subscriptionItemId, name, type, quantity, price, ... }] }

// Add an add-on to an organization's subscription
const result = await netiva.addons.add(org.id, {
  priceId: 'price_xxx',
  quantity: 5,  // optional, defaults to 1 for fixed/quantity types
})
// Returns: { success, subscriptionItem: { id, priceId, quantity } }

// Update add-on quantity
await netiva.addons.updateQuantity(org.id, 'si_xxx', 10)
// Returns: { success, subscriptionItem: { id, quantity } }

// Remove an add-on
await netiva.addons.remove(org.id, 'si_xxx')
// Returns: { success }

Metered Usage

For metered add-ons, report usage and retrieve summaries:

// Report metered usage
await netiva.addons.reportUsage(org.id, {
  subscriptionItemId: 'si_xxx',
  quantity: 100,
  timestamp: Math.floor(Date.now() / 1000),  // optional, unix timestamp in seconds, defaults to now
  action: 'increment',  // optional: 'increment' (default) or 'set'
})
// Returns: { success, usageRecord: { id, quantity, timestamp } }

// Get usage summary for current billing period
const { usage } = await netiva.addons.getUsage(org.id, 'si_xxx')
// Returns: { usage: { subscriptionItemId, totalUsage, period: { start, end } } }

Magic Links

Generate links for billing portal access. Use for both checkout and subscription management:

Checkout Flow (New Subscriptions)

Redirect users to select a plan and enter payment:

// Option 1: Let customer browse all plans
const { link } = await netiva.magicLink.generate({
  customerId: customer.id,
  organizationId: org.id,
  returnUrl: 'https://app.example.com/dashboard?billing=complete',
  redirectTo: '/plans',
})

// Option 2: Skip plan selection, go directly to checkout
const { link } = await netiva.magicLink.generate({
  customerId: customer.id,
  organizationId: org.id,
  returnUrl: 'https://app.example.com/dashboard?billing=complete',
  planId: 'prod_xxx',  // Stripe Product ID - bypasses /plans, goes straight to checkout
})

// Redirect user to checkout
res.redirect(link)

Checkout Flow:

  1. User signs up on your app
  2. You create customer + org in Netiva
  3. You redirect user to magic link (with redirectTo: '/plans')
  4. User selects plan, enters payment
  5. Netiva redirects back to returnUrl
  6. Webhook subscription.created fires

Manage Subscription

Generate links for "Manage Subscription" button - logs user into billing portal:

const { link } = await netiva.magicLink.generate({
  customerId: customer.id,
  returnUrl: 'https://app.example.com/settings/billing',
})

// Redirect user to manage their subscription
res.redirect(link)

Parameters

| Parameter | Required | Description | |-----------|----------|-------------| | customerId | Yes | Customer to authenticate | | organizationId | No | Organization context | | returnUrl | No | URL to return to after portal session | | expiresInMinutes | No | Link expiry (default: 15 minutes) | | redirectTo | No | Portal destination: /plans, /payment-methods, /invoices, /addons | | planId | No | Skip plan selection, go directly to checkout for this plan |

SSO Verification

When customers click "Launch App" in the portal, verify the token:

app.get('/auth/sso', (req, res) => {
  const result = netiva.sso.verify(req.query.token as string)

  if (!result.valid) {
    return res.status(401).json({ error: result.error })
  }

  // Authenticated! result.customer contains { id, email, firstName, lastName }
  req.session.userId = result.customer!.id
  res.redirect('/dashboard')
})

Webhooks

Verify incoming webhooks:

app.post('/webhooks/netiva', express.raw({ type: 'application/json' }), (req, res) => {
  const result = netiva.webhooks.verify(req.body, req.headers)

  if (!result.valid) {
    return res.status(401).json({ error: result.error })
  }

  const { event, data } = result.payload!
  
  switch (event) {
    case 'customer.created':
      // data: { id, email, metadata }
      break
    case 'subscription.created':
      // data: { subscriptionId, customerId, organizationId, planId, planName, status, currentPeriodEnd, metadata }
      break
    case 'subscription.updated':
      // data: { subscriptionId, customerId, organizationId, planId, currentPeriodEnd, metadata }
      break
    case 'subscription.cancelled':
      // data: { subscriptionId, organizationId, cancelledAt, metadata }
      break
    case 'subscription.reactivated':
      // data: { subscriptionId, organizationId, metadata }
      break
    case 'subscription.upgraded':
    case 'subscription.downgraded':
      // data: { subscriptionId, organizationId, previousPlanId, newPlanId, metadata }
      break
    case 'invoice.payment_succeeded':
      // data: { invoiceId, subscriptionId, organizationId, amount, currency, metadata }
      break
    case 'invoice.payment_failed':
      // data: { invoiceId, subscriptionId, organizationId, failureReason, metadata }
      break
    case 'addon.added':
      // data: { subscriptionItemId, priceId, quantity, organizationId, metadata }
      break
    case 'addon.removed':
      // data: { subscriptionItemId, organizationId, metadata }
      break
    case 'addon.quantity_updated':
      // data: { subscriptionItemId, quantity, organizationId, metadata }
      break
    case 'addon.usage_reported':
      // data: { subscriptionItemId, quantity, organizationId, metadata }
      break
  }

  res.json({ received: true })
})

Webhook Events

| Event | Description | |-------|-------------| | customer.created | New customer registered in the members portal | | lead.created | New lead captured from a landing page form | | subscription.created | Customer subscribed to a plan | | subscription.updated | Subscription details changed (e.g., quantity) | | subscription.cancelled | Customer cancelled their subscription | | subscription.reactivated | Cancelled subscription was reactivated | | subscription.upgraded | Customer upgraded to a higher plan | | subscription.downgraded | Customer downgraded to a lower plan | | invoice.payment_succeeded | Payment was successfully processed | | invoice.payment_failed | Payment failed (card declined, expired, etc.) | | addon.added | Add-on added to an organization's subscription | | addon.removed | Add-on removed from an organization's subscription | | addon.quantity_updated | Add-on quantity changed | | addon.usage_reported | Metered usage reported for an add-on |

Metadata Propagation: Metadata passed when creating customers/orgs is included in webhook payloads.

Error Handling

import { NetivaApiError, NetivaNetworkError, NetivaTimeoutError } from '@netiva-ai/sdk'

try {
  await netiva.customers.get('invalid-id')
} catch (error) {
  if (error instanceof NetivaApiError) {
    console.error(error.message, error.statusCode, error.errorCode)
  }
}

Configuration Options

| Option | Required | Default | Description | |--------|----------|---------|-------------| | workspaceId | Yes | — | Your Netiva workspace ID | | apiKey | Yes | — | API key (format: nsk_xxx) | | baseUrl | No | https://api.netiva.ai | API base URL | | timeout | No | 30000 | Request timeout (ms) | | retries | No | 0 | Retry attempts |

License

MIT