# Skakio Catalog API - LLM Quick Reference > **For AI Assistants:** This document provides everything needed to help developers integrate with the Skakio Catalog API. Copy code snippets directly - they are production-ready. ## TL;DR - Minimal Working Example ```typescript // 1. Get token (exchange API key for JWT) const tokenRes = await fetch('https://api.skakio.com/auth/token', { method: 'POST', headers: { 'X-API-Key': 'pk_live_YOUR_KEY' } }); const { data: { token } } = await tokenRes.json(); // 2. Make API calls const storeRes = await fetch('https://api.skakio.com/api/store/STORE_ID', { headers: { 'Authorization': `Bearer ${token}` } }); const { data: store } = await storeRes.json(); ``` --- ## API Overview | Item | Value | |------|-------| | Base URL | `https://api.skakio.com` | | Auth | API Key → JWT Token | | Token TTL | 15 minutes (configurable 1-60 min) | | Response Format | JSON with `{ code, status, data }` wrapper | ### API Key Types | Prefix | Type | Use | Permissions | |--------|------|-----|-------------| | `pk_live_` | Public | Client-side (browsers, mobile) | Read-only | | `sk_live_` | Secret | Server-side only | Full access | | `pk_test_` | Test Public | Development | Read-only, test data | | `sk_test_` | Test Secret | Development | Full access, test data | ### Rate Limits All `/api/*` endpoints require authentication. Rate limits vary by key type: | Key Type | Per Minute | Per Hour | |----------|------------|----------| | Public (pk_) | 100 | 1,000 | | Secret (sk_) | 500 | 5,000 | --- ## Authentication Flow ``` ┌─────────────────────────────────────────────────────────────┐ │ POST /auth/token → Get JWT token (15 min TTL) │ │ POST /auth/refresh → Refresh existing token │ │ POST /auth/validate → Check token validity │ └─────────────────────────────────────────────────────────────┘ ``` ### Get Token ```bash curl -X POST https://api.skakio.com/auth/token \ -H "X-API-Key: pk_live_your_key" ``` **Response:** ```json { "code": 200, "status": "OK", "data": { "token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 900 } } ``` ### Custom Token TTL ```bash curl -X POST https://api.skakio.com/auth/token \ -H "X-API-Key: pk_live_your_key" \ -H "Content-Type: application/json" \ -d '{"ttl_minutes": 30}' ``` ### Refresh Token ```bash curl -X POST https://api.skakio.com/auth/refresh \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." ``` --- ## Core Endpoints ### Catalog API (Read-Only, Requires Authentication) | Endpoint | Description | |----------|-------------| | `GET /api/store/:id` | Get store details | | `GET /api/store/:id/listings` | Get store's listings (categories) | | `GET /api/store/:id/payment-methods` | Get store's payment methods | | `GET /api/listing/:id` | Get listing details | | `GET /api/listing/:id?expand=publication` | Get listing with products | | `GET /api/publication/:id` | Get product details | | `GET /api/publication/:id/related` | Get related products | | `GET /api/publication/:id/reviews` | Get product reviews | | `GET /api/marketplace/search?q=term` | Search products | ### Query Parameters | Param | Type | Description | |-------|------|-------------| | `expand` | string | Include related data: `publication`, `listing`, `media` | | `page` | number | Page number (default: 1) | | `limit` | number | Items per page (default: 20, max: 50) | | `sort` | string | Sort field: `created_at`, `price`, `name` | | `order` | string | Sort order: `asc`, `desc` | ### Example: Get Store with Listings ```bash curl "https://api.skakio.com/api/store/store_abc123?expand=listing" \ -H "Authorization: Bearer TOKEN" ``` ### Example: Get Listing with Products ```bash curl "https://api.skakio.com/api/listing/list_xyz?expand=publication&limit=20" \ -H "Authorization: Bearer TOKEN" ``` ### Example: Search Products ```bash curl "https://api.skakio.com/api/marketplace/search?q=sneakers&limit=10" \ -H "Authorization: Bearer TOKEN" ``` --- ## Response Structures ### Store ```typescript interface Store { id: string; // "store_abc123" name: string; description: string; logo?: { url: string }; banner?: { url: string }; settings: { currency: string; // "USD", "MXN", etc. language: string; }; listings?: Listing[]; // When expanded } ``` ### Listing (Category) ```typescript interface Listing { id: string; // "list_xyz789" name: string; description: string; publicationCount: number; media?: { url: string; alt?: string }[]; publications?: Publication[]; // When expanded } ``` ### Publication (Product) ```typescript interface Publication { id: string; // "pub_123abc" title: string; description: string; price: { amount: number; // 29.99 currency: string; // "USD" }; quantity: { available: number; reserved: number; }; media?: { url: string; alt?: string; type: 'image' | 'video'; }[]; attributes?: { key: string; value: string; }[]; } ``` ### Pagination Response ```typescript interface PaginatedResponse { code: number; status: string; data: T[]; pagination: { page: number; limit: number; totalItems: number; totalPages: number; }; } ``` --- ## Production-Ready Client Class ```typescript const API_BASE = 'https://api.skakio.com'; class SkakioClient { private apiKey: string; private token: string | null = null; private tokenExpiresAt = 0; constructor(apiKey: string) { this.apiKey = apiKey; } private async getToken(): Promise { const now = Date.now(); const buffer = 60_000; // 1 minute buffer if (!this.token || now > this.tokenExpiresAt - buffer) { const res = await fetch(`${API_BASE}/auth/token`, { method: 'POST', headers: { 'X-API-Key': this.apiKey }, }); if (!res.ok) { const error = await res.json(); throw new Error(error.error?.message || 'Failed to get token'); } const { data } = await res.json(); this.token = data.token; this.tokenExpiresAt = now + data.expires_in * 1000; } return this.token!; } async fetch(path: string): Promise { const token = await this.getToken(); const res = await fetch(`${API_BASE}${path}`, { headers: { Authorization: `Bearer ${token}` }, }); if (res.status === 401) { // Token expired, force refresh this.token = null; return this.fetch(path); } if (res.status === 429) { const retryAfter = res.headers.get('Retry-After') || '60'; throw new Error(`Rate limited. Retry after ${retryAfter}s`); } if (!res.ok) { const error = await res.json(); throw new Error(error.error?.message || `API error: ${res.status}`); } const { data } = await res.json(); return data; } } // Usage const api = new SkakioClient('pk_live_your_key'); const store = await api.fetch('/api/store/store_abc123'); const listings = await api.fetch('/api/store/store_abc123/listings'); const products = await api.fetch('/api/listing/list_xyz?expand=publication'); ``` --- ## Framework Integration Patterns ### Next.js (App Router) ```typescript // lib/skakio.ts const api = new SkakioClient(process.env.SKAKIO_API_KEY!); export const STORE_ID = process.env.SKAKIO_STORE_ID!; // app/page.tsx export default async function Home() { const store = await api.fetch(`/api/store/${STORE_ID}`); return

