Partner SDK
Official JavaScript & TypeScript client for the Ownich Partner API. Works in Node.js, Deno, Bun, and modern browsers.
Installation
Install the SDK from npm. No peer dependencies required.
npm install ownich-partner-sdkThe 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.
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.
// 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 createdError handling
All API errors throw an OwnichApiError with a typed status and convenience boolean getters.
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
}
}| Status | Getter | Meaning |
|---|---|---|
| 401 | isAuthError | Invalid or expired API key |
| 403 | isFraudBlock / isAuthError | Fraud detection hard block or forbidden |
| 408 | — | Request timed out (AbortController) |
| 409 | isDuplicate | Serial 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.
// ─── 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
// 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
// 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
// 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.