> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/sdk/v3.md).

# v3

`@apps-in-toss/web-framework` 3.0.0을 `latest`로 배포했어요. 이제 `npm install @apps-in-toss/web-framework`를 실행하면 3.0.0이 설치돼요.

3.0.0은 웹 미니앱 개발에 맞게 SDK 구조를 새로 정비한 메이저 업데이트예요. 이 문서에서 2.x와 3.0.0의 차이를 확인할 수 있어요.

### 한눈에 보기

* 공개 API를 도메인 객체 중심으로 재편했어요. 도메인으로 묶인 기존 함수는 deprecated로 유지되어 코드 수정 없이 그대로 동작해요.
* 패키지가 가벼워졌어요. 설치 크기가 약 27MB에서 약 660KB로 줄었어요.
* 설정 파일이 `granite.config.ts`에서 `apps-in-toss.config.ts`로 바뀌었어요. `npx ait migrate v3` 명령으로 자동 변환할 수 있어요.
* 샌드박스 앱은 3.0을 지원하지 않아요. API를 모킹하는 devtools를 지원할 예정이에요. 그 전까지는 콘솔에서 발급한 QR코드로 토스 앱에서 테스트해 주세요.

### 도메인 객체 API

3.0.0의 공개 API는 기능 단위 도메인 객체로 묶여요. 도메인으로 묶인 기존 개별 함수는 deprecated 되었으니, 같은 기능의 도메인 멤버를 사용해 주세요.

```typescript
// 2.x 방식 — 동작하지만 deprecated 경고가 표시돼요.
import { openCamera } from "@apps-in-toss/web-framework";
const image = await openCamera();

// 3.0 방식
import { Device } from "@apps-in-toss/web-framework";
const image = await Device.openCamera();
```

기존 함수는 함수 이름부터 받는 값, 돌려주는 값까지 2.x와 똑같이 동작해요. 그래서 2.x 코드는 수정 없이 3.0에서 컴파일되고 동작해요. 다만 에디터에서 deprecated 표시가 나타나고, 새 코드는 도메인 멤버로 작성하는 것을 권장해요.

#### 기존 API와 도메인 멤버 대응표

| 도메인          | 기존 API (deprecated)                | 새 API                           |
| ------------ | ---------------------------------- | ------------------------------- |
| Clipboard    | `getClipboardText`                 | `Clipboard.getText`             |
| Clipboard    | `setClipboardText`                 | `Clipboard.setText`             |
| Device       | `fetchAlbumItems`                  | `Device.getAlbumItems`          |
| Device       | `fetchAlbumPhotos`                 | `Device.getPhotos`              |
| Device       | `fetchContacts`                    | `Device.getContacts`            |
| Device       | `getCurrentLocation`               | `Device.getLocation`            |
| Device       | `getLocale`                        | `Device.locale`                 |
| Device       | `getPlatformOS`                    | `Device.os`                     |
| Device       | `generateHapticFeedback`           | `Device.triggerHaptic`          |
| Device       | `openCamera`                       | `Device.openCamera`             |
| Device       | `openURL`                          | `Device.openURL`                |
| Device       | `startUpdateLocation`              | `Device.subscribeLocation`      |
| Environment  | `getDeviceId`                      | `Environment.deviceId`          |
| Environment  | `getGroupId`                       | `Environment.groupId`           |
| Environment  | `getOperationalEnvironment`        | `Environment.environment`       |
| Environment  | `getTossAppVersion`                | `Environment.tossAppVersion`    |
| Environment  | `env.getDeploymentId`              | `Environment.deploymentId`      |
| Environment  | `getSchemeUri`                     | `Environment.initialURL`        |
| Environment  | `getNetworkStatus`                 | `Environment.getNetworkStatus`  |
| Environment  | `getServerTime`                    | `Environment.getServerTime`     |
| File         | `saveBase64Data`                   | `File.saveBase64`               |
| File         | `openPDFViewer`                    | `File.openPDFViewer`            |
| Game         | `openGameCenterLeaderboard`        | `Game.openLeaderboard`          |
| Game         | `submitGameCenterLeaderBoardScore` | `Game.setLeaderboardScore`      |
| Game         | `getGameCenterGameProfile`         | `Game.getUserProfile`           |
| Game         | `getUserKeyForGame`                | `User.getAnonymousKey`          |
| Game         | `grantPromotionRewardForGame`      | `Promotion.grantReward`         |
| Notification | `requestNotificationAgreement`     | `Notification.requestAgreement` |
| Promotion    | `grantPromotionReward`             | `Promotion.grantReward`         |
| Review       | `requestReview`                    | `Review.request`                |
| SafeArea     | `getSafeAreaInsets`                | `SafeArea.get`                  |
| SafeArea     | `SafeAreaInsets.subscribe`         | `SafeArea.subscribe`            |
| Screen       | `closeView`                        | `Screen.close`                  |
| Screen       | `setScreenAwakeMode`               | `Screen.setAwakeMode`           |
| Screen       | `setSecureScreen`                  | `Screen.setSecure`              |
| Screen       | `setIosSwipeGestureEnabled`        | `Screen.setIosSwipeBack`        |
| Screen       | `setDeviceOrientation`             | `Screen.setOrientation`         |
| Share        | `getTossShareLink`                 | `Share.createLink`              |
| Share        | `share`                            | `Share.sendMessage`             |
| TossAuth     | `appLogin`                         | `TossAuth.login`                |
| TossAuth     | `getIsTossLoginIntegratedService`  | `TossAuth.isIntegrated`         |
| TossAuth     | `appsInTossSignTossCert`           | `TossAuth.sign`                 |
| TossPay      | `checkoutPayment`                  | `TossPay.authorize`             |
| TossPay      | `requestTossPayPaysBilling`        | `TossPay.authorizeSubscription` |
| User         | `getAnonymousKey`                  | `User.getAnonymousKey`          |
| User         | `getConsentedUserData`             | `User.getConsentedData`         |
| User         | `getDeclaredAgeRange`              | `User.getDeclaredAgeRange`      |

