Workspace IndexKnowledge Notes › HTTP 402 is the easy part — settlement owns the retry

#30PoC

HTTP 402 is the easy part — settlement owns the retry

x402 turns payment into HTTP middleware, but the product boundary is what happens when verification succeeds, settlement times out, and the client retries the paid request.

Protect one idempotent API route with @x402/express, inject a timeout after each stage — verification, on-chain submission, settlement, resource generation — then retry the identical signed request and assert the two invariants: at most one settled payment, exactly one durable entitlement per settled payment.

Why

The facilitator removes blockchain plumbing from the seller; it does not remove distributed-systems semantics. A paid API needs an idempotency key and a durable payment-to-resource state machine.

x402 makes stablecoin payment look like ordinary HTTP middleware: the server returns payment requirements, the client signs, and a facilitator verifies and settles. The difficult boundary appears when one stage succeeds and the next response is lost.

How it works

Put one idempotent API behind @x402/express, inject failures between verify, settle, and fulfillment, then prove that one signed payment produces at most one charge and one response entitlement.

PoC

Protect one idempotent API route with @x402/express. Inject a timeout after verification, after on-chain submission, after settlement, and after resource generation. Retry the identical signed request and assert two invariants: at most one payment settles, and one settled payment always maps to one durable entitlement.

What it proves

A facilitator removes node operation and settlement submission from the seller, but it cannot make a distributed workflow atomic. The application still needs a payment identifier, durable state, replay handling, and reconciliation between facilitator results and canonical receipts.

References: x402 facilitator, x402 v2 SDK.

Review clarification

The demo ends where the product begins

Returning HTTP 402 with payment requirements is an hour of work; the middleware makes the demo almost free. What the middleware cannot give you is the thing that makes it a product: the moment money moves in one system (the chain) and the good is delivered in another (your API), you have a distributed transaction, and distributed transactions cannot be made atomic. The real work sits exactly where the demo ends — the retry.

The failure window is between the stages

One "paid request" is four stages — verify → submit → settle → fulfill — each crossing a network boundary that can eat the response. That is why the PoC injects a timeout after each stage rather than failing the stages: every stage succeeded, only the response was lost, and the client does the only rational thing and retries the identical signed request.

Window What is true What the retry must do
After verify Nothing settled, no money moved Re-verify and continue — the cheapest window
After submit The dangerous one: did the transfer land? The authorization nonce makes the chain refuse a second settle — so read "already used" as this payment already succeeded, never as an error to show the user
After settle Money moved, no product yet The debt exists only in your database — it must have been recorded durably before the crash
After fulfill Resource exists, delivery lost Return the same resource, never generate again

Misclassifying the second window is how a paying customer gets an error screen for a payment that worked.

The two invariants are the whole product

At most one settled payment per signed request; exactly one durable entitlement per settled payment. Everything else — middleware, facilitator, SDK — is replaceable plumbing. This is exactly the Web2 payments playbook: Stripe's Idempotency-Key and a durable state machine (received → verified → submitted → settled → fulfilled) keyed by the payment nonce. x402 changes the rail, not the semantics. "Settlement owns the retry" means retry handling cannot live in generic HTTP retry logic; a retry is a lookup about an existing payment first, and a new attempt only after that lookup says so.

Vigilance is not the deliverable

You cannot monitor your way out of a double charge — by the time you see it, the money moved twice. The guarantee has to be structural: assume every response can be lost, treat the retry as the normal path, and ask in design review, for each arrow in the flow, "what happens if the response after this arrow is lost and the same request arrives again?" If any arrow answers "we charge again" or "we deliver nothing," that arrow is the bug — before any code is written. The reconciliation line at the end is receipt-is-not-settlement again: the facilitator saying "settled" is one service's claim; the canonical receipt on chain is the authority. And the reason x402 matters at all is agent commerce — pay-per-request with no account and no API key is the rail an AI agent would use.

Where it lands in Jayverse

  • Verex: give every payment/order an idempotency key and a durable state machine. Track received → verified → submitted → settled → fulfilled per order so a retried checkout call after a lost response can't double-charge or double-fulfill.
  • Wallet: treat "already used" as success, not error. When the wallet resubmits a signed tx after a lost response and the chain refuses a second settle, surface that as "this already went through," not a failure screen.
  • Auditor: write down that the onchain receipt outranks a facilitator's "settled" claim. For any payment rail Verex adds, the canonical receipt is the authority; a service saying settlement completed is only a claim to reconcile against it.

