x402 API가 메인넷에서 결제되었는데 Coinbase의 Bazaar에 나타나지 않나요? 문자 하나를 확인하세요.
요약
x402 API 결제 후 Coinbase Bazaar에 리스팅되지 않는 문제를 해결하는 방법을 다룹니다. 프록시 환경에서 프로토콜이 HTTP로 잘못 인식되는 원인과 Express의 'trust proxy' 설정을 통한 해결책을 제시합니다.
핵심 포인트
- HTTPS가 아닌 HTTP 리소스는 CDP 인덱싱에서 제외됨
- TLS 종료 프록시 사용 시 Express의 'trust proxy' 설정 필수
- 보안을 위해 'trust proxy' 값으로 true 대신 1을 권장
- resource.description은 500자 제한을 준수해야 함
우리는 두 개의 호출당 과금(pay-per-call) 방식의 x402 엔드포인트(교차 DEX 시장 데이터, Uniswap v4 hook 리스크 스캔)를 운영하고 있습니다. 우리는 4주 동안 CDP 퍼실리테이터(facilitator)를 통해 4건의 실제 메인넷 결제를 완료했습니다. 하지만 Bazaar 머천트(merchant) 엔드포인트는 계속해서 다음과 같은 응답만 반환했습니다:
{"pagination":{"limit":20,"offset":0,"total":0},"resources":[]}
우리는 한 달 동안 이를 "비동기 인덱싱 지연(async index lag)" 탓으로 돌렸습니다. 지연이 아니었습니다. 단 하나의 문자, 아니 다섯 글자 때문이었습니다: http://.
비용이 들지 않는 진단 방법
인덱싱이 "따라잡기를" 바라며 또 다른 결제를 진행하기 전에, 여러분의 402 문제를 직접 디코딩해 보세요:
curl -sI https://your-api.example.com/paid-route | \
grep -i payment-required | cut -d' ' -f2 | base64 -d | jq .resource.url
만약 결과가 https:// 대신 http://your-api...로 출력된다면, 문제를 찾은 것입니다. CDP는 resource.url이 HTTPS가 아닌 리소스를 인덱싱하는 것을 조용히 거부합니다. 에러도, 거부 상태도 발생하지 않습니다. 결제는 성공하고 돈은 이동하지만, 리스팅은 절대 나타나지 않습니다.
왜 거의 모든 사람에게 이런 일이 발생하는가
여러분은 Railway, Cloudflare, Render, Fly 또는 로드 밸런서와 같은 TLS 종료(TLS-terminating) 프록시 뒤에 있습니다. TLS는 에지(edge)에서 종료되므로, 여러분의 Express 앱은 일반 HTTP를 보게 되며 req.protocol === 'http'가 됩니다. x402 미들웨어(middleware)는 모든 402 챌린지(challenge)와 *모든 결제 페이로드(settle payload)*의 resource.url에 해당 프로토콜을 그대로 포함시킵니다.
해결책은 paymentMiddleware를 마운트하기 전에 단 한 줄을 추가하는 것입니다:
app.set('trust proxy', 1);
true가 아닌 1을 사용하세요. true를 사용하면 Express는 가장 왼쪽에 있는 X-Forwarded-For 항목을 가져오는데, 이는 어떤 클라이언트든 여러분의 속도 제한(rate limiter)을 피하기 위해 위조할 수 있습니다. 1을 사용하면 프록시가 관찰한 항목을 가져오며, 이는 위조할 수 없습니다. 우리는 16개의 위조된 X-Forwarded-For 값을 가진 16개의 병렬 요청을 통해 속도 제한이 여전히 올바르게 작동함을 확인했습니다.
이 한 줄을 배포한 후, 우리의 다음 결제는 1분도 채 되지 않아 인덱싱되었습니다. 4주 동안의 "지연"이 스킴(scheme)의 문자 하나로 해결되었습니다.
리스팅으로 가는 길에 마주치는 세 가지 추가 함정
1. 500자 설명 제한 (The 500-character description cap). CDP 퍼실리테이터(facilitator)는 resource.description이 500자를 초과하는 모든 결제(settle)를 하드 리젝트(hard-reject)합니다. 이때 구매자는 오해의 소지가 있는 스키마 유니온(schema-union) 에러를 보게 되며, 이는 단지 조용한 두 번째 402 에러로만 나타납니다. 이제 우리는 부팅 시점에 길이를 검증(assert)하여, 이 문제가 조용히 재발(regress)하지 않도록 조치했습니다.
2. 가격 하한선(Price floor)이 존재할 수 있습니다. 우리의 $0.001 경로는 결제에 성공했음에도 30분 이상 인덱싱(index)되지 않았습니다. 반면 동일한 경로를 $0.01로 설정했을 때는 다음 결제 후 4분 이내에 인덱싱되었습니다. (시간 경과라는 변수도 있었기에) 결정적인 증거는 아니지만, 만약 저렴한 경로가 리스팅되지 않는다면 다른 것을 디버깅하기 전에 $0.01 이상의 금액으로 결제를 시도해 보세요.
3. 탐색 트래픽(Probe traffic)이 수요를 사칭합니다. 리스팅 후 몇 시간 이내에, 무언가가 우리의 유료 경로를 시간당 약 240회의 기계적인 일정한 속도로 호출하기 시작했습니다 — 심지어 우리가 자체 발견 메타데이터(discovery metadata)에 작성한 예시 입력값과 정확히 일치하는 값을 재현(replaying)하고 있었습니다. 특정 User-Agent 해시가 전체의 94%를 차지했습니다. 만약 402 챌린지(challenge)를
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기