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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@inkress/admin-sdk

v1.1.42

Published

Official Inkress Commerce API SDK for JavaScript/TypeScript

Downloads

733

Readme

@inkress/admin-sdk

Official Inkress Commerce API SDK for JavaScript/TypeScript applications.

npm version TypeScript License: MIT

Features

  • 🚀 Modern TypeScript SDK - Built with TypeScript for excellent developer experience
  • 🔒 Secure Authentication - JWT-based authentication with automatic token management
  • 🌐 Public Endpoints - Access public merchant information without authentication
  • 📦 Comprehensive API Coverage - 23+ resources with full CRUD operations
  • 🎯 100% Type-Safe - Every method fully typed with specific interfaces
  • 🔄 Advanced Query System - Fluent query builder with intelligent transformations
  • 🌍 Contextual Translations - Human-readable strings automatically converted to API integers
  • 🛠️ Easy Integration - Simple setup and intuitive API design
  • 🔄 Automatic Retries - Built-in retry logic for resilient applications
  • 📱 Cross-Platform - Works in Node.js, browsers, and React Native

Installation

npm install @inkress/admin-sdk
yarn add @inkress/admin-sdk
pnpm add @inkress/admin-sdk

Quick Start

Basic Setup

import { InkressSDK } from '@inkress/admin-sdk';

const inkress = new InkressSDK({
  accessToken: 'your-jwt-token',
  username: 'merchant-username', // Optional
  mode: 'live', // Optional - 'live' (default) or 'sandbox'
});

Configuration Options

const inkress = new InkressSDK({
  // Required
  accessToken: 'your-jwt-token',
  
  // Optional
  username: 'merchant-username',    // For Client-Id header
  mode: 'live',                     // 'live' = api.inkress.com, 'sandbox' = api-dev.inkress.com
  apiVersion: 'v1',                 // API version (default: 'v1')
  timeout: 30000,                   // Request timeout in ms (default: 30000)
  retries: 3,                       // Number of retry attempts (default: 0)
  headers: {                        // Custom headers for all requests
    'X-Custom-Header': 'value'
  }
});

Why This SDK?

🎯 100% Type-Safe - Every single method across all 23 resources is fully typed:

// Every parameter and return value has explicit types
const balances: ApiResponse<MerchantBalance> = await inkress.merchants.balances();
// balances.data: { available: number, pending: number, currency: string }

🌍 Human-Readable API - Use contextual strings instead of cryptic integers:

// Clear, self-documenting code with contextual strings
await inkress.orders.update(123, {
  status: 'confirmed',
  kind: 'online'
});
// SDK automatically converts to integers for the API

🔍 Powerful Queries - Intuitive query syntax or fluent builders:

// Direct query syntax
await inkress.orders.query({
  status: ['confirmed', 'shipped'],
  total: { min: 100, max: 1000 },
  reference_id: { contains: 'VIP' }
});

// Fluent query builder
await inkress.orders.createQueryBuilder()
  .whereStatus(['confirmed', 'shipped'])
  .whereTotalRange(100, 1000)
  .whereReferenceContains('VIP')
  .execute();

📦 Complete Coverage - 22 resources with 125+ fully-typed methods:

  • Core: Merchants, Products, Categories, Orders, Users
  • Billing: Plans, Subscriptions, Payment Links, Payment Methods
  • Financial: Accounts, Requests, Fees, Currencies, Exchange Rates
  • Identity: Addresses, Tokens, Webhooks
  • Content: Public Data
  • And more...

Public Endpoints (No Authentication Required)

// Get public merchant information
const merchant = await inkress.public.getMerchant({ 
  username: 'merchant-username' 
});

// Get merchant products
const products = await inkress.public.getMerchantProducts('merchant-username', {
  limit: 20,
  search: 'laptop'
});

// Get merchant fees
const fees = await inkress.public.getMerchantFees('merchant-username', {
  currency: 'JMD',
  total: 1000
});

Authenticated Operations with Contextual Values

The SDK automatically translates human-readable strings to API integers:

// Create order with contextual strings
const order = await inkress.orders.create({
  total: 99.99,
  currency_code: 'USD',
  status: 'pending',      // SDK converts 'pending' → integer
  kind: 'online',         // SDK converts 'online' → integer
  customer: {
    email: '[email protected]',
    first_name: 'John',
    last_name: 'Doe'
  },
  reference_id: 'order-123'
});

// Update merchant with contextual values
const merchant = await inkress.merchants.update(123, {
  status: 'approved',               // SDK converts to integer
  platform_fee_structure: 'customer_pay',  // SDK converts to integer
  provider_fee_structure: 'merchant_absorb'
});

