> ## Documentation Index
> Fetch the complete documentation index at: https://docs.acedata.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK + X402 결제 훅

> Platform API guide - Ace Data Cloud

[X402](https://www.x402.org/)는 Coinbase가 제안한 "HTTP 402 청구"의 온체인 결제 프로토콜입니다: 서버는 토큰이 없는 요청에 대해 `402 Payment Required`를 반환하고, `accepts: [...]` 필드를 포함하여 수용 가능한 체인 / 자산 / 가격을 나열합니다; 클라이언트는 로컬에서 권한을 서명한 후 (EVM에서는 Permit2 / EIP-712, Solana에서는 SPL 토큰 전송 권한), base64로 인코딩된 envelope을 `PAYMENT-SIGNATURE` 헤더에 넣어 재전송합니다. 서버는 검증 후 실제로 체인에서 결제하고 비즈니스 결과를 반환합니다.

> Ace Data Cloud의 X402 클라이언트는 직접 목표 API를 호출하고, 해당 요청에서 실시간으로 반환된 `402 Payment Required`와 `accepts`를 가격 및 서명 근거로 사용합니다. Facilitator의 결제 능력은 [`/.well-known/x402`](https://facilitator.acedata.cloud/.well-known/x402)에서 검증할 수 있습니다.

`@acedatacloud/sdk`와 `acedatacloud`는 모두 `paymentHandler` 훅을 노출합니다: SDK가 발송한 요청이 `402`를 수신하면, 주입된 핸들러를 호출하여 `PAYMENT-SIGNATURE` 헤더를 가져오고 원래 요청을 재전송합니다. `@acedatacloud/x402-client` / `acedatacloud-x402`를 SDK와 함께 사용하면, **전체 프로세스는 비즈니스 코드에 완전히 투명합니다** — 당신은 단지 `client.openai.chat.completions.create(...)`를 사용하면 되며, 토큰 모드와 똑같이 보이지만, 기본적으로 호출에 따라 결제되며 사전 충전이 필요하지 않습니다.

본문:

* TS 측의 "무 토큰 + X402 핸들러 주입" 경로를 실제로 연결했습니다. (\[T12 검증]\(#네 실제 실행 검증))
* EVM / Solana 두 가지 서명 경로의 차이를 나열했습니다.
* `viem` 개인 키 모드, 브라우저 지갑 모드, Python `EVMAccountSigner` 모드 세 가지 적합성을 제시했습니다.
* `preferScheme` / `prefer_scheme` 이라는 쉽게 실수할 수 있는 필드를 명확히 설명했습니다.

## 일, 프로토콜 개요 (필독)

성공적인 X402 호출은 **3개의 HTTP RTT**를 포함합니다:

```text theme={null}
1. SDK -> /openai/v1/chat/completions               (Authorization 없음)
   <- 402 Payment Required
      { accepts: [{ scheme:'upto', network:'eip155:8453', maxAmountRequired:'10000', ... }] }

2. SDK 내부 -> paymentHandler({ url, method, body, accepts })   (로컬 서명, 0 RTT)
   <- { headers: { 'PAYMENT-SIGNATURE': '<base64-envelope>' } }

3. SDK -> /openai/v1/chat/completions               (PAYMENT-SIGNATURE 헤더 주입)
   <- 200 + 비즈니스 응답   (서버에서 결제 완료)
```

X402 envelope은 JSON의 일부분으로, base64로 인코딩되어 `PAYMENT-SIGNATURE` 헤더에 삽입됩니다. 구조(발췌):

```json theme={null}
{
  "x402Version": 2,
  "accepted": {
    "scheme": "upto",
    "network": "eip155:8453"
  },
  "payload": {
    "permit2": {
      "permitted": [{ "token": "0x...USDC", "amount": "10000" }],
      "nonce": "...",
      "deadline": "..."
    },
    "witness": { "...metered-billing-fields..." },
    "signature": "0x..."
  }
}
```

envelope의 최상위는 `x402Version: 2`이며, `accepted` 객체를 사용하여 이번에 선택한 `scheme`과 `network`(CAIP-2 식별자)를 선언합니다.

| scheme | 의미 |
| - | - |
| `exact` | 고정 가격(이미지 / 비디오 생성, 검색 등 가격 책정 시나리오). 서명된 금액 = 서버가 요구하는 금액. |
| `upto` | 측정 요금(채팅 완료 / 토큰 유형). **상한** 금액을 서명하고, 실제로 사용된 부분만 결제합니다(Permit2 + witness 기반). **세션 유형 API에 강력히 추천**합니다. |

`preferScheme` / `prefer_scheme`은 서버가 **여러 가지 scheme을 동시에 제공**할 때 선호도를 선택하는 데 사용됩니다. 서버가 `exact`만 노출하면 이 필드는 무시됩니다; `upto`를 설정했지만 서버가 노출하지 않으면 첫 번째 일치 항목으로 되돌아갑니다.

## 이, TypeScript: 브라우저 지갑 + 서버 viem 두 가지 사용법

### 설치

```bash theme={null}
npm install @acedatacloud/sdk @acedatacloud/x402-client
```

실제 테스트한 버전 번호:

```text theme={null}
@acedatacloud/sdk@2026.504.2
@acedatacloud/x402-client@2026.531.3
```

### `createX402PaymentHandler` 완전 서명

```ts theme={null}
export interface X402PaymentHandlerOptions {
  network: 'solana' | 'base' | 'skale';
  solanaWallet?: SolanaWalletAdapter;       // network='solana' 필수
  evmProvider?: EVMProvider;                // network='base'/'skale' 필수, EIP-1193
  evmAddress?: string;                      // network='base'/'skale' 필수
  preferScheme?: 'exact' | 'upto';
}
```

반환 값은 `(ctx) => Promise&lt;{ headers: Record<string, string> }>`로, SDK의 `paymentHandler` 훅 서명과 정확히 일치합니다.

### 사용법 1: 브라우저 (MetaMask / WalletConnect)

```ts theme={null}
import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';

// 1. 사용자가 지갑을 연결하도록 요청
const accounts: string[] = await (window as any).ethereum.request({
  method: 'eth_requestAccounts'
});
const userAddress = accounts[0];

// 2. Base 메인넷으로 전환
await (window as any).ethereum.request({
  method: 'wallet_switchEthereumChain',
  params: [{ chainId: '0x2105' }]   // 8453 = Base
});

// 3. SDK 클라이언트 구성, X402 핸들러 주입
//    주의: apiToken을 전달하지 않아 SDK가 402 경로를 따르도록 합니다.
const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'base',
    evmProvider: (window as any).ethereum,
    evmAddress: userAddress,
    preferScheme: 'upto'   // 채팅 유형 필수로 upto
  })
});

// 4. 정상 호출
const res: any = await client.openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'hi' }],
  max_tokens: 20
});
console.log(res.choices[0].message.content);
```

첫 번째 호출 시 브라우저는 **두 번의 서명 요청**을 표시합니다: 첫 번째는 Permit2에 대한 USDC의 일회성 승인(금액은 `MaxUint256`, 체인에 기록됨); 두 번째는 X402 envelope의 EIP-712 서명(체인에 올라가지 않으며, facilitator 검증을 위해서만 사용됨). 이후 호출은 두 번째 서명만 필요하며, 경험상 "서명 한 번 클릭 → 결과 받기"로 보입니다.

### 사용법 2: Node 서버 + viem 개인 키 (백엔드 / CLI에 적합)

`@acedatacloud/x402-client`는 TS 측에서 **EIP-1193 provider만 수용**합니다 — 개인 키를 직접 관리하지 않습니다. Node / CLI 시나리오에서는 표준 방법으로 [`viem`](https://viem.sh/)를 사용하여 개인 키를 `WalletClient`로 포장한 후, [`@ethereumjs/util`](https://www.npmjs.com/package/@ethereumjs/util) 또는 viem 내부의 EIP-1193 적응을 사용합니다.

```ts theme={null}
import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(process.env.BASE_RPC_URL)
});

// viem WalletClient 자가 EIP-1193 호환의 .request()를 제공하므로 evmProvider로 직접 사용할 수 있습니다.
const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'base',
    evmProvider: walletClient as any,   // walletClient.request는 EIP-1193을 충족합니다.
    evmAddress: account.address,
    preferScheme: 'upto'
  })
});

const res: any = await client.openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'hi' }],
  max_tokens: 20
});
console.log(res.choices[0].message.content);
```

> viem의 EIP-1193 적응이 충분히 안정적이지 않다고 생각되면, 더 낮은 수준의 [`signEVMUptoPayment`](https://github.com/AceDataCloud/SDK/blob/main/typescript/packages/x402-client/src/evm.ts)를 사용할 수 있으며, `accepts → signed envelope → PAYMENT-SIGNATURE header` 경로를 직접 연결하여 SDK 훅을 건너뛸 수 있습니다. 그러나 여전히 `createX402PaymentHandler`를 우선 선택하는 것이 좋습니다. 프로토콜 업그레이드를 직접 유지 관리할 필요가 없습니다.

### 사용법 3: Solana

```ts theme={null}
import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';
import { Keypair } from '@solana/web3.js';

const kp = Keypair.fromSecretKey(/* Uint8Array */);

const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'solana',
    solanaWallet: {
      publicKey: kp.publicKey,
      signTransaction: async (tx) => {
        tx.sign([kp]);
        return tx;
      }
    }
  })
});
```

Solana 체인에서는 현재 **오직 `exact` scheme**만 노출되므로 Solana에서는 `preferScheme`이 작동하지 않습니다.

## 삼、Python: 개인 키 모드

Python의 `acedatacloud-x402`는 **개인 키로 직접 서명**하는 경로를 따릅니다(이것은 EIP-1193 추상화가 없습니다), 서버 측 / 작업 실행기에 더 적합합니다.

### 설치

```bash theme={null}
pip install acedatacloud acedatacloud-x402
```

실제 테스트 버전 번호:

```text theme={null}
acedatacloud==2026.4.26.1
acedatacloud-x402==2026.5.31.3
```

### EVM(기본 / Skale)

```python theme={null}
import os
from acedatacloud import AceDataCloud
from acedatacloud_x402 import (
    create_x402_payment_handler,
    EVMAccountSigner,
)

# 1. 개인 키로 서명기 생성
signer = EVMAccountSigner.from_private_key(os.environ["EVM_PRIVATE_KEY"])

# 2. SDK 생성: api_token을 전달하지 않고 SDK가 402 경로를 따르도록 합니다.
client = AceDataCloud(
    payment_handler=create_x402_payment_handler(
        network="base",
        evm_signer=signer,
        prefer_scheme="upto",   # chat 유형은 반드시 upto를 선택해야 합니다.
    )
)

# 3. 정상 호출
res = client.openai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "hi"}],
    max_tokens=20,
)
print(res["choices"][0]["message"]["content"])
```

### Solana

```python theme={null}
import os
from acedatacloud import AceDataCloud
from acedatacloud_x402 import (
    create_x402_payment_handler,
    SolanaKeypairSigner,
)

signer = SolanaKeypairSigner.from_secret_key_base58(os.environ["SOLANA_PRIVATE_KEY"])

client = AceDataCloud(
    payment_handler=create_x402_payment_handler(
        network="solana",
        solana_signer=signer,
        rpc_url="https://api.mainnet-beta.solana.com",  # 선택 사항
    )
)
```

### 일회성 승인(오직 EVM 최초)

EVM Base에서 X402는 Permit2를 사용하므로, 지갑은 USDC에 대해 Permit2 계약에 대해 한 번 `MaxUint256`의 승인을 해야 합니다. `acedatacloud-x402`는 내장된 `approve_permit2`를 제공합니다:

```python theme={null}
from acedatacloud_x402 import approve_permit2

tx_hash = approve_permit2(
    evm_signer=signer,
    rpc_url=os.environ["BASE_RPC_URL"],
)
print("permit2_approve_tx", tx_hash)
```

이 거래는 한 번만 발송하면 되며, 이후 모든 X402 EVM 결제는 이 승인을 사용합니다. Solana는 필요하지 않습니다.

## 사、실제 실행 검증

테스트 목표: **TS SDK가 토큰을 전달하지 않고 X402 핸들러를 주입하여 요청을 정상적으로 구성하고 시작할 수 있는지 확인합니다**(실제 체인에서 USDC를 소모하지 않는 경량 검증).

```ts theme={null}
// /tmp/sdk-tests/ts/x402-wire-test.ts
import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';

const handler = createX402PaymentHandler({
  network: 'base',
  evmProvider: { request: async () => '0x0' } as any,   // 자리 표시자 provider
  evmAddress: '0x0000000000000000000000000000000000000000',
  preferScheme: 'upto'
});

console.log('handler_type', typeof handler);   // function

const client = new AceDataCloud({
  paymentHandler: handler
});

console.log('client_ctor_ok', client.constructor.name);   // AceDataCloud
```

출력:

```text theme={null}
handler_type function
client_ctor_ok AceDataCloud
```

결과 설명:

* `apiToken`을 전달하지 않았으므로 SDK 생성 시 **오류가 발생하지 않습니다**, 이는 X402 모드가 실제로 토큰의 합법적인 대체품임을 증명합니다.
* `createX402PaymentHandler`는 함수(훅)를 반환하며, SDK는 402를 수신할 때만 호출합니다.
* 실제 체인에서 결제하는 엔드 투 엔드 테스트는 실제 USDC 차감이 포함되므로 본 튜토리얼에 포함되지 않았습니다. [X402 통합 가이드](https://platform.acedata.cloud/documents/x402-integration)에서 e2e 예제를 참조할 수 있습니다.

> Python 측 `create_x402_payment_handler`도 동일한 검증을 수행했습니다 — 함수 반환 값은 호출 가능하며, `payment_handler=...`를 주입할 때 `AceDataCloud(...)` 생성 시 오류가 발생하지 않습니다. 양쪽의 의미가 일치합니다.

## 오、"Bearer token 모드"와의 비교

| 차원 | API Token | X402 |
| - | - | - |
| 적합한 상황 | 자사 백엔드, 장기 프로젝트 | 제3자 개발자, 사용량 기반 요금, Agentic 호출 |
| 등록 | [콘솔](https://platform.acedata.cloud/console/applications)에서 신청해야 함 | 필요 없음; 체인 상의 지갑만 있으면 됨 |
| 요금 정확도 | 미리 충전, 토큰 테이블에 따라 요금 부과 | 호출 시 실시간으로 체인에 기록 |
| 잔액 | 콘솔에서 확인 가능 | 체인 상의 지갑 USDC |
| 최초 비용 | 이메일 등록 시 무료 한도 제공 | USDC를 Base로 브리지하고, 최초 Permit2 승인 필요 |
| chat 유형에 적합 | ✅ | ✅（반드시 `preferScheme=upto`） |
| 일회성 결제 / 계정 간 대납에 적합 | ❌ | ✅ |
| 코드 변경 | `apiToken: '...'` | `paymentHandler: createX402PaymentHandler(...)` |
| 두 가지 모드는 공존할 수 있습니다——같은 프로세스 내에서 서로 다른 `client` 인스턴스에 서로 다른 인증 방식을 설정하면 됩니다. | | |

## 여섯, 일반적인 함정

1. **chat 클래스는 `preferScheme=upto` 여야 합니다**: `exact`를 사용하면 facilitator가 `maxAmountRequired`(실제 사용량이 아님)에 따라 USDC를 차감합니다.
2. **Node 측에서 `createX402PaymentHandler`에 원시 개인 키를 전달하지 마세요**: TS 패키지는 `{ privateKey }`를 수용하지 않으며, EIP-1193 provider로 포장해야 합니다(추천: viem `WalletClient`).
3. **첫 호출은 이중 서명입니다**: 첫 번째로 Permit2 approve에 서명(온체인, 가스 필요), 두 번째로 X402 envelope에 서명(온체인 아님). 이후 호출은 두 번째 서명만 남습니다.
4. **Solana에는 Permit2 개념이 없습니다**: 직접 SPL 토큰 전송 권한에 서명하며, approve가 필요하지 않습니다; 그러나 현재 Solana 체인에서는 `exact`만 지원합니다.
5. **비즈니스 오류와 결제 오류 구분**: 402 → 핸들러 실패 시 `X402SignError`를 발생시킵니다(구체적인 유형은 체인에 따라 다름); 이후 재전송 시 비즈니스 인터페이스의 오류(401 / 422 / 5xx)는 여전히 일반 SDK 예외로 분류됩니다.
6. **`viem`에 가장 안정적인 적합한 작성법**: `evmProvider: walletClient as any`는 타입 검사를 잃지만 호환성이 가장 좋습니다; 타입을 유지하고 싶다면 viem의 `.transport.request`로 `{ request }` 객체를 따로 포장하여 전달해야 합니다.

## 더 알아보기

* 📦 [`@acedatacloud/x402-client` on npm](https://www.npmjs.com/package/@acedatacloud/x402-client)
* 🐍 [`acedatacloud-x402` on PyPI](https://pypi.org/project/acedatacloud-x402/)
* 🗂 [X402 클라이언트 소스코드](https://github.com/AceDataCloud/SDK/tree/main/x402-client)
* 🔗 [X402 통합 가이드](https://platform.acedata.cloud/documents/x402-integration)
* 📘 [TypeScript SDK 접속 튜토리얼](https://platform.acedata.cloud/documents/sdk-typescript)
* 🐍 [Python SDK 접속 튜토리얼](https://platform.acedata.cloud/documents/sdk-python)
* 🌐 [x402.org](https://www.x402.org/)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.