Softment | 개발자센터

연동 가이드

소프트먼트 결제 API를 연동하여 온라인 결제를 구현하는 방법을 안내합니다.

사전 준비

소프트먼트 결제 API를 연동하기 위해 아래 사항을 확인하세요.

Pay Key는 소프트먼트 관리자 페이지에서 발급받을 수 있습니다.

개발/운영 환경

소프트먼트는 개발(테스트)과 운영 환경을 분리하여 제공합니다. 연동 개발 시에는 개발 환경을, 실서비스에는 운영 환경을 사용하세요.

환경Base URL용도
개발https://devpapi.softment.co.kr연동 개발 및 테스트
운영https://papi.softment.co.kr실서비스 운영
개발 환경에서 충분히 테스트한 후 운영 환경으로 전환하세요. Pay Key는 환경별로 별도 발급됩니다.

인증 방식

모든 API 요청 시 HTTP Header의 Authorization에 발급받은 Pay Key를 전달합니다.

Authorization: {your-pay-key}
Content-Type: application/json

연동 방식 선택

소프트먼트는 두 가지 결제 연동 방식을 제공합니다.

  • 소프트먼트 결제창을 통해 고객이 결제수단(신용카드/간편결제)을 선택
  • 별도 파라미터 없이 기본 거래등록 API로 연동
  • 모든 결제수단을 한 화면에서 제공
  • 통합결제창을 거치지 않고 특정 간편결제사 인증창을 바로 호출
  • 거래등록 시 directPay=YcpCode 파라미터 필수
  • 지원: 카카오페이(KKO), 네이버페이(NPAY), 토스페이(TOSS), 삼성페이(SAM), 페이코(PCO)
  • 네이버페이/토스페이는 cpType으로 결제타입(C:카드, M:포인트) 선택 가능

Step 1. 거래등록

결제에 필요한 거래 정보를 등록하고, 결제창 URL을 받아옵니다. 거래등록 API를 호출하면 고객을 결제창으로 안내할 수 있는 authPageUrl이 반환됩니다.

요청 파라미터

필드타입필수설명
trackIdString필수가맹점 주문번호 (고유값)
returnUrlString필수인증 완료 후 리다이렉트 URL
amountString필수결제 금액
goodsNameString필수상품명
deviceString필수디바이스 타입 (pc / mobile)
payerNameString선택구매자명
payerTelString선택구매자 연락처
appSchemeString(256)선택가맹점 앱스키마. 앱 WebView에서 결제 시 대외기관 앱 호출 후 복귀에 사용
directPayString(1)선택간편결제 직접호출 여부 (Y/N). 통합결제창을 거치지 않고 간편결제 인증창 직접 호출 시 Y
cpCodeString(4)조건부간편결제사 코드. directPay=Y일 때 필수. NPAY(네이버페이), KKO(카카오페이), TOSS(토스페이), SAM(삼성페이), PCO(페이코)
cpTypeString(1)선택간편결제 결제타입. 네이버페이/토스페이만 가능. C:신용카드, M:머니/포인트
rcptTypeString(1)선택네이버페이 포인트 결제시 현금영수증 신청타입. 0:미발행, 1:소득공제용(휴대폰번호), 2:지출증빙용(사업자번호)
rcptNoString(11)선택네이버페이 포인트 결제시 현금영수증 번호. 휴대폰번호(10~11자) 또는 사업자번호(10자)

요청 예제

{
  "amount": "1004",
  "returnUrl": "https://www.shop.co.kr/returnUrl",
  "device": "pc",
  "trackId": "TEST-202508080001",
  "goodsName": "테스트상품",
  "payerName": "홍길동",
  "payerTel": "010-1234-5678",
  "cardMethodInfo": {
    "cardInfoList": [
      {"cardCd": "029"},
      {"cardCd": "016"},
      {"cardCd": "006"}
    ]
  },
  "shopValueInfo": {
    "value1": "값1",
    "value2": "값2"
  }
}

네이버페이 카드결제 직접호출 예제입니다.

{
  "amount": "1004",
  "returnUrl": "https://www.shop.co.kr/returnUrl",
  "device": "pc",
  "trackId": "TEST-202509150006",
  "goodsName": "테스트상품",
  "payerName": "홍길동",
  "payerTel": "010-1234-5678",
  "directPay": "Y",
  "cpCode": "NPAY",
  "cpType": "C",
  "shopValueInfo": {
    "value1": "값1",
    "value2": "값2"
  }
}

cURL 요청 예시

