메인 콘텐츠로 건너뛰기

레시피

가장 일반적인 커머스 워크플로우를 위한 실용적인 코드 예제입니다. 모든 레시피는 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}`);
  }
}
CSV 파일 형식:
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 결제를 설정하세요.