레시피
가장 일반적인 커머스 워크플로우를 위한 실용적인 코드 예제입니다. 모든 레시피는 TypeScript SDK를 사용합니다.모든 예제는 SDK가 이미 설치 및 구성되어 있다고 가정합니다. 아직 설정하지 않았다면 소개를 참고하세요.
레시피 1: 고객 인증
신규 고객을 등록하고, 로그인하여 고객 토큰을 받은 후 주문 내역 등 보호된 라우트에 접근합니다.import { createStorefrontClient } from '@headless-commerce/sdk';
const client = createStorefrontClient({
apiKey: process.env.NEXT_PUBLIC_HC_API_KEY!,
});
// 1. 신규 고객 등록
const customer = await client.customers.register({
email: 'jane@example.com',
password: 'SecureP@ss123!',
first_name: 'Jane',
last_name: 'Doe',
});
// 2. 로그인하여 JWT 토큰 발급
const { token } = await client.customers.login({
email: 'jane@example.com',
password: 'SecureP@ss123!',
});
// 3. 이후 요청에 고객 토큰 설정
client.setCustomerToken(token);
// 4. 보호된 라우트 접근
const { data: orders } = await client.customers.orders.list({ limit: 10 });
const profile = await client.customers.me();
console.log(profile.email); // "jane@example.com"
레시피 2: 로그인 후 장바구니 병합
비회원으로 장바구니에 상품을 담은 후 로그인하면, 비회원 장바구니를 기존 고객 장바구니에 병합합니다.import { createStorefrontClient } from '@headless-commerce/sdk';
const client = createStorefrontClient({
apiKey: process.env.NEXT_PUBLIC_HC_API_KEY!,
});
// 1. 비회원이 상품을 담음
const guestCart = await client.carts.create({ session_id: 'anon-session-456' });
await client.carts.addItem(guestCart.id, {
variant_id: 'var_hoodie_l_navy',
quantity: 1,
});
// 2. 비회원이 로그인
const { token } = await client.customers.login({
email: 'jane@example.com',
password: 'SecureP@ss123!',
});
client.setCustomerToken(token);
// 3. 비회원 장바구니를 고객 장바구니에 병합
// 비회원 장바구니의 상품이 고객의 기존 장바구니에 추가됩니다.
// 동일 옵션의 상품은 수량이 합산됩니다.
const mergedCart = await client.carts.merge({
source_cart_id: guestCart.id,
});
console.log(mergedCart.items.length); // 두 장바구니의 합산된 상품 수
레시피 3: 할인 코드 워크플로우
관리자가 할인 코드를 생성하고, 스토어프론트에서 장바구니에 적용한 후 할인이 적용된 상태로 주문합니다.import { createAdminClient, createStorefrontClient } from '@headless-commerce/sdk';
// --- 관리자: 할인 생성 ---
const admin = createAdminClient({ apiKey: 'sk_live_xxx' });
const discount = await admin.discounts.create({
code: 'SUMMER20',
type: 'percentage',
value: 20, // 20% 할인
starts_at: '2025-06-01T00:00:00Z',
ends_at: '2025-08-31T23:59:59Z',
usage_limit: 500,
min_order_amount: 30000, // KRW
});
// --- 스토어프론트: 장바구니에 적용 ---
const client = createStorefrontClient({
apiKey: process.env.NEXT_PUBLIC_HC_API_KEY!,
});
const cart = await client.carts.create({ session_id: 'session-789' });
await client.carts.addItem(cart.id, {
variant_id: 'var_dress_s_red',
quantity: 1,
});
// 할인 코드 적용
const updated = await client.carts.applyDiscount(cart.id, { code: 'SUMMER20' });
console.log(updated.discount_total); // -8000 (40000의 20%)
// 할인이 적용된 상태로 주문
const order = await client.carts.checkout(cart.id, {
email: 'shopper@example.com',
shipping_address: { line1: '부산광역시 해운대구 456', city: '부산', country: 'KR' },
payment_method: 'stripe',
});
레시피 4: 재고 관리
재고 부족 상품을 조회하고, 재고 수량을 조정하며, 안전 재고 임계값을 설정합니다.import { createAdminClient } from '@headless-commerce/sdk';
const admin = createAdminClient({ apiKey: 'sk_live_xxx' });
// 1. 재고 부족 옵션 목록 조회
const { data: lowStock } = await admin.inventory.list({
status: 'low_stock',
limit: 20,
});
console.log(`${lowStock.length}개 상품이 안전 재고 이하입니다`);
// 2. 특정 옵션의 재고 조정 (예: 입고)
await admin.inventory.adjust({
variant_id: 'var_tshirt_m_black',
quantity: 50, // 양수 = 추가, 음수 = 차감
reason: '공급업체 발주 PO-2025-0042 입고',
});
// 3. 안전 재고 임계값 설정 (inventory.low 웹훅 트리거)
await admin.inventory.update('var_tshirt_m_black', {
safety_stock: 10,
track_inventory: true,
});
// 4. 옵션의 현재 재고 조회
const inv = await admin.inventory.get('var_tshirt_m_black');
console.log(inv.available); // 50
console.log(inv.safety_stock); // 10
레시피 5: 반품 및 환불 처리
고객이 반품을 요청하면, 관리자가 검토 후 승인, 수령, 완료 처리를 거쳐 환불을 진행합니다.import { createAdminClient, createStorefrontClient } from '@headless-commerce/sdk';
const client = createStorefrontClient({
apiKey: process.env.NEXT_PUBLIC_HC_API_KEY!,
});
client.setCustomerToken('cust_token_xxx');
// 1. 고객이 반품 요청
const returnReq = await client.returns.create({
order_id: 'order_abc123',
items: [
{ order_item_id: 'oi_item1', quantity: 1, reason: '사이즈 불일치' },
],
note: 'M 사이즈를 주문했는데 L 사이즈가 필요합니다',
});
// --- 관리자 측 ---
const admin = createAdminClient({ apiKey: 'sk_live_xxx' });
// 2. 관리자가 반품 승인
await admin.returns.approve(returnReq.id);
// 3. 관리자가 상품 수령 확인
await admin.returns.receive(returnReq.id, {
items: [{ order_item_id: 'oi_item1', quantity: 1, condition: 'good' }],
});
// 4. 관리자가 반품 완료 처리
await admin.returns.complete(returnReq.id);
// 5. 반품 상품에 대한 환불 생성
const refund = await admin.refunds.create({
order_id: 'order_abc123',
amount: 29000,
reason: '반품 - 사이즈 불일치',
items: [{ order_item_id: 'oi_item1', quantity: 1 }],
});
console.log(refund.status); // "pending" → 결제 공급자가 처리
레시피 6: 배송 처리 라이프사이클
주문에 대해 배송을 생성하고, 운송장 정보를 추가하고, 발송 처리 후 배송 완료로 변경합니다.import { createAdminClient } from '@headless-commerce/sdk';
const admin = createAdminClient({ apiKey: 'sk_live_xxx' });
// 1. 특정 주문 상품에 대한 배송 생성
const fulfillment = await admin.fulfillments.create({
order_id: 'order_abc123',
items: [
{ order_item_id: 'oi_item1', quantity: 2 },
{ order_item_id: 'oi_item2', quantity: 1 },
],
tracking_number: '1234567890',
tracking_company: 'CJ대한통운',
tracking_url: 'https://trace.cjlogistics.com/tracking/1234567890',
});
console.log(fulfillment.status); // "created"
// 2. 발송 처리 (fulfillment.shipped 웹훅 트리거)
await admin.fulfillments.ship(fulfillment.id, {
shipped_at: new Date().toISOString(),
notify_customer: true, // 발송 알림 이메일 전송
});
// 3. 배송 완료 처리 (fulfillment.delivered 웹훅 트리거)
await admin.fulfillments.deliver(fulfillment.id, {
delivered_at: new Date().toISOString(),
notify_customer: true,
});
레시피 7: 다중 지역 가격 설정
지역별로 다른 통화와 가격을 설정하여 다국가 판매를 지원합니다.import { createAdminClient } from '@headless-commerce/sdk';
const admin = createAdminClient({ apiKey: 'sk_live_xxx' });
// 1. 지역 생성
const krRegion = await admin.regions.create({
name: '대한민국',
currency: 'KRW',
countries: ['KR'],
tax_rate: 10,
});
const usRegion = await admin.regions.create({
name: 'United States',
currency: 'USD',
countries: ['US'],
tax_rate: 0, // 주(州)마다 상이
});
// 2. 옵션별 지역 가격 설정
await admin.variants.setRegionPrices('var_tshirt_m_black', [
{ region_id: krRegion.id, price: 29000 }, // 29,000 KRW
{ region_id: usRegion.id, price: 2200 }, // $22.00 USD
]);
// 3. 스토어프론트: 특정 지역의 가격 조회
import { createStorefrontClient } from '@headless-commerce/sdk';
const storefront = createStorefrontClient({
apiKey: process.env.NEXT_PUBLIC_HC_API_KEY!,
});
const product = await storefront.products.get('prod_abc123', {
region_id: krRegion.id,
});
// product.variants[0].price → 29000 (KRW)
레시피 8: CSV 대량 가져오기
CSV 스프레드시트에서 상품을 가져오고, 유효성 검사 오류를 처리합니다.import { createAdminClient } from '@headless-commerce/sdk';
import fs from 'node:fs';
const admin = createAdminClient({ apiKey: 'sk_live_xxx' });
// 1. CSV 파일 읽기
const csvBuffer = fs.readFileSync('./products.csv');
// 2. 가져오기 작업 시작
const job = await admin.imports.create({
type: 'products',
file: new Blob([csvBuffer], { type: 'text/csv' }),
options: {
on_duplicate: 'update', // "skip" | "update" | "error"
notify_on_complete: true,
},
});
console.log(job.id); // "import_xyz789"
console.log(job.status); // "processing"
// 3. 완료될 때까지 폴링
let result = await admin.imports.get(job.id);
while (result.status === 'processing') {
await new Promise((r) => setTimeout(r, 2000));
result = await admin.imports.get(job.id);
}
// 4. 결과 확인
console.log(`가져오기 완료: ${result.summary.created}개 생성, ${result.summary.updated}개 업데이트`);
if (result.summary.errors > 0) {
console.log('오류:');
for (const err of result.errors) {
console.log(` 행 ${err.row}: ${err.message}`);
}
}
name,sku,price,currency,status,variant_name,inventory_quantity
"클래식 티셔츠","TSH-001",29000,"KRW","active","M / 블랙",50
"클래식 티셔츠","TSH-002",29000,"KRW","active","L / 블랙",30
"여름 원피스","DRS-001",59000,"KRW","draft","S / 레드",20
다음 단계
웹훅
웹훅 설정, 서명 검증, 프로덕션급 처리 패턴.
API 레퍼런스
100개 이상의 REST 엔드포인트를 살펴보세요.
SDK
TypeScript, Python SDK 레퍼런스.
Stripe 연동
스토어프론트에 Stripe 결제를 설정하세요.