// Create user with contextual status and kind
const user = await inkress.users.create({
  email: '[email protected]',
  first_name: 'John',
  last_name: 'Doe',
  password: 'secure-password',
  status: 'pending',       // SDK converts to account_pending integer
  kind: 'organisation'     // SDK converts to user_organisation integer
});

Advanced Query System

Use the intuitive query system for powerful filtering:

// Query with multiple conditions
const orders = await inkress.orders.query({
  status: ['confirmed', 'shipped'],  // Array → IN query
  total: { min: 100, max: 1000 },   // Range query
  reference_id: { contains: 'VIP' }, // String search
  inserted_at: { after: '2024-01-01' },
  page: 1,
  page_size: 20
});

// Or use fluent query builder
const products = await inkress.products
  .createQueryBuilder()
  .whereStatus('published')
  .wherePriceRange(50, 500)
  .whereTitleContains('laptop')
  .whereCategory(5)
  .paginate(1, 20)
  .orderBy('price', 'desc')
  .execute();

Configuration Options

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | bearerToken | string | Yes | - | JWT token for API authentication | | clientId | string | No | - | Client ID for merchant-specific requests (format: m-{username}) | | endpoint | string | No | https://api.inkress.com | API endpoint URL | | apiVersion | string | No | v1 | API version to use | | timeout | number | No | 30000 | Request timeout in milliseconds | | retries | number | No | 3 | Number of retry attempts for failed requests | | headers | Record<string, string> | No | {} | Custom headers to include with requests |

API Resources

The SDK provides access to 23+ fully-typed resources:

Core Resources

  • Merchants - Merchant management and account operations
  • Products - Product catalog with full CRUD
  • Categories - Product categorization
  • Orders - Order processing and tracking
  • Users - User and account management

Billing & Subscriptions

  • Billing Plans - Subscription plan management
  • Subscriptions - Recurring billing and subscriptions
  • Payment Links - Payment link generation
  • Payment Methods - Payment method configuration

Financial

  • Financial Accounts - Account management
  • Financial Requests - Payout and withdrawal requests
  • Transaction Entries - Transaction tracking
  • Fees - Fee management and configuration
  • Exchange Rates - Currency exchange rates
  • Currencies - Multi-currency support

Identity & Access

  • Addresses - Address management
  • Tokens - API token management
  • Webhook URLs - Webhook configuration

Content & Other

  • Generics - Dynamic endpoint access
  • KYC - Know Your Customer operations
  • Payout - Payout processing
  • Public - Public-facing merchant data

Core Resource Examples

Merchants Resource

Merchants Resource

Full merchant management with contextual translations and account methods:

// List merchants with contextual filtering
const merchants = await inkress.merchants.list({
  status: 'approved',                 // Contextual: converts to integer
  platform_fee_structure: 'customer_pay',
  organisation_id: 123,
  q: 'coffee shop'
});

// Query merchants with advanced filtering
const merchants = await inkress.merchants.query({
  status: ['approved', 'active'],
  platform_fee_structure: 'customer_pay',
  inserted_at: { after: '2024-01-01' }
});

// Get merchant details
const merchant = await inkress.merchants.get(merchantId);

// Create merchant with contextual values
const newMerchant = await inkress.merchants.create({
  name: 'My Store',
  email: '[email protected]',
  username: 'mystore',
  status: 'pending',                  // Contextual
  platform_fee_structure: 'customer_pay',
  provider_fee_structure: 'merchant_absorb'
});

// Update merchant
await inkress.merchants.update(merchantId, { 
  name: 'Updated Store Name',
  status: 'approved'
});

// Merchant account methods (properly typed)
const balances = await inkress.merchants.balances();
// Returns: { available: number, pending: number, currency: string }

const limits = await inkress.merchants.limits();
// Returns: { transaction_limit: number, daily_limit: number, monthly_limit: number, currency: string }

const subscription = await inkress.merchants.subscription();
// Returns: { plan_name: string, status: string, billing_cycle: string, price: number, ... }

const invoices = await inkress.merchants.invoices();
// Returns: MerchantInvoice[]

const invoice = await inkress.merchants.invoice('invoice-123');
// Returns: MerchantInvoice

// Query builder
const merchants = await inkress.merchants
  .createQueryBuilder()
  .whereStatus('approved')
  .wherePlatformFeeStructure('customer_pay')
  .whereOrganisation(123)
  .search('electronics')
  .execute();

Products Resource

Complete product management with status translations and advanced querying:

// List products with contextual filtering
await inkress.products.list({
  status: 'published',      // Contextual: 'published' instead of integer
  category_id: 1,
  price: { min: 50, max: 500 },
  q: 'laptop'
});

// Query products with advanced filters
const products = await inkress.products.query({
  status: ['published', 'featured'],  // Array query
  category_id: [1, 2, 3],
  price: { min: 100 },
  title: { contains: 'gaming' },
  inserted_at: { after: '2024-01-01' }
});