`SafeAreaInsets`는 `SafeArea`와 같은 객체예요. 기존 이름 그대로 계속 쓸 수 있어요.

#### 그대로 유지되는 API

다음 API는 도메인으로 묶이지 않고 기존 형태 그대로 제공돼요. deprecated 없이 계속 사용하면 돼요.

* 객체형 API: `IAP`, `Storage`, `TossAds`, `GoogleAdMob`, `Analytics`, `partner`
* 광고: `loadFullScreenAd`, `showFullScreenAd`
* 권한: `getPermission`, `requestPermission`, `openPermissionDialog`와 권한 에러 클래스
* 이벤트: `appsInTossEvent`, `graniteEvent`, `tdsEvent`
* 환경: `isMinVersionSupported`, `getAppsInTossGlobals`

#### 새로 생긴 API

* `PermissionError`: 권한 에러의 공통 부모 클래스가 공개됐어요. `error instanceof PermissionError`로 모든 권한 에러를 한 번에 처리할 수 있어요.
* `TossPay` 도메인 객체: 2.x에서는 `checkoutPayment` 같은 개별 함수만 있었지만, 3.0에서는 `TossPay.authorize`, `TossPay.authorizeSubscription`으로 묶였어요.

#### 기존 함수와 도메인 멤버의 동작 차이

이름만 바뀐 것이 아니라 일부 동작 계약도 개선했어요. 마이그레이션할 때 다음 차이를 확인해 주세요.

* 상수형 API는 함수 호출이 아니라 속성으로 읽어요. 예를 들어 `getLocale()`은 `Device.locale`로, `getDeviceId()`는 `Environment.deviceId`로 바뀌어요.
* 도메인 멤버는 지원하지 않는 토스 앱 버전에서 `UNSUPPORTED_APP_VERSION` 또는 `UNSUPPORTED_OS_VERSION` 코드를 가진 에러를 던져요. 기존 함수는 2.x 계약대로 `undefined`나 `'ERROR'` 같은 값을 반환해요. 예를 들어 `getAnonymousKey`는 실패하면 `'ERROR'`를 반환하지만, `User.getAnonymousKey`는 에러를 던져요. `error.code`로 분기해서 "토스 앱을 업데이트해 주세요" 같은 안내를 보여줄 수 있어요.
* `Share.createLink`는 객체 인자를 받아요. `getTossShareLink(path, ogImageUrl)`은 `Share.createLink({ path, ogImageUrl })`로 바뀌어요.
* `IAP.createOneTimePurchaseOrder` 응답의 상품 식별자는 `sku`를 사용해요. `productId` 필드는 deprecated 됐어요.

