JavaScript / 브라우저 SDK
@lartech/infraio-checkout-js는 현재 공개된 유일한 SDK입니다. 브라우저에서
실행되며 호스팅 체크아웃을 엽니다. 백엔드 SDK(Node, Go, Python)는 로드맵에
있습니다. 그때까지는 게이트웨이와 직접 통신하세요 — HMAC 서명 헬퍼는
빠른 시작을 참조하세요.
- 현재 버전:
0.1.1-beta.17(pre-1.0; 마이너 변경 예상) - 포맷: ESM (
index.js), CJS (index.cjs), IIFE (index.global.js) - 타입 번들됨 (
index.d.ts) - 런타임 피어 없음 — React, jQuery 또는 기타 종속성 없음
서버 측 엔트리는 없습니다. 웹훅 서명 검증 헬퍼는 번들되지
않습니다 — crypto로 직접 구현하세요(서명 검증
페이지에 4개 언어로 복사하여 붙여넣을
수 있는 코드가 있습니다).
설치
npm
npm install @lartech/infraio-checkout-jsloadInfraIo(publicKey, options?)
Promise<InfraIoInstance>를 반환합니다.
import { loadInfraIo } from "@lartech/infraio-checkout-js";
const sdk = await loadInfraIo("pk_live_yourkeyhere", {
// 선택. 비프로덕션 환경을 가리킬 때만 오버라이드하세요.
checkoutUrl: "https://checkout-dev.infraio.xyz",
});| 매개변수 | 타입 | 필수 | 비고 |
|---|---|---|---|
publicKey | string | ✓ | pk_(live|test)_…와 일치해야 함 |
options.checkoutUrl | string | — | 기본 체크아웃 URL을 오버라이드합니다. 기본값: https://checkout.infraio.xyz. 일치하는 게이트웨이 URL은 체크아웃 페이지가 런타임에 결정합니다 — 각 checkout(-dev).infraio.xyz 배포는 컴파일 타임 NEXT_PUBLIC_API_URL을 가지므로 여기서 올바른 호스트명을 선택하면 올바른 백엔드가 자동으로 선택됩니다. 별도의 gatewayUrl 옵션은 없습니다. |
sdk.checkout({ … })
호스팅 체크아웃을 엽니다. void를 반환합니다(상태는 콜백 사용).
| 필드 | 타입 | 필수 | 비고 |
|---|---|---|---|
sessionId | string | ✓ | POST /b2b/v1/checkout-sessions/quick이 반환한 session_key |
checkoutUrl | string | — | 동일한 엔드포인트가 반환한 전체 URL. 생략 시 SDK가 loadInfraIo()의 checkoutUrl(또는 기본값) + sessionId로 구성합니다 |
mode | "popup" | "redirect" | "embed" | — | 기본값 "popup" |
container | string | HTMLElement | 임베드만 | iframe이 마운트될 CSS 선택자 또는 DOM 요소 |
width | number | — | 팝업 전용. 기본값 560. [320, 1280] 범위로 클램프 |
height | number | — | 팝업 전용. 기본값 780. [400, 1000] 범위로 클램프 |
timeoutMs | number | — | 팝업 전용. iframe 로드 타임아웃. 기본값 30000. 0을 전달하면 비활성화 |
locale | string | — | 체크아웃 페이지에 ?locale=로 전달되는 BCP-47 태그(en, ja, zh-CN, zh-TW) |
hideSummary | boolean | — | 주문 요약 컬럼 숨기기. 기본값 false |
hideHeader | boolean | — | InfraIO 헤더 및 내장 지갑 연결 버튼 숨기기. 기본값 false. 완전한 화이트 라벨을 위해 walletAddress와 함께 사용 |
walletAddress | string | — | 구매자 지갑 사전 연결. onSignRequest가 필요함 |
walletChainId | number | — | 사전 연결된 지갑의 EVM 체인 ID |
onReady | () => void | — | iframe이 상호작용 가능해질 때 발생. 팝업/임베드 전용 |
onSignRequest | (req: { method: string; params: unknown[] }) => Promise<string> | walletAddress 설정 시 | SDK가 지갑 RPC를 가맹점 핸들러로 프록시 — 서명된 hex를 반환 |
onSuccess | ({ sessionId }) => void | — | 성공적인 결제 시 발생. 권위 있는 신호가 아님 — 웹훅이 권위 있음 |
onCancel | () => void | — | 구매자가 결제하지 않고 팝업/임베드를 닫을 때 발생 |
onError | (err: InfraIoError) => void | — | iframe 로드 실패 시 발생(팝업 + 임베드 모드). 잘못된 인수는 동기적으로 throw되며 여기서 전달되지 않습니다. 리디렉션 모드는 런타임 오류 표면이 없음 — 실패는 리디렉션된 페이지에서 관찰됨. |
onSuccess는 권위 있는 신호가 아닙니다. 웹훅이 나중에 결제 실패를
결정하더라도 발생할 수 있습니다(테스트넷 reorg, 구매자 측 타이밍). UX에만
사용하세요(예: “감사합니다!” 표시, 리디렉션). 이행 처리 전에 항상 웹훅으로
확인하세요.
sdk.close()
열려 있는 팝업이나 임베드를 프로그래밍 방식으로 해제합니다. 리디렉션 모드에서는 no-op입니다.
sdk.checkout({ sessionId, mode: "popup", /* … */ });
// 나중에, 예를 들어 사용자가 페이지를 떠날 때
sdk.close();sdk.openRefundRequest({ … })
백엔드가 POST /b2b/v1/merchants/{merchant_id}/refund-requests로 발급한 일회성
토큰에 대해 호스팅 환불 요청 양식을 엽니다. 구매자는 저희 페이지에서 환불
목적지 주소 + 사유 + (선택) 메타데이터를 입력합니다. 가맹점 페이지는 열기/닫기
라이프사이클만 처리합니다. close() 함수를 반환합니다 — 호출하여 팝업을
프로그래밍 방식으로 해제하거나 임베드 iframe을 분리합니다. 리디렉션 모드에서
반환된 함수는 no-op입니다.
양식은 https://checkout.infraio.xyz/refund-request/:token에 있습니다. 이
메서드는 해당 URL을 팝업/리디렉션/임베드로 감싸서 구매자가 가맹점 도메인을
벗어나지 않거나(팝업/임베드) 자동으로 돌아오도록(리디렉션) 합니다. 백엔드가
토큰을 발급하기 위해 호출하는 엔드포인트는
POST /b2b/v1/merchants/{merchant_id}/refund-requests입니다 — 시크릿 키로
HMAC 서명하며, 나머지 B2B 표면과 동일한 인증입니다.
개념 → 환불을 참조하세요.
import { loadInfraIo } from "@lartech/infraio-checkout-js";
const sdk = await loadInfraIo("pk_live_yourkeyhere");
// 서버 측에서 토큰을 발급한 다음, 브라우저의 SDK에 전달합니다.
const { token } = await fetch("/api/mint-refund-token", { method: "POST" }).then(r => r.json());
const close = sdk.openRefundRequest({
token,
mode: "popup",
onSuccess: ({ linkToken, refundId }) => {
// 구매자가 양식을 제출했습니다.
// linkToken → /r/:linkToken 상태 페이지(구매자와 공유).
// refundId → 승인/거부에 B2B API와 함께 사용.
window.location.href = `/r/${linkToken}`;
},
onCancel: () => { /* 구매자가 제출 없이 닫음 */ },
});
// 나중에 필요하면 프로그래밍 방식으로 팝업 해제:
// close();| 필드 | 타입 | 필수 | 비고 |
|---|---|---|---|
token | string | ✓ | POST /b2b/v1/merchants/{merchant_id}/refund-requests가 반환한 rfqt_… 토큰 |
mode | "popup" | "redirect" | "embed" | — | 기본값 "popup". sdk.checkout()과 동일한 표면 시맨틱 — 모드 비고 참조 |
container | string | HTMLElement | 임베드만 | iframe이 마운트될 CSS 선택자 또는 DOM 요소 |
locale | string | — | ?locale=로 전달되는 BCP-47 태그(en, ja, zh-CN, zh-TW) |
hideHeader | boolean | — | iframe 내부의 InfraIO 헤더 숨기기. 팝업/임베드에서 SDK가 자체 모달 크롬을 그리므로 페이지 헤더는 일반적으로 노이즈입니다. 기본값 false |
hideSummary | boolean | — | 주문 요약 컬럼을 숨기고 환불 양식만 표시. 기본값 false |
walletAddress | string | — | 목적지 지갑 필드(?wallet_address=)를 사전 채움. 구매자의 지갑을 이미 알고 있는 가맹점이 수동 재입력을 건너뛸 수 있게 함 |
onSuccess | (data: { linkToken: string; refundId: string }) => void | — | 구매자가 양식을 제출한 후 발생. linkToken → 구매자와 공유할 /r/:linkToken 상태 페이지. refundId → 승인/거부에 B2B API와 함께 사용 |
onCancel | () => void | — | 구매자가 제출 없이 팝업/임베드를 닫을 때 발생 |
onError | (err: InfraIoError) => void | — | iframe 로드 실패 또는 잘못된 인수에 발생. 토큰 만료/취소는 호스팅 페이지에서 처리되며 onError로 처리되지 않습니다 |
onError를 통해 노출되는 토큰 상태
구매자가 만료된 토큰을 열면 페이지 자체가 표시를 처리하며(“만료됨 — 새 링크
요청” 안내 등을 렌더링), SDK는 이러한 경우 onError를 발생시키지 않습니다 —
구매자는 양식 흐름 내에 있고 가맹점 코드는 반응할 필요가 없습니다. onError는
가맹점 코드가 조치할 수 있는 경우(잘못된 인수, iframe 로드 시 네트워크 실패)
에만 발생합니다.
openRefundRequest는 환불 인텐트를 기록할 뿐 자금을 이동시키지
않습니다. onSuccess 이후 환불 행은 PENDING(또는 가맹점 구성이
고객 환불을 자동 승인하는 경우 APPROVED)입니다. 가맹점 지갑에서
온체인 송금을 서명하고 브로드캐스트한 다음, tx 해시를
POST /b2b/v1/refunds/:id/submit-tx로 게시해야 합니다. 전체
라이프사이클은 개념 → 환불을 참조하세요.
오류 클래스
import { InfraIoError } from "@lartech/infraio-checkout-js";
sdk.checkout({
sessionId,
onError: (err: InfraIoError) => {
switch (err.code) {
case "invalid_request_error": /* 잘못된 sessionId / 인수 */ break;
case "iframe_load_error": /* iframe 로드 실패 */ break;
case "iframe_timeout_error": /* timeoutMs 초과 */ break;
case "already_open_error": /* 다른 체크아웃이 이미 열려 있음 */ break;
case "network_error": /* 체크아웃 오리진과 통신 중 일시적인 네트워크 문제 */ break;
case "api_error": /* SDK 발급 호출에 대해 백엔드가 non-2xx 반환 */ break;
}
},
});sdk.openRefundRequest()는 invalid_request_error(누락 또는 잘못된 토큰/인수)만
동기적으로 throw합니다. iframe_load_error(환불 요청 iframe 로드 실패)는
throw되지 않고 onError를 통해 비동기적으로 전달됩니다. iframe_timeout_error
또는 already_open_error는 발생시키지 않습니다 — 환불 요청 팝업에는 로드
타임아웃이 없으며 여러 동시 팝업을 허용합니다.
모드 비고
팝업
- 어두운 반투명 배경의 중앙 정렬 오버레이
z-index: 2147483647(max int32) — 다른 모든 것 위에 위치- 열려 있는 동안 본문 스크롤 잠금. 닫히면 복원
- 닫기 버튼이 초기 포커스를 받음. Tab은 팝업 내에 트랩됨
- 닫기 방법: 닫기 버튼, Escape, 외부 클릭,
sdk.close(). 이들 모두onCancel을 호출 - 체크아웃 페이지는
postMessage로 리사이즈를 요청할 수 있음 — SDK가width/height제한 내로 클램프
리디렉션
window.location.href를 통한 하드 내비게이션?return_url=<current-page>를 자동으로 추가하여 구매자가 출발점으로 돌아오게 함. 세션의success_url/cancel_url이 이미 이를 처리하면 왕복은return_url을 무시
임베드
allow="payment; clipboard-write"가 있는 iframe (HTML5 Feature Policy 지시문 —sandbox속성이 아님). iframe은 체크아웃 오리진에서 제공되므로 구매자 측 지갑 팝업과 클립보드 쓰기는 추가 옵트인 없이 동작- 컨테이너 너비는 100%. 높이는
INFRAIO_RESIZEpostMessage를 통해 자동 조정,[200, 2000]px범위로 클램프 - iframe 경계 외에 CSS 격리 없음 — 부모 페이지 스타일은 누출되지 않음
- 체크아웃이 상호작용 가능해질 때 자체 로딩 상태를 숨길 수 있도록 항상
onReady를 연결
TypeScript
모든 타입이 번들됩니다. 가장 유용한 익스포트:
import type {
CheckoutOptions,
RefundRequestOptions,
LoadOptions,
InfraIoInstance,
InfraIoErrorCode,
} from "@lartech/infraio-checkout-js";
import { loadInfraIo, InfraIoError, VERSION } from "@lartech/infraio-checkout-js";VERSION은 SDK 자체의 버전 문자열입니다 — 버그 리포트에 유용합니다.
다음 단계
- React / Vue 프레임워크 래퍼 — 파일럿 가맹점 전반에서 vanilla JS
표면이 안정화된 후 출시 이후 반복을 위해 계획되었습니다. 현재 vanilla
SDK는 React 내부에서 잘 동작합니다 — 래퍼는 수동
useRef+ 라이프사이클 플러밍을 제거할 것입니다. - 크로스 탭 세션 재개 — 탭 A에서 체크아웃을 열고 탭 B에서 완료. 구매자가 흐름 중간에 매직 링크를 따라갈 때 유용합니다. 다음 마이너 릴리스에서 추적됩니다.
- CSS 변수를 통한 테마 — iframe에 작은 디자인 토큰 세트(radius, accent color)를 노출하여 가맹점이 페이지를 포크하지 않고 브랜드에 맞출 수 있게 합니다.
- 서버 측 헬퍼 — 백엔드 코드가 HMAC 의식을 복사하지 않도록
verifyWebhook()+signedRequest()를 노출하는 작은@lartech/infraio-server패키지. 출시 전까지 서명 검증 페이지에 TypeScript, Go, Python, Ruby의 드롭인 구현이 나와 있습니다.