// Get product details
await inkress.products.get(productId);

// Create product with contextual status
await inkress.products.create({
  name: 'Gaming Laptop',
  description: 'High-performance gaming laptop',
  price: 1299.99,
  category_id: 1,
  status: 'draft',          // Contextual
  kind: 'published'         // Contextual
});

// Update product
await inkress.products.update(productId, { 
  price: 1199.99,
  status: 'published'       // Contextual translation
});

// Delete product
await inkress.products.delete(productId);

// Query builder
const products = await inkress.products
  .createQueryBuilder()
  .whereStatus('published')
  .wherePriceRange(50, 500)
  .whereCategory(5)
  .whereTitleContains('laptop')
  .paginate(1, 20)
  .orderBy('price', 'desc')
  .search('gaming')
  .execute();

Categories Resource

Category management with kind translations:

// List categories with contextual filtering
await inkress.categories.list({ 
  kind: 'published',        // Contextual translation
  q: 'electronics'
});

// Query categories
const categories = await inkress.categories.query({
  kind: ['published', 'featured'],
  parent_id: 1
});

// Get category details
await inkress.categories.get(categoryId);

// Create category with contextual kind
await inkress.categories.create({
  name: 'Electronics',
  description: 'Electronic devices',
  kind: 'published',        // Contextual
  parent_id: null
});

// Update category
await inkress.categories.update(categoryId, { 
  name: 'Updated Name',
  kind: 'featured'          // Contextual
});

// Query builder
const categories = await inkress.categories
  .createQueryBuilder()
  .whereKind('published')
  .whereParent(1)
  .search('electronics')
  .execute();

Orders Resource

Order processing with full status and kind translations:

// Create order with contextual strings
await inkress.orders.create({
  total: 99.99,
  currency_code: 'USD',
  customer: {
    email: '[email protected]',
    first_name: 'John',
    last_name: 'Doe'
  },
  reference_id: 'order-123',
  kind: 'online',           // Contextual: converts to integer
  status: 'pending'         // Contextual: converts to integer
});

// Get order details
await inkress.orders.get(orderId);

// Update order status with contextual string
await inkress.orders.update(orderId, { 
  status: 'confirmed'       // Contextual translation
});

// List orders with contextual filtering
await inkress.orders.list({
  status: 'shipped',        // Contextual
  kind: 'online',          // Contextual
  customer_id: 123,
  q: 'electronics'
});

// Query orders with advanced filters
const orders = await inkress.orders.query({
  status: ['confirmed', 'shipped'],
  kind: ['online', 'subscription'],
  total: { min: 100, max: 1000 },
  reference_id: { contains: 'VIP' },
  inserted_at: { after: '2024-01-01' }
});

// Delete order
await inkress.orders.delete(orderId);

// Get order status (public endpoint)
await inkress.orders.getStatus(orderId);

// Query builder
const orders = await inkress.orders
  .createQueryBuilder()
  .whereStatus(['confirmed', 'shipped'])
  .whereKind('online')
  .whereTotalRange(100, 1000)
  .whereReferenceContains('PREMIUM')
  .whereCustomer(123)
  .paginate(1, 20)
  .execute();

Users Resource

User management with status and kind translations:

// List users with contextual filtering
await inkress.users.list({
  status: 'approved',       // Contextual: account_approved
  kind: 'organisation',     // Contextual: user_organisation
  organisation_id: 123,
  q: 'admin'
});

// Query users
const users = await inkress.users.query({
  status: ['approved', 'active'],
  kind: ['organisation', 'merchant'],
  inserted_at: { after: '2024-01-01' }
});

// Get user details
await inkress.users.get(userId);

// Create user with contextual values
await inkress.users.create({
  email: '[email protected]',
  first_name: 'John',
  last_name: 'Doe',
  password: 'secure-password',
  status: 'pending',        // Contextual
  kind: 'organisation'      // Contextual
});

// Update user with contextual status
await inkress.users.update(userId, { 
  first_name: 'Jane',
  status: 'approved'        // Contextual
});

// Delete user
await inkress.users.delete(userId);

// Query builder
const users = await inkress.users
  .createQueryBuilder()
  .whereStatus('approved')
  .whereKind('organisation')
  .whereOrganisation(123)
  .search('john')
  .execute();

Billing Plans Resource

Billing plan management with kind translations:

// List billing plans
await inkress.billingPlans.list({
  kind: 'subscription',     // Contextual
  status: 'active'
});

// Query plans
const plans = await inkress.billingPlans.query({
  kind: 'subscription',
  public: true,
  amount: { min: 10, max: 100 }
});

// Get plan details
await inkress.billingPlans.get(planId);

