SDK
Server API
서버 전용 API 메서드
Server API
ServerClient는 서버 환경에서만 사용할 수 있는 특별한 API 메서드를 제공합니다.
Server API는 secretKey가 필요하며, 브라우저에서 절대 노출되어서는 안 됩니다.
클라이언트 생성
import { createServerClient } from '@01.software/sdk'
const serverClient = createServerClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
secretKey: process.env.SOFTWARE_SECRET_KEY!,
})주문 API
createOrder()
새 주문을 생성합니다.
import { generateOrderNumber } from '@01.software/sdk'
const order = await serverClient.api.createOrder({
// 필수 필드
paymentId: 'pay_123456',
orderNumber: generateOrderNumber(),
email: 'customer@example.com',
orderProducts: [
{
product: 'product_id',
variant: 'variant_id',
quantity: 2,
price: 10000,
}
],
totalAmount: 20000,
// 선택 필드
customerName: '홍길동',
phone: '010-1234-5678',
shippingAddress: {
address: '서울시 강남구 테헤란로 123',
zipCode: '06234',
},
memo: '문 앞에 놓아주세요',
})
console.log(order.id)
console.log(order.orderNumber)파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
paymentId | string | O | 결제 ID (PG사에서 발급) |
orderNumber | string | O | 주문 번호 |
email | string | O | 고객 이메일 |
orderProducts | array | O | 주문 상품 목록 |
totalAmount | number | O | 총 결제 금액 |
customerName | string | X | 고객 이름 |
phone | string | X | 연락처 |
shippingAddress | object | X | 배송 주소 |
memo | string | X | 배송 메모 |
orderProducts 항목
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
product | string | O | 상품 ID |
variant | string | X | 상품 변형 ID |
quantity | number | O | 수량 |
price | number | O | 단가 |
updateOrder()
기존 주문을 업데이트합니다.
await serverClient.api.updateOrder('order_id', {
status: 'shipped',
trackingNumber: '1234567890',
shippedAt: new Date().toISOString(),
})업데이트 가능한 필드
interface OrderUpdateData {
status?: 'pending' | 'confirmed' | 'shipped' | 'delivered' | 'cancelled'
trackingNumber?: string
shippedAt?: string
deliveredAt?: string
cancelledAt?: string
cancelReason?: string
}주문 상태 흐름
pending → confirmed → shipped → delivered
↓
cancelled트랜잭션 API
updateTransaction()
결제 트랜잭션 상태를 업데이트합니다.
await serverClient.api.updateTransaction('transaction_id', {
status: 'paid',
paidAt: new Date().toISOString(),
})트랜잭션 상태
| 상태 | 설명 |
|---|---|
pending | 결제 대기 |
paid | 결제 완료 |
failed | 결제 실패 |
refunded | 환불 완료 |
partially_refunded | 부분 환불 |
유틸리티 함수
generateOrderNumber()
고유한 주문 번호를 생성합니다.
import { generateOrderNumber } from '@01.software/sdk'
const orderNumber = generateOrderNumber()
// 예: "ORD-20240115-A1B2C3D4"formatOrderName()
주문 상품들을 요약 문자열로 변환합니다.
import { formatOrderName } from '@01.software/sdk'
const orderName = formatOrderName([
{ name: '아이폰 15', quantity: 1 },
{ name: '에어팟 프로', quantity: 2 },
])
// 결과: "아이폰 15 외 1건"실전 예제
결제 완료 처리
import { NextRequest, NextResponse } from 'next/server'
import { serverClient, generateOrderNumber } from '@01.software/sdk'
export async function POST(request: NextRequest) {
const body = await request.json()
try {
// 1. PG사 결제 검증
const paymentResult = await verifyPayment(body.paymentKey)
if (!paymentResult.success) {
return NextResponse.json(
{ error: '결제 검증 실패' },
{ status: 400 }
)
}
// 2. 주문 생성
const order = await serverClient.api.createOrder({
paymentId: body.paymentKey,
orderNumber: generateOrderNumber(),
email: body.email,
customerName: body.customerName,
phone: body.phone,
orderProducts: body.products.map(p => ({
product: p.productId,
variant: p.variantId,
quantity: p.quantity,
price: p.price,
})),
totalAmount: paymentResult.amount,
shippingAddress: body.shippingAddress,
})
// 3. 트랜잭션 상태 업데이트 (자동 생성된 경우)
if (order.transaction) {
await serverClient.api.updateTransaction(order.transaction, {
status: 'paid',
paidAt: new Date().toISOString(),
})
}
return NextResponse.json({
success: true,
orderId: order.id,
orderNumber: order.orderNumber,
})
} catch (error) {
console.error('Order creation failed:', error)
return NextResponse.json(
{ error: '주문 생성 실패' },
{ status: 500 }
)
}
}배송 상태 업데이트
import { NextRequest, NextResponse } from 'next/server'
import { serverClient } from '@01.software/sdk'
export async function POST(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const body = await request.json()
try {
await serverClient.api.updateOrder(params.id, {
status: 'shipped',
trackingNumber: body.trackingNumber,
shippedAt: new Date().toISOString(),
})
// 알림 발송
await sendShippingNotification(params.id, body.trackingNumber)
return NextResponse.json({ success: true })
} catch (error) {
return NextResponse.json(
{ error: '배송 상태 업데이트 실패' },
{ status: 500 }
)
}
}주문 취소
import { NextRequest, NextResponse } from 'next/server'
import { serverClient } from '@01.software/sdk'
export async function POST(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const body = await request.json()
try {
// 1. 주문 취소
await serverClient.api.updateOrder(params.id, {
status: 'cancelled',
cancelledAt: new Date().toISOString(),
cancelReason: body.reason,
})
// 2. 결제 취소 (PG사)
const order = await serverClient.from('orders').findById(params.id)
if (order.data?.paymentId) {
await cancelPayment(order.data.paymentId)
}
// 3. 트랜잭션 상태 업데이트
if (order.data?.transaction) {
await serverClient.api.updateTransaction(order.data.transaction, {
status: 'refunded',
})
}
return NextResponse.json({ success: true })
} catch (error) {
return NextResponse.json(
{ error: '주문 취소 실패' },
{ status: 500 }
)
}
}Server Action 예제
'use server'
import { serverClient, generateOrderNumber } from '@01.software/sdk'
import { revalidatePath } from 'next/cache'
export async function createOrder(formData: FormData) {
const email = formData.get('email') as string
const products = JSON.parse(formData.get('products') as string)
const order = await serverClient.api.createOrder({
paymentId: formData.get('paymentId') as string,
orderNumber: generateOrderNumber(),
email,
customerName: formData.get('customerName') as string,
orderProducts: products,
totalAmount: products.reduce(
(sum: number, p: any) => sum + p.price * p.quantity,
0
),
})
revalidatePath('/orders')
return {
success: true,
orderId: order.id,
orderNumber: order.orderNumber,
}
}
export async function updateOrderStatus(orderId: string, status: string) {
await serverClient.api.updateOrder(orderId, {
status: status as any,
})
revalidatePath('/orders')
revalidatePath(`/orders/${orderId}`)
}보안 주의사항
Secret Key 보안
- 환경 변수 사용: Secret Key는 반드시 환경 변수로 관리하세요.
# .env.local
SOFTWARE_SECRET_KEY=your_secret_key_here- 서버에서만 사용: Secret Key가 포함된 코드는 서버 환경에서만 실행되어야 합니다.
// ✅ 올바른 사용: Server Component, API Route, Server Action
// ❌ 잘못된 사용: Client Component, 브라우저 코드- Git 제외:
.env.local파일은 반드시.gitignore에 추가하세요.
.env.local
.env*.local다음 단계
- Webhooks - 이벤트 수신 처리
- Error Handling - 에러 처리