### 설정 파일 변경

설정 파일 이름이 `granite.config.ts`에서 `apps-in-toss.config.ts`로 바뀌었고, 일부 옵션이 변경됐어요.

| 2.x (`granite.config.ts`)         | 3.0 (`apps-in-toss.config.ts`) | 설명                                              |
| --------------------------------- | ------------------------------ | ----------------------------------------------- |
| `web` (host, port, commands)      | 제거                             | 개발 서버와 빌드 실행이 SDK에서 `package.json` 스크립트로 이동했어요. |
| `brand.displayName`, `brand.icon` | 제거                             | `brand`에는 `primaryColor`만 남았어요.                 |
| `webViewProps`                    | `webView`                      | 이름이 바뀌었어요. 하위 옵션은 동일하고 `type`만 제거됐어요.           |
| `webViewProps.type`               | 제거                             | WebView frame type 옵션이 사라졌어요.                   |
| `outdir`                          | `webBundleDir`                 | 이름만 바뀌었어요. 기본값은 `dist`로 동일해요.                   |

설정 타입 이름도 `AppsInTossWebConfig`에서 `AppsInTossConfig`로 바뀌었어요.

웹 개발 서버와 빌드는 이제 `package.json` 스크립트에서 직접 실행해요.

```json
{
  "scripts": {
    "dev": "vite dev",
    "build": "vite build && ait build",
    "deploy": "ait deploy"
  }
}
```

### 패키지 구조 변경

| 항목           | 2.x         | 3.0                                                                  |
| ------------ | ----------- | -------------------------------------------------------------------- |
| 설치 크기        | 약 27MB      | 약 660KB                                                              |
| 모듈 포맷        | ESM 전용      | ESM + CJS 듀얼                                                         |
| dependencies | 13개         | 4개 (`@apps-in-toss/cli`, `@webview-bridge/web`, `semver`, `valibot`) |
| 라이선스         | LICENSE 파일만 | `Apache-2.0` 명시                                                      |

CJS 환경(`require`, 구형 번들러)에서도 사용할 수 있게 됐고, 의존성이 줄어 설치가 빨라지고 다른 패키지와의 버전 충돌 걱정도 줄었어요.

### 샌드박스와 개발 환경 모킹

샌드박스 앱은 3.0을 지원하지 않아요. 대신 샌드박스 앱 없이도 로컬 개발 환경에서 API를 모킹할 수 있도록 devtools를 곧 제공하려고 준비하고 있어요.

그때까지 3.0으로 만든 미니앱은 앱인토스 콘솔에서 발급한 QR코드로 토스 앱에서 테스트해 주세요.

### 3.0.0으로 마이그레이션하기

자동 마이그레이션 명령을 제공해요. 설정 파일 변환과 `package.json` 스크립트 재구성이 자동으로 처리돼요.

```bash
npx ait migrate v3
```

이 명령은 다음 작업을 수행해요.

* `granite.config.ts`를 `apps-in-toss.config.ts`로 변환해요 (`brand`는 `primaryColor`만 유지, `webViewProps`는 `webView`로 변경, `outdir`은 `webBundleDir`로 변경, `web` 블록 삭제).
* `package.json`의 `dev`, `build` 스크립트를 재구성해요.
* 변환 전 검증에 실패하면 파일을 변경하지 않고 원인과 해결 방법을 알려줘요.

마이그레이션 후에는 콘솔에 번들을 업로드하고 QR코드로 토스 앱에서 테스트해 주세요.

#### 꼭 확인해 주세요

* SDK 3.x로 빌드한 번들을 출시하면 2.x로 롤백할 수 없어요. QR코드로 충분히 테스트한 후 출시해 주세요.
* 3.0부터 미니앱이 `https://<appName>.web.tossmini.com`(라이브)과 `https://<appName>.private-web.tossmini.com`(QR 테스트) Origin에서 실행돼요. API 서버의 CORS 허용 목록에 두 도메인을 등록해 주세요.
* TDS를 사용한다면 `@toss/tds-mobile`과 `@toss/tds-mobile-ait`을 2.4.1 이상으로 함께 업데이트해 주세요.
* 3.0.0-rc.1과 rc.2는 의존성 문제로 설치할 수 없어요. 반드시 3.0.0 정식 버전을 사용해 주세요.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/sdk/v3.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
