@diffsome/sdk
Official TypeScript SDK for Diffsome - Headless CMS + E-commerce + Reservation Diffsome 공식 TypeScript SDK - 헤드리스 CMS + 이커머스 + 예약 시스템
Installation
npm install @diffsome/sdk
or with yarn: yarn add @diffsome/sdk | pnpm: pnpm add @diffsome/sdk
또는 yarn: yarn add @diffsome/sdk | pnpm: pnpm add @diffsome/sdk
Quick Start
import { Diffsome } from '@diffsome/sdk'
// Initialize the client
const client = new Diffsome({
tenantId: 'your-tenant-id',
apiKey: 'pky_xxxxxxxxxxxxxxxx', // Dashboard > Settings > API Tokens
baseUrl: 'https://www.superselling.co.kr', // optional
// Token persistence (auto login)
persistToken: true,
storageType: 'localStorage', // or 'sessionStorage'
onAuthStateChange: (token, user) => {
console.log('Auth changed:', user)
}
})
// Ready to use!
const { data: posts } = await client.blog.list()
const { data: products } = await client.shop.listProducts()
API Key Required: Get your API key from Dashboard > Settings > API Tokens API Key 필수: Dashboard > 설정 > API 토큰에서 API 키를 발급받으세요
Available Resources 사용 가능한 리소스
client.site
Site info, currency & price formatting 사이트 정보, 통화 & 가격 포맷
getInfo, getCurrency, formatPrice
client.auth
Authentication & member management 인증 & 회원 관리
login, register, logout, me, social
client.blog
Blog posts with categories & tags 카테고리 & 태그 지원 블로그
list, get, featured, byCategory, byTag
client.boards
Community boards & posts 커뮤니티 게시판 & 게시글
list, listPosts, createPost, updatePost
client.shop
E-commerce: products, cart, orders 이커머스: 상품, 장바구니, 주문
listProducts, getCart, createOrder
client.reservation
Booking system 예약 시스템
listServices, getAvailableSlots, create
client.forms
Dynamic form submissions 동적 폼 제출
list, get, submit, mySubmissions
client.comments
Unified comments (board, blog, standalone) 통합 댓글 (게시판, 블로그, 독립)
boardPost, blogPost, standalone, like
client.entities
Custom entities (dynamic data) 커스텀 엔티티 (동적 데이터)
list, listRecords, createRecord, typed
client.chat
Real-time live chat with WebSocket WebSocket 실시간 채팅
start, connect, send, poll, close
Site
Get site information, settings, and currency configuration 사이트 정보, 설정, 통화 구성 조회
// Get site info & settings
const info = await client.site.getInfo()
console.log(info.name, info.description)
// Get currency settings
const currency = await client.site.getCurrency()
// Format price with currency
const formatted = client.site.formatPrice(50000)
// -> "₩50,000" or "$50.00"
Authentication
Token Persistence 토큰 자동 저장
With persistToken: true, tokens are automatically saved to localStorage and restored on page reload.
persistToken: true 설정 시 토큰이 localStorage에 자동 저장되고 페이지 새로고침 시 복원됩니다.
Login / Register
// Register
await client.auth.register({
name: 'John Doe',
email: 'john@example.com',
password: 'password',
password_confirmation: 'password'
})
// Login (token auto-saved with persistToken)
const { member, token } = await client.auth.login({
email: 'john@example.com',
password: 'password'
})
// Logout (token auto-deleted)
await client.auth.logout()
// Check auth status
client.auth.isAuthenticated() // true/false
// Get current user
const me = await client.auth.me()
// Update profile
await client.auth.updateProfile({ name: 'New Name' })
Social Login
// Get available providers
const providers = await client.auth.getSocialProviders()
// ['google', 'kakao', 'naver']
// Get auth URL and redirect
const { url } = await client.auth.getSocialAuthUrl('google')
window.location.href = url
// Handle callback (after redirect back)
const { member, token } = await client.auth.socialCallback('google', code)
Password Reset
// Request password reset email
await client.auth.forgotPassword({ email: 'john@example.com' })
// Reset password with token
await client.auth.resetPassword({
token: 'reset-token',
email: 'john@example.com',
password: 'newpassword',
password_confirmation: 'newpassword'
})
Token Management
// Set token manually
client.auth.setToken('token_string')
// Get current token
const token = client.auth.getToken()
Blog
// List posts with pagination & filters
const { data, meta } = await client.blog.list({
page: 1,
per_page: 10,
category: 'tech',
tag: 'laravel',
search: 'keyword'
})
// Get single post by slug
const post = await client.blog.get('my-post-slug')
// Featured posts
const featured = await client.blog.featured(5)
// Filter by category or tag
const { data } = await client.blog.byCategory('news')
const { data } = await client.blog.byTag('featured')
// Get all categories & tags
const categories = await client.blog.categories() // string[]
const tags = await client.blog.tags() // string[]
// Get post by ID
const post = await client.blog.getById(123)
// Search posts
const { data } = await client.blog.search('keyword', { per_page: 10 })
Boards
// List boards
const { data: boards } = await client.boards.list()
// Get board by slug
const board = await client.boards.get('notices')
// List posts in a board
const { data: posts } = await client.boards.listPosts('notices', {
page: 1,
per_page: 10,
search: 'keyword'
})
// Get single post
const post = await client.boards.getPost(postId)
// Create post (auth required)
await client.boards.createPost({
board_id: 1,
title: 'Post Title',
content: 'Post content...',
is_secret: false
})
// Update & delete post
await client.boards.updatePost(postId, { title: 'New Title' })
await client.boards.deletePost(postId)
// Board-level comments
const { data: comments } = await client.boards.listComments(postId)
await client.boards.createComment(postId, { content: 'Nice post!' })
await client.boards.updateComment(commentId, { content: 'Updated' })
await client.boards.deleteComment(commentId)
Shop - Products
// List products with filters
const { data: products } = await client.shop.listProducts({
category: 'electronics',
is_featured: true,
min_price: 10000,
max_price: 50000,
search: 'keyword'
})
// Get product by slug
const product = await client.shop.getProduct('product-slug')
// Featured products
const featured = await client.shop.featuredProducts(8)
// Categories
const categories = await client.shop.listCategories()
// Search products
const { data } = await client.shop.searchProducts('hoodie', { per_page: 10 })
// Product types
const digital = await client.shop.getDigitalProducts()
const subscriptionProducts = await client.shop.getSubscriptionProducts()
const bundles = await client.shop.getBundleProducts()
const items = await client.shop.getBundleItems('bundle-slug')
Product Reviews
// Get reviews with stats
const { data: reviews, stats } = await client.shop.getProductReviews('product-slug', {
page: 1,
per_page: 10,
rating: 5 // filter by rating
})
// stats = { average_rating: 4.5, total_count: 123, rating_counts: { 5: 80, 4: 30, ... } }
// Write review (auth + purchase required)
await client.shop.createReview('product-slug', {
rating: 5,
title: 'Great product!',
content: 'Highly recommended.',
images: ['https://...']
})
// Update & delete review
await client.shop.updateReview(reviewId, { rating: 4 })
await client.shop.deleteReview(reviewId)
// Mark as helpful
await client.shop.markReviewHelpful(reviewId)
// My reviews
const { data: myReviews } = await client.shop.myReviews()
Cart & Orders
Authentication required for cart and order operations 장바구니 및 주문 기능은 인증이 필요합니다
// Cart operations
const cart = await client.shop.getCart()
await client.shop.addToCart({
product_id: 1,
quantity: 2,
variant_id: 3 // optional, for variants
})
await client.shop.updateCartItem(itemId, { quantity: 3 })
await client.shop.removeFromCart(itemId)
await client.shop.clearCart()
// Create order
const order = await client.shop.createOrder({
orderer_name: 'John Doe',
orderer_email: 'john@example.com',
orderer_phone: '010-1234-5678',
shipping_name: 'John Doe',
shipping_phone: '010-1234-5678',
shipping_zipcode: '12345',
shipping_address: '서울시 강남구',
shipping_address_detail: '101동 101호',
shipping_memo: '부재시 경비실',
coupon_code: 'SAVE10' // optional
})
// Order management
const { data: orders } = await client.shop.listOrders()
const orderDetail = await client.shop.getOrder(orderId)
await client.shop.cancelOrder(orderId)
// Coupon validation
const result = await client.shop.validateCoupon('SAVE10', 50000)
// { valid: true, discount_amount: 5000, coupon: { ... } }
// My coupons
const coupons = await client.shop.myCoupons()
Wishlist
Wishlist management (authentication required) 위시리스트 관리 (인증 필요)
// Get wishlist
const { data: wishlist } = await client.shop.getWishlist()
// Add to wishlist
await client.shop.addToWishlist({ product_id: 1, variant_id: 3 })
// Remove from wishlist
await client.shop.removeFromWishlist(wishlistId)
// Toggle wishlist
await client.shop.toggleWishlist(productId, variantId)
// Check if product is in wishlist
const inWishlist = await client.shop.isInWishlist(productId)
// Get wishlist count
const count = await client.shop.getWishlistCount()
// Move wishlist items to cart
await client.shop.moveWishlistToCart([wishlistId1, wishlistId2])
Digital Downloads
Access digital product downloads (authentication required) 디지털 상품 다운로드 (인증 필요)
// My downloads
const { data: downloads } = await client.shop.getMyDownloads()
// Downloads for a specific order
const { data: orderDownloads } = await client.shop.getOrderDownloads('ORD-123')
// Get download URL
const { url } = await client.shop.getDownloadUrl('download-token')
Subscriptions
Manage product subscriptions (authentication required) 상품 구독 관리 (인증 필요)
// List subscriptions
const { data: subs } = await client.shop.getSubscriptions()
// Get subscription details
const sub = await client.shop.getSubscription(subId)
// Create subscription
await client.shop.createSubscription({ product_id: 1, payment_method: 'stripe' })
// Cancel subscription
await client.shop.cancelSubscription(subId, true)
// Pause & resume
await client.shop.pauseSubscription(subId)
await client.shop.resumeSubscription(subId)
Payments
Supports Toss Payments (Korea), Stripe (Global), and Nice Payments (Korea) 토스페이먼츠(한국), Stripe(글로벌), 나이스페이먼츠(한국) 지원
Toss Payments
// Prepare payment (deprecated - use tossPaymentReady)
const payment = await client.shop.preparePayment({
order_number: 'ORD-123',
success_url: 'https://mysite.com/payment/success',
fail_url: 'https://mysite.com/payment/fail'
})
// payment = { client_key, order_id, order_name, amount, customer_name, ... }
// Confirm payment (deprecated - use tossPaymentConfirm)
await client.shop.confirmPayment({
payment_key: 'toss_payment_key',
order_id: 'ORD-123',
amount: 50000
})
Stripe Payments
// Stripe Checkout
const { url } = await client.shop.stripeCheckout({
order_number: 'ORD-123',
success_url: 'https://mysite.com/success',
cancel_url: 'https://mysite.com/cancel'
})
// Verify payment
await client.shop.stripeVerify({ session_id: 'cs_xxx' })
// Refund
await client.shop.stripeRefund('ORD-123', 'Customer request', 50000)
Nice Payments
// Prepare payment
const payment = await client.shop.nicePaymentReady({
order_number: 'ORD-123',
amount: 50000
})
// Confirm payment
await client.shop.nicePaymentConfirm({ tid: 'nice_tid', amount: 50000 })
// Cancel payment
await client.shop.nicePaymentCancel('ORD-123', 'Reason', 50000)
Reservation
// Public APIs
const settings = await client.reservation.getSettings()
const services = await client.reservation.listServices()
const staff = await client.reservation.listStaff(serviceId)
// Check available dates
const dates = await client.reservation.getAvailableDates({
service_id: 1,
staff_id: 2,
start_date: '2026-01-01',
end_date: '2026-01-31'
})
// Check available time slots
const slots = await client.reservation.getAvailableSlots({
service_id: 1,
date: '2026-01-15',
staff_id: 2
})
// Create reservation (auth required)
await client.reservation.create({
service_id: 1,
staff_id: 2,
reservation_date: '2026-01-15',
start_time: '14:00',
customer_name: 'John Doe',
customer_phone: '010-1234-5678',
customer_email: 'john@example.com',
notes: 'Special request'
})
// Manage reservations
const { data } = await client.reservation.list({ status: 'confirmed' })
const upcoming = await client.reservation.upcoming(5)
const past = await client.reservation.past(10)
// Get reservation details
const reservation = await client.reservation.get('RES-20260115-001')
// Cancel reservation
await client.reservation.cancel('RES-20260115-001', 'Schedule change')
Forms
// List forms
const { data: forms } = await client.forms.list()
// Get form with field definitions
const form = await client.forms.get('contact')
// Submit form
await client.forms.submit('contact', {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello!'
})
// My submissions (auth required)
const { data: submissions } = await client.forms.mySubmissions()
// Get single submission
const submission = await client.forms.getSubmission(submissionId)
Media
File upload and management (authentication required) 파일 업로드 및 관리 (인증 필요)
// Upload file
const media = await client.media.upload(file)
// Upload multiple files
const mediaList = await client.media.uploadMultiple([file1, file2])
// List my media
const { data: myMedia } = await client.media.list({ type: 'image/jpeg' })
// Delete media
await client.media.delete(mediaId)
Custom Entities
Create and manage dynamic data structures 동적 데이터 구조 생성 및 관리
// Entity definitions
const entities = await client.entities.list()
const entity = await client.entities.get('customers')
// Create entity
await client.entities.create({
name: 'Customer',
slug: 'customers',
schema: {
fields: [
{ name: 'company', label: 'Company', type: 'text', required: true },
{ name: 'email', label: 'Email', type: 'email', required: true },
{ name: 'status', label: 'Status', type: 'select', options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' }
]}
]
}
})
// Records CRUD
const { data: records } = await client.entities.listRecords('customers', {
search: 'ACME',
filters: JSON.stringify({ status: 'active' })
})
const record = await client.entities.getRecord('customers', 1)
await client.entities.createRecord('customers', {
company: 'ACME Corp',
email: 'contact@acme.com',
status: 'active'
})
await client.entities.updateRecord('customers', 1, { status: 'inactive' })
await client.entities.deleteRecord('customers', 1)
// Update & delete entity definitions
await client.entities.update('customers', { name: 'Updated Name' })
await client.entities.delete('customers')
await client.entities.delete('customers', true) // force delete with records
Typed Entities
interface Customer {
company: string
email: string
status: 'active' | 'inactive'
}
const customers = client.entities.typed<Customer>('customers')
const { data } = await customers.list() // data: Customer[]
TypeScript Support
Full TypeScript support with auto-generated types for all API responses. 모든 API 응답에 대해 자동 생성된 타입과 함께 완전한 TypeScript 지원.
import {
Diffsome,
// Types
Product,
BlogPost,
BoardPost,
Member,
Order,
Reservation,
ListResponse,
PromptlyError
} from '@diffsome/sdk'
// All responses are fully typed
const products: Product[] = await client.shop.listProducts()
const posts: BlogPost[] = await client.blog.list()
// List response type
interface ListResponse<T> {
data: T[]
meta: {
current_page: number
last_page: number
per_page: number
total: number
from: number | null
to: number | null
}
}
Error Handling
import { Diffsome, PromptlyError } from '@diffsome/sdk'
try {
await client.auth.login({
email: 'wrong@email.com',
password: 'wrong'
})
} catch (error) {
if (error instanceof PromptlyError) {
console.log(error.message) // "Invalid credentials"
console.log(error.status) // 401
console.log(error.errors) // { email: ["Invalid email or password"] }
}
}
Chat
Real-time live chat with WebSocket support (falls back to polling) WebSocket 지원 실시간 채팅 (폴링 폴백)
Available Methods
| Method | Description |
|---|---|
configureWebSocket(config) | Configure WebSocket connection |
start(data) | Start a conversation |
list(params) | List conversations |
get(conversationId) | Get conversation details |
send(conversationId, data) | Send a message |
getMessages(conversationId, params) | Get messages |
poll(conversationId, lastMessageId) | Poll for new messages |
close(conversationId) | Close conversation |
sendTyping(conversationId) | Send typing indicator |
checkAvailability() | Check agent availability |
connect(conversationId) | Real-time connection (WebSocket/polling) |
setVisitorId(visitorId) | Set visitor ID |
getVisitorId() | Get visitor ID |
Usage Example
@diffsome/react
React hooks & components for Diffsome SDK
Installation
npm install @diffsome/sdk @diffsome/react
Peer dependency: react >= 18
Quick Start
import { Diffsome } from '@diffsome/sdk'
import { useProducts, useCart, useAuth, ChatBubble } from '@diffsome/react'
import '@diffsome/react/chat.css'
const client = new Diffsome({
tenantId: 'my-shop',
apiKey: 'pky_...'
})
function App() {
const { products, loading } = useProducts(client)
const { cart, addToCart } = useCart(client)
const { user, login, logout } = useAuth(client)
return (
<div>
{products.map(p => (
<div key={p.id}>
<h2>{p.name}</h2>
<button onClick={() => addToCart(p.id)}>Add to Cart</button>
</div>
))}
<ChatBubble client={client} />
</div>
)
}
Hooks Reference
| Category | Hook | Description |
|---|---|---|
| Site | useSite | Site info, settings, theme |
useCurrency | Currency formatting helper | |
| Auth | useAuth | Login, register, logout, current user |
useSocialAuth | Google, Kakao, Naver OAuth login | |
| Shop | useProducts | Product list with filters, pagination |
useProduct | Single product by slug | |
useCategories | Product categories | |
useCart | Cart management (add, remove, update qty) | |
useWishlist | Wishlist toggle & list | |
useOrders | Order history & details | |
| Payment | usePaymentStatus | Available payment methods |
useTossPayment | Toss Payments integration | |
useNicePayment | NicePay integration | |
useStripePayment | Stripe integration | |
| Blog | useBlog | Blog posts with pagination |
useBlogPost | Single blog post by slug | |
useBlogCategories | Blog categories & tags | |
| Board | useBoards | Board list |
useBoardPosts | Posts in a board | |
useCreateBoardPost | Create new board post | |
| Comments | useComments | CRUD for post, blog, page comments |
| Reviews | useProductReviews | Product reviews list |
useCreateReview | Submit a review | |
useCanReview | Check if user can review | |
| Reservation | useReservationServices | Available services & staff |
useAvailableSlots | Available time slots | |
useCreateReservation | Book a reservation | |
| Forms | useForm | Load form schema & submit |
| Media | useMedia | Upload & list media files |
| Chat | useChat | Live chat messaging |
| Entities | useEntityRecords | Custom entity record list |
useTypedEntity | Typed entity with generics | |
| Coupons | useCoupons | List & validate coupons |
| Subscriptions | useSubscriptions | Subscription plans & management |
| Downloads | useDownloads | Digital product downloads |
Components
<ChatBubble />
Drop-in live chat widget. Floating bubble with expandable chat window.
import { ChatBubble } from '@diffsome/react'
import '@diffsome/react/chat.css'
<ChatBubble
client={client}
position="bottom-right"
greeting="How can we help?"
/>
<RichContent />
Renders HTML content from blog posts and board posts safely.
import { RichContent } from '@diffsome/react'
<RichContent html={post.content} />
Changelog
v3.4.0
- Chat resource with WebSocket & polling support
- Site resource (info, currency, price formatting)
- Wishlist API (add, remove, toggle, move to cart)
v3.3.0
- Stripe payments (checkout, verify, refund)
- Nice payments (ready, confirm, cancel)
v3.2.0
- Digital downloads API
- Subscription products management
v3.1.0
- Product search API
- Bundle products support
v3.0.0
- Major release with improved TypeScript types
- Consistent API naming conventions
- Enhanced error handling
v2.18.0
- Product review API
- Shipping settings API
v2.15.0
- Toss Payments integration
v2.12.0
- Blog category/tag filters
- Added
category,tags,views,published_atfields
v2.10.0
persistTokenoption for auto token persistenceonAuthStateChangecallbackstorageTypeoption
v2.5.0
- Board secret post support (
is_secret,is_mine)
v2.3.0
- Polymorphic comments API (board, blog, standalone)
v2.0.0
- Breaking: API key required
Comments
Unified comment system supporting board posts, blog posts, and standalone pages (guestbook, feedback, etc.) 게시판, 블로그, 독립 페이지(방명록, 피드백 등)를 지원하는 통합 댓글 시스템