# 거래등록 요청
curl -X POST https://papi.softment.co.kr/api/webpay/create \
  -H "Authorization: your-pay-key" \
  -H "Content-Type: application/json" \
  -d '{
    "trackId": "ORDER-20260702001",
    "returnUrl": "https://yoursite.com/return",
    "amount": "50000",
    "goodsName": "프리미엄 구독",
    "device": "pc",
    "payerName": "홍길동"
  }'
const axios = require('axios');

const { data } = await axios.post(
  'https://papi.softment.co.kr/api/webpay/create',
  {
    trackId: 'ORDER-20260702001',
    returnUrl: 'https://yoursite.com/return',
    amount: '50000',
    goodsName: '프리미엄 구독',
    device: 'pc',
    payerName: '홍길동'
  },
  { headers: { Authorization: 'your-pay-key' } }
);
import requests

res = requests.post(
    'https://papi.softment.co.kr/api/webpay/create',
    json={
        'trackId': 'ORDER-20260702001',
        'returnUrl': 'https://yoursite.com/return',
        'amount': '50000',
        'goodsName': '프리미엄 구독',
        'device': 'pc',
        'payerName': '홍길동'
    },
    headers={'Authorization': 'your-pay-key'}
)

응답 예시

{
  "resultCode": "S000",
  "resultMsg": "성공",
  "data": {
    "trxId": "T250702001234",
    "trackId": "ORDER-20260702001",
    "authPageUrl": "https://papi.softment.co.kr/auth/pay?token=abc123..."
  }
}
trackId는 가맹점별로 고유해야 합니다. 중복 시 S019 에러가 발생합니다.

Step 2. 결제창 호출

거래등록 응답에서 받은 authPageUrl로 고객을 리다이렉트합니다. 고객은 결제창에서 카드를 선택하고 결제 정보를 입력합니다.

// 결제창으로 리다이렉트
window.location.href = data.authPageUrl;

결제 흐름

  1. 고객이 결제창에서 카드사를 선택하고 인증을 완료합니다.
  2. 인증이 완료되면 거래등록 시 지정한 returnUrl로 리다이렉트됩니다.
  3. returnUrl에는 result 파라미터가 포함되어 전달됩니다.

returnUrl 콜백 데이터

returnUrl로 전달되는 result 파라미터에는 아래 데이터가 JSON 형태로 포함됩니다.

필드타입설명
trxIdString거래 고유번호
amountString인증된 결제 금액
authorizationIdString인증 데이터 (승인요청 시 필요)
// returnUrl 콜백 데이터 예시
{
  "trxId": "T250702001234",
  "amount": "50000",
  "authorizationId": "AUTH_DATA_abc123..."
}

Step 3. 승인요청

returnUrl에서 받은 인증 데이터로 최종 승인 요청을 수행합니다. 승인이 완료되면 실제 결제가 이루어집니다.

요청 파라미터

필드타입필수설명
trxIdString필수거래 고유번호
amountString필수결제 금액
authorizationIdString필수인증 데이터
curl -X POST https://papi.softment.co.kr/api/approval \
  -H "Authorization: your-pay-key" \
  -H "Content-Type: application/json" \
  -d '{
    "trxId": "T250702001234",
    "amount": "50000",
    "authorizationId": "AUTH_DATA_abc123..."
  }'
const { data } = await axios.post(
  'https://papi.softment.co.kr/api/approval',
  {
    trxId: req.body.trxId,
    amount: req.body.amount,
    authorizationId: req.body.authorizationId
  },
  { headers: { Authorization: 'your-pay-key' } }
);
res = requests.post(
    'https://papi.softment.co.kr/api/approval',
    json={
        'trxId': trx_id,
        'amount': '50000',
        'authorizationId': authorization_id
    },
    headers={'Authorization': 'your-pay-key'}
)
금액 검증을 반드시 수행하세요. 인증 시 금액과 승인요청 금액이 다르면 S037 에러가 발생합니다.

응답 예시

{
  "resultCode": "S000",
  "resultMsg": "성공",
  "data": {
    "trxId": "T250702001234",
    "trackId": "ORDER-20260702001",
    "amount": "50000",
    "status": "APPROVED",
    "approvedAt": "2026-07-02T14:30:00+09:00",
    "cardName": "신한카드",
    "cardNumber": "9410-****-****-1234"
  }
}

거래 취소

승인 완료된 거래를 취소(환불)합니다. 전체 취소 또는 부분 취소를 지원합니다.

요청 파라미터