Key expressions

Words and phrases from this page worth keeping, with the Korean meaning and the sentence they come from.

Expression뜻 · 쓰이는 자리
idempotent멱등의, 같은 요청을 여러 번 보내도 결과가 같은 · API·결제 요청 설계에서 핵심 성질. "protect one idempotent API route"
idempotency key멱등성 키 · 같은 요청을 식별해 중복 처리를 막는 값. "Stripe's Idempotency-Key and a durable state machine"
plumbing(비유) 배후 인프라, 배관 작업 · 겉으로 안 보이는 기반 시스템을 가리킬 때. "removes blockchain plumbing from the seller"
atomic원자적인, 쪼갤 수 없는 · 여러 단계가 한 번에 전부 성공하거나 실패해야 할 때. "distributed transactions cannot be made atomic"
reconciliation대사, 대조 확인 · 서로 다른 시스템의 기록이 일치하는지 맞춰보는 절차. "reconciliation between facilitator results and canonical receipts"
canonical기준이 되는, 정본의 · 여러 기록 중 진짜로 신뢰할 원본을 가리킬 때. "the canonical receipt on chain is the authority"
durable영속적인, 사라지지 않는 · 장애가 나도 남아 있어야 하는 상태·기록을 말할 때. "one durable entitlement per settled payment"
eat the response응답을 삼켜버리다, 유실시키다 · 네트워크 장애로 응답이 사라지는 상황. "a network boundary that can eat the response"
misclassify잘못 분류하다 · 상황을 틀리게 판단해 엉뚱하게 대응할 때. "gets an error screen for a payment that worked"
structural (guarantee)구조적인 (보장) · 사람의 주의력이 아니라 설계로 담보되는 안전장치. "the guarantee has to be structural"
x402HTTP 402(Payment Required) 상태 코드를 이용해 스테이블코인 결제를 HTTP 미들웨어로 만드는 프로토콜 · 에이전트가 계정·API 키 없이 요청마다 결제하게 하는 레일. "x402 turns payment into HTTP middleware"
facilitator결제 검증·정산을 대행하는 제3자 서비스(x402 프로토콜의 역할) · 블록체인 연동 작업을 판매자 대신 처리하지만 분산 트랜잭션 문제까지 없애주지는 않음. "The facilitator removes blockchain plumbing from the seller"
HTTP 402"결제 필요(Payment Required)" HTTP 상태 코드 · 원래 거의 쓰이지 않던 코드를 x402가 실제 결제 트리거로 되살려 쓰는 것. "Returning HTTP 402 with payment requirements is an hour of work"

← All Knowledge Notes · Workspace Index · Top ↑

HTTP 402 는 쉬운 부분이다 — 재시도는 정산의 책임이다

x402 는 결제를 HTTP 미들웨어로 만들지만, 제품의 경계는 검증이 성공하고 정산이 타임아웃된 뒤 클라이언트가 이미 결제한 요청을 재시도할 때 드러납니다.

@x402/express 로 멱등한 API 경로 하나를 보호하고, 단계마다 — 검증, 온체인 제출, 정산, 리소스 생성 직후 — 타임아웃을 주입합니다. 동일한 서명 요청을 재시도하며 두 불변식을 확인합니다: 정산은 최대 한 번, 정산된 결제 하나에 지속성 있는 사용 권한 하나.

Facilitator 는 판매자에게서 블록체인 배관을 없애 주지만, 분산 시스템의 의미론까지 없애 주지는 않습니다. 유료 API 에는 멱등성 키와 결제→리소스의 지속성 있는 상태 머신이 필요합니다.

x402 는 스테이블코인 결제를 평범한 HTTP 미들웨어처럼 보이게 합니다: 서버가 결제 조건을 돌려주고, 클라이언트가 서명하고, facilitator 가 검증하고 정산합니다. 어려운 경계는 한 단계가 성공한 뒤 다음 응답이 사라질 때 나타납니다.

동작 방식

멱등한 API 하나를 @x402/express 뒤에 두고, 검증·정산·이행 사이에 실패를 주입한 뒤, 서명된 결제 하나가 최대 한 번의 청구와 하나의 응답 권한만 만든다는 것을 증명합니다.

