한국 상품권 결제를 온라인 서비스에 연결하세요.
결제 요청 생성부터 수취 확인, 결과 통지, 건별 정산 내역까지 하나의 흐름으로 잇습니다. 한국 사용자는 익숙한 상품권으로 결제하고, 고객사는 API 호출 하나와 웹훅 하나로 연결합니다.
결제
2026년 9월 · 3,418건
고객사 1
결제 금액
33,000원
주문번호 ORD-58214
상품권 결제
안내에 따라 제출했어요
결제를 확인하고 있어요
보통 1분 안에 끝나요
marupay
payment.completed131ms200evt_5hRm6Ty1Gb 검증됨 · v1=3b7e…c04dstl_2Wr3Q8a433,000원 기록됨2026년 7월부터 해외 온라인 서비스 3곳이 MaruPay로 운영 중
- 게임재화 충전, 시즌 패스
- 디지털 콘텐츠이용권, 회차 열람
- 크리에이터 도구요금제, 에셋 팩
- 교육수강료, 수업 이용권
- 소프트웨어좌석, 사용량 크레딧
결제에 필요한 모든 것을 한 플랫폼에서.
결제를 받고, 확인하고, 고객사 서비스에 알리고, 기록을 남깁니다. 각각이 자기 화면을 가진 제품이라, 모든 팀이 같은 결제를 보고 일합니다.
한국 사용자가 있는 온라인 서비스를 위해.
한국 사용자가 이미 디지털 상품을 구매하는 온라인 서비스에 맞습니다. 지금은 게임 퍼블리셔, 디지털 콘텐츠 플랫폼, 온라인 교육 서비스가 운영 중이고, 크리에이터 도구와 소프트웨어도 같은 흐름을 씁니다.
- 카드
- 간편결제
- 상품권 결제 MaruPay 연결
상점이 구매를 반영하는 방식은 그대로 두고, 한국 플레이어에게 게임 재화, 시즌 패스, 아이템 묶음을 판매하세요.
주로 결제하는 것
- 재화 충전
- 시즌 패스
- 아이템 묶음
- 고객사 1 · 게임 퍼블리셔
2026년 7월부터 실서비스에서 운영하고 있습니다.
여기 있는 숫자는 모두 고객사가 콘솔에서 보는 것과 같은 기록에서 나옵니다.
- 12억 원
- 2026년 7월 출시 이후 처리액
- 3
- 연동해 운영 중인 온라인 서비스
- 99.97%
- 재시도 일정 안에 전달된 웹훅 이벤트
- 38초
- 결제 제출부터 수취 확인까지 중앙값
도입한 팀에서 달라진 것.
고객사 이름은 계약에 따라 공개하지 않고 번호로 표기합니다.
고객 사례 전체 보기- 고객사 2리더 패스 · 30일9,900원
- 카드
- 간편결제
- 상품권 결제 MaruPay 연결새로 추가
상품권으로 결제하기고객사 2 · 디지털 콘텐츠 플랫폼
11일 만에 한국 독자에게 오픈
한 디지털 콘텐츠 플랫폼이 리더 패스 결제에 카드 옆으로 상품권 결제를 더했습니다. 확인된 결제만 완료되자 ‘결제했는데 안 돼요’ 문의가 줄었습니다.
11일착수부터 실결제 오픈까지
- 고객사 1/정산이번 달 기록 · 2026년 9월112,846,500원
stl_2Wq8b1eORD-5821311,000원stl_2Wq5C8qORD-5821155,000원stl_2Wq1a0sORD-5820622,000원CSV 내보내기고객사 1 · 게임 퍼블리셔
내보내기 파일 하나로 월 마감
한 게임 퍼블리셔의 재무팀은 인게임 구매를 건별 정산 기록과 자사 주문번호로 맞춰 봅니다.
파일 1개한 달 치 구매 대사에 필요한 내보내기
- 고객사 3/결제
ORD-58199300,000원완료- 결제 생성
13:18:46 - 수취 확인
13:20:11 - 웹훅 전달
13:20:11
진행 기록으로 답변 완료
고객사 3 · 온라인 교육 서비스
결제 문의 3분의 1 감소
한 온라인 교육 서비스의 고객센터는 개발팀에 넘기지 않고 콘솔의 진행 기록으로 결제 문의에 답합니다.
−34%결제 1,000건당 결제 문의
- 결제 생성
API 호출 하나, 웹훅 하나.
고객사 서버에서 결제를 만들고, 돌려받은 결제 화면으로 사용자를 보낸 뒤, 서명된 payment.completed 이벤트가 오면 주문을 반영하세요. 수취 확인, 귀속, 재시도는 MaruPay가 맡습니다.
전체 문서는 승인된 고객사 계정에 제공됩니다.
create-payment.sh
curl https://api.marupay.app/v1/payments \
-H "Authorization: Bearer mp_live_••••••••" \
-H "Idempotency-Key: ORD-58202-1" \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORD-58202",
"customerId": "u_6624",
"amount": 49500,
"currency": "KRW",
"returnUrl": "https://example.com/orders/ORD-58202"
}'
HTTP/1.1 201 Created
{
"data": {
"id": "pay_2MzV6hTf9w",
"orderId": "ORD-58202",
"amount": 49500,
"currency": "KRW",
"status": "pending",
"payUrl": "https://pay.marupay.app/p/2MzV6hTf9w",
"expiresAt": "2026-09-29T05:01:58Z"
}
}
webhook.http
POST /webhooks/marupay HTTP/1.1
Host: api.example.com
Content-Type: application/json
MaruPay-Event-Id: evt_5hRd0Xw8Ne
MaruPay-Signature: t=1790656319,v1=e2c97b…0f5a
{
"id": "evt_5hRd0Xw8Ne",
"type": "payment.completed",
"data": {
"paymentId": "pay_2MzV6hTf9w",
"orderId": "ORD-58202",
"amount": 49500,
"currency": "KRW",
"completedAt": "2026-09-29T04:31:58Z"
}
}
HTTP/1.1 200 OK
verify.ts
import crypto from "node:crypto";
// header: "t=<unix>,v1=<hex>" body: the raw request body
export function verify(body: string, header: string, secret: string) {
const [, t, v1] = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header) ?? [];
if (!t || !v1) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${body}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) <= 300;
return fresh && crypto.timingSafeEqual(
Buffer.from(v1, "hex"),
Buffer.from(expected, "hex"),
);
}
// Retried deliveries reuse the event ID: credit each one once.
if (await processed.has(event.id)) return res.status(200).end();
결제 한 건, 요청부터 정산 기록까지
마우스를 올리면 멈춤 · 단계 선택
POST /v1/paymentsIdempotency-Key: ORD-58211-1{"orderId": "ORD-58211","customerId": "u_2210","amount": 55000,"currency": "KRW","returnUrl": "https://example.com/orders/ORD-58211"}
{ "id": "pay_6nHs4ZpC8q", "status": "pending","payUrl": "https://pay.marupay.app/p/6nHs4ZpC8q" }