--- title: "Checkout 연동하기" description: "원활한 Checkout 연동으로 플레이어에게 세계 각국의 다양한 결제 수단을 제공하세요." source: "https://docs.tokenz.one/ko-KR/v1/checkout/get-started" api_version: "v1" locale: "ko-KR" version_status: "legacy" docs_stage: "prod" --- # Checkout 연동하기 원활한 Checkout 연동으로 플레이어에게 세계 각국의 다양한 결제 수단을 제공하세요. ## 사전 준비 연동에 사용할 Tokenz 비밀 키를 준비하세요. 키는 대시보드의 Developers → API keys에서 관리할 수 있습니다. Tokenz Checkout의 동작 방식은 [Checkout](https://docs.tokenz.one/ko-KR/v1/checkout)을 참고하세요. ## 서버 설정 #### Python ```python import os from flask import Flask, request, redirect from flask_cors import CORS import requests # Replace the keys with yours SECRET_KEY = os.environ.get("SECRET_KEY", "secret_test_YOUR_KEY_HERE") app = Flask(__name__, static_url_path="") CORS(app) root = "../client/build" @app.route("/", methods=["GET"]) def index(): return redirect("http://localhost:3080") ``` #### PHP ```php run(); ``` #### Go ```go package main import ( "encoding/json" "fmt" "io" "net/http" "os" "strings" "time" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.StaticFile("/demo.css", "../client/build/demo.css") router.StaticFile("/", "../client/build/index.html") router.StaticFile("/payment-success", "../client/build/payment-success.html") router.StaticFile("/payment-canceled", "../client/build/payment-canceled.html") ... router.Run(":5001") } ``` #### NodeJS ```js import express from "express"; const app = express(); const port = 3000; app.get("/", (req, res) => { res.send( "
", ); }); app.listen(port, () => { console.log(`Sandbox listening on port ${port}`); }); ``` ## Checkout Session 생성 서버에 Checkout Session을 생성하는 엔드포인트를 추가하세요. Checkout Session은 상품 항목, 주문 금액, 통화, 사용 가능한 결제 수단 등 Tokenz 호스팅 결제 페이지에 표시할 내용을 제어합니다. ### 상품 항목 정의 가격과 재고 등 민감한 상품 정보는 고객이 클라이언트에서 조작할 수 없도록 항상 서버에 보관하세요. Checkout Session을 생성할 때 상품 정보를 지정합니다. **세금.** 이 빠른 시작 가이드와 예제 페이로드는 Tokenz 계정의 기본 설정인 Merchant of Record(MoR) 모델을 설명합니다. 이 모델에서는 Tokenz가 세금을 자동으로 계산하고 징수하므로 각 항목의 `taxCategory`만 지정하면 됩니다. 계정이 별도로 Payment Gateway 모델로 설정되어 있다면 모든 Checkout Session에 최소 단위의 최상위 `tax` 객체도 포함해야 합니다(예: `"tax": { "amount": 0, "currency": "USD" }`). 이를 생략하면 `order.tax-required` 오류로 요청이 거부됩니다. 계정에 적용된 모델이 확실하지 않으면 Tokenz 담당자에게 문의하세요. ### 성공 및 취소 URL 지정 성공 페이지와 취소 페이지의 URL을 지정하세요. Tokenz가 고객을 해당 페이지로 이동시킬 수 있도록 외부에서 접근할 수 있어야 합니다. 같은 URL에서 성공 상태와 취소 상태를 모두 처리해도 됩니다. ### [선택] 사용 가능한 결제 수단 지정 이번 결제에서 고객에게 제공할 결제 수단 목록을 지정하세요. 생략하거나 빈 목록을 전송하면 사용 가능한 모든 결제 수단이 표시됩니다. ### 고객을 Tokenz Checkout으로 이동 세션을 생성한 후 응답에 반환된 결제 페이지 URL로 고객을 이동시키세요. #### Python ```python @app.route("/create-tokenz-checkout", methods=['POST']) def create_tokenz_checkout(): CALLBACK_URL_PREFIX = request.headers['referer'] headers = {"Authorization": f'Bearer {SECRET_KEY}'} print(headers) payload = { "amount": { "currency": "JPY", "amount": 5200 }, "itemDetails": [ { "product": { "label": "ひとにぎりのエメラルド", "description": "80+8", "images": [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp" ], "quantity": 3, "price": { "currency": "JPY", "amount": 1200 }, "taxCategory": "DIGITAL_GOODS_AND_SERVICES" } }, { "product": { "label": "エメラルドの荷車", "description": "100+10", "images": [], "quantity": 1, "price": { "currency": "JPY", "amount": 1600 }, "taxCategory": "DIGITAL_GOODS_AND_SERVICES" } } ], "customerInfo": {}, "successUrl": "http://localhost:9000/success", "pendingUrl": "http://localhost:9000/pending", "cancelUrl": "http://localhost:9000/cancel" } res = requests.post( "https://api.tokenz.one/v1/checkoutsession", json=payload, headers=headers ) session = res.json() return redirect(session["url"], 303) ``` #### PHP ```php $app->map(['get', 'post'], '/', function ($request, $response, $args) { $fileName = trim($request->getUri()->getBasePath(), '/'); if ($request->isPost()) { $client = new \GuzzleHttp\Client(); try { $checkoutSessionResponse = $client->request('POST', 'https://api.tokenz.one/v1/checkoutsession', [ 'body' => '{ "amount": { "currency": "JPY", "amount": 5200 }, "itemDetails": [ { "product": { "label": "ひとにぎりのエメラルド", "description": "80+8", "images": [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp" ], "quantity": 3, "price": { "currency": "JPY", "amount": 1200 }, "taxCategory": "DIGITAL_GOODS_AND_SERVICES" } }, { "product": { "label": "エメラルドの荷車", "description": "100+10", "images": [], "quantity": 1, "price": { "currency": "JPY", "amount": 1600 }, "taxCategory": "DIGITAL_GOODS_AND_SERVICES" } } ], "customerInfo": {}, "successUrl": "http://localhost:9000/success", "pendingUrl": "http://localhost:9000/pending", "cancelUrl": "http://localhost:9000/cancel" }', 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer secret_test_YOUR_KEY_HERE', ], ]); $checkoutSession = json_decode($checkoutSessionResponse->getBody()); } catch (Exception $e) { echo $e; echo \GuzzleHttp\Psr7\Message::toString($e->getResponse()); } return $response->withRedirect($checkoutSession->url, 302); } else { $filePath = __DIR__ . '/../client/build/' . $fileName; switch (pathinfo($filePath, PATHINFO_EXTENSION)) { case 'css': $mimeType = 'text/css'; break; default: $mimeType = 'text/html'; } $body = $response->getBody(); $body->write(file_get_contents($filePath)); return $response ->withHeader('Content-Type', $mimeType . '; charset=UTF-8') ->withBody($body); } }); ``` #### Go ```go router.POST("/create-tokenz-checkout", func(c *gin.Context) { url := "https://api.tokenz.one/v1/checkoutsession" payload := strings.NewReader( `{ "amount": { "currency": "JPY", "amount": 5200 }, "itemDetails": [ { "product": { "label": "ひとにぎりのエメラルド", "description": "80+8", "images": [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp" ], "quantity": 3, "price": { "currency": "JPY", "amount": 1200 }, "taxCategory": "DIGITAL_GOODS_AND_SERVICES" } }, { "product": { "label": "エメラルドの荷車", "description": "100+10", "images": [], "quantity": 1, "price": { "currency": "JPY", "amount": 1600 }, "taxCategory": "DIGITAL_GOODS_AND_SERVICES" } } ], "customerInfo": {}, "successUrl": "http://localhost:9000/success", "pendingUrl": "http://localhost:9000/pending", "cancelUrl": "http://localhost:9000/cancel" }`) req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("SECRET_KEY"))) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() bodyBytes, _ := io.ReadAll(resp.Body) var result Response if err := json.Unmarshal(bodyBytes, &result); err != nil { fmt.Println("Can not unmarshal JSON") } checkoutUrl := result.URL c.Redirect(http.StatusSeeOther, checkoutUrl) }) ``` #### NodeJS ```js app.post("/create-tokenz-checkout", (req, res) => { const API_ENDPOINT = "https://api.tokenz.one/v1/checkoutsession"; const payload = { amount: { currency: "JPY", amount: 5200, }, itemDetails: [ { product: { label: "ひとにぎりのエメラルド", description: "80+8", images: [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp", ], quantity: 3, price: { currency: "JPY", amount: 1200, }, taxCategory: "DIGITAL_GOODS_AND_SERVICES", }, }, { product: { label: "エメラルドの荷車", description: "100+10", images: [], quantity: 1, price: { currency: "JPY", amount: 1600, }, taxCategory: "DIGITAL_GOODS_AND_SERVICES", }, }, ], customerInfo: {}, successUrl: "http://localhost:9000/success", pendingUrl: "http://localhost:9000/pending", cancelUrl: "http://localhost:9000/cancel", }; fetch(API_ENDPOINT, { method: "POST", body: JSON.stringify(payload), headers: { "content-type": "application/json", authorization: "Bearer " + process.env.SECRET_KEY, }, }) .then((response) => response.json()) .then((session) => { console.log(session); res.redirect(303, session.url); }); }); ``` ## 결제 화면 구성 ### 성공 페이지 추가 Checkout Session의 `successUrl`에 지정한 URL에 성공 페이지를 만들어 주문 확인 메시지나 주문 정보를 표시하세요. 고객이 결제를 완료하면 Tokenz가 이 페이지로 이동시킵니다. ```html Thanks for your order!

We appreciate your business! If you have any questions, please email orders@example.com.

``` ### 결제 처리 중 페이지 추가 편의점 결제나 계좌이체 같은 비동기 결제 수단은 결제 처리 중 상태가 몇 분에서 며칠까지 이어질 수 있습니다. `pendingUrl`에 해당하는 페이지를 추가하세요. 고객이 비동기 결제 안내 페이지를 닫으면 Tokenz가 이 페이지로 이동시킵니다. ```html Thanks for your order!

Your payment is being processed! We will let you know as soon as it is completed. If you have any questions, please email orders@example.com.

``` ### 취소 페이지 추가 `cancelUrl`에 해당하는 페이지도 추가하세요. 고객이 결제 중 뒤로 가기 버튼을 클릭하면 Tokenz가 이 페이지로 이동시킵니다. ```html Checkout canceled

Forgot to add something to your cart? Shop around then come back to pay!

``` ### 결제 버튼 추가 마지막으로 고객이 주문을 미리 볼 수 있는 페이지를 추가하세요. 이 페이지에서 주문을 확인하거나 수정할 수 있게 하세요. Checkout 페이지에 진입하면 주문이 확정되므로, 수정하려면 새 Checkout Session을 생성해야 합니다. 주문 미리 보기 페이지에 버튼을 추가하세요. 고객이 이 버튼을 클릭하면 Tokenz 호스팅 결제 페이지로 이동합니다. ```html Buy cool new product
ひとにぎりのエメラルド

ひとにぎりのエメラルド

1,200円
```