Skip to content

Callback URL

결제 완료 후 브라우저 리다이렉트를 통해 결과를 전달받는 프론트엔드 방식입니다.

개요

사용자가 결제를 완료(또는 실패/닫기)하면, SoloPay 위젯은 결제 생성 시 지정한 successUrl 또는 failUrl로 사용자를 리다이렉트합니다. 이때 paymentId, orderId, status가 쿼리 파라미터로 자동 추가됩니다.

사용자 결제 완료

SoloPay 위젯이 successUrl 또는 failUrl로 리다이렉트

가맹점 페이지에서 쿼리 파라미터 수신

서버에서 GET /merchant/payments/:id 호출하여 검증 (필수)

동작 방식

  • PC 환경: 팝업 창에서 결제가 진행되며, 결제 완료 후 팝업이 닫히고 successUrl 또는 failUrl로 리다이렉트됩니다.
  • 모바일 환경: 전체 화면 페이지로 리다이렉트되어 결제가 진행되며, 완료 후 successUrl 또는 failUrl로 이동합니다.

successUrl / failUrl 설정

위젯 호출 시 successUrlfailUrl을 지정합니다.

typescript
solopay.requestPayment({
  orderId: 'order-001',
  amount: '10.5',
  tokenAddress: '0xE4C687167705Abf55d709395f92e254bdF5825a2',
  successUrl: 'https://yourshop.com/payment/success',
  failUrl: 'https://yourshop.com/payment/fail',
});
  • successUrl — 결제 성공 시 리다이렉트
  • failUrl — 결제 실패 또는 사용자가 위젯을 닫았을 때 리다이렉트

쿼리 파라미터

위젯이 리다이렉트 시 다음 파라미터를 자동으로 추가합니다.

파라미터설명
paymentId고유 결제 식별자
orderId가맹점 주문 ID
status결제 결과: success, fail, closed 중 하나
sigHMAC 콜백 서명 (t=timestamp,v1=signature). 가맹점에 웹훅 시크릿이 설정된 경우 포함. closed 상태에서는 포함되지 않음.

status 값 상세

리다이렉트 URL설명
successsuccessUrl결제가 성공적으로 완료됨
failfailUrl트랜잭션 실패 등으로 결제가 실패함
closedfailUrl사용자가 결제 완료 전에 위젯을 닫음 (결제가 생성되지 않았을 수 있음)

예시 URL

https://yourshop.com/payment/success?paymentId=0xabc123...&orderId=order-001&status=success&sig=t%3D1700000000%2Cv1%3Dabcdef...
https://yourshop.com/payment/fail?paymentId=0xabc123...&orderId=order-001&status=fail&sig=t%3D1700000000%2Cv1%3Dabcdef...
https://yourshop.com/payment/fail?paymentId=0xabc123...&orderId=order-001&status=closed

프론트엔드 처리 예시

successUrl 또는 failUrl 페이지에서 쿼리 파라미터를 파싱하고, 서버 API로 결제 상태를 검증합니다.

typescript
// successUrl 페이지 (예: /payment/success)
const params = new URLSearchParams(window.location.search);
const paymentId = params.get('paymentId');
const orderId = params.get('orderId');
const status = params.get('status');

if (paymentId) {
  // 서버에서 결제 상태 검증 (필수)
  const response = await fetch(`/api/verify-payment?paymentId=${paymentId}`);
  const result = await response.json();

  if (result.verified) {
    // 주문 완료 화면 표시
  } else {
    // 검증 실패 처리
  }
}
typescript
// failUrl 페이지 (예: /payment/fail)
const params = new URLSearchParams(window.location.search);
const status = params.get('status');

if (status === 'closed') {
  // "결제가 취소되었습니다" 안내
} else {
  // "결제에 실패했습니다. 다시 시도해주세요" 안내
}

결제 결과 검증 (필수)

URL 파라미터를 신뢰하지 마세요

쿼리 파라미터는 사용자가 조작할 수 있습니다. status=success라도 반드시 서버에서 API를 호출하여 실제 결제 상태를 확인해야 합니다.

paymentId를 수신하면 서버에서 GET /merchant/payments/:id를 호출하여 최종 상태를 검증합니다.

bash
curl https://gateway.dev.solonetwork.io/merchant/payments/0xabc123... \
  -H "x-api-key: sk_xxxxx"

검증 체크리스트

  • [ ] status === 'PAID' 확인 (결제 성공)
  • [ ] amount자사 주문 DB에 저장된 기대 금액과 일치 확인 (위젯은 클라이언트에서 실행되므로 금액이 변조될 수 있음)
  • [ ] tokenAddress가 기대한 토큰 컨트랙트 주소와 일치 확인
  • [ ] orderId가 기대한 orderId와 일치 확인
  • [ ] 동일 paymentId의 중복 완료 처리 방지

HMAC 콜백 서명 검증

가맹점에 웹훅 서명 시크릿이 설정되어 있으면, 위젯이 successUrlfailUrl 리다이렉트 시 sig 쿼리 파라미터를 추가합니다 (closed 상태 제외). 이를 통해 서버에서 리다이렉트가 SoloPay에서 발생했는지 검증할 수 있습니다.

서명 형식은 웹훅 서명과 동일합니다: t=timestamp,v1=signature. 서명 대상 페이로드는 timestamp.paymentId.orderId.status입니다.

SDK 사용

typescript
import { verifyCallbackSignature } from '@solo-pay/gateway-sdk';

// success/fail 페이지에서 (서버 사이드)
const { paymentId, orderId, status, sig } = queryParams;

if (sig) {
  const isValid = verifyCallbackSignature(
    sig,
    paymentId,
    orderId,
    status,
    process.env.WEBHOOK_SECRET
  );
  if (!isValid) {
    // 리다이렉트가 변조되었을 수 있음
  }
}

반드시 API로 검증하세요

콜백 서명이 유효하더라도, 반드시 서버에서 GET /merchant/payments/:id를 호출하여 최종 결제 상태를 확인해야 합니다. 콜백 서명은 추가적인 진위 확인 레이어이며, 서버 사이드 검증을 대체하지 않습니다.

한계 및 주의 사항

  • Callback URL은 브라우저 리다이렉트 기반이므로 네트워크 장애 등으로 유실될 수 있습니다.
  • 사용자가 결제 중간에 브라우저를 닫거나 네트워크가 끊기면 successUrl/failUrl에 도달하지 못할 수 있습니다.
  • Callback URL 단독으로는 결제 결과 수신을 보장할 수 없습니다.

Webhook 병행 권장

Callback URL의 한계를 보완하기 위해, 반드시 Webhook과 함께 사용하는 것을 권장합니다.

방식전달 경로신뢰성용도
Callback URL브라우저낮음사용자에게 결과 화면 표시
Webhook서버높음서버에서 주문 상태 갱신
  • Callback URL — 사용자 경험(결과 페이지 표시)에 활용
  • Webhook — 서버 사이드에서 주문 완료 처리에 활용
  • 두 채널 모두에서 GET /merchant/payments/:id로 최종 검증 필수

다음 단계

Non-custodial Web3 payment infrastructure for ERC-20 checkout, sponsored gas, and wallet-to-wallet settlement.