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

@ownichat/sdk

v0.1.0

Published

Official owni.chat API client: product catalog sync, knowledge sources, allowed domains, webhook verification and the public widget API.

Readme

@ownichat/sdk

Official API client for owni.chat — the AI chat widget that answers from your real catalog.

npm bundle types license

npm install @ownichat/sdk

| | | | --- | --- | | 🛍️ Catalog sync | Push products, prices and stock — batching handled for you | | 📚 Knowledge | Create URL, text and FAQ sources, upload files, trigger reindexing | | 🌐 Domains | Register the origins the widget may load on | | 🔐 Webhooks | Verify HMAC-signed deliveries, with replay protection | | 💬 Widget API | Talk to the public chat API when building your own UI |

Zero runtime dependencies. Node 18+ (uses the global fetch), and works in Deno, Bun, Cloudflare Workers and other edge runtimes. Ships ESM and CJS with types for both.

Quick start

Create an API key in the owni.chat dashboard under Settings → API keys. It looks like ak_live_… and must stay server-side.

import { createOwniClient } from '@ownichat/sdk';

const owni = createOwniClient({ apiKey: process.env.OWNI_API_KEY! });

// Everything the key is bound to — including the public key for the widget script tag
const { project } = await owni.me();
console.log(project.project_key); // pk_…

That single call is what makes one-field installs possible: the merchant pastes the API key, and your integration discovers the project id and the widget key on its own.

Sync a product catalog

await owni.products.bulkUpsert([
  {
    external_id: '1042',                       // your shop's product id
    title: 'Merino wool scarf',
    description: 'Lightweight, 100% merino.',
    url: 'https://shop.example.com/p/1042',    // required
    price: '49.00',
    old_price: '69.00',
    currency: 'EUR',
    image_url: 'https://shop.example.com/i/1042.jpg',
    availability: 'in_stock',
    category: 'Accessories',
    brand: 'Example',
    attributes: [{ name: 'Colour', value: 'Charcoal' }],
  },
]);

bulkUpsert accepts any number of products and splits them into the API's 100-item batches for you, sequentially, so a full catalog sync stays within the rate limit.

Other catalog calls:

await owni.products.list({ page: 1, pageSize: 50 });
await owni.products.get('1042');
await owni.products.upsert({ external_id: '1042', title: '…', url: '…' });
await owni.products.delete('1042');

Keep external_id equal to your shop's own product id — it is what the widget's "add to cart" snippet interpolates when a visitor buys from a product card.

Allowed domains

The widget only loads on origins registered for the project. Register the storefront you're installed on so staging sites and secondary domains work without dashboard edits:

await owni.domains.add('staging.shop.example.com'); // idempotent
await owni.domains.list();

Knowledge sources

await owni.knowledge.createSource({ type: 'url', name: 'Shipping policy', source_url: 'https://shop.example.com/shipping' });
await owni.knowledge.createSource({ type: 'faq', name: 'FAQ', raw_text: 'Q: …\nA: …' });

const file = new Blob([await readFile('./returns.pdf')]);
await owni.knowledge.uploadFile({ file, filename: 'returns.pdf' });

Webhooks

owni.chat signs outgoing webhooks with X-Owni-Signature (HMAC-SHA256 over <timestamp>.<raw body>) and X-Owni-Timestamp. Verify both — the timestamp is what stops a captured delivery from being replayed later.

import { parseWebhookRequest } from '@ownichat/sdk/webhooks';

export async function POST(request: Request) {
  const body = await request.text(); // raw body, not request.json()

  const result = parseWebhookRequest({
    body,
    headers: request.headers,
    secret: process.env.OWNI_WEBHOOK_SECRET!,
  });

  if (!result.valid) {
    return new Response(result.reason, { status: 401 });
  }

  if (result.event.event === 'lead_captured') {
    // …
  }
  return new Response('ok');
}

verifyWebhookSignature is available separately if you already parse the body yourself. Both work with a Headers object and with a plain Node header record.

The signing secret is shown once when you connect the webhook integration, and can be regenerated from Integrations → Webhooks → Rotate secret. Integrations created before signing existed keep receiving unsigned deliveries until you rotate.

Widget API (browser)

Only needed when building a custom chat UI — the standard embed script already does this.

import { createWidgetClient } from '@ownichat/sdk/widget';

const widget = createWidgetClient({ projectKey: 'pk_…' });
const config = await widget.getConfig();
const session = await widget.createSession({ source_page_url: location.href });

Requests are origin-checked server-side, so the page must run on the project domain or one of its registered domains.

Errors and retries

import { OwniApiError, OwniConnectionError } from '@ownichat/sdk';

try {
  await owni.products.bulkUpsert(products);
} catch (error) {
  if (error instanceof OwniApiError && error.isAuthError) {
    // wrong, revoked, expired or under-scoped key — retrying will not help
  }
}

429 and 5xx responses are retried automatically with exponential backoff, honouring Retry-After. Configure with maxRetries (default 3) and timeoutMs (default 30 000).

Options

| Option | Default | Notes | | --- | --- | --- | | apiKey | — | Required. ak_live_…, server-side only. | | baseUrl | https://app.owni.chat | Point at your own instance if self-hosting. | | projectId | resolved via me() | Supply it to skip one round trip. | | fetch | global fetch | Inject your own for tests or proxies. | | maxRetries | 3 | Applies to 429 and 5xx only. | | timeoutMs | 30000 | Per request, including retries individually. |

Related packages

| Package | For | | --- | --- | | @ownichat/react | Widget provider, hooks and inline chat panel | | @ownichat/next | Next.js server component, client hooks and webhook route |

Running a ready-made platform? owni.chat ships official plugins for WordPress/WooCommerce, Shopify and OpenCart — see owni.chat/integrations.

Notes

The widget bundle shipped by owni.chat has its own copy of the browser API types; the two are kept in sync by hand for now. If you spot a drift, the backend's Joi schemas are the source of truth.

License

MIT © owni.chat