{store.name}

; } ``` ### Astro ```astro --- // src/pages/index.astro const api = new SkakioClient(import.meta.env.SKAKIO_API_KEY); const store = await api.fetch(`/api/store/${import.meta.env.SKAKIO_STORE_ID}`); ---

{store.name}

``` ### React (Client-Side) ```tsx // Use public key only in client-side code const api = new SkakioClient('pk_live_xxx'); function ProductList({ listingId }: { listingId: string }) { const [products, setProducts] = useState([]); useEffect(() => { api.fetch(`/api/listing/${listingId}?expand=publication`) .then(listing => setProducts(listing.publications || [])); }, [listingId]); return products.map(p =>
{p.title}
); } ``` --- ## Error Handling ### Error Response Format ```json { "code": 401, "status": "error", "error": { "code": "TOKEN_EXPIRED", "message": "Token has expired" } } ``` ### Common Error Codes | HTTP | Code | Meaning | Action | |------|------|---------|--------| | 401 | `TOKEN_EXPIRED` | JWT expired | Refresh token | | 401 | `INVALID_API_KEY` | Bad API key | Check key in Studio | | 403 | `STORE_ACCESS_DENIED` | No store access | Check key scope | | 404 | `NOT_FOUND` | Resource missing | Verify ID | | 429 | `RATE_LIMIT_EXCEEDED` | Too many requests | Wait and retry | ### Error Handling Pattern ```typescript try { const data = await api.fetch('/api/store/xxx'); } catch (err) { if (err.message.includes('Rate limited')) { // Wait and retry } else if (err.message.includes('TOKEN_EXPIRED')) { // Token auto-refreshed, retry } else { // Handle other errors console.error(err); } } ``` --- ## Environment Variables ```bash # .env.local (Next.js) or .env (other) SKAKIO_API_KEY=pk_live_your_public_key_here SKAKIO_STORE_ID=store_your_store_id_here # For server-side only operations SKAKIO_SECRET_KEY=sk_live_your_secret_key_here ``` --- ## Quick Checklist for Integration 1. **Get API Key** - Go to `/studio/api-keys` and create a key 2. **Store Key Securely** - Use environment variables, never commit to git 3. **Exchange for Token** - POST to `/auth/token` with `X-API-Key` header 4. **Cache Token** - Reuse until expiry, refresh proactively 5. **Handle 401** - Auto-refresh token on expiry 6. **Handle 429** - Implement backoff and respect `Retry-After` 7. **Use Expand** - Reduce requests by expanding related data --- ## Common Use Cases ### Build a Storefront ```typescript // 1. Get store info const store = await api.fetch(`/api/store/${STORE_ID}`); // 2. Get categories (listings) const listings = await api.fetch(`/api/store/${STORE_ID}/listings`); // 3. Get products in a category const listing = await api.fetch(`/api/listing/${listingId}?expand=publication`); // 4. Get single product const product = await api.fetch(`/api/publication/${productId}`); ``` ### Search Products ```typescript const results = await api.fetch( `/api/marketplace/search?q=${encodeURIComponent(query)}&limit=20` ); ``` ### Paginate Results ```typescript async function* getAllProducts(listingId: string) { let page = 1; let hasMore = true; while (hasMore) { const res = await api.fetch>( `/api/listing/${listingId}/publications?page=${page}&limit=50` ); yield* res.data; hasMore = page < res.pagination.totalPages; page++; } } ``` --- ## Links - **API Keys**: `/studio/api-keys` - **Interactive Reference**: `/docs/api` - **Rate Limits**: `/docs/api/rate-limits` - **Error Codes**: `/docs/api/errors`