SDK Usage Guide
The Arky SDK (arky-sdk) is a TypeScript client library that simplifies integration with Arky’s APIs. It handles authentication, token refresh, API key management, and provides typed interfaces for all endpoints.
Installation
Section titled “Installation”npm install arky-sdkpnpm add arky-sdkyarn add arky-sdkCreating the SDK Instance
Section titled “Creating the SDK Instance”Configuration
Section titled “Configuration”import { createArkySDK } from 'arky-sdk';
const sdk = createArkySDK({ baseUrl: 'https://api.arky.io', storageUrl: 'https://storage.arky.io/prod', businessId: 'your_business_id', market: 'us', getToken: async () => { // Return stored tokens (from localStorage, cookies, etc.) return { accessToken: localStorage.getItem('accessToken') || '', refreshToken: localStorage.getItem('refreshToken') || '', provider: localStorage.getItem('provider') || 'GUEST', expiresAt: parseInt(localStorage.getItem('expiresAt') || '0'), }; }, setToken: (tokens) => { // Store tokens securely localStorage.setItem('accessToken', tokens.accessToken); if (tokens.refreshToken) { localStorage.setItem('refreshToken', tokens.refreshToken); } if (tokens.provider) { localStorage.setItem('provider', tokens.provider); } if (tokens.expiresAt) { localStorage.setItem('expiresAt', tokens.expiresAt.toString()); } }, logout: () => { // Clear tokens on logout localStorage.clear(); window.location.href = '/login'; }, autoGuest: true, // Automatically create guest token if none exists isAuthenticated: () => { return !!localStorage.getItem('accessToken'); },});Config Options
Section titled “Config Options”| Option | Type | Required | Default | Description |
|---|---|---|---|---|
baseUrl | string | ✅ | — | API base URL (e.g., https://api.arky.io) |
storageUrl | string | ❌ | https://storage.arky.io/dev | CDN base URL for media files |
businessId | string | ✅ | — | Your business ID |
market | string | ✅ | — | Market/zone code (e.g., us, eu, global) |
getToken | () => Promise<AuthTokens> | ✅ | — | Function to retrieve stored tokens |
setToken | (tokens) => void | ✅ | — | Function to persist tokens |
logout | () => void | ✅ | — | Function to clear auth and redirect |
autoGuest | boolean | ❌ | true | Auto-create guest token on init |
isAuthenticated | () => boolean | ❌ | () => false | Check if user is authenticated |
Per-call callbacks (non-GET)
Section titled “Per-call callbacks (non-GET)”You can pass callbacks to handle success/error locally for mutating requests. GET requests do not invoke callbacks.
await sdk.user.updateUser({ name: 'Alice' }, { onSuccess: ({ data }) => toast('Profile updated'), onError: ({ error }) => toast(error.message || 'Update failed'),});Authentication Flows
Section titled “Authentication Flows”Guest Tokens (Anonymous Users)
Section titled “Guest Tokens (Anonymous Users)”If autoGuest: true (default), the SDK automatically creates a guest token on initialization if no tokens exist.
const sdk = createArkySDK({ // ... config autoGuest: true, // Guest token created automatically});
// No manual login needed for browsing products, CMS content, etc.const products = await sdk.eshop.products.list({ page: 1, limit: 20 });Email + Password Login
Section titled “Email + Password Login”const result = await sdk.user.login({ password: 'secure_password', provider: 'EMAIL',});
// Tokens are automatically stored via setToken()console.log(result.user); // User objectOAuth (Google)
Section titled “OAuth (Google)”// Redirect user to Google OAuthwindow.location.href = `https://api.arky.io/v1/users/oauth/google?businessId=your_business_id&redirectUrl=${encodeURIComponent(window.location.origin + '/auth/callback')}`;
// On callback page, extract code from query paramsconst urlParams = new URLSearchParams(window.location.search);const code = urlParams.get('code');
if (code) { const result = await sdk.user.loginWithOAuth({ provider: 'GOOGLE', code, }); // Tokens stored, user logged in}Refresh Token Flow
Section titled “Refresh Token Flow”The SDK automatically refreshes tokens when the access token expires (using expiresAt timestamp).
// No manual refresh needed — SDK handles it internallyconst profile = await sdk.user.getProfile(); // Automatically refreshes if expiredLogout
Section titled “Logout”// Clear tokens and redirect (via logout callback)sdk.logout();API Modules
Section titled “API Modules”The SDK is organized into domain-specific modules:
sdk.user // User auth, profile, phone verificationsdk.business // Business CRUD, subscriptions, invitationssdk.media // File upload, media librarysdk.role // Role/permission managementsdk.notification // Notifications, email trackingsdk.promoCode // Promo codes CRUDsdk.analytics // Metrics query, health checksdk.cms // Collections, entries, AI blocks, newsletter subscriptionssdk.eshop // Products, orders, checkoutsdk.reservation // Services, providers, reservationssdk.payment // Quote engine, markets, Stripe webhooksCommon SDK Usage
Section titled “Common SDK Usage”Fetching CMS Content
Section titled “Fetching CMS Content”// List collectionsconst collections = await sdk.cms.collections.list({ page: 1, limit: 50,});
// Get a collectionconst collection = await sdk.cms.collections.get('collection_id');
// List entriesconst entries = await sdk.cms.entries.list('collection_id', { page: 1, limit: 20, hydrate: true, // Hydrate relationships});
// Get single entryconst entry = await sdk.cms.entries.get('collection_id', 'entry_id', { hydrate: true,});E-shop Operations
Section titled “E-shop Operations”// List productsconst products = await sdk.eshop.products.list({ page: 1, limit: 20, search: 'laptop', categoryId: 'cat_123',});
// Get product with pricingconst product = await sdk.eshop.products.get('prod_123');
// Create order (checkout)const order = await sdk.eshop.orders.create({ marketId: 'market_us', parts: [ { productId: 'prod_123', quantity: 2, blocks: [], // Optional custom fields }, ], blocks: [], // Customer info blocks payment: { provider: 'STRIPE', currency: 'usd', amount: 9999, // In cents },});
// List user ordersconst orders = await sdk.eshop.orders.list({ page: 1, limit: 10 });Reservations
Section titled “Reservations”// List servicesconst services = await sdk.reservation.services.list({ page: 1, limit: 20 });
// Get available slotsconst slots = await sdk.reservation.slots.getAvailable({ serviceId: 'service_123', providerId: 'provider_456', date: '2025-02-01',});
// Create reservationconst reservation = await sdk.reservation.reservations.create({ serviceId: 'service_123', providerId: 'provider_456', startTime: 1706803200, endTime: 1706806800, marketId: 'market_us', parts: [{ serviceId: 'service_123', quantity: 1, blocks: [] }], blocks: [], // Customer info payment: { provider: 'STRIPE', currency: 'usd', amount: 5000, },});Newsletter Subscription
Section titled “Newsletter Subscription”Newsletters are Collections with type: 'NEWSLETTER'. See CMS API - Newsletters for full details.
// Subscribe to newsletter (requires planId)await sdk.cms.subscribeToCollection({ collectionId: 'newsletter_123', planId: 'plan_free', // Required - specify which plan});
// Get subscribersconst subscribers = await sdk.cms.getCollectionSubscribers({ id: 'newsletter_123',});
// Unsubscribe via token (from email link)await sdk.cms.unsubscribeFromCollection({ token: 'unsubscribe_token_xyz',});Utility Functions
Section titled “Utility Functions”The SDK includes utility functions for common operations:
Block Utilities
Section titled “Block Utilities”import { getBlockValue, getBlockTextValue, extractBlockValues } from 'arky-sdk/utils/blocks';
const entry = await sdk.cms.entries.get('posts', 'post_123');
// Extract single block valueconst title = getBlockValue(entry, 'title'); // Returns first value
// Extract localized textconst description = getBlockTextValue( entry.blocks.find(b => b.key === 'description'), 'en');
// Extract all block values as objectconst values = extractBlockValues(entry.blocks);// { title: "...", body: "...", featured: true }See Blocks Guide for full block utilities documentation.
Price Utilities
Section titled “Price Utilities”const product = await sdk.eshop.products.get('prod_123');
// Get price for current marketconst price = sdk.utils.getMarketPrice(product.prices, sdk.getMarket());console.log(price.currency, price.amount); // 'usd', 2999
// Format price (cents to dollars)const formatted = sdk.utils.formatMinor(price.amount, price.currency);console.log(formatted); // "$29.99"
// Get currency symbolconst symbol = sdk.utils.getCurrencySymbol('eur');console.log(symbol); // "€"Text Utilities
Section titled “Text Utilities”// Slugify (URL-safe strings)const slug = sdk.utils.slugify('Hello World! 123');console.log(slug); // "hello-world-123"
// Humanize (convert snake_case to Title Case)const label = sdk.utils.humanize('product_name');console.log(label); // "Product Name"
// Format dateconst formatted = sdk.utils.formatDate(1706803200, 'en-US');console.log(formatted); // "Feb 1, 2025"Timezone Utilities
Section titled “Timezone Utilities”// Get timezone groups (for select dropdowns)const tzGroups = sdk.utils.tzGroups;console.log(tzGroups[0]); // { label: "United States", zones: [...] }
// Find timezone by city/countryconst tz = sdk.utils.findTimeZone('New York');console.log(tz); // "America/New_York"Validation
Section titled “Validation”// Validate phone number (E.164 format)const isValid = sdk.utils.validatePhoneNumber('+12345678901');console.log(isValid); // true or falseAPI Keys vs. JWT Tokens
Section titled “API Keys vs. JWT Tokens”JWT Tokens (User Auth)
Section titled “JWT Tokens (User Auth)”- Used for user-facing apps (React, Vue, Svelte, mobile)
- Stored in
localStorage/ cookies - Automatically refreshed via
refreshToken - Sent as
Authorization: Bearer <token>header
API Keys
Section titled “API Keys”- Used for server-side integrations (Astro SSR, Node.js backends)
- Stored securely in
.envor secrets manager - Never expire (rotate manually)
- Sent as
X-API-Key: <key>header
Example: Server-side SDK with API Key
const sdk = createArkySDK({ baseUrl: process.env.API_URL, businessId: process.env.BUSINESS_ID, market: 'us', getToken: async () => ({ accessToken: process.env.ARKY_API_KEY, provider: 'API', }), setToken: () => {}, logout: () => {}, autoGuest: false,});
const products = await sdk.eshop.products.list({ page: 1, limit: 50 });Error Handling
Section titled “Error Handling”All SDK methods can throw errors with the following structure:
try { const product = await sdk.eshop.products.get('invalid_id');} catch (error: any) { console.error('Error name:', error.name); // "ApiError", "NetworkError", "ParseError" console.error('Status code:', error.statusCode); // 404, 401, 500, etc. console.error('Message:', error.message); // Human-readable error console.error('Request ID:', error.requestId); // For debugging with support console.error('Validation errors:', error.validationErrors); // Field-level errors}Error Types
Section titled “Error Types”| Error Name | Description |
|---|---|
ApiError | Server returned an error (4xx/5xx) |
NetworkError | Network failure (timeout, no connection) |
ParseError | Failed to parse JSON response |
Validation Errors
Section titled “Validation Errors”When the API returns validation errors (e.g., invalid email format), they’re available in error.validationErrors:
try { await sdk.user.register({ email: 'invalid', password: '123' });} catch (error: any) { console.log(error.validationErrors); // { // email: ["Invalid email format"], // password: ["Password must be at least 8 characters"] // }}Best Practices
Section titled “Best Practices”Token Storage
Section titled “Token Storage”- Browser apps: Use
localStorageorsessionStorage(simplest, suitable for most cases) - Server apps: Use environment variables or secrets manager
- Mobile apps: Use secure storage (Keychain, Keystore)
Market Switching
Section titled “Market Switching”If your app supports multiple markets/regions:
// Switch market dynamicallysdk.setMarket('eu');
// Fetch products with new market pricingconst products = await sdk.eshop.products.list({ page: 1, limit: 20 });Multi-Business Apps
Section titled “Multi-Business Apps”If your app serves multiple businesses:
// Switch business dynamicallysdk.setBusinessId('another_business_id');
// Fetch collections for new businessconst collections = await sdk.cms.collections.list({ page: 1, limit: 50 });Pagination
Section titled “Pagination”Always handle pagination for large datasets:
let page = 1;let allProducts = [];let hasMore = true;
while (hasMore) { const products = await sdk.eshop.products.list({ page, limit: 100 }); allProducts = [...allProducts, ...products]; hasMore = products.length === 100; page++;}TypeScript Support
Section titled “TypeScript Support”The SDK is fully typed. Import types directly:
import type { Business, Product, Order, Reservation, Entry } from 'arky-sdk';
const product: Product = await sdk.eshop.products.get('prod_123');const order: Order = await sdk.eshop.orders.create({ ... });Related Guides
Section titled “Related Guides”- Blocks System — Working with block utilities
- Business API — Business management
- CMS API — Content management
- E-shop API — Products and orders
- Reservations API — Bookings and services