> ## Documentation Index
> Fetch the complete documentation index at: https://daehan-base.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 결제 수락 (x402)

> x402로 에이전트의 엔드포인트를 게이팅하여 다른 에이전트에게 요청별 요금 청구

export const AcceptingPaymentsDemo = () => {
  const mono = "ui-monospace,'Cascadia Code','Source Code Pro',Menlo,Monaco,Consolas,monospace";
  const col = {
    dim: "#3f3f46",
    muted: "#52525b",
    active: "#60a5fa",
    success: "#34d399",
    code: "#d4d4d8"
  };
  const steps = [{
    delay: 350,
    left: [{
      t: "> npm install x402-express express",
      c: "active"
    }],
    right: [{
      t: "── Middleware Config ───────────────────",
      c: "dim"
    }, {
      t: "{",
      c: "code"
    }]
  }, {
    delay: 650,
    left: [{
      t: "  ✓ x402-express installed",
      c: "success"
    }],
    right: [{
      t: '  "path": "/api/data",',
      c: "code"
    }, {
      t: '  "price": "$0.01",',
      c: "code"
    }, {
      t: '  "network": "base",',
      c: "code"
    }, {
      t: '  "payTo": "0x742d...c4f2"',
      c: "code"
    }, {
      t: "}",
      c: "code"
    }]
  }, {
    delay: 500,
    left: [{
      t: "> configure x402 middleware...",
      c: "active"
    }],
    right: []
  }, {
    delay: 600,
    left: [{
      t: "  ✓ paymentMiddleware applied",
      c: "success"
    }],
    right: []
  }, {
    delay: 400,
    left: [{
      t: "  ✓ endpoint live: /api/data · $0.01/req",
      c: "success"
    }],
    right: [{
      t: "",
      c: "dim"
    }, {
      t: "── Live endpoint ───────────────────────",
      c: "dim"
    }, {
      t: "  GET /api/data → 402 (unpaid)",
      c: "muted"
    }, {
      t: "  GET /api/data + sig → 200 (paid)",
      c: "success"
    }]
  }, {
    delay: 900,
    left: [{
      t: "  waiting for requests...",
      c: "muted"
    }],
    right: [{
      t: "",
      c: "dim"
    }, {
      t: "── Incoming request ────────────────────",
      c: "dim"
    }, {
      t: "GET /api/data",
      c: "code"
    }, {
      t: "X-Payment-Sig: 0xc3d1...f891",
      c: "success"
    }]
  }, {
    delay: 700,
    left: [{
      t: "  ← payment verified · 0.01 USDC",
      c: "muted"
    }],
    right: [{
      t: "",
      c: "dim"
    }, {
      t: "── Payment verified ────────────────────",
      c: "dim"
    }, {
      t: "  amount: 0.01 USDC ✓",
      c: "success"
    }, {
      t: "  sig valid: true ✓",
      c: "success"
    }]
  }, {
    delay: 400,
    left: [{
      t: "  ✓ serving data  · balance +0.01 USDC",
      c: "success",
      bold: true
    }],
    right: []
  }];
  const [leftLines, setLeftLines] = useState([]);
  const [rightLines, setRightLines] = useState([]);
  const [running, setRunning] = useState(false);
  const [done, setDone] = useState(false);
  const [blink, setBlink] = useState(true);
  const leftRef = useRef(null);
  const rightRef = useRef(null);
  useEffect(() => {
    const t = setInterval(() => setBlink(b => !b), 530);
    return () => clearInterval(t);
  }, []);
  useEffect(() => {
    if (leftRef.current) leftRef.current.scrollTop = leftRef.current.scrollHeight;
  }, [leftLines]);
  const play = () => {
    setLeftLines([]);
    setRightLines([]);
    setRunning(true);
    setDone(false);
    let i = 0;
    const next = () => {
      if (i >= steps.length) {
        setRunning(false);
        setDone(true);
        return;
      }
      const s = steps[i];
      setTimeout(() => {
        if (s.left && s.left.length) setLeftLines(prev => [...prev, ...s.left]);
        if (s.right && s.right.length) setRightLines(prev => [...prev, ...s.right]);
        i++;
        next();
      }, s.delay);
    };
    next();
  };
  useEffect(() => {
    setTimeout(play, 350);
  }, []);
  const renderLine = (item, i) => {
    if (!item.t) return <div key={i} style={{
      height: 6
    }} />;
    return <div key={i} style={{
      fontFamily: mono,
      fontSize: 12,
      lineHeight: "20px",
      color: col[item.c] || col.code,
      fontWeight: item.bold ? 600 : 400,
      whiteSpace: "pre"
    }}>{item.t}</div>;
  };
  return <div style={{
    margin: "28px 0",
    borderRadius: 12,
    overflow: "hidden",
    border: "1px solid #27272a",
    background: "#09090b"
  }}>
      <div style={{
    display: "flex",
    alignItems: "center",
    padding: "8px 12px",
    background: "#111113",
    borderBottom: "1px solid #27272a"
  }}>
        <div style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: 28,
    height: 24,
    borderRadius: 6,
    background: "#1e1e20",
    border: "1px solid #27272a",
    marginRight: 10,
    flexShrink: 0
  }}>
          <span style={{
    fontFamily: mono,
    fontSize: 11,
    color: "#71717a",
    userSelect: "none"
  }}>{">"}_</span>
        </div>
        <span style={{
    fontFamily: mono,
    fontSize: 12,
    color: "#52525b"
  }}>Accepting Payments</span>
        <div style={{
    flex: 1
  }} />
        <button onClick={play} title="Reset" style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: 28,
    height: 24,
    borderRadius: 6,
    background: "transparent",
    border: "1px solid transparent",
    cursor: "pointer",
    color: "#3f3f46",
    fontSize: 15,
    lineHeight: 1
  }} onMouseEnter={e => {
    e.currentTarget.style.color = "#a1a1aa";
    e.currentTarget.style.background = "#1e1e20";
    e.currentTarget.style.borderColor = "#27272a";
  }} onMouseLeave={e => {
    e.currentTarget.style.color = "#3f3f46";
    e.currentTarget.style.background = "transparent";
    e.currentTarget.style.borderColor = "transparent";
  }}>
          {"\u21ba"}
        </button>
      </div>

      <div style={{
    height: 250,
    borderBottom: "1px solid #27272a",
    overflow: "hidden",
    display: "flex",
    flexDirection: "column"
  }}>
        <div style={{
    padding: "7px 16px 5px",
    borderBottom: "1px solid #1c1c1e"
  }}>
          <span style={{
    fontFamily: mono,
    fontSize: 10,
    fontWeight: 600,
    letterSpacing: "0.1em",
    textTransform: "uppercase",
    color: "#3f3f46"
  }}>Agent</span>
        </div>
        <div ref={leftRef} style={{
    flex: 1,
    overflowY: "hidden",
    padding: "12px 16px"
  }}>
          {leftLines.map(renderLine)}
          {running && <div style={{
    fontFamily: mono,
    fontSize: 12,
    lineHeight: "20px",
    color: "#60a5fa",
    opacity: blink ? 1 : 0
  }}>{"▋"}</div>}
        </div>
      </div>

      <div style={{
    padding: "8px 16px",
    display: "flex",
    justifyContent: "center",
    minHeight: 37,
    alignItems: "center"
  }}>
        {done && <button onClick={play} style={{
    fontFamily: mono,
    fontSize: 11,
    color: "#52525b",
    background: "none",
    border: "none",
    cursor: "pointer",
    padding: "4px 10px",
    borderRadius: 4
  }} onMouseEnter={e => {
    e.currentTarget.style.color = "#a1a1aa";
    e.currentTarget.style.background = "#18181b";
  }} onMouseLeave={e => {
    e.currentTarget.style.color = "#52525b";
    e.currentTarget.style.background = "none";
  }}>
            {"\u21ba"} Play again
          </button>}
      </div>
    </div>;
};

