Merchant API 수수료와 한도
청구서에는 받는 금액에서 떼는 서비스 수수료가 붙고, 송금과 송금 링크에는 금액 한도가 걸려요. 아래 숫자는 지금 설정된 값이지 계약 조건이 아니에요. 앱 화면과 다르면 앱이 맞고, 가장 믿을 만한 근거는 언제나 내가 받은 청구서예요.
청구서 수수료
내는 사람은 언제나 청구서의 액면 금액을 그대로 내요. 수수료는 가맹점 쪽에서 빠져요. 앱 잔액에는 수수료를 뺀 금액이 들어와요.
수수료는 청구 금액의 **3%**이고, 최근 30일 결제액에 따라 자동으로 내려가요.
| 30일 거래량 | 수수료 |
|---|---|
| $10,000 미만 | 3% |
| $10,000 이상 | 2.9% |
| $25,000 이상 | 2.8% |
| $50,000 이상 | 2.7% |
| $75,000 이상 | 2.6% |
| $100,000 이상 | 2.5% |
숫자보다 중요한 규칙이 두 가지 있어요.
- 수수료는 결제하는 시점에 정해져서 그대로 굳어요. 나중에 요율이 바뀌어도 이미 결제된 청구서는 건드리지 않아요.
- 결제액이 늘면 요율도 달라져요. 최근 30일 결제액이 많아지면 자동으로 낮은 구간으로 옮겨 가요. 신청할 것도, 설정할 것도 없어요.
실제로 얼마가 빠졌는지 보려면 결제된 청구서의 fee_asset과 fee_amount를
읽어 보세요. invoice_paid webhook의 페이로드에도, getInvoices 응답에도
들어 있어요. 장부에 쓸 값은 이거예요.
환불해도 수수료는 돌아오지 않아요. refundInvoice로 나가는 돈은 내 잔액에서
빠지고, 수수료는 부분 환불이든 전액 환불이든 돌려주지 않아요.
구독 결제에도 가맹점 쪽 수수료가 붙어요. 건별 금액은
subscription_charged webhook의 charge.fee 필드에 들어 있어요.
송금 한도
transfer에는 한 번에 보낼 수 있는 최소·최대 금액이 걸려요. 자산별 숫자가 아니라
현재 시세로 환산한 미국 달러 추정치로 따져요. 범위를 벗어나면 이유가 분명한
오류로 돌아오니까, 연동할 때 amount_too_small과 amount_too_big을 처리해
주세요.
이럴 때도 송금이 실패해요.
- 그 자산의 앱 잔액이 부족할 때,
- 받는 사람이 앱을 쓰고 있지 않을 때 — 모르는 Telegram ID나 잘못 적은 ID로 보내면 아무도 열지 않을 지갑에 넣는 대신 오류가 나요,
- 받는 사람의 계정이 차단됐을 때.
호출 한도
돈이 움직이는 메서드에는 앱 단위로 호출 한도가 걸려요(그 앱의 모든 토큰이 함께
써요). 분당 createInvoice와 createCheck는 60까지, refundInvoice와
transfer는 30까지, transferBatch는 10까지예요. 읽기 메서드에는 한도가 없어요.
얌전한 연동이라면 부딪칠 일이 없지만, 재시도 루프는 부딪쳐요. 계속 두드리는
대신 rate_limited가 오면 간격을 두고 다시 보내 주세요.
멱등키
transfer에는 직접 만든 **spend_id**가 꼭 있어야 하고, createCheck와
refundInvoice도 받아 줘요. 같은 값을 다시 쓰면 돈이 한 번 더 나가는 대신
원래 결과가 그대로 돌아와요. 그래서 응답이 늦은 요청은 같은 spend_id로
다시 보내면 안전하고, 진짜 새로운 지급에만 새 값을 주면 돼요.
돈이 안 드는 것
Merchant API에는 네트워크 수수료가 아예 없어요. 청구서도, 송금도, 송금 링크도 체인이 아니라 앱 안에서 끝나거든요. 돈이 드는 건 청구서에 붙는 서비스 수수료 하나예요.
⚠️ 수수료를 직접 계산하지 마세요
퍼센트를 코드에 박아 두거나, 액면 금액에서 실수령액을 거꾸로 계산하지 마세요. 구간과 요율은 바뀌고, 낡은 상수는 장부를 조용히 망가뜨려요. 수수료는 매번 청구서에 기록된 값을 읽어 주세요.
이 문서가 도움이 됐나요?
의견 고마워요.