Documentación Optimizada para LLM

Copia o descarga esta referencia para pegarla en el contexto de tu asistente de IA para ayuda con la integración de la API de Skakio.

Ver Original

URLs Rápidas: /llms.txt /llms.md

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

// 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

ItemValue
Base URLhttps://api.skakio.com
AuthAPI Key → JWT Token
Token TTL15 minutes (configurable 1-60 min)
Response FormatJSON with { code, status, data } wrapper

API Key Types

PrefixTypeUsePermissions
pk_live_PublicClient-side (browsers, mobile)Read-only
sk_live_SecretServer-side onlyFull access
pk_test_Test PublicDevelopmentRead-only, test data
sk_test_Test SecretDevelopmentFull access, test data

Rate Limits

All /api/* endpoints require authentication. Rate limits vary by key type:

Key TypePer MinutePer Hour
Public (pk_)1001,000
Secret (sk_)5005,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

curl -X POST https://api.skakio.com/auth/token \
  -H "X-API-Key: pk_live_your_key"

Response:

{
  "code": 200,
  "status": "OK",
  "data": {
    "token": "eyJhbGciOiJSUzI1NiIs...",
    "token_type": "Bearer",
    "expires_in": 900
  }
}

Custom Token TTL

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

curl -X POST https://api.skakio.com/auth/refresh \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Core Endpoints

Catalog API (Read-Only, Requires Authentication)

EndpointDescription
GET /api/store/:idGet store details
GET /api/store/:id/listingsGet store’s listings (categories)
GET /api/store/:id/payment-methodsGet store’s payment methods
GET /api/listing/:idGet listing details
GET /api/listing/:id?expand=publicationGet listing with products
GET /api/publication/:idGet product details
GET /api/publication/:id/relatedGet related products
GET /api/publication/:id/reviewsGet product reviews
GET /api/marketplace/search?q=termSearch products

Query Parameters

ParamTypeDescription
expandstringInclude related data: publication, listing, media
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 50)
sortstringSort field: created_at, price, name
orderstringSort order: asc, desc

Example: Get Store with Listings

curl "https://api.skakio.com/api/store/store_abc123?expand=listing" \
  -H "Authorization: Bearer TOKEN"

Example: Get Listing with Products

curl "https://api.skakio.com/api/listing/list_xyz?expand=publication&limit=20" \
  -H "Authorization: Bearer TOKEN"

Example: Search Products

curl "https://api.skakio.com/api/marketplace/search?q=sneakers&limit=10" \
  -H "Authorization: Bearer TOKEN"

Response Structures

Store

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)

interface Listing {
  id: string;              // "list_xyz789"
  name: string;
  description: string;
  publicationCount: number;
  media?: { url: string; alt?: string }[];
  publications?: Publication[];  // When expanded
}

Publication (Product)

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

interface PaginatedResponse<T> {
  code: number;
  status: string;
  data: T[];
  pagination: {
    page: number;
    limit: number;
    totalItems: number;
    totalPages: number;
  };
}

Production-Ready Client Class

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<string> {
    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<T>(path: string): Promise<T> {
    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<Store>('/api/store/store_abc123');
const listings = await api.fetch<Listing[]>('/api/store/store_abc123/listings');
const products = await api.fetch<Publication[]>('/api/listing/list_xyz?expand=publication');

Framework Integration Patterns

Next.js (App Router)

// 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<Store>(`/api/store/${STORE_ID}`);
  return <h1>{store.name}</h1>;
}

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}`);
---
<h1>{store.name}</h1>

React (Client-Side)

// Use public key only in client-side code
const api = new SkakioClient('pk_live_xxx');

function ProductList({ listingId }: { listingId: string }) {
  const [products, setProducts] = useState<Publication[]>([]);

  useEffect(() => {
    api.fetch<Listing>(`/api/listing/${listingId}?expand=publication`)
      .then(listing => setProducts(listing.publications || []));
  }, [listingId]);

  return products.map(p => <div key={p.id}>{p.title}</div>);
}

Error Handling

Error Response Format

{
  "code": 401,
  "status": "error",
  "error": {
    "code": "TOKEN_EXPIRED",
    "message": "Token has expired"
  }
}

Common Error Codes

HTTPCodeMeaningAction
401TOKEN_EXPIREDJWT expiredRefresh token
401INVALID_API_KEYBad API keyCheck key in Studio
403STORE_ACCESS_DENIEDNo store accessCheck key scope
404NOT_FOUNDResource missingVerify ID
429RATE_LIMIT_EXCEEDEDToo many requestsWait and retry

Error Handling Pattern

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

# .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

// 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

const results = await api.fetch(
  `/api/marketplace/search?q=${encodeURIComponent(query)}&limit=20`
);

Paginate Results

async function* getAllProducts(listingId: string) {
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const res = await api.fetch<PaginatedResponse<Publication>>(
      `/api/listing/${listingId}/publications?page=${page}&limit=50`
    );
    yield* res.data;
    hasMore = page < res.pagination.totalPages;
    page++;
  }
}

  • API Keys: /studio/api-keys
  • Interactive Reference: /docs/api
  • Rate Limits: /docs/api/rate-limits
  • Error Codes: /docs/api/errors