// Create billing plan with contextual kind
await inkress.billingPlans.create({
  name: 'Premium Plan',
  amount: 29.99,
  currency: 'USD',
  kind: 'subscription',     // Contextual
  status: 'active'
});

// Update plan
await inkress.billingPlans.update(planId, {
  amount: 24.99,
  status: 'active'
});

// Delete plan
await inkress.billingPlans.delete(planId);

// Query builder
const plans = await inkress.billingPlans
  .createQueryBuilder()
  .whereKind('subscription')
  .wherePublic(true)
  .whereAmountRange(10, 50)
  .execute();

Subscriptions Resource

Subscription management with proper typing for all methods:

// List subscriptions
await inkress.subscriptions.list({
  status: 'active',         // Contextual
  billing_plan_id: 1,
  customer_id: 123
});

// Query subscriptions
const subscriptions = await inkress.subscriptions.query({
  status: ['active', 'trialing'],
  billing_plan_id: [1, 2, 3],
  inserted_at: { after: '2024-01-01' }
});

// Get subscription details
await inkress.subscriptions.get(subscriptionId);

// Create subscription with contextual values
await inkress.subscriptions.create({
  billing_plan_id: 1,
  record: 'customer',
  record_id: 123,
  start_date: '2024-01-01',
  status: 'active',         // Contextual
  kind: 'recurring'         // Contextual
});

// Delete subscription
await inkress.subscriptions.delete(subscriptionId);

// Create subscription link (fully typed)
const link = await inkress.subscriptions.createLink({
  reference_id: 'sub-123',
  title: 'Premium Subscription',
  plan_uid: 'plan-abc',
  customer: {
    first_name: 'John',
    last_name: 'Doe',
    email: '[email protected]'
  }
});
// Returns: CreateSubscriptionLinkResponse

// Charge subscription (fully typed)
const charge = await inkress.subscriptions.charge('sub-uid', {
  reference_id: 'charge-123',
  total: 29.99,
  title: 'Monthly charge'
});
// Returns: ChargeSubscriptionResponse with typed transaction

// Record usage (fully typed)
const usage = await inkress.subscriptions.usage('sub-uid', {
  reference_id: 'usage-123',
  total: 5.00,
  title: 'API calls'
});
// Returns: SubscriptionUsageResponse

// Cancel subscription (fully typed)
const cancelled = await inkress.subscriptions.cancel(123, 'reason-code');
// Returns: SubscriptionCancelResponse

// Get subscription periods
const periods = await inkress.subscriptions.getPeriods('sub-uid', {
  status: 'paid',
  limit: 10
});

// Query builder
const subscriptions = await inkress.subscriptions
  .createQueryBuilder()
  .whereStatus('active')
  .whereBillingPlan(1)
  .whereCustomer(123)
  .execute();

Additional Resources

Payment Links

// List payment links
await inkress.paymentLinks.list({ status: 'active' });

// Create payment link
await inkress.paymentLinks.create({
  title: 'Product Payment',
  amount: 99.99,
  currency: 'USD',
  status: 'active'
});

// Update payment link
await inkress.paymentLinks.update(linkId, { amount: 89.99 });

// Delete payment link
await inkress.paymentLinks.delete(linkId);

Financial Accounts

// List financial accounts
await inkress.financialAccounts.list();

// Create account
await inkress.financialAccounts.create({
  name: 'Main Account',
  type: 'checking',
  currency: 'USD'
});

// Update account
await inkress.financialAccounts.update(accountId, { name: 'Updated Name' });

Tokens

// List tokens
await inkress.tokens.list({ kind: 'api', enabled: true });

// Create token
await inkress.tokens.create({
  title: 'Production API Key',
  provider: 'stripe',
  kind: 'api'
});

// Delete token
await inkress.tokens.delete(tokenId);

Addresses

// List addresses
await inkress.addresses.list({ country: 'US' });

// Create address
await inkress.addresses.create({
  line1: '123 Main St',
  city: 'New York',
  state: 'NY',
  country: 'US',
  postal_code: '10001'
});

// Update address
await inkress.addresses.update(addressId, { line1: '456 Broadway' });

// Delete address
await inkress.addresses.delete(addressId);

Fees

// List fees
await inkress.fees.list({ active: true });

// Create fee
await inkress.fees.create({
  name: 'Processing Fee',
  amount: 2.50,
  percentage: 2.9,
  kind: 'transaction'
});

// Update fee
await inkress.fees.update(feeId, { amount: 2.75 });

// Delete fee
await inkress.fees.delete(feeId);

Exchange Rates & Currencies

// List currencies
await inkress.currencies.list();

// Create currency
await inkress.currencies.create({
  code: 'USD',
  name: 'US Dollar',
  symbol: '$'
});

// List exchange rates
await inkress.exchangeRates.list({ from_currency: 'USD' });