x402를 사용하여 다른 에이전트에게 접근 비용을 청구하는 에이전트 서비스를 구축할 수 있습니다. 클라이언트가 결제 없이 엔드포인트를 호출하면 결제 요건과 함께 `402`를 반환합니다. 클라이언트가 결제하면 퍼실리테이터가 결제를 검증하고 서버가 응답을 전달합니다.

## 모의 데모

<AcceptingPaymentsDemo />

## 옵션 1 — OpenClaw monetize-service 스킬 (가장 간단)

CDP Agentic Wallet 스킬이 설치된 경우 단일 프롬프트로 유료 엔드포인트를 노출할 수 있습니다:

```bash Terminal theme={null}
npx skills add coinbase/agentic-wallet-skills
```

그런 다음 에이전트에게 요청합니다:

```text theme={null}
Set up a paid endpoint for my market data at $0.01 per request
```

`monetize-service` 스킬이 x402 게이팅을 설정하고 엔드포인트를 배포합니다. 서버 코드가 필요하지 않습니다.

[CDP Agentic Wallet 스킬 →](https://docs.cdp.coinbase.com/agentic-wallet/skills)

## 옵션 2 — Sponge Wallet 결제 링크

다른 에이전트가 서비스에 접근하기 전에 결제하는 재사용 가능한 x402 결제 링크를 생성합니다:

```bash Terminal theme={null}
curl -X POST "https://api.wallet.paysponge.com/api/payment-links" \
  -H "Authorization: Bearer $SPONGE_API_KEY" \
  -H "Sponge-Version: 0.2.1" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "0.01",
    "description": "Access to my market data API"
  }'
```

반환된 결제 링크 URL을 클라이언트와 공유합니다. 결제 상태 확인:

```bash Terminal theme={null}
curl "https://api.wallet.paysponge.com/api/payment-links/{paymentLinkId}" \
  -H "Authorization: Bearer $SPONGE_API_KEY" \
  -H "Sponge-Version: 0.2.1"
```

[Sponge Wallet 문서 →](https://wallet.paysponge.com/skill.md)

## 옵션 3 — x402-express를 사용한 커스텀 서버

`x402-express` 패키지를 사용하여 Express 엔드포인트에 결제 게이팅을 추가합니다:

```bash Terminal theme={null}
npm install x402-express express
```

```typescript TypeScript theme={null}
import express from "express";
import { paymentMiddleware } from "x402-express";

const app = express();

app.use(
  paymentMiddleware(
    "0xYourAgentWalletAddress",
    {
      "/api/data": {
        price: "$0.01",
        network: "base-sepolia",
      },
    }
  )
);

app.get("/api/data", (req, res) => {
  res.json({ data: "premium content" });
});

app.listen(3000);
```

미들웨어는 미결제 호출자에게 `402`를 반환합니다. CDP 퍼실리테이터가 검증과 온체인 정산을 처리합니다.

[x402 셀러 퀵스타트 →](https://docs.cdp.coinbase.com/x402/docs/client-server-model)

## 퍼실리테이터 설정

퍼실리테이터는 결제 페이로드를 검증하고 온체인에서 결제를 정산하는 오프체인 서비스입니다. 두 가지 옵션이 있습니다:

| 퍼실리테이터              | 사용 시기                                |
| ------------------- | ------------------------------------ |
| **CDP 퍼실리테이터** (기본) | 프로덕션 — CDP API 키 필요, Base와 Solana 지원 |
| **공개 테스트넷 퍼실리테이터**  | 개발 — API 키 불필요, Base Sepolia 전용      |

공개 테스트넷 퍼실리테이터 엔드포인트는 `https://www.x402.org/facilitator`입니다. 메인넷에서는 CDP 퍼실리테이터로 전환합니다. 전체 엔드포인트 세부 정보는 [x402 클라이언트-서버 모델](https://docs.cdp.coinbase.com/x402/docs/client-server-model)을 참조하세요.

## 가격 및 결제 조건

* USD로 가격 설정 (예: `"$0.01"`) — 미들웨어가 적절한 토큰 금액으로 변환
* 결제는 기본적으로 Base의 USDC로 정산
* 최소 결제 금액 없음 — 1센트 미만의 금액도 지원
* 지갑이 직접 결제를 받음 — 프로토콜에서 별도 수수료 없음

## 엔드포인트를 검색 가능하게 만들기

`/.well-known/SKILL.md`에 엔드포인트의 입력, 출력, 가격, 인증 요건을 설명하는 `SKILL.md` 파일을 호스팅합니다. 에이전트는 이 경로를 확인하여 서비스를 검색합니다.

```markdown SKILL.md template theme={null}
# Your Agent Service

## Description
What your service does, in plain language.

## Endpoints

### GET /api/data
- **Description:** Returns premium market data
- **Payment:** $0.01 per request via x402 (Base, USDC)
- **Output:** JSON with current prices and volume

## Authentication
x402 payment required. No API key needed.
```

ERC-8004 레지스트리에 서비스를 등록하면 에이전트가 카테고리별로 검색할 수 있습니다 — [에이전트 등록](/ai-agents/setup/agent-registration)을 참조하세요.

## 관련 항목

<CardGroup cols={2}>
  <Card title="x402 프로토콜" icon="bolt" href="/ai-agents/payments/pay-for-services-with-x402">
    클라이언트 측에서 본 x402 작동 방식입니다.
  </Card>

  <Card title="x402 클라이언트-서버 모델" icon="file-contract" href="https://docs.cdp.coinbase.com/x402/docs/client-server-model">
    퍼실리테이터 엔드포인트와 프로토콜 주소입니다.
  </Card>
</CardGroup>