필드타입필수설명
trxIdString필수거래 고유번호
cancelReasonString필수취소 사유
amountString선택부분 취소 금액 (미입력 시 전액 취소)
curl -X POST https://papi.softment.co.kr/api/webpay/cancel \
  -H "Authorization: your-pay-key" \
  -H "Content-Type: application/json" \
  -d '{
    "trxId": "T250702001234",
    "cancelReason": "고객 요청에 의한 환불",
    "amount": "20000"
  }'
부분 취소 시 amount 값을 원래 결제 금액보다 적게 입력합니다. 미입력 시 전액 취소됩니다.

거래 조회

거래의 현재 상태를 조회합니다.

curl -X POST https://papi.softment.co.kr/api/webpay/status \
  -H "Authorization: your-pay-key" \
  -H "Content-Type: application/json" \
  -d '{ "trxId": "T250702001234" }'

거래 상태값


WebView 연동

브라우저가 아닌 앱 WebView에서 결제창을 호출할 경우 앱스킴 처리가 필요합니다.

Android 설정

AndroidManifest.xml<queries>에 패키지명을 등록합니다.

<queries>
    <package android:name="com.shcard.smartpay" />      <!-- 신한페이판 -->
    <package android:name="kr.co.samsungcard.mpocket" /> <!-- 삼성앱카드 -->
    <package android:name="com.kbcard.cxh.appcard" />    <!-- KB Pay -->
    <package android:name="nh.smart.nhallonepay" />      <!-- NH올원페이 -->
    <package android:name="com.lcacApp" />               <!-- 롯데카드 -->
    <package android:name="kvp.jjy.MispAndroid320" />    <!-- ISP/페이북 -->
    <package android:name="com.hanaskcard.paycla" />     <!-- 하나카드 -->
    <package android:name="com.hyundaicard.appcard" />   <!-- 현대카드 -->
    <package android:name="com.nhn.android.search" />    <!-- 네이버페이 -->
    <package android:name="com.kakao.talk" />            <!-- 카카오페이 -->
    <package android:name="viva.republica.toss" />       <!-- 토스페이 -->
    <package android:name="com.samsung.android.spay" />  <!-- 삼성페이 -->
    <!-- ... 기타 카드사/대외기관 앱 -->
</queries>

WebViewClientshouldOverrideUrlLoading을 오버라이드합니다.

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (!URLUtil.isNetworkUrl(url) && !URLUtil.isJavaScriptUrl(url)) {
        final Uri uri;
        try {
            uri = Uri.parse(url);
        } catch (Exception e) {
            return false;
        }
        if ("intent".equals(uri.getScheme())) {
            return startSchemeIntent(url);
        } else {
            try {
                startActivity(new Intent(Intent.ACTION_VIEW, uri));
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }
    return false;
}

iOS 설정

Info.plistLSApplicationQueriesSchemes에 앱스킴을 등록합니다.

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>ispmobile</string>
    <string>kb-acp</string>
    <string>shinhan-sr-ansimclick</string>
    <string>nhallonepayansimclick</string>
    <string>lottesmartpay</string>
    <string>mpocket.online.ansimclick</string>
    <string>cloudpay</string>
    <string>hdcardappcardansimclick</string>
    <string>naversearchthirdlogin</string>
    <string>kakaotalk</string>
    <string>supertoss</string>
    <string>samsungpay</string>
    <!-- ... 기타 앱스킴 -->
</array>

WKWebViewdecidePolicyForNavigationAction을 구현합니다.

func webView(_ webView: WKWebView,
             decidePolicyFor navigationAction: WKNavigationAction,
             decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    guard let url = navigationAction.request.url else {
        decisionHandler(.allow)
        return
    }
    if url.scheme != "http" && url.scheme != "https" {
        UIApplication.shared.open(url, options: [:], completionHandler: nil)
        decisionHandler(.cancel)
        return
    }
    decisionHandler(.allow)
}

코드 샘플

전체 결제 연동 흐름을 언어별로 확인할 수 있습니다.

# 1. 거래등록
curl -X POST https://papi.softment.co.kr/api/webpay/create \
  -H "Authorization: your-pay-key" \
  -H "Content-Type: application/json" \
  -d '{
    "trackId": "ORDER-20260702001",
    "returnUrl": "https://yoursite.com/return",
    "amount": "50000",
    "goodsName": "프리미엄 구독",
    "device": "pc",
    "payerName": "홍길동"
  }'

# 2. 승인요청 (returnUrl에서 받은 데이터로)
curl -X POST https://papi.softment.co.kr/api/approval \
  -H "Authorization: your-pay-key" \
  -H "Content-Type: application/json" \
  -d '{
    "trxId": "T250702001234",
    "amount": "50000",
    "authorizationId": "인증데이터..."
  }'
