v1.0.0ownich-partner-sdk

Partner SDK

Official JavaScript & TypeScript client for the Ownich Partner API. Works in Node.js, Deno, Bun, and modern browsers.

Zero dependencies
Fraud detection built-in
Node · Deno · Bun · Browser
Full TypeScript types

Installation

Install the SDK from npm. No peer dependencies required.

npm install ownich-partner-sdk

The SDK is also available as a raw TypeScript file at /sdk/ownich-partner-sdk.ts for Deno or projects that prefer vendoring dependencies.

Quick start

Initialise the client with your API key and make your first call in under a minute. Get your key from the Partner Portal.

verify-item.ts
import OwnichClient from 'ownich-partner-sdk';

const client = new OwnichClient({
  apiKey: 'pk_live_your_api_key_here',
});

// Verify a serial number
const result = await client.verifySerial({
  serialNumber: 'SN-12345',
  brand: 'Rolex',
});

if (result.found) {
  console.log('Certificate found:', result.certId);
  if (result.isStolen) {
    console.warn('⚠️  Item reported stolen');
  }
} else {
  console.log('No certificate found for this serial');
}

API keys start with pk_live_ for production and pk_test_ for sandbox. Never expose live keys in client-side code.

Sandbox mode

Use a pk_test_ key to run all operations against the sandbox. No real certificates are created and no fraud signals are triggered.

sandbox.ts
// Use a test key (pk_test_…) to enable sandbox mode
const client = new OwnichClient({
  apiKey: 'pk_test_your_test_key_here',
});

// client.isSandbox === true
// All operations run against the sandbox — no real certs are created

Error handling

All API errors throw an OwnichApiError with a typed status and convenience boolean getters.

error-handling.ts
import OwnichClient, { OwnichApiError } from 'ownich-partner-sdk';

try {
  const cert = await client.createCertificate({ /* … */ });
} catch (err) {
  if (err instanceof OwnichApiError) {
    if (err.isFraudBlock) {
      // 403 — fraud detection blocked this request
      console.error('Blocked by fraud detection:', err.body.message);
    } else if (err.isDuplicate) {
      // 409 — serial number already has a certificate
      console.error('Duplicate serial number');
    } else if (err.isAuthError) {
      // 401/403 — invalid or revoked API key
      console.error('Authentication failed — check your API key');
    } else {
      console.error(`API error ${err.status}:`, err.message);
    }
  } else {
    throw err; // re-throw unexpected errors
  }
}
StatusGetterMeaning
401isAuthErrorInvalid or expired API key
403isFraudBlock / isAuthErrorFraud detection hard block or forbidden
408—Request timed out (AbortController)
409isDuplicateSerial number already has a certificate
422—Validation error — check body fields
500—Ownich server error — retry with backoff

Methods

All methods are async and return typed promises. Click a method to expand its full reference.

Type reference

All types are exported from the package and available in your IDE via TypeScript intellisense.

types.d.ts
// ─── Config ──────────────────────────────────────────────────────────────────
interface OwnichConfig {
  apiKey: string;       // pk_live_… or pk_test_…
  baseUrl?: string;     // default: https://ownich.io
  timeout?: number;     // ms, default: 10000
}

// ─── verifySerial ─────────────────────────────────────────────────────────────
interface VerifySerialResult {
  found: boolean;
  sandbox?: boolean;
  certId?: string;
  brand?: string;
  model?: string;
  category?: string;
  isAuthentic?: boolean;
  isStolen?: boolean;
  issuedAt?: string;
  brandMatch?: boolean;
  fraudFlag?: FraudFlag | null;
}

interface FraudFlag {
  shouldBlock: boolean;
  maxSeverity: 'low' | 'medium' | 'high' | 'critical';
  hits: FraudHit[];
}

interface FraudHit {
  type: string;
  severity: 'low' | 'medium' | 'high' | 'critical';
  reason: string;
}

// ─── createCertificate ────────────────────────────────────────────────────────
interface CreateCertificateResult {
  certId: string;
  partnerId: number;
  sandbox?: boolean;
  note?: string;
}

// ─── getProfile ───────────────────────────────────────────────────────────────
interface PartnerProfile {
  id: number;
  name: string;
  slug: string;
  contactName: string;
  contactEmail: string;
  website: string;
  status: string;
  integrationType: string;
  activatedAt: string | null;
  createdAt: string;
}

interface PartnerStats {
  totalCerts: number;
  stolenCerts: number;
}

// ─── Error ────────────────────────────────────────────────────────────────────
class OwnichApiError extends Error {
  status: number;
  body: { status: number; error: string; message?: string };
  get isFraudBlock(): boolean;   // 403 + fraud in error message
  get isDuplicate(): boolean;    // 409
  get isAuthError(): boolean;    // 401 or 403
}

Integration guides

Common integration patterns for the most frequent use cases.

Verify at point of sale

Check a serial number before accepting a trade-in or resale item

pos-verify.ts
// Point-of-sale: verify before accepting a trade-in
async function verifyTradeIn(serialNumber: string, brand: string) {
  const result = await client.verifySerial({ serialNumber, brand });

  if (!result.found) {
    return { status: 'no_certificate', message: 'No Ownich certificate found' };
  }
  if (result.isStolen) {
    return { status: 'stolen', message: 'Item reported stolen — do not accept' };
  }
  if (result.fraudFlag?.shouldBlock) {
    return { status: 'fraud_blocked', message: 'Fraud signal detected' };
  }
  if (!result.brandMatch) {
    return { status: 'brand_mismatch', message: 'Certificate brand does not match' };
  }

  return { status: 'verified', certId: result.certId };
}

Register at manufacture

Create a certificate when an item leaves the production line

manufacture-register.ts
// Register a certificate at the point of manufacture
async function registerAtManufacture(item: {
  name: string; brand: string; model: string;
  serial: string; category: string;
}) {
  try {
    const cert = await client.createCertificate({
      itemName: item.name,
      category: item.category,
      brand: item.brand,
      model: item.model,
      serialNumber: item.serial,
      owner: 'Unregistered',  // owner unknown at manufacture
      condition: 'new',
    });

    // Store certId in your product database
    await db.products.update(item.serial, { ownichCertId: cert.certId });
    return cert;
  } catch (err) {
    if (err instanceof OwnichApiError && err.isDuplicate) {
      // Already registered — fetch existing cert
      const existing = await client.verifySerial({ serialNumber: item.serial });
      return { certId: existing.certId, alreadyExisted: true };
    }
    throw err;
  }
}

Handle fraud flags

Distinguish hard blocks from soft flags and route accordingly

fraud-handling.ts
// Handle fraud flags gracefully
async function handleFraudFlags(serialNumber: string) {
  const result = await client.verifySerial({ serialNumber });

  if (!result.fraudFlag) return 'clean';

  const { shouldBlock, maxSeverity, hits } = result.fraudFlag;

  if (shouldBlock) {
    // Hard block — log and reject
    await logFraudEvent({ serialNumber, severity: maxSeverity, hits });
    throw new Error('Transaction blocked: fraud detected');
  }

  // Soft flag — log and flag for manual review
  await flagForReview({ serialNumber, severity: maxSeverity, hits });
  return 'flagged_for_review';
}

Ready to integrate?

Apply for a partner account to get your API key and start building.