개요
무엇인가요
MONDO를 통해 Apple Pay 결제 수락
필요한 것들
MONDO 계정 ID + 비밀 키
보낸 사진
Apple Pay 토큰 + 금액 + 통화
받는 것
완료됨 또는 거부됨 상태
작동 방식
옵션 A: 자체 호스팅
Apple Pay 버튼을 사이트에 표시하고 토큰을 전송하세요
옵션 B: MONDO-주최
모든 것을 처리합니다 - 고객을 저희에게로 리디렉션하세요
빠른 시작 (자체 호스팅)
POST https://server-to-server.getmondo.co/payment/
{
"company_account_id": "your_id",
"gateway_secret_key": "your_key",
"apple_pay_token": { /* from Apple Pay JS */ },
"transaction_amount": "99.99",
"transaction_currency_iso3": "EUR",
"live_or_sandbox": "sandbox"
}
Apple Pay 정보
Apple Pay는 고객이 빠르고 안전하며 개인적으로 결제할 수 있는 방법을 제공합니다. MONDO를 여러분의 결제 서비스 제공자(PSP)로 사용하면, 별도의 Apple 개발자 계정 없이도 Apple Pay를 수락할 수 있습니다.
MONDO가 당신의 PSP로
- ✓ MONDO가 Apple Merchant ID를 소유합니다
- ✓ MONDO는 Apple Pay 인증서를 관리합니다
- ✓ MONDO가 상인 검증을 처리합니다
- ✓ MONDO는 결제 토큰을 해독하고 처리합니다
토큰 처리 - 누가 무엇을 하나요?
Apple Pay는 카드 소유자 데이터를 보호하기 위해 종단 간 암호화를 사용합니다. 책임이 어떻게 나뉘어져 있는지는 다음과 같습니다:
| 애플 (고객의 기기) | 암호화된 결제 토큰 생성 - 카드 데이터, 암호문, 인증 세부 정보 포함 |
| 당신 (상인) | 암호화된 토큰을 apple_pay_token 파라미터를 통해 MONDO에 직접 전달하세요 — 복호화를 시도하지 마세요 |
| 몬도 (PSP) | 토큰을 해독하고 Apple Pay 결제 처리 인증서를 사용하여 CardCorp와 결제를 처리합니다 |
통합 방법 선택
📋 필수 조건
- ✓ 파트너 계정 ID - 고유한 MONDO 계정 식별자
- ✓ 파트너 비밀 키 - API 인증 키
- ✓ HTTPS - HTTPS를 사용해야 합니다
⚠️ 도메인 확인 필요
Apple을 통해 MONDO에 도메인을 등록해야 합니다. 이는 일회성 설정입니다.
- 이동 GETMONDO.CO
- Login → Developer → Apple Pay → Add Apple Pay Domain
🔄 결제 흐름
웹사이트에서
네이티브 애플 페이 인터페이스
JS가 MONDO의 검증 엔드포인트를 호출합니다
Face ID / Touch ID
POST to /payment/ with apple_pay_token
사용자가 성공/실패 URL로 리디렉션되었습니다
🔗 API 엔드포인트
상인 검증 엔드포인트
상인 검증 매개변수
| 파라미터 | 유형 | 필요함 | 설명 |
|---|---|---|---|
| validationURL | string | ✓ 예 | Apple에서 제공한 URL onvalidatemerchant 이벤트 |
| company_account_id | string | ✓ 예 | 귀하의 MONDO 파트너 계정 ID |
| gateway_secret_key | string | ✓ 예 | 당신의 MONDO 파트너 비밀 키 |
| domain_name | string | ○ 조건부 | Apple Pay 도메인(예: paynow.yoursite.com). 브라우저 Origin 헤더를 사용할 수 없는 서버 간 호출에 필요합니다. 브라우저에서 직접 호출하는 경우 필요하지 않습니다. |
백엔드가 상인 검증 호출을 프록시하는 경우(즉, 서버가 브라우저 대신 MONDO를 호출하는 경우), 반드시 포함해야 합니다
domain_name Apple Pay 버튼이 표시되는 도메인으로 설정하세요. 이렇게 하면 Apple Pay 세션이 결제 페이지 도메인과 일치하게 됩니다. 📝 필수 매개변수 (결제 처리)
| 파라미터 | 유형 | 설명 |
|---|---|---|
| company_account_id | string | 귀하의 MONDO 파트너 계정 ID |
| gateway_secret_key | string | 당신의 MONDO 파트너 비밀 키 |
| apple_pay_token | object | 암호화됨 토큰 발급 완료 event.payment.token — pass directly to MONDO as-is (암호 해독 금지) |
| transaction_amount | decimal | 결제 금액 (예: 99.99) |
| transaction_currency_iso3 | string | 통화 코드 (EUR, USD, GBP) |
| cardholder_email_address | string | 고객 이메일 |
선택적 매개변수
| 파라미터 | 설명 |
|---|---|
| partner_return_url_completed | 성공적인 결제 리디렉션 URL |
| partner_return_url_rejected | 거절된 결제 리디렉션 URL |
| partner_webhook_url | 웹훅 알림 URL |
| live_or_sandbox | live 또는 sandbox |
📤 API 응답
Apple Pay 결제는 즉시 처리됩니다. 응답에는 최종 거래 상태가 포함됩니다:
{
"status": "success",
"transaction_status": "COMPLETED",
"gateway_session_id": "73d68b79579eeaa4a1f35f667509ba19",
"transaction_id": "37819a4707f3736b6fb42148d98f05ab",
"gateway_message": "Transaction succeeded",
"redirect_url": "https://yoursite.com/success?gateway_session_id=...&payment_status=COMPLETED"
}
응답 필드
| 필드 | 설명 |
|---|---|
| status | success 또는 error |
| transaction_status | COMPLETED 또는 REJECTED |
| gateway_session_id | 이 트랜잭션의 고유 세션 식별자 |
| transaction_id | 고유 거래 식별자 - 콜백과 연동하려면 이것을 사용하세요 |
| gateway_message | 사람이 읽을 수 있는 상태 메시지 |
| redirect_url | 결제 후 사용자를 리디렉션할 URL (선택 사항 - UX 전용) |
3D Secure 리디렉션을 요구하는 카드 결제와 달리, Apple Pay 거래는 즉시 처리됩니다. 응답을 받을 때 결제는 이미 완료되어 있습니다.
🍎 Apple Pay JS 통합
단계 1: Apple Pay 버튼 추가
<apple-pay-button buttonstyle="black" type="plain" locale="en" onclick="startApplePayPayment()"></apple-pay-button>
단계 2: 사용 가능 여부 확인
if (window.ApplePaySession && ApplePaySession.canMakePayments()) {
document.getElementById('apple-pay-button').style.display = 'block';
}
단계 3: 구현 완료
async function startApplePayPayment() {
const paymentRequest = {
countryCode: 'US',
currencyCode: 'EUR',
merchantCapabilities: ['supports3DS'],
supportedNetworks: ['visa', 'masterCard'],
total: { label: 'Your Company', amount: '99.99', type: 'final' }
};
const session = new ApplePaySession(3, paymentRequest);
// Merchant Validation
session.onvalidatemerchant = async (event) => {
const resp = await fetch('https://server-to-server.getmondo.co/payment/apple_pay_validate_merchant.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
validationURL: event.validationURL,
company_account_id: 'YOUR_ACCOUNT_ID',
gateway_secret_key: 'YOUR_SECRET_KEY',
domain_name: 'your-domain.com' // Required for server-to-server; optional if browser calls directly
})
});
session.completeMerchantValidation(await resp.json());
};
// Payment Authorization - Apple provides ENCRYPTED token in event.payment.token
// IMPORTANT: Pass the token directly to MONDO - do NOT attempt to decrypt it
session.onpaymentauthorized = async (event) => {
const resp = await fetch('https://server-to-server.getmondo.co/payment/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
company_account_id: 'YOUR_ACCOUNT_ID',
gateway_secret_key: 'YOUR_SECRET_KEY',
apple_pay_token: event.payment.token, // Encrypted token - MONDO decrypts
transaction_amount: '99.99',
transaction_currency_iso3: 'EUR',
cardholder_email_address: 'customer@example.com',
partner_return_url_completed: 'https://yoursite.com/success',
partner_return_url_rejected: 'https://yoursite.com/failed',
live_or_sandbox: 'live'
})
});
const result = await resp.json();
if (result.transaction_status === 'COMPLETED') {
session.completePayment(ApplePaySession.STATUS_SUCCESS);
// Payment already processed - redirect is optional for user experience
if (result.redirect_url) {
window.location.href = result.redirect_url;
}
} else {
session.completePayment(ApplePaySession.STATUS_FAILURE);
if (result.redirect_url) {
window.location.href = result.redirect_url;
}
}
};
session.begin();
}
테스트 모드
MONDO는 두 가지 테스트 모드를 지원합니다. 차이점을 이해하는 것이 성공적인 통합에 중요합니다.
무슨 일이 일어나나요
- ✅ 토큰 구조가 검증되었습니다
- ✅ 모든 필수 필드가 확인되었습니다
- ⏭️ 암호 해독이 생략됨 (모의 데이터 반환)
- ⏭️ CardCorp API 호출이 건너뛰어졌습니다
- ✅ 전체 결제 과정이 실행되었습니다
무슨 일이 일어나나요
- ✅ 토큰 구조가 검증되었습니다
- ✅ 모든 필수 필드가 확인되었습니다
- ✅ 실제 암호 해독
- ✅ Real CardCorp API 처리
- ✅ 실제 금액이 청구됩니다
🎯 SANDBOX가 동일한 토큰 구조를 요구하는 이유
이 디자인은 SANDBOX에서 LIVE로 전환할 때 코드 변경 없이 통합이 즉시 작동하도록 보장합니다.
⚙️ 모드 설정
포함하다 live_or_sandbox API 요청의 매개변수:
{
"company_account_id": "your_account_id",
"gateway_secret_key": "your_secret_key",
"apple_pay_token": { ... },
"transaction_amount": "99.99",
"transaction_currency_iso3": "EUR",
"live_or_sandbox": "sandbox" // or "live" for production
}
🎭 샌드박스: 강제 거래 결과
SANDBOX 모드에서는 테스트를 위해 특정 거래 결과를 강제로 적용할 수 있습니다:
| 파라미터 | 가치 | 결과 |
|---|---|---|
| sandbox_force_transaction_status | COMPLETED |
✅ 결제 승인됨 |
| sandbox_force_transaction_status | REJECTED |
❌ 결제 거절됨 |
Apple Pay 토큰 구조
Apple Pay 토큰은 다음과 같은 구조를 가져야 합니다. 이것은 SANDBOX와 LIVE 모드 모두에 동일합니다.
"***") SANDBOX 모드에서도 오류가 발생합니다. 필요한 토큰 구조
{
"paymentData": {
"version": "EC_v1",
"data": "BASE64_ENCRYPTED_PAYMENT_DATA",
"signature": "BASE64_SIGNATURE",
"header": {
"ephemeralPublicKey": "BASE64_EPHEMERAL_KEY",
"publicKeyHash": "BASE64_PUBLIC_KEY_HASH",
"transactionId": "UNIQUE_TRANSACTION_ID"
}
},
"paymentMethod": {
"displayName": "Visa 1234",
"network": "Visa",
"type": "debit"
},
"transactionIdentifier": "APPLE_TRANSACTION_ID"
}
필드 설명
| 필드 | 필요함 | 설명 |
|---|---|---|
| paymentData.version | ✓ | 항상 EC_v1 |
| paymentData.data | ✓ | Apple에서 암호화된 Base64 결제 데이터 |
| paymentData.signature | ✓ | Base64 서명 확인 |
| paymentData.header.ephemeralPublicKey | ✓ | Base64 일시적 공개 키 |
| paymentData.header.publicKeyHash | ✓ | 상인의 공개 키 Base64 해시 |
| paymentData.header.transactionId | ✓ | 고유 거래 식별자 |
| paymentMethod.network | ○ | 카드 네트워크 (Visa, Mastercard, Amex) |
| paymentMethod.displayName | ○ | Apple Wallet에서 표시 이름 |
✓ = 필요함 | ○ = 추천
샌드박스 테스트 토큰
SANDBOX 테스트를 위해 이 토큰을 복사하세요. 암호화된 값은 실제일 필요가 없습니다 - 구조만 검증됩니다.
{
"paymentData": {
"version": "EC_v1",
"data": "c2FuZGJveF9lbmNyeXB0ZWRfZGF0YV8xNzAyMjU2MDAwMDAw",
"signature": "c2FuZGJveF9zaWduYXR1cmVfMTcwMjI1NjAwMDAwMA==",
"header": {
"ephemeralPublicKey": "c2FuZGJveF9lcGhlbWVyYWxfa2V5XzE3MDIyNTYwMDAwMDA=",
"publicKeyHash": "c2FuZGJveF9wdWJsaWNfa2V5X2hhc2g=",
"transactionId": "SANDBOX_TXN_1702256000000_a1b2c3d4e5f6"
}
},
"paymentMethod": {
"displayName": "Visa 4242",
"network": "Visa",
"type": "debit"
},
"transactionIdentifier": "SANDBOX_TXN_1702256000000_a1b2c3d4e5f6"
}
일반 토큰 오류
| 오류 | 원인 | 솔루션 |
|---|---|---|
| Invalid token format | 토큰이 JSON 객체가 아닙니다 | 토큰을 문자열이 아닌 객체로 보내세요. |
| Missing paymentData | 토큰에 paymentData 속성이 없습니다 | Apple Pay JS에서 전체 토큰 포함 |
| Missing header fields | ephemeralPublicKey, publicKeyHash 또는 transactionId가 누락되었습니다 | 모든 헤더 필드가 있는지 확인하세요 |
토큰은 어디서 오나요?
LIVE 모드에서 토큰은 사용자가 결제를 승인할 때 Apple Pay JS에서 제공됩니다:
session.onpaymentauthorized = (event) => {
// This is the token you send to MONDO
const token = event.payment.token;
// Send to MONDO API
fetch('/payment/', {
body: JSON.stringify({
apple_pay_token: token, // Pass the entire token object
...
})
});
};
거래 상태
완전한 통합을 위해 거래 상태를 이해하고 조회하는 방법이 필수적입니다.
최종 거래 상태
웹후크 또는 /details 엔드포인트를 조회할 때 받게 될 가능한 최종 상태입니다:
중간 상태
거래가 생성되었으나 아직 처리 중입니다. 다음과 같은 경우에 발생할 수 있습니다:
- 사용자가 3D 보안 인증을 완료 중입니다
- 카드 네트워크에서 결제 처리 중입니다
- 사용자가 결제 과정을 중단했습니다
언제 거래 상태를 조회해야 하나요?
- 예상 시간 내에 웹훅을 받지 못했습니다 (예: 5분)
- 거래 상태를 수동으로 확인해야 합니다
- 웹후크 엔드포인트가 일시적으로 사용할 수 없습니다
거래 상태 조회
거래 상태를 확인하려면 세부 정보 엔드포인트에 POST 요청을 하세요:
요청 매개변수
| 파라미터 | 필요함 | 설명 |
|---|---|---|
| company_account_id | ✓ | 귀하의 MONDO 파트너 계정 ID |
| gateway_secret_key | ✓ | 당신의 MONDO 파트너 비밀 키 |
| gateway_session_id | ✓ | 초기 결제 요청에서 반환된 세션 ID |
예제 요청
curl -X POST https://server-to-server.getmondo.co/details/ \
-H "Content-Type: application/json" \
-d '{
"company_account_id": "your_account_id",
"gateway_secret_key": "your_secret_key",
"gateway_session_id": "sess_abc123xyz"
}'
예시 응답
{
"success": true,
"transaction_status": "COMPLETED",
"gateway_session_id": "sess_abc123xyz",
"transaction_amount": "99.99",
"transaction_currency_iso3": "EUR",
"card_last_4_digits": "4242",
"card_brand": "VISA",
"gateway_result_code": "000.000.000",
"gateway_result_description": "Transaction succeeded",
"created_at": "2024-12-10T22:30:00Z",
"completed_at": "2024-12-10T22:31:15Z"
}
상태 업데이트 수신
최종 거래 상태를 받는 두 가지 방법:
| 방법 | 작동 방식 | 사용 시기 |
|---|---|---|
| Webhook 추천 | MONDO가 POST 요청을 보냅니다 partner_webhook_url |
기본 방식 - 자동, 실시간 |
| Redirect URL | 사용자가 리디렉션됩니다 partner_return_url_completed 또는 partner_return_url_rejected |
사용자 확인을 위해 |
| Query /details | 상태 확인을 위해 POST 요청을 합니다 | 웹훅 수신 실패 시 |
거래가 시작됨 유지
거래가 15분 이상 INITIATED 상태로 남아 있다면, 다음을 의미할 가능성이 높습니다:
- 사용자가 3D 보안 도전을 포기했습니다
- 사용자가 결제 중에 브라우저를 닫았습니다
- 처리 중 네트워크 문제가 발생했습니다
동작: /details 엔드포인트를 조회하여 현재 상태를 확인하세요. 이 트랜잭션은 결국 타임아웃되어 FAILED 또는 CANCELED 상태로 변경됩니다.