// Create exchange rate
await inkress.exchangeRates.create({
  from_currency: 'USD',
  to_currency: 'EUR',
  rate: 0.85
});

// Update exchange rate
await inkress.exchangeRates.update(rateId, { rate: 0.86 });

Public Resource

Access public merchant information without authentication:

// Get merchant by username or domain
await inkress.public.getMerchant({ username: 'merchant-name' });
await inkress.public.getMerchant({ 'domain.cname': 'store.example.com' });

// Get merchant products with filtering
await inkress.public.getMerchantProducts('merchant-name', {
  search: 'laptop',
  category: 'electronics',
  limit: 20
});

// Get merchant fees (fully typed)
const fees = await inkress.public.getMerchantFees('merchant-name', {
  currency: 'USD',
  total: 100
});
// Returns: PublicMerchantFees

Advanced Query System

The SDK provides a powerful type-safe query system with two interfaces:

1. Direct Query Method

Use the query() method with an intuitive object-based syntax:

// Simple equality
await inkress.orders.query({
  status: 'confirmed',
  customer_id: 123
});

// Array queries (IN operations)
await inkress.orders.query({
  status: ['confirmed', 'shipped', 'delivered'],
  id: [1, 2, 3, 4, 5]
});

// Range queries
await inkress.products.query({
  price: { min: 100, max: 1000 },
  rating: { min: 4 }
});

// String contains
await inkress.products.query({
  title: { contains: 'laptop' },
  description: { contains: 'gaming' }
});

// Date ranges
await inkress.orders.query({
  inserted_at: { after: '2024-01-01', before: '2024-12-31' },
  updated_at: { on: '2024-06-15' }
});

// Complex combined queries
await inkress.orders.query({
  status: ['confirmed', 'shipped'],
  kind: 'online',
  total: { min: 50, max: 500 },
  reference_id: { contains: 'VIP' },
  customer_id: [100, 101, 102],
  inserted_at: { after: '2024-01-01' },
  page: 1,
  page_size: 20,
  q: 'electronics'
});

2. Fluent Query Builder

Use the query builder for a fluent, chainable interface:

// Products query builder
const products = await inkress.products
  .createQueryBuilder()
  .whereStatus('published')
  .whereStatusIn(['published', 'featured'])
  .whereCategory(5)
  .whereCategoryIn([1, 2, 3])
  .wherePriceRange(50, 500)
  .wherePriceMin(50)
  .wherePriceMax(500)
  .whereTitleContains('gaming')
  .whereDescriptionContains('RGB')
  .whereCreatedAfter('2024-01-01')
  .whereCreatedBefore('2024-12-31')
  .whereCreatedBetween('2024-01-01', '2024-12-31')
  .paginate(1, 20)
  .orderBy('price', 'desc')
  .search('laptop')
  .execute();

// Orders query builder
const orders = await inkress.orders
  .createQueryBuilder()
  .whereStatus('confirmed')
  .whereStatusIn(['confirmed', 'shipped'])
  .whereKind('online')
  .whereKindIn(['online', 'subscription'])
  .whereTotalRange(100, 1000)
  .whereReferenceContains('VIP')
  .whereCustomer(123)
  .whereCustomerIn([100, 101, 102])
  .whereCreatedBetween('2024-01-01', '2024-12-31')
  .paginate(1, 20)
  .search('electronics')
  .execute();

// Merchants query builder
const merchants = await inkress.merchants
  .createQueryBuilder()
  .whereStatus('approved')
  .wherePlatformFeeStructure('customer_pay')
  .whereProviderFeeStructure('merchant_absorb')
  .whereOrganisation(123)
  .whereNameContains('coffee')
  .paginate(1, 50)
  .execute();

// Users query builder
const users = await inkress.users
  .createQueryBuilder()
  .whereStatus('approved')
  .whereKind('organisation')
  .whereOrganisation(123)
  .whereEmailContains('@company.com')
  .paginate(1, 50)
  .search('admin')
  .execute();

Query Transformation

The SDK automatically transforms your clean queries into API-compatible format:

// You write:
{
  status: ['confirmed', 'shipped'],
  total: { min: 100, max: 1000 },
  reference_id: { contains: 'VIP' }
}

// SDK transforms to:
{
  status_in: [4, 7],           // Contextual strings → integers with _in suffix
  total_min: 100,              // min/max → _min/_max suffixes
  total_max: 1000,
  "contains.reference_id": "VIP"  // contains → prefix format
}

Available Query Operations

| Operation | Input Syntax | API Output | Description | |-----------|-------------|------------|-------------| | Equality | field: value | field: value | Direct match | | Array (IN) | field: [1,2,3] | field_in: [1,2,3] | Value in array | | Range Min | field: {min: 10} | field_min: 10 | Minimum value | | Range Max | field: {max: 100} | field_max: 100 | Maximum value | | Contains | field: {contains: 'text'} | "contains.field": "text" | String contains | | Date After | field: {after: 'date'} | "after.field": "date" | After date | | Date Before | field: {before: 'date'} | "before.field": "date" | Before date | | Date On | field: {on: 'date'} | "on.field": "date" | Exact date |

