본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 23. 22:59

AI에게 지갑을 준 날 — Sonnet 4.6, AgentCore Payments, Rakuten 및 Stripe를 사용하여 승인 게이트가

요약

Claude Sonnet 4.6과 AgentCore Payments를 활용하여 AI 에이전트가 결제를 수행할 때 인간의 승인을 거치도록 하는 PoC를 구축했습니다. Stripe와 Rakuten을 연동하여 소액 결제부터 실제 제품 구매까지 안전하게 처리하는 승인 게이트 아키텍처를 구현했습니다.

핵심 포인트

  • Claude Sonnet 4.6 기반의 AI 에이전트 결제 시스템 구현
  • 인간의 승인 없이는 결제가 불가능한 '승인 게이트' 메커니즘 적용
  • AgentCore Payments와 Stripe를 결합한 다단계 결제 아키텍처
  • Next.js와 DynamoDB를 활용한 프로덕션 수준의 웹 서비스 구축

요약 (TL;DR)
저는 단일 Strands Agent 뒤에 Bedrock AgentCore Payments (x402 + USDC) Rakuten + Stripe Checkout을 연결하는 PoC(Proof of Concept, 개념 증명)를 구축했습니다. 그리고 에이전트가 인간의 승인 카드 없이는 단 1센트도 소비할 수 없도록 만들었습니다. Vercel에 프로덕션 배포되었으며, 8개 언어 UI를 지원합니다.

내가 이것을 구축한 이유

저는 **다섯 가지의 서로 다른 강연 / CFP (Call for Papers)**를 준비하고 있습니다 — re:Invent 2026 COM 트랙, Qiita Tech Festa, iOSDC LT, re:Deploy Security, 그리고 Slack Hackathon — 이 모든 것은 동일한 아이디어, 즉 **"AI에게 지갑을 주는 날, 그리고 승인 게이트(approval gate)가 어떤 모습인지"**에 집중되어 있습니다.

슬라이드만으로는 메시지를 전달하기에 부족했습니다. 청중 앞에서 실시간으로 실행할 수 있는 **공통 구현 기반 (shared implementation base)**이 필요했습니다.

목표의 형태는 간단했습니다:

사용자가 자연어 (natural language)로 질문함 → 에이전트가 옵션을 선택함 → 승인 카드 (approval card)가 나타남 → 인간이 승인 또는 거절함 → 승인 시 실제 결제가 실행됨 → 결과가 사용자에게 요약되어 전달됨.

저는 이를 두 가지 축에서 증명하고 싶었습니다: 호출당 비용이 발생하는 유료 API (microtransactions, 소액 결제)와 실제 제품 구매입니다.

아키텍처 (Architecture)

  • 프론트엔드: Vercel의 Next.js 16 (승인 목록 + 채팅 + 결제 결과)
  • 상태(State): DynamoDB — wallet_agent_tasks / approvals / txns, 스트림 및 PITR
  • 에이전트: AgentCore Runtime (ARM64 컨테이너) + Strands Agent + Claude Sonnet 4.6
  • 결제(Payments) — 1단계: AgentCore Payments → Privy (StripePrivy) → x402 → base-sepolia USDC
  • 결제(Payments) — 2단계: Rakuten Ichiba IchibaItem/Search → Stripe Checkout (테스트 모드)
  • 현지화(Localisation): ja / en / zh / ko / fr / it / es / ar (RTL) — 8개 언어, localStorage + navigator.language 자동 감지, 기본 글꼴로 LINE Seed JP Bold 사용

이 모든 것—코드, CloudFormation, 데모 스크립트—은 yama3133/wallet-agent에 있습니다.

에이전트 자체

이 에이전트는 Strands Agent에 연결된 단 6개의 @tool 함수로 구성되어 있습니다.

@tool
def search_paid_resources(query: str = "") -> list[dict]: ...  # x402 카탈로그

...

핵심은 request_*_approvalDynamoDB에 행을 작성하고 대기한다는 것입니다. 이 도구 체인(tool chain)은 인간 사용자가 해당 행을 APPROVED로 변경할 때까지 진행될 수 없습니다. 이 단 하나의 원시 기능(primitive)이 LLM이 통제 불능 상태가 되는 것을 막아줍니다.

1단계 — AgentCore Payments 서명자 함정

제가 가장 많은 시간을 허비했던 부분이 바로 여기입니다.

ProcessPayment → AccessDeniedException
"Privy credentials are invalid. Please verify the credential configuration." 

저는 boto3를 사용하여 PaymentManager, PaymentConnector, 그리고 PaymentInstrument (임베디드 암호화 지갑)을 아무 문제 없이 만들 수 있었습니다. 하지만 ProcessPayment 호출만 통과하지 않았습니다.

Privy 대시보드를 살펴보니, AWS의 CreatePaymentInstrument가 생성한 지갑은 내부적으로 생성된 Privy 사용자에게 소유되어 있었고, 저의 인증 키(Authorization Key)는 어떤 지갑에서도 서명자로 등록되어 있지 않았습니다.

해결 방법은 Privy의 공식 템플릿인 privy-io/aws-agentcore-sdk를 로컬에서 실행하고 브라우저에서 "Connect agent" UI를 클릭하여 진행하는 것입니다. 해당 UI는 Privy의 내부 API를 호출하여 사용자의 인증 키(Authorization Key)를 지갑의 additional_signers에 추가합니다.