PoC

@x402/express 로 멱등한 API 경로 하나를 보호합니다. 검증 직후, 온체인 제출 직후, 정산 직후, 리소스 생성 직후에 각각 타임아웃을 주입합니다. 동일한 서명 요청을 다시 보내면서 두 불변식을 확인합니다: 결제는 최대 한 번만 정산되고, 정산된 결제 하나는 항상 지속성 있는 사용 권한 하나에 연결됩니다.

무엇을 증명하나

Facilitator 는 판매자가 노드를 운영하고 정산 트랜잭션을 제출하는 일을 없애 주지만, 분산 워크플로를 원자적으로 만들지는 못합니다. 애플리케이션에는 여전히 결제 식별자, 지속성 있는 상태, 재생 처리, facilitator 결과와 정규 체인 receipt 사이의 대사가 필요합니다.

참고: x402 facilitator, x402 v2 SDK.

검토 후 보완

데모가 끝나는 곳에서 제품이 시작된다

HTTP 402 와 결제 조건을 돌려주는 것은 한 시간짜리 일이고, 미들웨어는 데모를 거의 공짜로 만들어 줍니다. 미들웨어가 못 주는 것이 이것을 제품으로 만드는 부분입니다: 돈이 한 시스템(체인)에서 움직이고 상품이 다른 시스템(내 API)에서 전달되는 순간 분산 트랜잭션이 생기고, 분산 트랜잭션은 원자적으로 만들 수 없습니다. 진짜 일은 정확히 데모가 끝나는 자리 — 재시도 — 에 있습니다.

실패의 창은 단계 사이에 있다

"유료 요청" 하나는 네 단계 — verify → submit → settle → fulfill — 이고, 각 단계 사이의 네트워크 경계가 응답을 삼킬 수 있습니다. 그래서 PoC 는 단계를 실패시키는 게 아니라 각 단계 직후에 타임아웃을 주입합니다: 단계는 전부 성공했고 응답만 사라졌으며, 클라이언트는 합리적으로 동일한 서명 요청을 재시도합니다.

무엇이 사실인가 재시도가 해야 할 일
검증 직후 정산 없음, 돈 안 움직임 다시 검증하고 진행 — 가장 싼 창
제출 직후 위험한 창: 전송이 실렸나? 인가의 논스 덕에 체인이 두 번째 정산을 거부한다 — 그러니 "already used" 를 이 결제는 이미 성공했다로 읽어야지, 사용자에게 보여줄 에러로 읽으면 안 된다
정산 직후 돈은 움직였는데 상품이 아직 없음 그 부채는 내 DB 에만 존재한다 — 크래시 전에 지속성 있게 기록돼 있어야 한다
이행 직후 리소스는 있는데 전달이 유실됨 같은 리소스를 돌려준다, 절대 다시 생성하지 않는다

두 번째 창을 오분류하는 것이, 결제가 성공한 고객이 에러 화면을 보는 경로입니다.

두 불변식이 제품의 전부다

서명 요청당 정산은 최대 한 번; 정산된 결제당 지속성 있는 사용 권한 정확히 하나. 나머지 — 미들웨어, facilitator, SDK — 는 교체 가능한 배관입니다. 이것은 정확히 Web2 결제의 교과서입니다: Stripe 의 Idempotency-Key 와, 결제 논스를 키로 삼는 지속성 있는 상태 머신(received → verified → submitted → settled → fulfilled). x402 가 바꾸는 것은 레일이지 의미론이 아닙니다. "재시도는 정산의 책임"이라는 말은 재시도 처리가 일반 HTTP 재시도 로직에 살 수 없다는 뜻입니다 — 재시도는 먼저 기존 결제에 대한 조회이고, 그 조회가 허락할 때에만 새 시도입니다.

주시가 산출물이 아니다

