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

  1. Create checkout session via API
  2. Redirect customer to hosted checkout page
  3. Customer enters payment details directly with payment gateway
  4. Payment gateway processes payment securely
  5. Webhook notifies your server of payment result
  6. 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

DNS A 레코드:76.76.19.123
DNS CNAME 레코드: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.

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"
    }
  }
}