Skip to Content

Checkout

Checkout Session은 구매자를 결제창으로 넘기기 위한 일회성 세션이에요.
내 서버에서 세션을 만들면 결제창 url을 받고, 그 주소로 구매자를 리다이렉트해요.
세션에 담은 metadata는 결제가 끝나면 order.paid 웹훅으로 그대로 돌아와요.

세션은 발급 후 30분 동안만 유효해요.
이 시간이 지나면 상태가 expired로 바뀌고 결제창을 열 수 없어요.

세션 생성

POSThttps://api.payri.kr/v1/checkout/sessionsscope checkout:write
curl -X POST https://api.payri.kr/v1/checkout/sessions \ -H "X-Api-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "linkId": "lnk_a1b2c3", "customer": { "name": "김구매", "email": "buyer@example.com" }, "metadata": { "userUuid": "u_9f2c" }, "successUrl": "https://myapp.com/done", "cancelUrl": "https://myapp.com/cart" }'

요청 본문

필드타입필수설명
linkIdstring결제 링크 ID (상품 객체의 linkId)
customerobject결제창에 미리 채울 구매자 정보 (name·email·phone)
metadataobject값이 문자열인 키-값 쌍. 결제 완료 시 회신
successUrlstring결제 완료 후 돌려보낼 URL (http/https)
cancelUrlstring구매자가 결제를 취소했을 때 돌려보낼 URL (http/https)

세션 ID는 cs_로 시작해요.
url로 구매자를 리다이렉트하면 결제창이 열려요.

{ "id": "cs_7h2k9d", "linkId": "lnk_a1b2c3", "productId": "prod_88x", "status": "open", "orderId": null, "successUrl": "https://myapp.com/done", "cancelUrl": "https://myapp.com/cart", "expiresAt": "2026-06-16T04:00:00.000Z", "createdAt": "2026-06-16T03:30:00.000Z", "url": "https://pay.payri.kr/checkout/lnk_a1b2c3?session=cs_7h2k9d" }

브라우저에서 세션 생성

세션 생성은 서버 없이 프런트엔드에서 직접 호출할 수도 있어요.
이때는 secret 키 대신 browser 키를 쓰세요.
/v1 경로는 CORS가 열려 있어 브라우저의 fetch로 바로 호출돼요.

const res = await fetch('https://api.payri.kr/v1/checkout/sessions', { method: 'POST', headers: { 'X-Api-Key': 'pk_live_xxxxxxxxxxxxxxxxxxxxxxxx', 'Content-Type': 'application/json' }, body: JSON.stringify({ linkId: 'lnk_a1b2c3', metadata: { userUuid: 'u_9f2c' } }), }) const session = await res.json() location.href = session.url // 결제창으로 이동

browser 키는 세션 생성(checkout:write)만 할 수 있어요.
세션 조회를 포함한 나머지 API는 secret 키로 서버에서 호출해야 해요.

세션 조회

GEThttps://api.payri.kr/v1/checkout/sessions/:idscope checkout:read
curl https://api.payri.kr/v1/checkout/sessions/cs_7h2k9d \ -H "X-Api-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

결제가 끝나면 statuscompleted로 바뀌고 orderId가 채워져요.
조회 응답에는 생성 때 담은 metadata가 포함돼요.

{ "id": "cs_7h2k9d", "linkId": "lnk_a1b2c3", "productId": "prod_88x", "status": "completed", "orderId": "ord_3kf9a2", "successUrl": "https://myapp.com/done", "cancelUrl": "https://myapp.com/cart", "expiresAt": "2026-06-16T04:00:00.000Z", "createdAt": "2026-06-16T03:30:00.000Z", "url": "https://pay.payri.kr/checkout/lnk_a1b2c3?session=cs_7h2k9d", "metadata": { "userUuid": "u_9f2c" } }

주요 필드

필드타입설명
idstring세션 ID (cs_로 시작)
linkIdstring세션을 만든 결제 링크 ID
productIdstring링크가 가리키는 상품 ID
statusenumopen · completed · expired
orderIdstring결제가 완료되면 연결된 주문 ID (그 전엔 null)
expiresAtstring세션 만료 시각 (생성 30분 뒤, ISO 8601)
metadataobject생성 때 담은 메타데이터 (조회 응답에만 포함)

metadata 회신

metadata는 세션을 거쳐 주문으로 복사돼요.
결제가 완료되면 order.paid 웹훅 페이로드의 metadata 필드로 그대로 돌아와요.
내 시스템의 사용자·장바구니 식별자를 결제와 이어 붙일 때 쓰세요.

{ "id": "ord_3kf9a2", "productId": "prod_88x", "status": "paid", "metadata": { "userUuid": "u_9f2c" } }

리다이렉트

결제가 끝나면 구매자는 successUrl로 돌아가요.
이때 페이리가 order_idsession_id 쿼리를 붙여요.
서버에서 이 값으로 GET /v1/orders/:id를 호출해 최종 상태를 확인하세요.

https://myapp.com/done?order_id=ord_3kf9a2&session_id=cs_7h2k9d

리다이렉트 쿼리만으로 지급을 확정하지 마세요.
결제 확정의 신뢰 가능한 신호는 order.paid 웹훅과 GET /v1/orders/:id 조회예요.

관련 에러

코드HTTP상황
PAYMENT_LINK_NOT_FOUND404linkId에 해당하는 결제 링크가 없음
FORBIDDEN403다른 스토어의 링크이거나 키의 상품 범위
CHECKOUT_URL_INVALID400successUrl/cancelUrl이 올바른 http/https 주소가 아님
CHECKOUT_SESSION_NOT_FOUND404세션이 없거나 키 범위 밖
CHECKOUT_SESSION_NOT_OPEN409이미 완료됐거나 만료된 세션

공통 에러 형태와 코드는 에러 코드에서 다뤄요.

Last updated on