AP2 — Stripe 정산 데모
에이전트가 데이터를 사고 Stripe Checkout(test mode)으로 정산하는 교육용 예시. 실제 결제는 발생하지 않습니다.
프리미엄 시장 인사이트
에이전트가 구매하는 목업 프리미엄 데이터 — 실제 시세 조언이 아닙니다.
$0.50
테스트 카드: 4242 4242 4242 4242, 임의의 미래 만료일 / CVC / 우편번호.
기술 노트
각 항목이 실제로 무엇을 보여주고 어떻게 동작하는지 — 위 카드보다 자세한 기술 설명입니다.
AP2 — Stripe 정산라이브
목적: "에이전틱 결제" 패턴의 최소 예시 — 자율 에이전트가 무언가를 구매하고 표준 법정화폐 결제 레일로 정산하는 흐름을, Stripe의 호스팅 Checkout을 정산 계층으로 삼아 보여줍니다.
동작 방식: 일반 HTML 폼이 서버 라우트로 POST 되면, 서버 전용 secret key로 Stripe SDK를 통해 Checkout Session을 생성한 뒤 Stripe의 호스팅 결제 페이지로 리다이렉트합니다. 결제 후 돌아오면 같은 서버 컴포넌트가 Stripe API로 세션의 payment_status를 다시 독립적으로 검증한 뒤에만 구매 콘텐츠를 공개합니다 — 클라이언트 리다이렉트만 믿지 않기 때문에 "결제 건너뛰고 success URL 직접 호출" 같은 공격을 막습니다.
관련 코드:
"""AP2 -- Stripe settlement PoC -- client "paid" claim vs server-side re-verification.
Illustrates the core mechanism: the server never trusts a client redirect alone; it
independently checks payment_status against its own mock payment record store.
"""
from dataclasses import dataclass
@dataclass
class PaymentRecord:
session_id: str
payment_status: str # "paid" | "unpaid"
class MockStripe:
"""Stands in for Stripe's API: the source of truth the server re-checks against."""
def __init__(self):
self._sessions: dict[str, PaymentRecord] = {}
def create_checkout_session(self, session_id: str) -> str:
self._sessions[session_id] = PaymentRecord(session_id, "unpaid")
return f"https://checkout.mock/{session_id}"
def pay(self, session_id: str) -> None:
"""Simulates the buyer actually paying on Stripe's hosted page."""
self._sessions[session_id].payment_status = "paid"
def retrieve(self, session_id: str) -> PaymentRecord:
return self._sessions[session_id]
class Server:
def __init__(self, stripe: MockStripe):
self.stripe = stripe
def release_content(self, session_id: str, client_claims_paid: bool) -> str:
# The point of the demo: client_claims_paid is IGNORED. Only Stripe's own
# record, fetched server-side, decides whether content is released.
record = self.stripe.retrieve(session_id)
if record.payment_status == "paid":
return "CONTENT RELEASED: here is your purchased data"
return "DENIED: payment_status is not 'paid' per Stripe -- redirect alone proves nothing"
if __name__ == "__main__":
stripe = MockStripe()
server = Server(stripe)
session_id = "cs_test_123"
url = stripe.create_checkout_session(session_id)
print(f"server created checkout session -> {url}")
print("\nattacker skips payment, hits the success URL directly claiming paid=True:")
print(" ", server.release_content(session_id, client_claims_paid=True))
print("\nlegit buyer actually pays on Stripe's hosted page:")
stripe.pay(session_id)
print(" ", server.release_content(session_id, client_claims_paid=True))