이중 청구는 지켜봐서 막을 수 없습니다 — 눈에 보였을 때는 이미 돈이 두 번 움직인 뒤입니다. 보장은 구조적이어야 합니다: 모든 응답은 사라질 수 있다고 가정하고, 재시도를 정상 경로로 취급하고, 설계 리뷰에서 플로우의 화살표 하나하나에 "이 화살표 직후의 응답이 사라지고 같은 요청이 다시 오면 무슨 일이 생기는가?"를 묻습니다. 어느 화살표든 답이 "또 청구된다"거나 "아무것도 전달 안 된다"면, 코드를 쓰기 전에 그 화살표가 버그입니다. 마지막의 대사(reconciliation) 줄은 receipt-is-not-settlement 의 반복입니다: facilitator 의 "정산됨"은 한 서비스의 주장이고, 권위는 체인 위의 정규 receipt 에 있습니다. 그리고 x402 가 애초에 중요한 이유는 에이전트 커머스입니다 — 계정도 API 키도 없는 요청당 결제는 AI 에이전트가 쓸 레일입니다.

Jayverse에서의 위치

  • Verex: 모든 결제/주문에 idempotency 키와 durable 상태 머신을 붙인다. received → verified → submitted → settled → fulfilled 단계를 주문 단위로 추적해서, 응답이 유실된 뒤 재시도된 체크아웃 호출이 이중 청구나 이중 이행으로 이어지지 않게 한다.
  • Wallet: "이미 사용됨"을 실패가 아니라 성공으로 취급한다. 응답 유실 후 지갑이 서명된 트랜잭션을 재전송했는데 체인이 두 번째 정산을 거부하면, 이를 오류 화면이 아니라 "이미 처리됨"으로 보여준다.
  • Auditor: 온체인 영수증이 facilitator의 "정산됨" 주장보다 우선한다고 명시한다. Verex가 추가하는 어떤 결제 레일이든 캐노니컬 영수증이 최종 권위이고, 서비스가 정산 완료라고 말하는 것은 그것과 대조해야 할 하나의 주장일 뿐이다.

핵심 표현

이 페이지의 영어 본문에서 배울 만한 단어와 표현, 뜻과 나온 자리.

Expression뜻 · 쓰이는 자리
idempotent멱등의, 같은 요청을 여러 번 보내도 결과가 같은 · API·결제 요청 설계에서 핵심 성질. "protect one idempotent API route"
idempotency key멱등성 키 · 같은 요청을 식별해 중복 처리를 막는 값. "Stripe's Idempotency-Key and a durable state machine"
plumbing(비유) 배후 인프라, 배관 작업 · 겉으로 안 보이는 기반 시스템을 가리킬 때. "removes blockchain plumbing from the seller"
atomic원자적인, 쪼갤 수 없는 · 여러 단계가 한 번에 전부 성공하거나 실패해야 할 때. "distributed transactions cannot be made atomic"
reconciliation대사, 대조 확인 · 서로 다른 시스템의 기록이 일치하는지 맞춰보는 절차. "reconciliation between facilitator results and canonical receipts"
canonical기준이 되는, 정본의 · 여러 기록 중 진짜로 신뢰할 원본을 가리킬 때. "the canonical receipt on chain is the authority"
durable영속적인, 사라지지 않는 · 장애가 나도 남아 있어야 하는 상태·기록을 말할 때. "one durable entitlement per settled payment"
eat the response응답을 삼켜버리다, 유실시키다 · 네트워크 장애로 응답이 사라지는 상황. "a network boundary that can eat the response"
misclassify잘못 분류하다 · 상황을 틀리게 판단해 엉뚱하게 대응할 때. "gets an error screen for a payment that worked"
structural (guarantee)구조적인 (보장) · 사람의 주의력이 아니라 설계로 담보되는 안전장치. "the guarantee has to be structural"
x402HTTP 402(Payment Required) 상태 코드를 이용해 스테이블코인 결제를 HTTP 미들웨어로 만드는 프로토콜 · 에이전트가 계정·API 키 없이 요청마다 결제하게 하는 레일. "x402 turns payment into HTTP middleware"
facilitator결제 검증·정산을 대행하는 제3자 서비스(x402 프로토콜의 역할) · 블록체인 연동 작업을 판매자 대신 처리하지만 분산 트랜잭션 문제까지 없애주지는 않음. "The facilitator removes blockchain plumbing from the seller"
HTTP 402"결제 필요(Payment Required)" HTTP 상태 코드 · 원래 거의 쓰이지 않던 코드를 x402가 실제 결제 트리거로 되살려 쓰는 것. "Returning HTTP 402 with payment requirements is an hour of work"

← 전체 기술 노트 · 워크스페이스 인덱스 · 맨 위 ↑