const axios = require('axios');

const PAY_KEY = 'your-pay-key';
const BASE_URL = 'https://papi.softment.co.kr';

// 1. 거래등록
const { data: createRes } = await axios.post(`${BASE_URL}/api/webpay/create`, {
  trackId: 'ORDER-20260702001',
  returnUrl: 'https://yoursite.com/return',
  amount: '50000',
  goodsName: '프리미엄 구독',
  device: 'pc',
  payerName: '홍길동'
}, {
  headers: { Authorization: PAY_KEY, 'Content-Type': 'application/json' }
});

// 결제창으로 리다이렉트
// res.redirect(createRes.data.authPageUrl);

// 2. returnUrl 콜백에서 승인요청
const { data: approvalRes } = await axios.post(`${BASE_URL}/api/approval`, {
  trxId: req.body.trxId,
  amount: req.body.amount,
  authorizationId: req.body.authorizationId
}, {
  headers: { Authorization: PAY_KEY, 'Content-Type': 'application/json' }
});
import requests

PAY_KEY = 'your-pay-key'
BASE_URL = 'https://papi.softment.co.kr'
headers = {'Authorization': PAY_KEY, 'Content-Type': 'application/json'}

# 1. 거래등록
create_res = requests.post(f'{BASE_URL}/api/webpay/create', json={
    'trackId': 'ORDER-20260702001',
    'returnUrl': 'https://yoursite.com/return',
    'amount': '50000',
    'goodsName': '프리미엄 구독',
    'device': 'pc',
    'payerName': '홍길동'
}, headers=headers)

auth_page_url = create_res.json()['data']['authPageUrl']

# 2. 승인요청
approval_res = requests.post(f'{BASE_URL}/api/approval', json={
    'trxId': trx_id,
    'amount': '50000',
    'authorizationId': authorization_id
}, headers=headers)
import java.net.http.*;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
String payKey = "your-pay-key";

// 1. 거래등록
String createBody = """
    {"trackId":"ORDER-20260702001","returnUrl":"https://yoursite.com/return",
     "amount":"50000","goodsName":"프리미엄 구독","device":"pc","payerName":"홍길동"}
    """;

HttpRequest createReq = HttpRequest.newBuilder()
    .uri(URI.create("https://papi.softment.co.kr/api/webpay/create"))
    .header("Authorization", payKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(createBody))
    .build();

HttpResponse<String> createRes = client.send(
    createReq, HttpResponse.BodyHandlers.ofString()
);

// authPageUrl로 리다이렉트 후, returnUrl에서 승인요청 수행
$payKey = 'your-pay-key';
$baseUrl = 'https://papi.softment.co.kr';

// 1. 거래등록
$ch = curl_init("$baseUrl/api/webpay/create");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: $payKey",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'trackId' => 'ORDER-20260702001',
        'returnUrl' => 'https://yoursite.com/return',
        'amount' => '50000',
        'goodsName' => '프리미엄 구독',
        'device' => 'pc',
        'payerName' => '홍길동'
    ]),
    CURLOPT_RETURNTRANSFER => true
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);

$authPageUrl = $result['data']['authPageUrl'];

// 2. returnUrl 콜백에서 승인요청
$ch = curl_init("$baseUrl/api/approval");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: $payKey",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'trxId' => $_POST['trxId'],
        'amount' => $_POST['amount'],
        'authorizationId' => $_POST['authorizationId']
    ]),
    CURLOPT_RETURNTRANSFER => true
]);
$approval = json_decode(curl_exec($ch), true);
curl_close($ch);

자주 묻는 질문

아닙니다. 인증 완료 후 반드시 승인요청 API(/api/approval)까지 호출해야 결제가 확정됩니다.
통합결제창은 소프트먼트 결제창을 거쳐 고객이 결제수단을 선택하는 방식이고, 직접호출은 거래등록 시 directPay=YcpCode를 전달하여 특정 간편결제사 인증창을 바로 호출하는 방식입니다.
directPayY로 설정한 경우 cpCode(간편결제사 코드)는 필수입니다. 누락 시 S040, 사용할 수 없는 코드인 경우 S041로 응답됩니다.
테스트 아이디로 결제 테스트 시 상위 PG사 정책에 따라 실결제가 발생할 수 있으므로 테스트 후 반드시 취소하셔야 합니다.
결제수단은 소프트먼트에서 설정합니다. 허용되지 않은 결제수단은 직접호출 시에도 사용할 수 없습니다.