Query Builder Methods

All resources with query support provide these methods:

Equality Methods:

  • .whereField(value) - Direct equality
  • .whereFieldIn([values]) - Array IN query

Range Methods:

  • .whereFieldRange(min, max) - Min and max
  • .whereFieldMin(value) - Minimum value
  • .whereFieldMax(value) - Maximum value

String Methods:

  • .whereFieldContains(text) - String contains

Date Methods:

  • .whereCreatedAfter(date) - After date
  • .whereCreatedBefore(date) - Before date
  • .whereCreatedBetween(start, end) - Date range
  • .whereUpdatedAfter(date) - After date
  • .whereUpdatedBefore(date) - Before date

Utility Methods:

  • .paginate(page, pageSize) - Pagination
  • .orderBy(field, direction) - Sorting
  • .search(query) - General search (q parameter)
  • .execute() - Execute the query

Field Type Validation

The SDK validates field types at runtime to prevent API errors:

// Runtime validation ensures correct types
await inkress.products.query({
  price: 99.99,           // ✅ Number field
  unlimited: true,        // ✅ Boolean field
  category_id: 5,         // ✅ Integer field
  inserted_at: '2024-01-01'  // ✅ String field
});

// Type mismatches are caught early
await inkress.products.query({
  price: { contains: 'text' }  // ❌ Error: price is numeric, not string
});

Search and Filtering

All list operations support comprehensive search and filtering capabilities:

General Search with q

Use the q parameter for intelligent searching across multiple relevant fields:

// Search merchants - searches name, email, username, etc.
await inkress.merchants.list({ q: 'john smith' });

// Search products - searches title, description, etc.
await inkress.products.list({ q: 'gaming laptop' });

// Search orders - searches reference ID, customer details, etc.
await inkress.orders.list({ q: 'ORDER-12345' });

String-Based Status and Kind Values

The SDK supports human-readable string values for better code clarity:

// Use descriptive strings for merchants
await inkress.merchants.list({
  status: 'account_approved',
  platform_fee_structure: 'customer_pay',
  q: 'electronics'
});

// Filter orders with readable values
await inkress.orders.list({
  status: 'order_confirmed',
  kind: 'order_online',
  q: 'laptop'
});

// Filter products by status
await inkress.products.list({
  status: 'product_published',
  q: 'smartphone'
});

// Integers also work for backward compatibility
await inkress.merchants.list({
  status: 2,
  platform_fee_structure: 1
});

Available String Values

Status Values:

  • Orders: order_pending, order_confirmed, order_shipped, order_delivered, order_cancelled, etc.
  • Accounts: account_pending, account_approved, account_suspended, etc.
  • Products: product_draft, product_published, product_archived
  • Transactions: transaction_pending, transaction_authorized, transaction_captured, etc.

Kind Values:

  • Orders: order_online, order_offline, order_subscription, order_invoice
  • Products: product_draft, product_published, product_archived
  • Users: user_address, role_organisation, role_store
  • Billing: billing_plan_subscription, billing_plan_payout

Fee Structure Values:

  • customer_pay - Customer pays the fees
  • merchant_absorb - Merchant absorbs the fees

Database Field Filtering

Filter by any database field for precise results:

// Filter products by specific criteria
await inkress.products.list({
  status: 'product_published',  // Published only (string format)
  category_id: 5,               // Specific category
  price: 1000,                 // Exact price
  unlimited: true,             // Unlimited quantity
  inserted_at: '2024-01-01'    // Created after date
});

// Filter merchants by organization
await inkress.merchants.list({
  organisation_id: 123,
  status: 'account_approved',
  platform_fee_structure: 'customer_pay'
});

Combining Search and Filters

Mix general search with specific filters for powerful queries:

await inkress.products.list({
  q: 'phone',                    // General search
  status: 'product_published',   // Published only
  category_id: 5,               // Electronics category
  page: 1,                      // Pagination
  per_page: 20,                 // Results per page
  sort: 'price',                // Sort by price
  order: 'desc'                 // Descending order
});

Legacy Search Field

Many resources still support the legacy search field for backward compatibility:

// Legacy approach (still works)
await inkress.products.list({ search: 'laptop' });

// Recommended approach
await inkress.products.list({ q: 'laptop' });

Error Handling

The SDK provides structured error handling with detailed error information:

try {
  const product = await inkress.products.get(123);
} catch (error) {
  if (error.response?.status === 404) {
    console.log('Product not found');
  } else if (error.response?.status === 422) {
    console.log('Validation errors:', error.response.result);
  } else {
    console.log('Unexpected error:', error.message);
  }
}

