Razorpay 통합 가이드: 결제를 망치는 5가지 실수
Source: Dev.to
많은 개발자들이 체크아웃 페이지를 열 수는 하지만, 여전히 다음과 같은 문제에 직면합니다:
- ❌ 결제가 검증되지 않음
- ❌ 청구 금액이 잘못됨
- ❌ 성공한 결제가 기록되지 않음
- ❌ 주문 상태가 업데이트되지 않음
여러 Razorpay 통합을 수정하면서 흥미로운 점을 발견했습니다:
대부분의 결제 실패는 몇 가지 작은 실수 때문에 발생합니다.
이 가이드에서는 가장 흔한 Razorpay 통합 실수 5가지와 이를 피하는 방법을 배울 수 있습니다.
📚 목차
- Razorpay 결제 흐름
- 실수 #1: 프런트엔드에서 주문 생성하기
- 실수 #2: 잘못된 금액 형식 사용하기
- 실수 #3: 결제 검증 생략하기
- 실수 #4: 웹훅 구현 안하기
- 실수 #5: 프로덕션에서 테스트 키 사용하기
- 마무리 생각
Razorpay 결제 흐름 (개요)
실수를 살펴보기 전에 올바른 결제 흐름을 이해하는 것이 중요합니다.
flowchart TD
A[User clicks Pay] --> B[Frontend sends request to Backend]
B --> C[Backend creates order using Razorpay API]
C --> D[Order ID returned to Frontend]
D --> E[Frontend opens Razorpay Checkout]
E --> F[User completes payment]
F --> G[Frontend sends payment details to Backend]
G --> H[Backend verifies payment signature]
H --> I[Payment confirmed]
핵심 원칙
- ✔ 주문은 백엔드에서 생성해야 합니다.
- ✔ 체크아웃은 프론트엔드에서 실행됩니다.
- ✔ 결제 검증은 백엔드에서 수행되어야 합니다.
이러한 분리는 보안 및 신뢰성을 보장합니다.
❌ 실수 #1: 프론트엔드에서 주문 생성하기
매우 흔한 실수는 Razorpay 주문을 프론트엔드에서 직접 생성하려는 것입니다.
❌ 잘못된 접근법
// frontend (DO NOT DO THIS)
fetch("https://api.razorpay.com/v1/orders")
이렇게 하면 비밀 API 키가 노출되어 매우 위험합니다. 누구든 코드를 검사하고 악용할 수 있습니다.
✅ 올바른 접근법
주문은 항상 백엔드에서 생성해야 합니다.
// backend (Node.js example)
const Razorpay = require("razorpay");
const razorpay = new Razorpay({
key_id: process.env.RAZORPAY_KEY_ID,
key_secret: process.env.RAZORPAY_KEY_SECRET,
});
const order = await razorpay.orders.create({
amount: 50000, // amount in paise
currency: "INR",
receipt: "receipt_123",
});
안전한 주문 생성 흐름
flowchart TD
A[User clicks Pay] --> B[Frontend requests backend to create order]
B --> C[Backend calls Razorpay API]
C --> D[Razorpay returns Order ID]
D --> E[Backend sends Order ID to frontend]
E --> F[Checkout opens]
❌ 실수 #2: 잘못된 금액 형식 사용
Razorpay는 루피가 아닌 파이세 단위의 금액을 기대합니다. 이 작은 디테일 때문에 많은 통합이 실패합니다.
❌ 잘못된 예시
amount: 500 // ❌ This is 500 INR, but Razorpay expects paise
✅ 올바른 예시
amount: 500 * 100 // ✅ 500 INR → 50000 paise
고객이 ₹500을 결제해야 한다면, Razorpay는 다음과 같이 기대합니다:
50000 // 500 × 100
금액 변환 흐름
flowchart TD
A[Customer payment: 500 INR] --> B[Convert to paise]
B --> C[500 × 100]
C --> D[Send 50000 to Razorpay]
기억할 규칙
Amount sent to Razorpay = Rupees × 100
❌ 실수 #3: 결제 검증 생략
많은 개발자들은 Razorpay Checkout에 “Payment Successful”(결제 성공)이라고 표시되면 결제가 완료된 것으로 가정합니다. 이는 충분한 증거가 아닙니다.
백엔드에서 결제 서명을 반드시 검증해야 합니다.
결제 검증 흐름
flowchart TD
A[User completes payment] --> B[Razorpay sends payment response to frontend]
B --> C[Frontend sends payment_id, order_id, signature to backend]
C --> D[Backend verifies signature using Razorpay secret key]
D --> E[Backend confirms payment]
검증이 없으면 공격자는 결제 응답을 위조할 수 있습니다.
❌ Mistake #4: Not Implementing Webhooks
프론트엔드 응답에만 의존하면 테스트 단계에서는 동작하지만, 실제 운영 환경에서는 결제가 다음과 같이 지연, 재시도, 환불, 부분 캡처될 수 있습니다.
- 지연됨
- 재시도됨
- 환불됨
- 부분 캡처됨
웹훅은 이러한 이벤트가 발생할 때 백엔드에 알림을 보냅니다.
Webhook Event Flow
flowchart TD
A[Payment event occurs on Razorpay] --> B[Razorpay sends webhook request]
B --> C[Your backend webhook endpoint receives event]
C --> D[Backend updates database]
D --> E[Order status updated]
일반적인 웹훅 이벤트는 다음과 같습니다:
payment.captured
payment.failed
refund.processed
웹훅이 없으면 백엔드가 실제 결제 상태를 알 수 없습니다.
❌ 실수 #5: 프로덕션에서 테스트 키 사용
이 실수는 생각보다 더 자주 발생합니다. 개발 중에 Razorpay는 테스트 API 키를 제공합니다. 해당 키가 프로덕션에 배포되면 실제 결제가 실패합니다.
환경 변수
RAZORPAY_KEY_ID=
RAZORPAY_KEY_SECRET=
배포 흐름
flowchart TD
A[Development] --> B[Use Razorpay Test Keys]
B --> C[Testing completed]
C --> D[Switch to Live Keys]
D --> E[Deploy to Production]
배포 전에 키를 항상 두 번 확인하세요.
최종 생각
결제 통합은 복잡한 코드 때문에 실패하는 경우는 드뭅니다. 개발자들이 간과하는 작은 세부 사항 때문에 실패합니다, 예를 들어:
- 잘못된 레이어에서 주문 생성
- 잘못된 금액 전송
- 결제 검증 생략
- 웹훅 무시
- 테스트 자격 증명으로 배포
위에서 설명한 패턴을 따르면, 안전하고 신뢰할 수 있는 Razorpay 통합을 구축할 수 있으며, 프로덕션 환경에서도 완벽히 동작합니다. 즐거운 코딩 되세요!
일반적인 Razorpay 통합 실수
- 웹훅 무시
- 테스트 키로 배포
이 다섯 가지 실수를 고치면 Razorpay 통합이 다음과 같이 됩니다:
- ✅ 안전함
- ✅ 신뢰성
- ✅ 프로덕션 준비 완료
💬 토론
프로덕션에서 Razorpay를 통합하면서 문제를 겪은 적이 있나요?
결제 통합에서 가장 어려웠던 부분은 무엇이었나요?
댓글에 경험을 공유해주세요 👇