x402 HTTP 스테이블코인 결제
도입
x402는 HTTP 402 Payment Required를 실제 결제 흐름으로 되살리는 모델이다. 서버는 paid resource 요청에 결제 요구사항을 반환하고, client 또는 agent는 결제 payload를 만들어 재요청한다. 서버는 payment를 verify/settle한 뒤 resource 접근을 허용한다.
AI agent 결제에서 x402가 중요한 이유는 단순하다. agent는 사람보다 더 자주 API를 호출하고, 결제 payload를 자동으로 만들 수 있다. 그래서 한도, merchant allowlist, idempotency, receipt, refund policy가 강의의 중심이 된다.
학습 목표
- HTTP 402 기반 결제 요청과 settlement 흐름을 설명한다.
- agent가 결제하는 API의 인증, 한도, 환불 정책을 설계한다.
개념 설명
개념 읽기
HTTP 402 기반 결제 요청과 settlement 흐름을 설명한다.
실패 상태 확인
서명 권한과 지출 한도가 분리되는가
실습 산출물 작성
x402 HTTP 스테이블코인 결제 이해 점검
완료 기준 대조
x402 흐름을 설명했다.
기본 handshake는 다음과 같다.
서버가 요구사항에 포함해야 할 필드는 제품마다 다르지만, 최소한 아래 판단은 필요하다.
| 필드 | 목적 |
|---|---|
| resource | 어떤 endpoint 또는 content에 대한 결제인가 |
| amount | exact price 또는 최대 승인액 |
| asset | token address, mint, decimals, symbol spoofing 방지 정보 |
| network | CAIP-2 같은 chain identifier |
| payee | settlement recipient |
| scheme | exact, upto 등 결제 방식 |
| expiry | payment payload 유효 기간 |
| idempotency key | 재시도와 중복 결제 방지 |
ERC-3009와 x402는 잘 맞는다. API 결제는 보통 정확한 payee와 amount에 대해 한 번만 지불하면 되기 때문이다. 다만 usage-based billing에서는 "최대 승인액"과 "실제 정산액"을 분리해야 한다.
코드로 확인하기
x402 흐름은 HTTP 402를 결제 협상 프로토콜로 다시 쓰는 모델이다. 서버는 "돈을 내라"가 아니라 "이 리소스는 어떤 네트워크, 어떤 자산, 어떤 수신자로 결제할 수 있다"를 구조화해서 돌려줘야 한다.
이 강의는 x402의 HTTP 협상과 정책 경계를 다룬다. 실제 결제 서버를 조립하는 실습은 x402 payment server lab에서 이어진다.
백엔드402 응답에 결제 요구사항 담기
function paymentRequired(resource: string) { return Response.json( { x402Version: 1, resource, accepts: [ { network: "eip155:8453", // CAIP-2: Base mainnet asset: "USDC", amount: "250000", decimals: 6, recipient: "0xMerchantTreasury" } ] }, { status: 402 } );}export async function GET(request: Request) { const payment = request.headers.get("x-payment"); if (!payment) return paymentRequired("/api/report/alpha"); return Response.json({ reportId: "alpha", body: "paid content" });}학습자가 봐야 할 점은 amount, asset, recipient, network가 응답에 명시된다는 것이다. 결제 요청이 모호하면 agent가 잘못된 체인이나 잘못된 수신자로 결제할 수 있다.
백엔드결제 header 검증 후 리소스 열기
type PaymentProof = { txHash: string; network: `eip155:${number}`; asset: string; amount: bigint; recipient: string;};async function authorizeX402(proof: PaymentProof, expectedAmount: bigint) { if (proof.network !== "eip155:8453") return { ok: false, reason: "wrong_network" }; if (proof.asset !== "USDC") return { ok: false, reason: "wrong_asset" }; if (proof.amount < expectedAmount) return { ok: false, reason: "underpaid" }; if (proof.recipient !== "0xMerchantTreasury") return { ok: false, reason: "wrong_recipient" }; return { ok: true, reason: "paid" };}결제 검증은 HTTP 레이어에서 끝나지 않는다. settlement 확인, 중복 txHash 방지, 환불 정책이 뒤따라야 실제 상품 전달과 연결된다.
클라이언트agent가 서명 전에 requirement를 읽는 방식
type X402Requirement = { network: `eip155:${number}`; asset: "USDC"; amount: string; decimals: 6; recipient: `0x${string}`; resource: string; expiry: string;};function summarizeRequirement(requirement: X402Requirement) { const amount = Number(requirement.amount) / 10 ** requirement.decimals; return { headline: `${amount} ${requirement.asset} 결제 필요`, riskCopy: `${requirement.network}에서 ${requirement.recipient}에게 결제`, canAutoPay: requirement.network === "eip155:8453" && requirement.asset === "USDC" && amount <= 1 };}agent payment에서 client 요약문은 보안 경계다. 사용자가 보지 못한 network, recipient, amount로 agent가 결제하면 서명은 유효해도 제품은 실패한 것이다.
인덱서x402 receipt 중복 처리
create unique index x402_receipts_once on x402_receipts (network, tx_hash, log_index, resource);select resource, count(*) as paid_attemptsfrom x402_receiptswhere created_at >= now() - interval '24 hours'group by resourcehaving count(*) > 1;HTTP retry가 많아지면 같은 결제가 여러 번 "성공"으로 기록될 수 있다. network + tx_hash + log_index + resource를 중복 방지 키로 두면 access grant와 회계가 함께 안정된다.
강의 포인트
| 관점 | 확인할 질문 | 증거로 남길 것 |
|---|---|---|
| payment requirement | 서버가 agent에게 충분한 결제 정보를 제공하는가 | requirement JSON 예시 |
| policy | agent가 결제 가능한 endpoint와 금액이 제한되어 있는가 | agent spending policy |
| settlement proof | 결제 완료 후 어떤 receipt를 저장하는가 | receipt schema |
| retry/idempotency | 네트워크 재시도에서 중복 결제가 막히는가 | idempotency design |
| refund/credit | service failure 후 환불 또는 credit 처리가 있는가 | refund policy |
실무 예시
유료 market data API를 agent가 호출한다고 가정한다. 첫 요청은 결제 없이 들어오고, 서버는 402 requirement를 반환한다. agent policy는 endpoint가 allowlist에 있고 요청 금액이 하루 한도 안에 있을 때만 signer를 호출한다. payment payload가 정산되면 서버는 receipt를 저장하고 응답을 제공한다.
| 상태 | 시스템 동작 | 실패 시 대응 |
|---|---|---|
PaymentRequired | 402 requirement 반환 | requirement에 network/asset/payee 누락 시 blocker |
PaymentSigned | agent가 payload 서명 | cap 초과 또는 merchant 미승인 시 중단 |
PaymentSubmitted | payload 재요청 | idempotency key로 중복 방지 |
Settled | facilitator 또는 chain settlement 확인 | receipt 저장 |
AccessGranted | resource 반환 | delivery log 저장 |
ServiceFailed | 결제 후 서비스 실패 | refund 또는 credit 정책 실행 |
흔한 오해와 실패 시나리오
| 오해 | 실제로 확인할 것 |
|---|---|
| x402는 단순히 402 status code만 쓰는 기능이라고 본다. | requirement, payment payload, verify/settle, receipt, access grant가 모두 필요하다. |
| agent 결제는 wallet이 알아서 막아준다고 본다. | agent policy layer가 merchant, endpoint, amount, frequency를 제한해야 한다. |
| 결제 후 API 실패를 예외로 둔다. | service failure는 refund 또는 credit 정책으로 설계해야 한다. |
| 재시도는 HTTP 클라이언트 문제라고 본다. | idempotency key와 receipt lookup이 없으면 중복 결제가 생긴다. |
| 네트워크를 이름으로만 저장한다. | CAIP-2 또는 동등한 chain identifier와 token address/mint가 필요하다. |
실습 과제
- x402 HTTP 스테이블코인 결제 이해 점검: paid endpoint의 402 requirement JSON 예시를 작성한다.
- agent 지출 한도 정의: endpoint allowlist, per-call cap, daily cap, monthly cap, merchant blocklist, manual approval threshold를 표로 만든다.
- 정산 증거 저장 방식 작성: resource, payer, payee, asset, network, amount, nonce/idempotency key, settlement tx, receipt status를 포함한 schema를 만든다.
- request/response/state model 작성: PaymentRequired, PaymentSigned, PaymentSubmitted, Settled, AccessGranted, ServiceFailed 상태와 전환 조건을 설계한다.
완료 기준
- x402 흐름을 설명했다.
- agent 지출 한도를 정의했다.
- 정산 증거 저장 방식을 만들었다.
근거 자료
- x402 HTTP 스테이블코인 결제: 05-계정추상화-에이전트결제/04-x402-HTTP-스테이블코인-결제.md
- x402 에이전트 결제 문서: 90-출처/원문-노트/x402-에이전트-결제-문서.md
- x402 How It Works: https://docs.cdp.coinbase.com/x402/core-concepts/how-it-works
- x402 Quickstart for Sellers: https://docs.cdp.coinbase.com/x402/quickstart-for-sellers