Headless Checkout API Documentation
Integrate Korean payment processing into your application with our REST API. Build custom checkout experiences while we handle payment processing, compliance, and Korean market requirements.
📋 Prerequisites
- API key from your dashboard
- HTTPS endpoint for webhooks
- Basic understanding of REST APIs
- Korean business registration (for live payments)
Base URL
Production: https://api.koreacheckout.com
Sandbox: https://sandbox-api.koreacheckout.com
Basic Integration Flow
1. Create Checkout Session
Start by creating a checkout session with your order details:
curl -X POST https://api.koreacheckout.com/api/checkout/create-session \
-H "x-api-key: sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"platform": "headless",
"platformOrderId": "order_123",
"items": [
{
"name": "Sample Product",
"price": 29000,
"quantity": 1,
"productId": "prod_123"
}
],
"customer": {
"name": "홍길동",
"email": "customer@example.com",
"phone": "+82-10-1234-5678"
},
"totalAmount": 29000,
"currency": "KRW",
"returnUrl": "https://yourstore.com/success",
"cancelUrl": "https://yourstore.com/cancel",
"webhookUrl": "https://yourstore.com/webhooks/checkout"
}'
2. Redirect Customer
Use the returned checkout URL to redirect your customer:
// Response from session creation
{
"success": true,
"sessionId": "cs_1234567890abcdef",
"checkoutUrl": "https://checkout.koreacheckout.com/cs_1234567890abcdef",
"expiresAt": "2024-01-01T12:00:00Z"
}
// Redirect customer to checkout
window.location.href = response.checkoutUrl;
3. Handle Webhook Events
Listen for payment completion via webhooks:
// Your webhook endpoint
app.post('/webhooks/checkout', (req, res) => {
const { event, data } = req.body;
if (event === 'payment.completed') {
// Update order status in your database
updateOrderStatus(data.sessionId, 'paid');
fulfillOrder(data.platformOrderId);
}
res.status(200).send('OK');
});
WordPress Plugin Integration
The WordPress plugin provides seamless WooCommerce integration with Korean payment methods, address search, and customizable checkout experiences. Ideal for developers building Korean e-commerce sites.
🔧 Developer Features
- • Full WooCommerce integration with order sync
- • Korean address search (Daum Postcode API)
- • Customizable checkout forms and styling
- • WordPress hooks and filters for customization
- • Support for Korean payment methods (cards, virtual accounts)
- • Webhook handling for order status updates
Installation & Setup
# 1. Download plugin from your dashboard
# 2. Upload to WordPress via Plugins > Add New > Upload
# 3. Configure in WooCommerce > Korea Checkout
// Required Configuration
API URL: https://api.koreacheckout.com
API Key: sk_live_your_key_here
Order Status Mapping: Automatic
Developer Customization
// Filter checkout fields
add_filter('korea_checkout_fields', function($fields) {
// Add custom fields or modify existing ones
$fields['custom_field'] = array(
'type' => 'text',
'label' => 'Custom Field',
'required' => false
);
return $fields;
});
// Hook into payment completion
add_action('korea_checkout_payment_complete', function($order_id, $payment_data) {
// Custom logic after successful payment
$order = wc_get_order($order_id);
// Send custom emails, update inventory, etc.
do_action('custom_order_processing', $order, $payment_data);
}, 10, 2);
// Customize checkout appearance
add_filter('korea_checkout_css_vars', function($vars) {
$vars['--primary-color'] = '#your-brand-color';
$vars['--button-radius'] = '8px';
return $vars;
});
💡 WordPress Best Practices
- • Test in sandbox mode before going live
- • Use WordPress hooks instead of modifying plugin files
- • Implement proper error handling for payment failures
- • Use WordPress transients for caching API responses
API Keys
Your API key is used to authenticate all requests to our API. Keep it secure and never expose it in client-side code.
✅ Unified API Key
- • Single key for all payment methods and features
- • Automatic gateway detection and routing
- • Built-in fraud detection and analytics
- • Unified webhook endpoints for all events
⚠️ Security Best Practices
- • Never use API keys in frontend JavaScript
- • Regenerate keys if compromised
- • Always use HTTPS for API requests
🔑 API Key Format
All API keys start with sk_live_ for production or sk_test_ for sandbox mode
sk_live_1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Authentication
API requests are authenticated using API keys. Include your API key in the x-api-key header of all requests.
curl -X GET https://api.koreacheckout.com/api/checkout/session/cs_123 \
-H "x-api-key: sk_live_your_key_here" \
-H "Content-Type: application/json"
🔐 Security Notes
- • Keep your API keys secure and never expose them in client-side code
- • Use environment variables to store API keys
- • Rotate keys regularly for enhanced security
- • Different keys for sandbox and production environments
Base URL & Environments
Choose the appropriate base URL depending on your environment. Always test in sandbox before deploying to production.
🚀 Production
https://api.koreacheckout.com
Real payments, live Korean payment gateways
🧪 Sandbox
https://sandbox-api.koreacheckout.com
Test payments, mock responses
🔄 Rate Limiting
- • Production: 1000 requests per minute per API key
- • Sandbox: 100 requests per minute per API key
- • Rate limit headers included in all responses
Sessions API
Create and manage checkout sessions for processing payments. Sessions contain all the information needed to complete a purchase.
Create Session
POST /api/checkout/create-session
curl -X POST https://api.koreacheckout.com/api/checkout/create-session \
-H "x-api-key: sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"platform": "custom",
"platformOrderId": "order_123",
"items": [
{
"name": "Sample Product",
"price": 29000,
"quantity": 1,
"description": "Product description"
}
],
"customer": {
"name": "홍길동",
"email": "customer@example.com",
"phone": "+82-10-1234-5678"
},
"totalAmount": 29000,
"currency": "KRW",
"returnUrl": "https://yourstore.com/success",
"cancelUrl": "https://yourstore.com/cancel",
"metadata": {
"internal_order_id": "12345"
}
}'
Get Session
GET /api/checkout/session/{{sessionId}}
curl -X GET https://api.koreacheckout.com/api/checkout/session/cs_1234567890abcdef \
-H "x-api-key: sk_live_your_key_here"
// Response
{{
"success": true,
"data": {{
"sessionId": "cs_1234567890abcdef",
"status": "completed",
"platformOrderId": "order_123",
"totalAmount": 29000,
"currency": "KRW",
"customer": {{
"name": "홍길동",
"email": "customer@example.com"
}},
"createdAt": "2024-01-01T10:00:00Z",
"expiresAt": "2024-01-02T10:00:00Z",
"completedAt": "2024-01-01T10:30:00Z"
}}
}}
Session Management
Advanced session management features for handling complex checkout flows, session updates, and expiration handling.
Update Session
PATCH /api/checkout/session/{{sessionId}}
{{
"customer": {{
"name": "김철수",
"email": "updated@example.com"
}},
"metadata": {{
"updated_reason": "customer_info_change"
}}
}}
Session Expiration
⏰ Session Lifecycle
- • Sessions expire after 24 hours by default
- • Custom expiration can be set (max 7 days)
- • Expired sessions cannot be used for payment
- • Webhook sent when session expires
Payment Integration
Payment processing is handled securely through Korean payment gateways (Toss, KCP, Inicis). Card data never passes through our servers for PCI compliance.
🔒 Secure Payment Flow
- Create checkout session via API
- Redirect customer to hosted checkout page
- Customer enters payment details directly with payment gateway
- Payment gateway processes payment securely
- Webhook notifies your server of payment result
- Verify payment status via session API
Verify Payment Status
// Check if payment completed via session status
GET /api/checkout/session/{{sessionId}}
// Response when payment completed
{{
"success": true,
"data": {{
"sessionId": "cs_1234567890abcdef",
"status": "completed",
"totalAmount": 29000,
"currency": "KRW",
"paymentMethod": "card",
"gateway": "toss",
"gatewayTransactionId": "toss_tx_123456",
"completedAt": "2024-01-01T10:05:00Z"
}}
}}
Request Refund
POST /api/checkout/session/{{sessionId}}/refund
{{
"amount": 10000, // Partial refund (optional, defaults to full)
"reason": "고객 요청 환불",
"notify_customer": true
}}
// Response
{{
"refundId": "ref_1234567890abcdef",
"status": "processing",
"amount": 10000,
"reason": "고객 요청 환불",
"processedAt": "2024-01-01T11:00:00Z"
}}
Payment Status Values
- • pending - Session created, payment not started
- • processing - Customer completing payment
- • completed - Payment successfully processed
- • failed - Payment failed or declined
- • cancelled - Customer cancelled payment
- • expired - Session expired before payment
- • refunded - Payment was refunded (full)
- • partially_refunded - Payment partially refunded
Payment Handling
Best practices for handling payments, error scenarios, and ensuring reliable payment processing in your application.
✅ Payment Flow Best Practices
- • Always verify payment status via webhook AND API call
- • Implement idempotency for payment requests
- • Handle payment failures gracefully with user-friendly messages
- • Store payment IDs for refund and dispute handling
- • Implement timeout handling for long-running payments
Payment Status Monitoring
// Monitor payment status after creating session
const monitorPayment = async (sessionId) => {{
try {{
const response = await fetch(`/api/checkout/session/${sessionId}`, {{
headers: {{
'x-api-key': process.env.API_KEY
}}
}});
const session = await response.json();
if (!response.ok) {{
throw new Error(session.error.message);
}}
// Handle different payment statuses
switch (session.status) {{
case 'completed':
handlePaymentSuccess(session);
break;
case 'failed':
handlePaymentFailure(session);
break;
case 'cancelled':
handlePaymentCancellation(session);
break;
case 'expired':
handleSessionExpiry(session);
break;
case 'processing':
// Continue polling
setTimeout(() => monitorPayment(sessionId), 2000);
break;
}}
return session;
}} catch (error) {{
console.error('Payment monitoring error:', error);
throw error;
}}
}};
// Webhook handler for real-time updates
app.post('/webhooks/payment', (req, res) => {{
const event = req.body;
switch (event.event) {{
case 'payment.completed':
handlePaymentSuccess(event.data);
break;
case 'payment.failed':
handlePaymentFailure(event.data);
break;
}}
res.status(200).send('OK');
}});
Shops API
Manage shop information, settings, and configurations. The Shops API allows you to create and manage multiple shop profiles under your account.
Create Shop
POST /api/shops
{{
"name": "My Korean Store",
"description": "Premium Korean products",
"website": "https://mystore.com",
"business_info": {{
"business_number": "123-45-67890",
"business_name": "My Store Co., Ltd.",
"ceo_name": "김철수",
"address": "Seoul, Gangnam-gu, Teheran-ro 123"
}},
"contact": {{
"email": "contact@mystore.com",
"phone": "+82-2-1234-5678"
}},
"settings": {{
"currency": "KRW",
"timezone": "Asia/Seoul",
"language": "ko"
}}
}}
Get Shop Details
GET /api/shops/{{shopId}}
// Response
{{
"id": "shop_1234567890abcdef",
"name": "My Korean Store",
"status": "active",
"business_info": {{
"business_number": "123-45-67890",
"verified": true
}},
"payment_methods": [
"card",
"virtual_account",
"kakao_pay",
"naver_pay"
],
"created_at": "2024-01-01T00:00:00Z"
}}
Update Shop Settings
PATCH /api/shops/{{shopId}}
{{
"settings": {{
"webhook_url": "https://mystore.com/webhooks",
"notification_email": "admin@mystore.com",
"auto_refund_enabled": true,
"payment_timeout": 1800
}}
}}
🏪 Multi-Shop Features
- • Separate payment settings per shop
- • Individual webhook endpoints
- • Shop-specific analytics and reporting
- • Different branding and checkout themes
- • Isolated transaction histories
Custom Domains
Use custom domains to enhance your branding and improve checkout experience. Customers stay on your domain throughout the entire payment process, increasing trust and conversion rates.
🌐 Custom Domain Benefits
- • Enhanced Branding - Keep your brand throughout checkout
- • Increased Trust - Customers pay on a domain they trust
- • Higher Conversion - Consistent user experience reduces drop-off
- • SEO Benefits - All payment traffic stays on your domain
Setup Process
Step 1: Add Domain in Dashboard
Add your domain in the Custom Domain section of your dashboard and complete DNS configuration:
Example domain: checkout.yourstore.com
76.76.19.123
cname.vercel-dns.com
Step 2: Domain Verification
Add a TXT record to verify domain ownership:
# DNS TXT Record for verification
# Name: _vercel-challenge.checkout
# Value: provided-verification-code-from-dashboard
# Example:
Name: _vercel-challenge.checkout.yourstore.com
Type: TXT
Value: vc-domain-verify-abc123xyz456
Step 3: Verify API Integration
Once verified, checkout sessions will automatically use your custom domain:
// API Response with custom domain
{
"success": true,
"sessionId": "cs_1234567890abcdef",
"checkoutUrl": "https://checkout.yourstore.com/checkout/cs_1234567890abcdef",
"expiresAt": "2024-01-01T12:00:00Z"
}
// WordPress Plugin automatically uses custom domain
// No code changes required!
Advanced Configuration
Check Domain Status
GET /api/shops/{shopId}
// Response includes custom domain status
{
"id": "shop_123",
"name": "My Store",
"custom_domain": "checkout.yourstore.com",
"domain_verification_status": "verified", // pending, verified, failed
"domain_configuration_status": "configured", // pending, configured, failed
"created_at": "2024-01-01T00:00:00Z"
}
Manual Domain Configuration
PATCH /api/shops/{shopId}/custom-domain
Content-Type: application/json
x-api-key: sk_live_your_key_here
{
"domain": "checkout.yourstore.com"
}
// Response
{
"success": true,
"domain": "checkout.yourstore.com",
"verification_records": [
{
"type": "TXT",
"name": "_vercel-challenge.checkout",
"value": "vc-domain-verify-abc123xyz456"
}
]
}
⚠️ Important Notes
- • Domain verification can take up to 24 hours to complete
- • SSL certificates are automatically issued and renewed
- • Default domain is used until custom domain is verified
- • Only subdomains are supported (e.g., checkout.yourstore.com)
✅ Success Example
After custom domain setup, customers complete payments on checkout.yourstore.com, and success/failure pages are also displayed on the same domain. WordPress plugin users automatically get custom domain support without any code changes.
Korean Address Integration
Korean address input is handled directly through Daum Postcode API on the frontend. Our hosted checkout pages include this integration automatically.
🏠 Address Integration Options
- • Hosted Checkout - Address search included automatically
- • Custom Integration - Use Daum Postcode API directly
- • WordPress Plugin - Built-in address search widget
Custom Daum Postcode Integration
<!-- Include Daum Postcode API -->
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
// JavaScript integration
function openAddressSearch() {
new daum.Postcode({
oncomplete: function(data) {
// data.address - 주소
// data.zonecode - 우편번호
// data.roadAddress - 도로명주소
// data.jibunAddress - 지번주소
document.getElementById('address').value = data.address;
document.getElementById('postalCode').value = data.zonecode;
// Send to your backend if needed
updateCheckoutAddress({
address: data.address,
postalCode: data.zonecode,
roadAddress: data.roadAddress
});
}
}).open();
}
// Update checkout session with address
const updateCheckoutAddress = async (addressData) => {
await fetch(`/api/checkout/session/${sessionId}/address`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(addressData)
});
};
React Component Example
import React, { useEffect } from 'react';
const KoreanAddressInput = ({ onAddressSelect }) => {
useEffect(() => {
// Load Daum Postcode script
const script = document.createElement('script');
script.src = '//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js';
document.head.appendChild(script);
}, []);
const handleAddressSearch = () => {
new window.daum.Postcode({
oncomplete: function(data) {
onAddressSelect({
address: data.address,
postalCode: data.zonecode,
roadAddress: data.roadAddress
});
}
}).open();
};
return (
<div>
<input
type="text"
placeholder="주소를 검색하세요"
readOnly
onClick={handleAddressSearch}
/>
<button onClick={handleAddressSearch}>
주소 검색
</button>
</div>
);
};
📍 Korean Address Best Practices
- • Always use Daum Postcode API for accurate Korean addresses
- • Prefer road-name addresses (도로명주소) over lot-number addresses
- • Include detailed address field for building/apartment info
- • Validate postal codes are 5 digits
- • Store both Korean and English address versions if needed
Coupon System API
Manage discount coupons programmatically. Create, validate, and track coupon usage across your checkout flow.
🎫 Supported Coupon Types
- • percentage - Percentage discount (e.g., 10% off)
- • fixed_amount - Fixed amount discount (e.g., ₩5,000 off)
- • free_shipping - Free shipping coupon
- • product_specific - Discount for specific products
Create Coupon
POST /api/coupons/create
curl -X POST https://api.koreacheckout.com/api/coupons/create \
-H "x-api-key: sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"code": "WELCOME10",
"name_ko": "신규 고객 할인",
"name_en": "New Customer Discount",
"type": "percentage",
"discount_value": 10,
"valid_from": "2024-01-01T00:00:00Z",
"valid_until": "2024-12-31T23:59:59Z",
"usage_limit": 1000,
"usage_limit_per_customer": 1,
"minimum_order_amount": 50000,
"applies_to": "cart_total"
}'
Apply Coupon to Session
POST /api/coupons/apply
{
"sessionId": "cs_1234567890abcdef",
"couponCode": "WELCOME10"
}
// Response
{
"success": true,
"discount": {
"type": "percentage",
"value": 10,
"amount": 2900
},
"newTotal": 26100
}
Integration Example (Node.js)
// Create a welcome coupon for new customers
const welcomeCoupon = await fetch('https://api.koreacheckout.com/api/coupons/create', {
method: 'POST',
headers: {
'x-api-key': process.env.KOREA_CHECKOUT_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
code: 'WELCOME15',
name_ko: '신규 가입 할인',
type: 'percentage',
discount_value: 15,
valid_from: new Date().toISOString(),
valid_until: new Date(Date.now() + 30*24*60*60*1000).toISOString(), // 30 days
usage_limit_per_customer: 1,
minimum_order_amount: 30000
})
});
// Apply coupon during checkout
const applyCoupon = async (sessionId, couponCode) => {
const response = await fetch('https://api.koreacheckout.com/api/coupons/apply', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
sessionId,
couponCode
})
});
return response.json();
};
💡 Coupon Best Practices
- • Set reasonable usage limits to prevent abuse
- • Use minimum order amounts for higher-value discounts
- • Test coupon validation in sandbox mode first
- • Track coupon performance via analytics API
- • Set clear expiration dates for promotional campaigns
Webhooks
Receive real-time notifications about payment events. Webhooks are HTTP POST requests sent to your server when events occur.
📡 Event Types
- • payment.completed - Payment successfully processed
- • payment.failed - Payment failed or was declined
- • payment.refunded - Payment was refunded
- • session.expired - Checkout session expired
Webhook Payload
{
"event": "payment.completed",
"data": {
"sessionId": "cs_1234567890abcdef",
"platformOrderId": "order_123",
"totalAmount": 29000,
"currency": "KRW",
"paymentMethod": "card",
"customer": {
"name": "홍길동",
"email": "customer@example.com"
},
"completedAt": "2024-01-01T12:00:00Z"
}
}
Handling Webhooks
app.post('/webhooks/checkout', express.raw({type: 'application/json'}), (req, res) => {
const payload = req.body;
const signature = req.headers['x-korea-checkout-signature'];
// Verify webhook signature (recommended)
if (!verifySignature(payload, signature)) {
return res.status(400).send('Invalid signature');
}
const event = JSON.parse(payload);
switch (event.event) {
case 'payment.completed':
handlePaymentCompleted(event.data);
break;
case 'payment.failed':
handlePaymentFailed(event.data);
break;
default:
console.log('Unknown event type:', event.event);
}
res.status(200).send('OK');
});
Korean Payment Methods
Support for all major Korean payment methods including credit cards, bank transfers, and mobile payments.
💳 Credit Cards
- • Visa, MasterCard, JCB
- • Korean domestic cards (BC, 삼성, 현대)
- • Installment payments (할부)
- • Corporate cards support
🏦 Bank Transfers
- • Virtual account (가상계좌)
- • Real-time bank transfer
- • All major Korean banks
- • Automatic reconciliation
📱 Mobile Payments
KakaoPay, NaverPay, Samsung Pay, and other popular Korean mobile payment solutions are supported through our unified API.
Error Handling
Our API uses conventional HTTP response codes to indicate the success or failure of requests. Error responses include detailed information to help you debug issues.
🚨 Common Error Codes
- • 400 - Bad Request (invalid parameters)
- • 401 - Unauthorized (invalid API key)
- • 404 - Not Found (session or resource not found)
- • 429 - Rate Limited (too many requests)
- • 500 - Internal Server Error
Error Response Format
{
"error": {
"code": "invalid_session",
"message": "The specified session ID is invalid or has expired",
"details": {
"sessionId": "cs_invalid123",
"field": "sessionId"
}
}
}