TypeScript Support

The SDK is built with TypeScript and provides 100% type safety across all 128+ methods:

Complete Type Coverage

Every method has:

  • ✅ Fully typed input parameters (no any types)
  • ✅ Fully typed return values with specific interfaces
  • ✅ IDE autocomplete for all fields and methods
  • ✅ Compile-time type checking
import { 
  InkressSDK, 
  // Core types
  Product, 
  Category, 
  Order, 
  Merchant,
  User,
  BillingPlan,
  Subscription,
  
  // Create/Update types
  CreateProductData,
  UpdateProductData,
  CreateOrderData,
  UpdateMerchantData,
  CreateUserData,
  
  // Response types
  ApiResponse,
  ProductListResponse,
  OrderListResponse,
  MerchantBalance,
  MerchantLimits,
  MerchantSubscription,
  MerchantInvoice,
  
  // Query types
  ProductQueryParams,
  OrderQueryParams,
  RangeQuery,
  StringQuery,
  
  // Enum types
  OrderStatus,
  OrderKind,
  AccountStatus,
  UserKind,
  FeeStructureKey,
  StatusKey,
  KindKey
} from '@inkress/admin-sdk';

// All responses are properly typed
const response: ApiResponse<ProductListResponse> = await inkress.products.list();
const products: Product[] = response.result?.entries || [];

// Create operations with full typing
const createData: CreateProductData = {
  name: 'Gaming Laptop',
  price: 1299.99,
  category_id: 1,
  status: 'published',
  kind: 'published'
};
const product: ApiResponse<Product> = await inkress.products.create(createData);

// Update operations with full typing
const updateData: UpdateMerchantData = {
  name: 'Updated Store',
  status: 'approved',
  platform_fee_structure: 'customer_pay'
};
await inkress.merchants.update(123, updateData);

// Merchant account methods with specific types
const balances: ApiResponse<MerchantBalance> = await inkress.merchants.balances();
// balances.data: { available: number, pending: number, currency: string }

const limits: ApiResponse<MerchantLimits> = await inkress.merchants.limits();
// limits.data: { transaction_limit: number, daily_limit: number, monthly_limit: number, currency: string }

const subscription: ApiResponse<MerchantSubscription> = await inkress.merchants.subscription();
// subscription.data: { plan_name: string, status: string, billing_cycle: string, price: number, ... }

const invoices: ApiResponse<MerchantInvoice[]> = await inkress.merchants.invoices();
// invoices.data: Array of typed MerchantInvoice objects

// Query with full type safety
const orderQuery: OrderQueryParams = {
  status: ['confirmed', 'shipped'],
  total: { min: 100, max: 1000 },
  reference_id: { contains: 'VIP' },
  page: 1,
  page_size: 20
};
const orders: ApiResponse<OrderListResponse> = await inkress.orders.query(orderQuery);

// Contextual enums for type safety
const status: OrderStatus = 'confirmed';  // Only valid order statuses allowed
const kind: OrderKind = 'online';         // Only valid order kinds allowed
const feeStructure: FeeStructureKey = 'customer_pay';  // Only valid fee structures allowed

Type-Safe Query Building

Query builders provide complete type safety:

// Typed query builder - only valid methods for each field type
const products = await inkress.products
  .createQueryBuilder()
  .whereStatus('published')           // String field - contextual value
  .whereCategory(5)                   // Number field - direct value
  .wherePriceRange(50, 500)          // Number field - range
  .whereTitleContains('gaming')      // String field - contains
  .whereUnlimited(true)              // Boolean field - direct value
  .whereCreatedAfter('2024-01-01')   // Date field - after
  .paginate(1, 20)
  .execute();

// TypeScript ensures you can't use wrong query types
products
  .wherePrice({ contains: 'text' })  // ❌ Compile error: price is numeric
  .whereTitle(123);                  // ❌ Compile error: title is string

Response Type Handling

Handle responses with full type awareness:

async function getProduct(id: number): Promise<Product | null> {
  try {
    const response: ApiResponse<Product> = await inkress.products.get(id);
    
    // TypeScript knows the exact structure
    if (response.result) {
      return response.result;  // Product type
    }
    return null;
  } catch (error) {
    console.error('Failed to fetch product:', error);
    return null;
  }
}

async function listProducts(): Promise<Product[]> {
  const response: ApiResponse<ProductListResponse> = await inkress.products.list();
  
  // TypeScript knows ProductListResponse structure
  const entries = response.result?.entries || [];
  
  // entries is Product[]
  return entries.map(product => ({
    ...product,
    discounted_price: product.price * 0.9  // TypeScript knows price is a number
  }));
}

