01.software 문서
전문 연동

Membership

유료 구독 준비와 서명된 청구 결과 전달.

Membership

명시된 호출자 환경에서만 사용하세요. 먼저 자격 증명을 설정하세요. 패키지 surface는 SDK README가 소유합니다.

유료 Membership 구독

이 흐름에는 customers와 membership을 활성화하세요. 상품과 주문도 사용하려면 ecommerce를 별도로 선택하세요.

server.memberships.subscribe()는 유료 Membership을 준비하며 provider 결제 식별자를 받거나 Membership을 활성화하지 않습니다. 서버 보관 Secret Key로 호출한 뒤 응답 union을 분기하세요. 유료 응답은 incomplete이며 tenant PSP에 전달할 정확한 금액, 통화, 기간 시작, 만료 시각, 그리고 firstCharge.idempotencyKey를 포함합니다. 이 키로 PSP를 결제한 다음 기존의 서명된 charge-result webhook으로 결과를 전송합니다. Trial 응답은 즉시 trialing이고 first-charge 지시가 없습니다. 유료 subscribe 전에는 tenant의 활성 delegated billing connection을 구성해야 하며, 없으면 Console은 lifecycle write 없이 409 conflict를 반환합니다.

import { createServerClient } from '@01.software/sdk/server'

type Server = ReturnType<typeof createServerClient>

type Prepared = Awaited<ReturnType<Server['memberships']['subscribe']>>
type FirstCharge = Extract<Prepared, { status: 'incomplete' }>['firstCharge']

export async function prepareSubscription(
  server: Server,
  input: Parameters<Server['memberships']['subscribe']>[0],
  tenantPsp: { charge: (charge: FirstCharge) => Promise<void> },
) {
  const prepared = await server.memberships.subscribe(input)
  if (prepared.status === 'incomplete') {
    const expiresAt = Date.parse(prepared.firstCharge.expiresAt)
    if (!Number.isFinite(expiresAt) || Date.now() >= expiresAt) {
      throw new Error('First charge instruction expired or invalid')
    }
    await tenantPsp.charge(prepared.firstCharge)
  }
  return prepared
}

활성화는 서명된 결과 webhook 또는 기존 reconciliation query만 결정합니다. 첫 결제가 pending인 동안에는 같은 subscribe idempotency key로 재시도할 수 있고, 결제 완료나 expiresAt 이후 재시도는 새 결제 지시 대신 409를 반환합니다. expiresAt이 유효하지 않거나 해당 시각에 도달했으면 PSP 결제를 시작하지 마세요. tenant PSP는 firstCharge.idempotencyKey로 중복 결제를 막아야 합니다. 늦은 paid 결과는 증빙으로 보존되지만 Membership을 활성화하지 않으므로 tenant는 이 API 밖에서 환불을 처리해야 합니다.

다음 액션

목차