외부 연동 가이드
API 사용방법
다른 프로젝트에서 우리 결제를 호출해 결제창을 띄우고, 결과를 돌려받는 방법입니다.
기본
· Base URL: https://api-pay.apls.kr
· 모든 요청 헤더에 Authorization: Bearer <API_KEY> (오른쪽 "API 발급"으로 받은 Key ID)
· 발급 시 함께 나온 Secret은 결과 콜백 서명 검증용 — 그 프로젝트 서버에만 보관하세요.
① 결제 만들기
POST /api/ext/payments
요청 본문(JSON):
{
"orderName": "퍼스널컬러 강의", // 필수 · 항목명
"amount": 50000, // 필수 · KRW/JPY 정수, USD/EUR 소수2
"currency": "KRW", // 필수 · KRW | JPY | USD | EUR
"externalId": "your-order-0001", // 선택 · 그쪽 주문번호(같은 값 재요청=기존 반환)
"customerName": "홍길동", // 선택
"customerPhone": "010-1234-5678", // 선택 · 문자알림용
"notifyUrl": "https://내서버/webhook", // 선택 · 결과 콜백 받을 주소
"redirectUrl": "https://내사이트/done", // 선택 · 결제 후 고객 이동
"metadata": { "any": "value" } // 선택 · 결과에 그대로 반환
}
응답:
{
"orderId": "abc123",
"payUrl": "https://pay.apls.kr/p/?order=abc123",
"status": "pending",
"embed": { "storeId":"store-...", "channelKey":"channel-...",
"totalAmount":50000, "orderName":"...", "payMethod":"CARD",
"paymentIdPrefix":"apl-abc123-" }
}
방식 A · 링크 (제일 간단, 코드 거의 없음)
응답의 payUrl로 고객을 보내면 끝. 결제창·검증을 우리가 다 처리합니다.
결제 완료 여부는 → ④ 결과 콜백(notifyUrl로 자동 푸시) 또는 ③ 상태 조회로 확인합니다. (notifyUrl·redirectUrl 은 ① 결제 만들기에서 지정)
방식 B · 임베드 (그쪽 페이지에서 결제창 직접 띄우기)
응답의 embed 값으로 브라우저에서 PortOne SDK를 호출합니다. (국내 KRW/이니시스 기준)
import * as PortOne from "https://cdn.portone.io/v2/browser-sdk.esm.js";
// paymentId 는 반드시 embed.paymentIdPrefix 로 시작해야 함
const paymentId = embed.paymentIdPrefix + Date.now();
const res = await PortOne.requestPayment({
storeId: embed.storeId,
channelKey: embed.channelKey,
paymentId,
orderName: embed.orderName,
totalAmount: embed.totalAmount,
currency: embed.currency, // "KRW"
payMethod: "CARD", // 카드창에 간편결제도 함께 노출
customer: { fullName, email, phoneNumber } // 이니시스는 셋 다 필수
});
if (res.code) {
// 결제 실패/취소 (res.message)
} else {
// 성공 → 우리 서버로 검증 요청 (아래 ②)
await fetch(`/proxy/verify`, { method:"POST", body: JSON.stringify({ orderId:"abc123", paymentId: res.paymentId }) });
}
※ storeId·channelKey는 공개값이라 그대로 써도 됩니다. 별도 이니시스 계약 불필요(정산은 APL COLOR로 모임).
② 결제 확인 (임베드 전용)
POST /api/ext/payments/{orderId}/verify
{ "paymentId": "apl-abc123-1724..." } // 국내(포트원)
// 해외(PayPal)면: { "paypalOrderId": "..." }
우리가 금액·통화·상태를 검증하고 paid 처리 후 { "status":"paid" } 반환. (반드시 서버에서 호출)
③ 상태 조회
GET /api/ext/payments/{orderId}
{ "orderId":"abc123","externalId":"your-order-0001","status":"paid",
"amount":50000,"currency":"KRW","provider":"portone","paidAt":"..." }
④ 결과 콜백 (우리 → 당신의 notifyUrl)
결제완료/실패/환불 시 우리가 notifyUrl로 POST를 보냅니다.
헤더: X-APLPay-Timestamp, X-APLPay-Signature
본문:
{ "event":"payment.paid", // payment.paid | payment.failed | payment.refunded
"orderId":"abc123","externalId":"your-order-0001","status":"paid",
"amount":50000,"currency":"KRW","provider":"portone",
"paidAt":"...","refundedAt":null,"metadata":{...} }
서명 검증 (Node 예시):
const crypto = require("crypto");
const ts = req.headers["x-aplpay-timestamp"];
const sig = req.headers["x-aplpay-signature"];
const expected = crypto.createHmac("sha256", SECRET) // 발급 시 받은 Secret
.update(ts + "." + rawBody).digest("hex");
if (sig !== expected) return res.sendStatus(400); // 위조
// 정상 → 처리 후 200 응답 (200 아니면 우리가 재전송)
※ 콜백을 놓쳐도 ③ 상태조회로 언제든 확인 가능합니다.