Discriminated Unions

Use TypeScript's discriminated unions for status/kind handling:

type OrderStatusAction = 
  | { status: 'pending', action: 'await_payment' }
  | { status: 'confirmed', action: 'process_order' }
  | { status: 'shipped', action: 'track_shipment' }
  | { status: 'delivered', action: 'request_feedback' };

async function handleOrder(orderId: number, statusAction: OrderStatusAction) {
  await inkress.orders.update(orderId, { status: statusAction.status });
  
  // TypeScript narrows the type based on status
  switch (statusAction.status) {
    case 'pending':
      // statusAction.action is 'await_payment'
      break;
    case 'confirmed':
      // statusAction.action is 'process_order'
      break;
  }
}

Environment Configuration

Development

const inkress = new InkressSDK({
  accessToken: process.env.INKRESS_DEV_TOKEN,
  mode: 'sandbox',
  username: 'mour-dev-merchant-username'
});

Production

const inkress = new InkressSDK({
  accessToken: process.env.INKRESS_PROD_TOKEN,
  mode: 'live',
  username: 'your-merchant-username'
});

React/Next.js Integration

Server-Side Usage (API Routes)

// pages/api/products.ts or app/api/products/route.ts
import { InkressSDK } from '@inkress/admin-sdk';

const inkress = new InkressSDK({
  accessToken: process.env.INKRESS_TOKEN!,
  username: process.env.INKRESS_USERNAME!
});

export async function GET() {
  const products = await inkress.products.list();
  return Response.json(products);
}

Client-Side Usage (Public Endpoints)

// hooks/usePublicMerchant.ts
import { InkressSDK } from '@inkress/admin-sdk';

const sdk = new InkressSDK({
  accessToken: '', // Empty for public endpoints
  mode: 'live'
});

export async function getPublicMerchant(username: string) {
  return await sdk.public.getMerchant({ username });
}

Best Practices

1. Environment Variables

Store sensitive configuration in environment variables:

INKRESS_TOKEN=your-jwt-token
INKRESS_USERNAME=your-merchant

2. Error Handling

Always implement proper error handling:

async function fetchProducts() {
  try {
    const response = await inkress.products.list();
    return response.result || [];
  } catch (error) {
    console.error('Failed to fetch products:', error);
    return [];
  }
}

3. Rate Limiting

Be mindful of API rate limits and implement appropriate throttling in your application.

4. Caching

Cache frequently accessed data like merchant information and categories:

const merchantCache = new Map();

async function getCachedMerchant(username: string) {
  if (merchantCache.has(username)) {
    return merchantCache.get(username);
  }
  
  const merchant = await inkress.public.getMerchant({ username });
  merchantCache.set(username, merchant);
  return merchant;
}

4. Webhook Verification

Verify incoming webhook requests from Inkress using HMAC SHA256:

import { WebhookUtils } from '@inkress/admin-sdk';

// Method 1: Verify with signature, body, and secret
app.post('/webhooks/inkress', (req, res) => {
  const signature = req.headers['x-inkress-webhook-signature'];
  const body = JSON.stringify(req.body);
  const secret = process.env.INKRESS_WEBHOOK_SECRET;
  
  const isValid = WebhookUtils.verifySignature(body, signature, secret);
  
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Process webhook...
  res.status(200).json({ received: true });
});

// Method 2: Let the SDK extract everything from the request
app.post('/webhooks/inkress', (req, res) => {
  const secret = process.env.INKRESS_WEBHOOK_SECRET;
  
  try {
    const { isValid, body } = WebhookUtils.verifyRequest(req, secret);
    
    if (!isValid) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
    
    // Parse the verified body
    const webhookPayload = WebhookUtils.parsePayload(body);
    
    // Process webhook...
    res.status(200).json({ received: true });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Method 3: Use Express middleware for automatic verification
import { createWebhookMiddleware } from '@inkress/admin-sdk';

app.use('/webhooks/inkress', createWebhookMiddleware(process.env.INKRESS_WEBHOOK_SECRET));

app.post('/webhooks/inkress', (req, res) => {
  // Request is already verified, payload attached to req.webhookPayload
  const { webhookPayload } = req;
  
  console.log(`Received event: ${webhookPayload.event.action}`);
  
  res.status(200).json({ received: true });
});

Webhook Signature Format:

  • Header: X-Inkress-Webhook-Signature
  • Algorithm: HMAC SHA256
  • Encoding: Base64
  • Equivalent to: crypto.mac(:hmac, :sha256, secret, body) |> Base.encode64()

See examples/webhook-server.ts for a complete implementation.

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Migrating from Older Versions

See MIGRATION.md for upgrade instructions and breaking changes between versions.

Support

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

See CHANGELOG.md for a list of changes and version history.


Made with ❤️ by the Inkress team.