git clone https://github.com/privy-io/aws-agentcore-sdk ~/wallet-agent-privy-template
cd ~/wallet-agent-privy-template
# .env.local 파일에 NEXT_PUBLIC_PRIVY_APP_ID / PRIVY_APP_SECRET / NEXT_PUBLIC_PRIVY_SIGNER_ID를 입력하세요
...

그 후, process_payment는 **PROOF_GENERATED**를 반환하며, 가맹점(https://drvd12nxpcyd5.cloudfront.net/market-recap, 공개 x402 데모 엔드포인트)이 페이로드(payload)를 수락합니다.

[bedrock_agentcore.payments.manager] Successfully processed payment for user test-user-yama3133
[bedrock_agentcore.payments.manager] Successfully generated payment header for user test-user-yama3133

교훈: AgentCore Payments 설정은 순수하게 서버 측(server-side)에서만 완료할 수 없습니다. 데모 흐름을 설계할 때 첫날부터 Privy 프론트엔드를 포함하도록 설계하세요.

2단계 — Rakuten과 Referer의 함정

2단계는 훨씬 더 평범한 WebAPI에서의 실패였습니다.

새로운 Rakuten 웹서비스 애플리케이션을 등록하고, Application ID(UUID 형식)를 가져와 https://openapi.rakuten.co.jp/ichibams/api/IchibaItem/Search/20260401로 요청을 보냈습니다. 결과는 다음과 같았습니다:

{"errors":{"errorCode":403,"errorMessage":"REQUEST_CONTEXT_BODY_HTTP_REFERRER_MISSING"}}

Referer: https://wallet-agent.vercel.app/를 추가해도 도움이 되지 않았습니다. 실제 원인은 **User-Agent 봇 탐지(bot detection)**였습니다. User-Agent: wallet-agent/0.1은 거부됩니다. 브라우저와 유사한 Mozilla/5.0 ...으로 교체하면 요청이 통과됩니다.

최종적인 tools/rakuten.py는 다음과 같은 모습입니다:

headers = {
    "User-Agent": (
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
...

그다음 과정은 다음과 같습니다: 1,980엔짜리 검은색 양말 한 켤레, Stripe Checkout Session, 테스트 카드 4242 4242 4242 4242, 그리고 **"Paid / 1,980 JPY."**가 표시되는 https://wallet-agent.vercel.app/checkout/success?session_id=cs_test_...로의 리다이렉트입니다.

DynamoDB 및 Vercel 프론트엔드 (frontend)

승인 상태는 DynamoDB의 **wallet_agent_approvals**에 저장됩니다. 로컬 개발 환경에서는 agent/.approvals.json을 사용하며, 이는 WALLET_AGENT_STORAGE=local|dynamo 설정에 따라 전환됩니다.

Next.js 16 App Router 측은 소수의 라우트 핸들러 (route handlers)로 구성됩니다:

// /api/approvals (GET) — PENDING(대기 중) 목록 조회
const r = await ddb().send(new ScanCommand({
  TableName: TABLES.approvals,
...

저는 한 번 **error가 DynamoDB 예약어 (reserved word)**라는 함정에 빠진 적이 있습니다. 이를 업데이트하려면 ExpressionAttributeNames: { "#e": "error" }가 필요하며, 그렇지 않으면 ValidationException: Invalid UpdateExpression 오류가 발생합니다.

8개 언어 UI 및 LINE Seed JP

apps/web/src/lib/i18n.ts는 8개 언어 × 31개 키로 구성된 단순한 플랫 사전 (flat dictionary)이며, 작은 useI18n() 컨텍스트 (Context)에 연결되어 있습니다. 아랍어 로케일 (locale)은 document.documentElement.dir을 `

  1. Privy 서명자 벽 (signer wall)은 서버 측에서 해결할 수 없습니다. 데모 구축 첫날부터 "에이전트 연결 (Connect agent)" 프론트엔드 단계를 포함하여 만드세요.
  2. agentcore configure는 기본적으로 대화형 (interactive)입니다. -ni 옵션, 직접 만든 ECR 리포지토리 (repo), 그리고 번들 내의 Dockerfile을 사용하면 CI에서 문제없이 구동할 수 있습니다.
  3. **Vercel의 60초 Hobby 타임아웃 (timeout)**은 오래 실행되는 에이전트를 동기적으로 호출하는 방식과 잘 맞지 않습니다. waitUntil 또는 폴링 (polling) 패턴을 계획하세요.
  4. 하나의 "인간 승인 카드 (human approval card)" 도구만 있으면 LLM을 구조적으로 안전하게 (safe-by-construction) 만들기에 충분합니다. 동일한 프리미티브 (primitive)가 수정 없이 1단계와 2단계를 모두 해결합니다.

링크 (Links)

이 PoC (Proof of Concept)는 하나의 공유된 구현체로 다섯 가지의 서로 다른 강연을 지원하기 위해 만들어졌습니다. 해당 이벤트들이 다가옴에 따라 내용을 개선해 나갈 예정입니다. 피드백은 언제나 환영합니다.

@yama3133 (AWS Community Builder, AI Engineering / 2026)

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0