forked from tossdev/tossdev.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gettingstarted.html
936 lines (905 loc) · 64.4 KB
/
gettingstarted.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>토스 결제 시작하기</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" type="image/x-icon" href="https://toss.im/assets/img/favicon.ico">
<!-- stylesheets -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="css/prism.css" />
<link rel="stylesheet" type="text/css" href="css/tossdev.css" />
<!-- javascript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body id="gettingstarted" data-spy="scroll" data-target="#guide" data-offset="0">
<!-- Google Tag Manager -->
<noscript>
<iframe src="//www.googletagmanager.com/ns.html?id=GTM-TPTMLG" height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
<script>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src =
'//www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-TPTMLG');
</script>
<!-- End Google Tag Manager -->
<!--
<header id="tossdev-header">
<div class="container">
<div class="row">
<a href="index.html"><img class="logo" src="images/logo_tossdev.png" alt="toss developers logo"></a>
</div>
</div>
</header>
-->
<div class="sidebar">
<div class="logo">
<a href="index.html"><img src="images/logo_tossdev.png" alt="toss developers logo"></a>
</div>
<div id="guide">
<h1>
<a href="#">토스 결제 시작하기</a>
</h1>
<ul class="menu nav">
<li>
<a href="#overview">가입부터 결제 완료까지</a>
<ul class="nav">
<li><a href="#overview-0">0. 시작</a></li>
<li><a href="#overview-1">1. 가맹점 계정 만들기</a></li>
<li><a href="#overview-2">2. 토스 결제 생성 요청</a></li>
<li><a href="#overview-3">3. 구매자 승인 받기</a></li>
<li><a href="#overview-4">4. 구매자 승인 완료</a></li>
<li><a href="#overview-5">5. 가맹점 최종 승인</a></li>
</ul>
</li>
<li>
<a href="#create">결제 생성하기</a>
<ul class="nav">
<li><a href="#create-1">API Endpoint</a></li>
<li><a href="#create-2">필수 Parameters</a></li>
<!--<li><a href="#create-4">결제 결과 callback URL</a></li>-->
<li><a href="#create-6">결제 만료 기한</a></li>
<li><a href="#create-7">에스크로 여부</a></li>
<li><a href="#create-8">현금영수증 발급 가능 여부</a></li>
<li><a href="#create-9">자동 승인 여부</a></li>
<li><a href="#create-10">결제 연관 data 기록</a></li>
<li><a href="#create-11">복합과세 처리</a></li>
</ul>
</li>
<li>
<a href="#execute">결제 승인하기</a>
<ul class="nav">
<li><a href="#execute-1">API Endpoint</a></li>
<li><a href="#execute-2">필수 Parameters</a></li>
<li><a href="#execute-3">유효성 추가 검증</a></li>
</ul>
</li>
<li>
<a href="#cancel">결제 취소하기</a>
<ul class="nav">
<li><a href="#cancel-1">API Endpoint</a></li>
<li><a href="#cancel-2">필수 Parameters</a></li>
<li><a href="#cancel-3">취소 사유 남기기</a></li>
<li><a href="#cancel-4">구매자의 결제 취소 대응</a></li>
</ul>
</li>
<li>
<a href="#refund">환불하기</a>
<ul class="nav">
<li><a href="#refund-1">API Endpoint</a></li>
<li><a href="#refund-2">필수 Parameters</a></li>
<li><a href="#refund-3">환불할 금액</a></li>
<li><a href="#refund-4">복합과세 결제 환불 처리</a></li>
</ul>
</li>
<li>
<a href="#checkstatus">결제 상태 알아보기</a>
<ul class="nav">
<li><a href="#checkstatus-1">API Endpoint</a></li>
<li><a href="#checkstatus-2">필수 Parameters</a></li>
<li><a href="#checkstatus-3">결제 상태 확인 요청에 대한 응답</a></li>
<li><a href="#checkstatus-4">결제 상태 목록</a></li>
</ul>
</li>
<li>
<a href="#escrow">에스크로 결제 진행</a>
<ul class="nav">
<li><a href="#escrow-1">API Endpoint</a></li>
<li><a href="#escrow-2">필수 Parameters</a></li>
<li><a href="#escrow-3">에스크로 결제 정책</a></li>
</ul>
</li>
<li>
<a href="api.html" target="_blank">API 문서 참조 <i class="fa fa-external-link" style="margin-left:4px;"></i></a>
</li>
</ul>
</div>
</div>
<div id="contents">
<div id="methods">
<div class="method" id="overview">
<div class="method-description">
<h3>가입부터 결제 완료까지</h3>
<h4 id="overview-0">0. 당신은 온라인 상점 '토스몰'을 열었습니다.</h4>
<p>당신은 티셔츠를 파는 온라인 상점 '토스몰'을 열었습니다.</p>
<p>물건을 구매하려는 손님에게 어떻게 돈을 받을지 고민하던 당신, 여러 결제 서비스를 보며 고민하다가 개발이 쉽고 손님들도 편하게 쓸 수 있는 '토스 결제 서비스'를 써보기로 합니다.</p>
<h4 id="overview-1">1. 토스 가맹점 계정을 만듭니다.</h4>
<p>먼저 <a href="https://pay.toss.im/pay" target="_blank">가입 문의</a>를 통해 가맹점 가입을 신청합니다. 가입 승인이 완료되면 가맹점 계정이 발급되고, <a href="https://pay.toss.im/tosspay/" target="_blank">가맹점 관리자</a>에 로그인하여 상점을 등록할 수 있습니다.</p>
<p>당신은 안내에 따라 정보를 입력하고 상점 '토스몰 (가칭)'을 생성합니다. 생성이 완료되면 상점 '토스몰'의 <strong>API Key가 발급됩니다.</strong> (발급받은 API Key는 '가맹점 관리자 > 상점 정보'에서 확인할 수 있습니다)</p>
<p>발급된 상점 API Key는 결제 생성 / 환불 등 모든 거래에서 인증 수단으로 활용합니다.</p>
<div class="alert alert-warning" role="alert">
<i class="fa fa-exclamation-triangle pull-left" aria-hidden="true" style="margin-top:8px;margin-left:6px"></i>
<p style="margin-left:40px">
API Key가 외부에 유출되면 원치않는 결제 생성이나 환불 처리가 발생하여 금전적인 손실이 발생할 수 있습니다. API key가 웹사이트에 노출되거나 외부인에게 유출되지 않도록 주의해주세요.
</p>
</div>
<p>발급되는 API Key는 두 가지입니다. (테스트용 / 실거래용) 두 Key는 아래와 같은 차이가 있습니다.</p>
<ul>
<li><strong>테스트용 Key</strong> : 이 Key를 사용하면 결제의 모든 과정이 실제 결제와 동일하게 진행됩니다. 통장에서 결제 금액이 '출금'되는 것만 빼고요. 돈 빠져나갈 걱정 없이 마음껏 테스트해볼 수 있기 때문에 개발 시 유용하게 사용할 수 있습니다.</li>
<li><strong>실거래용 Key</strong> : 이 Key를 사용해야 진짜 '출금'되는 결제를 할 수 있습니다. 상점에 오신 손님과 결제를 진행할 땐 꼭 이것을 사용해야 합니다.</li>
</ul>
<p>토스 결제를 한번 테스트 해보고싶지만 당장 가입하긴 귀찮다면, 아래 테스트용 Key를 사용하세요.</p>
<div class="well">테스트용 API Key : sk_test_apikey1234567890</div>
<h4 id="overview-2">2. 토스몰에 첫 손님 등장 - 토스 결제 생성을 요청합니다.</h4>
<p>'홍길동'씨는 토스몰을 둘러보다가 35,000원짜리 '토스 티셔츠'를 선택하여 결제를 요청합니다. 이 때 토스몰은 토스 결제 서버에게 '결제 생성'을 요청해야합니다. 결제 생성 API를 호출하세요!</p>
<div class="well">
결제 생성 API Endpoint
<br>
<strong>POST https://pay.toss.im/api/v1/payments</strong></div>
<p>'홍길동'씨의 결제는 아래와 같이 요청합니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
<a class="language" data-lang="language-java" href="#">Java</a>
<a class="language" data-lang="language-php" href="#">PHP</a>
</div>
<pre><code class="language-bash">curl https://pay.toss.im/api/v1/payments \
-H "Content-Type: application/json" \
-d '{
"orderNo":"1",
"amount":35000,
"amountTaxFree":0,
"productDesc":"토스티셔츠",
"apiKey":"sk_test_apikey1234567890",
"autoExecute":false,
"retUrl":"http://YOUR-SITE.COM/ORDER-CHECK"
}'</code><code class="language-java">URL url = null;
URLConnection connection = null;
StringBuilder responseBody = new StringBuilder();
try {
url = new URL("https://pay.toss.im/api/v1/payments");
connection = url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
org.json.simple.JSONObject jsonBody = new JSONObject();
jsonBody.put("orderNo", "2015072012211");
jsonBody.put("amount", 35000);
jsonBody.put("amountTaxFree", 0);
jsonBody.put("productDesc", "토스티셔츠");
jsonBody.put("apiKey", "sk_test_apikey1234567890");
jsonBody.put("autoExecute", false);
jsonBody.put("retUrl", "http://YOUR-SITE.COM/ORDER-CHECK");
BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
bos.write(jsonBody.toJSONString().getBytes());
bos.flush();
bos.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
responseBody.append(line);
}
br.close();
} catch (Exception e) {
responseBody.append(e);
}
System.out.println(responseBody.toString());</code><code class="language-php">$arrayBody = array();
$arrayBody["orderNo"] = "2015072012211";
$arrayBody["amount"] = 10000;
$arrayBody["amountTaxFree"] = 0;
$arrayBody["productDesc"] = "토스티셔츠";
$arrayBody["apiKey"] = "sk_test_apikey1234567890";
$arrayBody["autoExecute"] = false;
$arrayBody["retUrl"] = "http://YOUR-SITE.COM/ORDER-CHECK";
$jsonBody = json_encode($arrayBody);
$ch = curl_init('https://pay.toss.im/api/v1/payments');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonBody);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($jsonBody))
);
$result = curl_exec($ch);
curl_close($ch);
echo "Response: ".$result;</code></pre>
</div>
<p>위 예제에서 알 수 있듯이 '결제 생성'을 위해서는 7가지 설정값을 담아 토스에 요청해야합니다.</p>
<ol>
<li><strong>orderNo (상점 주문번호)</strong> : 추후 상점 주문 정보와 결제 정보를 매칭하기 위해 필요</li>
<li><strong>amount (결제 금액)</strong> : 손님으로부터 받을 금액</li>
<li><strong>amountTaxFree (비과세 금액)</strong> : 손님으로부터 받을 금액중 비과세 금액</li>
<li><strong>productDesc (상품 정보)</strong> : 결제할 상품에 대한 정보 (상품명)</li>
<li><strong>apiKey (상점 API Key)</strong> : 이곳에 '테스트용 Key'를 넣으면 테스트 결제가, '실거래용 Key'를 넣으면 진짜 출금되는 결제가 생성됩니다.</li>
<li><strong>autoExecute (자동 승인 설정)</strong> : false로 설정할 것을 권장합니다. 이 값을 true로 설정할 경우, 가맹점의 최종 승인 과정 없이 결제가 자동 완료됩니다.</li>
<li><strong>retUrl (인증 완료 후 연결할 URL)</strong> : 구매자가 결제 인증을 완료하면 이 곳에 입력한 URL로 연결해드립니다. 일반적으로 '가맹점의 최종 승인을 대기' 하는 페이지를 이곳에 넣습니다.</li>
</ol>
<div class="alert alert-warning" role="alert">
<i class="fa fa-exclamation-triangle pull-left" aria-hidden="true" style="margin-top:8px;margin-left:6px"></i>
<p style="margin-left:40px">
앞서 말씀 드렸듯, API Key는 절대 유출되어선 안됩니다. 결제 요청 내용이 웹페이지에 그대로 드러나지 않게 다시 한번 주의해주세요!</p>
</div>
<p>요청하신 결제 생성이 무사히 완료되면, 토스는 아래와 같이 응답합니다.</p>
<div class="method-example">
<pre><code class="always-visible language-bash">{"code":0,"checkoutPage":"https://pay.toss.im/payfront/auth?payToken=test_token1234567890
&retUrl=http://YOUR-SITE.COM/ORDER-CHECK","payToken":"test_token1234567890"}</code></pre>
</div>
<p><span class="bg-info">code '0'</span>은 결제 생성에 '성공'했음을 나타냅니다.</p>
<p><span class="bg-info">checkoutPage</span>는 생성된 결제를 진행할 웹페이지 URL입니다. (구매자를 이 URL로 보내주세요)</p>
<p><span class="bg-info">payToken</span> 값은 생성된 결제건의 고유번호입니다. 결제를 진행할 때, 결제를 취소하거나 환불할 때, 결제의 현재 상태를 파악할 때 이 고유번호를 통해 해당 결제 건에 접근하게 되니 잘 보관해주세요!</p>
<h4 id="overview-3">3. 구매자 승인 받기</h4>
<p>Toss 결제 진행은 간단합니다. 결제 생성 시 응답으로 받은 <span class="bg-info">'checkoutPage'</span> URL로 구매자를 보내주시기만 하면 됩니다.</p>
<p>위 예제의 checkoutPage는 아래와 같습니다. (매 결제마다 다른 URL이 발급됩니다)</p>
<div class="method-example">
<pre class=" language-http"><code class="always-visible language-http">https://pay.toss.im/payfront/auth?payToken=test_token1234567890
&retUrl=http://YOUR-SITE.COM/ORDER-CHECK</code></pre>
</div>
<p>그 후, 결제 승인까지의 모든 과정은 토스가 알아서 해드립니다. (결제에 사용할 계좌번호를 받고, 계좌의 유효성을 검증하고, 계좌의 주인인지 철저히 알아보는 등...)</p>
<p>
올바른 URL로 연결하셨다면 홍길동님은 아래와 같은 화면을 통해 결제를 진행하게 됩니다.
<img src="images/flow_pay.png" alt="결제 진행 흐름">
</p>
<div class="well">
1. <strong>홍길동님이 토스 결제를 처음 만났다면</strong> : 사용할 계좌를 등록하고, 결제 시 사용할 암호를 등록한 후 결제 완료 (액티브X나 앱설치가 필요 없습니다)
<br> 2. <strong>홍길동님이 토스 결제를 써봤다면</strong> : 전화번호와 암호를 입력하면 결제 완료 (보안상 필요 시 ARS 인증을 거칩니다)
<br>
<br> 직접 경험해보고 싶으시다면... <a href="https://pay.toss.im/payfront/demo" target="_blank">>> 결제 데모 페이지 바로가기</a>
</div>
<div class="well">
(선택 구현 사항)<br>앱내 웹뷰 연동 가이드
사용자의 결제 승인을 위해 토스 앱을 띄우고자 하신다면 아래와 같은 구현이 필요합니다.<br>
<strong>Android</strong>
<ol>
<li>App 설정에서 supertoss:// scheme을 허용 </li>
<li>toss 결제 웹페이지 → 가맹점 native app 통신을 위한 javascript interface 구현 </li>
<ul>
<li>interface name: TossPaymentInterface</li>
<li>method : checkTossAppInstall(string)</li>
<li>
<p>
결제 브릿지페이지가 안드로이드 웹뷰에서 열렸을 경우 위의 인터페이스 method를 호출합니다.<br>
위의 method를 호출하였을때의 기대하는 동작은 다음과 같습니다.<br>
"supertoss://" 앱스킴을 가진 Toss 앱이 사용자의 device에 설치여부에 따라 다음 javascript 함수 호출 <br>
<ul>
<li> Toss 앱 설치: callbackOnTossAppInstalled() 호출 </li>
<li> Toss 앱 미설치: callbackOnTossAppNotyet() 호출 </li>
</ul>
</p>
</li>
<li>
Interface 등록 예제
<ul>
<li>
<div class="method-example">
<pre><code class="always-visible language-java">webView.addJavascriptInterface(new TossPaymentJavascriptInterface(), "TossPaymentInterface");</code></pre>
<pre><code class="always-visible language-java">
public class TossPaymentJavascriptInterface {
....
@JavascriptInterface
public void checkTossAppInstall(String tossScheme) {
//TODO implement : "supertoss://" 스킴 값 또는 tossScheme 값을 이용하여 사용자의
// device에 토스 앱이 설치되어있는지를 확인 후 설치 유무에 따른 callback 호출을 구현
...
}
}
</code></pre>
</div>
</li>
<li>
<a href="https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)">Android Interface reference</a>
</li>
</ul>
</li>
</ul>
</ol>
<strong>iOS</strong>
<ol>
<li>App 설정에서 supertoss:// scheme을 허용 </li>
<li>toss 결제 웹페이지 → 가맹점 native app 통신을 위한 evaluate javascript interface 구현</li>
<ul>
<li> method: checkTossAppInstalledHandler(string)</li>
<li>
<p>
결제 브릿지페이지가 아이폰 앱의 웹뷰에서 열렸을 경우 위의 인터페이스 method를 호출합니다.<br>
위의 method를 호출하였을때의 기대하는 동작은 다음과 같습니다.<br>
"supertoss://" 앱스킴을 가진 Toss 앱이 사용자의 device에 설치여부에 따라 다음 javascript 함수 호출 <br>
<ul>
<li> Toss 앱 설치: callbackOnTossAppInstalled() 호출 </li>
<li> Toss 앱 미설치: callbackOnTossAppNotyet() 호출 </li>
</ul>
</p>
</li>
</ul>
<li> <a href="https://github.com/toss/ios-toss-pay-demo" target="_blank">Sample Project</a></li>
</ol>
<div class="alert alert-warning" role="alert">
<i class="fa fa-exclamation-triangle pull-left" aria-hidden="true" style="margin-top:8px;margin-left:6px"></i>
인앱브라우저 구현시 cookie등의 storage 설정을 disable하면 iOS10이하에서는 private mode로 페이지가 오픈되어 정상적인 결제가 이루어지지 않을 수 있습니다. <br>
참고 : <a href="https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532934-nonpersistent">nonPersistent WKWebsiteDataStore</a>
</div>
<strong>공통 callback</strong>
<ol>
<li>
가맹점 native app -> toss 결제 웹페이지 (토스 앱이 설치된 사용자)
<ul>
<li> method: callbackOnTossAppInstalled() </li>
<li>
사용자의 mobile device에 토스 App이 설치되었을때 토스 앱을 띄우는 함수입니다. <br>
해당 함수가 호출되면 supertoss:// 스킴을 이용해 새탭에서 앱을 여는 시도와 함께 결제 대기 페이지로 사용자를 이동시키게 됩니다.
</li>
</ul>
</li>
<li>
가맹점 native app -> toss 결제 웹페이지 (토스 앱 미설치 사용자)
<ul>
<li> method: callbackOnTossAppNotyet() </li>
<li>
사용자의 mobile device에 토스 App이 미설치되어 있다고 판단한 경우 호출하는 함수입니다.
이 함수를 호출할 경우 os에 맞는 마켓 설치 페이지 - 안드로이드는 플레이마켓, ios는 앱스토어 - 로 사용자를 이동시킵니다.
</li>
</ul>
</li>
</ol>
</div>
<h4 id="overview-4">4. 구매자 승인 완료</h4>
<p>
아래 그림과 같이, 홍길동님이 결제 암호를 잘 입력하면 구매자 승인이 완료됩니다. 그러면 토스는 결제 생성 시 넘겨주신 <span class="bg-info">'retUrl'</span>로 홍길동님을 보내드립니다.
<img src="images/flow_pay_complete.png" alt="결제 완료 처리"></p>
<p>retUrl로 홍길동님을 보내면서, 주문 번호 (orderNo)와 승인 결과 (status) query string 파라미터로 함께 보내드립니다. 예시는 다음과 같습니다.</p>
<div class="method-example">
<pre class=" language-http"><code class="always-visible language-http">http://YOUR-SITE.COM/ORDER-CHECK?orderNo=1&status=PAY_APPROVED</code></pre>
</div>
<p>여기서 status 값을 확인해주세요.</p>
<ul>
<li><strong>승인 완료한 경우</strong> : ?status=PAY_APPROVED</li>
<li><strong>결제를 취소한 경우</strong> : ?status=PAY_CANCEL</li>
</ul>
<p>결제를 취소한 경우에는 결제 취소 안내 화면을 보여주시고, 승인 완료한 경우엔 다음 단계 - 가맹점 최종 승인을 진행합니다.</p>
<h4 id="overview-5">5. 가맹점 최종 승인</h4>
<p>홍길동님은 결제를 승인했지만, 아직 결제가 완료된 상태는 아닙니다. '토스몰'의 최종 승인 단계가 남아있습니다.</p>
<p>최종 승인 전, 토스몰은 토스티셔츠의 재고가 충분한지 다시 한번 확인하고 문제가 없음을 확인한 후 '승인 요청'을 보내고자 합니다.</p>
<div class="well">
결제 승인 API Endpoint
<br>
<strong>POST https://pay.toss.im/api/v1/execute</strong>
</div>
<p>결제 승인 요청은 아래와 같이 '상점 API key'와 'payToken'값을 담아 보냅니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
<a class="language" data-lang="language-java" href="#">Java</a>
<a class="language" data-lang="language-php" href="#">PHP</a>
</div>
<pre><code class="language-bash">curl https://pay.toss.im/api/v1/execute \
-H "Content-Type: application/json" \
-d '{
"apiKey":"sk_test_apikey1234567890",
"payToken":"test_token1234567890"
}'</code><code class="language-java">URL url = null;
URLConnection connection = null;
StringBuilder responseBody = new StringBuilder();
try {
url = new URL("https://pay.toss.im/api/v1/execute");
connection = url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
org.json.simple.JSONObject jsonBody = new JSONObject();
jsonBody.put("apiKey", "sk_test_apikey1234567890");
jsonBody.put("payToken", "test_token1234567890");
BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
bos.write(jsonBody.toJSONString().getBytes());
bos.flush();
bos.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
responseBody.append(line);
}
br.close();
} catch (Exception e) {
responseBody.append(e);
}
System.out.println(responseBody.toString());</code><code class="language-php">$arrayBody = array();
$arrayBody["apiKey"] = "sk_test_apikey1234567890";
$arrayBody["payToken"] = "test_token1234567890";
$jsonBody = json_encode($arrayBody);
$ch = curl_init('https://pay.toss.im/api/v1/execute');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonBody);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($jsonBody))
);
$result = curl_exec($ch);
curl_close($ch);
echo "Response: ".$result;</code></pre>
</div>
<p>토스몰의 승인 요청을 받으면 토스 결제 서버는 먼저 구매자의 승인이 정말 완료되었는지 다시 한번 확인합니다. (구매자가 악의적으로 URL 변조를 통해 승인 완료인 척 했다면 여기서 결제가 중지됩니다)</p>
<p>승인이 완료된 것을 확인한 후, 구매자의 결제 계좌에서 결제 금액을 출금합니다. 출금이 완료되면 승인 요청에 대한 응답을 토스몰로 보냅니다.</p>
<div class="method-example">
<pre><code class="always-visible language-bash">{"code":0}</code></pre>
</div>
<p>'성공'을 의미하는 '0' 코드를 받으셨다면, 결제를 완료 처리하고 구매자를 결제 완료 페이지로 안내해주세요.</p>
<p>실패를 의미하는 '-1' 코드를 받으셨거나, 응답을 받지 못했다면 결제를 완료 처리하지 마십시오.</p>
<div class="alert alert-warning" role="alert">
<i class="fa fa-exclamation-triangle pull-left" aria-hidden="true" style="margin-top:8px;margin-left:6px"></i>
<p style="margin-left:40px">
다시 한번 말씀드리지만, 결제 승인 API 요청의 응답이 '성공' (코드 0)인지 반드시 확인하셔야 합니다.
<br> 계좌 잔액 부족이나 구매자의 URL 변조가 확인되어 '실패' (코드 -1)응답을 받을 수 있습니다. 응답을 확인하지 않고 결제 완료 처리하는 경우, 결제는 실패했으나 물품은 발송되어버릴 수도 있으니 주의하세요!
</p>
</div>
<div class="alert alert-info" role="alert">
<i class="fa fa-info-circle pull-left" aria-hidden="true" style="margin-top:8px;margin-left:6px"></i>
<p style="margin-left:40px">
결제 상태가 명확하지 않거나 다시 한번 확인하고 싶다면 <a href="#checkstatus">'결제 상태 확인 API'</a>를 통해 결제 상태를 조회하세요.
</p>
</div>
</div>
</div>
<div class="method" id="create">
<div class="method-description">
<h3>결제 생성하기</h3>
<p>결제 생성 요청에 대해 좀 더 자세히 알아봅니다. 아래 예제는 결제 생성 API가 지원하는 모든 파라미터를 사용한 코드입니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
</div>
<pre><code class="language-bash">curl https://pay.toss.im/api/v1/payments \
-H "Content-Type: application/json" \
-d '{
"orderNo":"1", # 토스몰 고유의 주문번호 (필수)
"amount":35000, # 결제 금액 (필수)
"amountTaxFree":0, # 비과세 금액 (필수)
"productDesc":"토스티셔츠", # 상품 정보 (필수)
"apiKey":"sk_test_apikey1234567890", # 상점의 API Key (필수)
"retUrl":"http://YOUR-SITE.COM/ORDER-CHECK?orderno=1", # 결제 완료 후 연결할 웹페이지 URL
"amountTaxable":22727, # 결제 금액 중 과세금액
"amountTaxFree":10000, # 결제 금액 중 비과세금액
"amountVat":2273, # 결제 금액 중 부가세
"amountServiceFee":0, # 결제 금액 중 봉사료
"expiredTime":"2015-12-01 12:47:35", # 결제 만료 예정 시각
"escrow":false, # 에스크로 여부
"cashReceipt":true, # 현금영수증 발급 가능 여부
"autoExecute":false, # 자동 승인 여부
"metadata":"{'size':'XL','color':'Red'}" # metadata 값
}'</code></pre>
</div>
<h4 id="create-1">결제 생성 API의 Endpoint</h4>
<div class="well">POST https://pay.toss.im/api/v1/payments</div>
<h4 id="create-2">필수 Parameters</h4>
<p>결제 생성 요청 시 반드시 아래 5가지 값을 함께 보내주셔야합니다.</p>
<ol>
<li><strong>상점 주문번호</strong> : 추후 상점 주문 정보와 결제 정보를 매칭하기 위해 필요</li>
<li><strong>결제 금액</strong> : 손님으로부터 받을 금액</li>
<li><strong>비과세 금액</strong> : 손님으로부터 받을 금액중 비과세 금액</li>
<li><strong>상품 정보</strong> : 결제할 상품에 대한 정보 (상품명)</li>
<li><strong>상점 API Key</strong> : 이곳에 '테스트용 Key'를 넣으면 테스트 결제가, '실거래용 Key'를 넣으면 진짜 출금되는 결제가 생성됩니다.</li>
<li><strong>구매자 승인 완료 후 연결할 URL</strong> : 구매자가 결제를 승인하면 이 파라미터를 통해 등록한 URL로 구매자를 보내드립니다. 일반적으로 구매 완료 페이지 또는 구매 완료 페이지로 연결할 수 있는 곳을 지정합니다.</li>
</ol>
<!--
<h4 id="create-4">결제 결과 callback URL (resultCallback)</h4>
<p>결제 생성이 성공적으로 끝나면, 해당 결제건은 '결제 대기' 상태가 됩니다. 이후, 결제는 '완료'되거나 '취소'되거나 혹은 '환불'처리됩니다.</p>
<p>그러한 상태 변경이 있을 때 마다 상점의 주문 상태를 변경하거나 구매자에게 안내를 해주어야 한다면 '결제 결과에 대한 callback' 파라미터를 사용하세요. 이 파라미터에 응답을 받을 URL을 등록하시면, 아래와 같이 callback을 보내드리겠습니다.</p>
<div class="method-example">
<pre><code class="always-visible language-bash">{
"payToken":"test_token1234567890", # 상태가 바뀐 결제건의 고유 번호
"orderNo":"1", # 결제건과 연결된 상점 주문번호
"status":"PAY_COMPLETE" # 최종적으로 바뀐 결과
"metadata":"{'size':'XL','color':'Red'}" # 결제 생성 시 저장한 metadata
}</code></pre>
</div>
<p>"status" 값은 결제 결과에 따라 다음과 같이 보내드립니다.</p>
<ul>
<li><strong>PAY_COMPLETE</strong> : 결제가 성공적으로 완료되었음</li>
<li><strong>PAY_CANCEL</strong> : 결제가 완료되기 전에 취소됨</li>
<li><strong>REFUND_SUCCESS</strong> : 완료된 결제가 환불 처리됨</li>
</ul>
-->
<h4 id="create-6">결제 만료 기한 (expiredTime)</h4>
<p>이 파라미터를 통해 '결제 생성 후, 언제까지 결제 승인을 진행할 수 있는지' 설정할 수 있습니다. '결제 대기' 상태인 결제건의 만료 기한이 도래하면 자동으로 결제가 취소됩니다.</p>
<p>상점 혹은 판매 물품에 특성에 따라 결제 만료 기간을 길게 혹은 짧게 설정할 수 있습니다.</p>
<ul>
<li>재고의 변동이 적고, 구매자의 결제가 급하지 않다면 결제 만료 기한을 길게 설정하세요. 구매자는 먼저 주문만 해두고 원하는 시점에 결제할 수 있습니다. (예를 들어, 주문은 오전에 하고 밤에 Toss 앱을 설치하여 결제를 완료할 수 있습니다)</li>
<li>재고의 변동이 크거나 '결제 대기' 상태를 오래 지속하고싶지 않은 경우엔 결제 만료 기한을 짧게 설정하세요.</li>
</ul>
<p>결제 만료 기한은 <span class="bg-info">최대 1시간</span>이며, 따로 설정하지 않는 경우 15분으로 설정됩니다.</p>
<h4 id="create-7">에스크로 여부 (escrow)</h4>
<p>에스크로 결제로 진행할지 설정할 수 있습니다.</p>
<ul>
<li><strong>true</strong> : 에스크로 결제를 생성합니다.</li>
<li><strong>false</strong> : 일반 결제를 생성합니다. (값을 설정하지 않으면 false)</li>
</ul>
<p>에스크로 결제는 일종의 '구매자 보호 정책'입니다. 온라인 상에서 실물거래를 하는 경우, 구매자가 판매자에게 입금은 하였으나 물품을 받지 못하거나 원치 않는 물품을 받았을 경우 금전적 손실이 발생할 수 있는데, 이를 방지하기 위한 것입니다.</p>
<p>결제가 완료되면 결제 금액만큼 구매자의 계좌에서 출금되지만, 구매자가 물품을 정상적으로 받았다고 확정(구매확정)하기 전까지는 정산되지 않습니다. 따라서 구매자는 좀 더 안심하고 물품을 구매할 수 있습니다.</p>
<p class="alert alert-warning" role="alert">온라인상에서 실물을 판매하는 경우, 구매자에게 '에스크로 결제'를 선택할 수 있는 권한을 필수적으로 제공해야합니다.</p>
<p class="alert alert-warning" role="alert">에스크로 결제 생성 및 승인 완료 후, 반드시 '진행' 처리를 해주어야 합니다. <a href="#escrow">'에스크로 결제 진행'</a> 문서를 꼭 확인하세요.</p>
<h4 id="create-8">현금영수증 발급 가능 여부 (cashReceipt)</h4>
<p>
현금영수증 발급 가능 여부를 설정할 수 있습니다.
<br> (참고 : 문화상품권이나 백화점상품권, 모바일 쿠폰 등 과세 대상에서 제외되는 유가증권 등의 상품은 현금영수증 발행 대상에서 제외됩니다)
</p>
<ul>
<li><strong>true</strong> : 현금영수증 발급 가능 (값을 설정하지 않으면 true)</li>
<li><strong>false</strong> : 현금영수증 발급 불가</li>
</ul>
<h4 id="create-9">자동 승인 여부 (autoExecute)</h4>
<p>구매자의 인증이 완료되면 바로 결제 완료 처리할지, 최종적으로 가맹점의 승인을 거칠지 설정할 수 있습니다.</p>
<ul>
<li><strong>true</strong> : 구매자 인증 완료 시 바로 결제 완료 처리합니다.</li>
<li><strong>false</strong> : 구매자 인증 완료 후 가맹점의 최종 승인 시 결제 완료 처리합니다.</li>
</ul>
<p>재고 상황이 빠르게 변하는 경우나 서비스 흐름 상 결제의 최종 승인은 가맹점이 해야하는 경우, 자동 승인을 false로 설정함으로써 대응할 수 있습니다. </p>
<h4 id="create-10">결제 연관 data 기록 (metadata)</h4>
<p>
생성하는 결제 건과 연관된 추가적인 데이터가 있다면 이 파라미터를 활용하여 저장해둘 수 있습니다. (결제가 완료될 때 보내드리는 callback에 여기에 저장해준 데이터를 함께 보내드립니다)
</p>
<h4 id="create-11">복합과세 처리 (amount-)</h4>
<p>
전체 결제 금액 중 '비과세' 처리해야할 금액이 섞여있거나 부가세, 봉사료 비중을 원하는대로 설정하고 싶다면 결제 생성 시 '복합과세' 파라미터를 이용하세요.
</p>
<ul>
<li><strong>amountTaxable</strong> : 결제 금액 중 '과세금액' 비중</li>
<li><strong>amountTaxFree</strong> : 결제 금액 중 '비과세금액' 비중</li>
<li><strong>amountVat</strong> : 결제 금액 중 '부가세' 비중</li>
<li><strong>amountServiceFee</strong> : 결제 금액 중 '봉사료' 비중</li>
</ul>
<p>
위 네 가지 값 중 하나라도 0이 아닌 값으로 설정하면 해당 결제 건은 '복합과세' 결제로 처리되며, 네 가지 값의 합은 총 결제 금액(amount)과 반드시 동일해야합니다. (동일하지 않을 시 에러 발생)
<br> 위 파라미터를 통해 설정한 값은 현금 영수증 발행 시 그대로 반영됩니다.
</p>
<p>
위 파라미터 값을 설정하지 않는 경우, 자동으로 아래와 같이 처리됩니다.
</p>
<ul>
<li><strong>부가세</strong> : 전체 금액(amount)을 11로 나눈 후 소수점 첫째 자리에서 올림</li>
<li><strong>과세금액</strong> : 전체 금액에서 부가세를 뺀 나머지 값</li>
<li><strong>비과세금액, 봉사료</strong> : 0</li>
</ul>
<p>
단, 현금영수증 발행 불가 결제(cashReceipt = false)인 경우, 아래와 같이 처리됩니다.
</p>
<ul>
<li><strong>과세금액</strong> : 전체 금액(amount)과 동일</li>
<li><strong>부가세, 비과세금액, 봉사료</strong> : 0</li>
</ul>
</div>
</div>
<div class="method" id="execute">
<div class="method-description">
<h3>결제 승인하기</h3>
<p>
Toss 결제는 기본적으로 '구매자'의 인증이 완료되면 바로 구매자의 결제 계좌에서 출금하고 결제를 완료시킵니다. 하지만 상황에 따라 결제를 '최종 승인'하는 주체가 가맹점이어야 하는 경우가 있습니다. 그럴땐 아래 두 가지 조치를 통해 대응할 수 있습니다.
</p>
<ol>
<li><strong>결제 생성 시, autoExecute를 'false'로 설정</strong> : 해당 결제건은 가맹점의 최종 승인 전까진 대기 상태에 머무르게 됩니다. (PAY_APPROVED 상태)</li>
<li><strong>결제 승인 API를 통해 최종 승인 (execute API)</strong> : PAY_APPROVED 상태의 결제건에 대해 승인을 요청하면 출금을 시도하고 출금 완료 시 결제 완료로 상태를 변경합니다.</li>
</ol>
<p>
아래 그림을 참고하세요.
<img src="images/flow_autoExecute.png" alt="결제 승인 흐름">
</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
</div>
<pre><code class="language-bash">curl "https://pay.toss.im/api/v1/execute" \
-H "Content-Type: application/json" \
-d '{
"apiKey":"sk_test_apikey1234567890", # 상점의 API Key (필수)
"payToken":"test_token1234567890", # 결제 고유 번호 (필수)
"orderNo":"2017091401892", # 상점의 주문번호
"amount":9900, # 결제 금액
}'
</code></pre>
</div>
<h4 id="execute-1">결제 승인 API의 Endpoint</h4>
<div class="well">POST https://pay.toss.im/api/v1/execute</div>
<h4 id="execute-2">필수 Parameters</h4>
<p>필수 파라미터는 딱 2가지 입니다. '어느 가맹점'에서 '어떤 결제건'을 최종 승인할지 알려주세요!</p>
<ol>
<li><strong>상점 API Key</strong> : 결제를 생성한 상점의 API key가 필요합니다.</li>
<li><strong>결제 고유 토큰 (payToken)</strong> : 결제 생성 완료 후 받은 결제 고유번호</li>
</ol>
<h4 id="execute-3">유효성 추가 검증</h4>
<p>결제 승인 시 orderNo (상점의 주문번호)와 amount (결제 금액)을 함께 보내면 일치 여부를 확인합니다. 결제 고유 번호 (payToken)와 연결된 결제건과 orderNo나 amount가 다르면 승인 실패처리하여 다시 한번 유효성을 검증합니다.</p>
</div>
</div>
<div class="method" id="cancel">
<div class="method-description">
<h3>결제 취소하기</h3>
<p>결제가 아직 완료되지 않은 '대기' 상태에서 결제를 취소할 수 있습니다. 아래 예제는 결제 취소 API가 지원하는 모든 파라미터를 사용한 코드입니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
</div>
<pre><code class="language-bash">curl "https://pay.toss.im/api/v1/cancel" \
-H "Content-Type: application/json" \
-d '{
"apiKey":"sk_test_apikey1234567890", # 상점의 API Key (필수)
"payToken":"test_token1234567890", # 결제 고유 번호 (필수)
"reason":"재고 부족" # 취소 사유
}'
</code></pre>
</div>
<h4 id="cancel-1">결제 취소 API의 Endpoint</h4>
<div class="well">POST https://pay.toss.im/api/v1/cancel</div>
<h4 id="cancel-2">필수 Parameters</h4>
<p>필수 파라미터는 딱 2가지 입니다. '어느 가맹점'에서 '어떤 결제건'을 취소하는지만 알려주세요!</p>
<ol>
<li><strong>상점 API Key</strong> : 결제를 생성한 상점의 API key가 필요합니다.</li>
<li><strong>결제 고유 토큰 (payToken)</strong> : 결제 생성 완료 후 받은 결제 고유번호</li>
</ol>
<h4 id="cancel-3">취소 사유 남기기 (reason)</h4>
<p>결제 취소 사유를 기록해야한다면 이 파라미터를 활용하세요. <span class="bg-info">최대 50자까지</span> 남길 수 있습니다. (string)</p>
<h4 id="cancel-4">구매자의 결제 취소 대응</h4>
<p>구매자도 결제를 취소할 수 있습니다. 이에 대응하기 위해 결제 생성 시 callback URL을 등록하고, '취소'가 발생한 경우 적절한 처리를 해주세요. (주문 상태 변경 등)</p>
</div>
</div>
<div class="method" id="refund">
<div class="method-description">
<h3>환불하기</h3>
<p>결제 완료 건의 결제 금액 중 일부 또는 전부를 구매자에게 돌려줍니다. (환불 요청에 성공하는 즉시 구매자의 계좌로 요청하신 금액이 입금되며, 환불한 금액은 상점의 다음 정산에 반영됩니다)</p>
<p>아래 예제는 결제 환불 API가 지원하는 모든 파라미터를 사용한 코드입니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
</div>
<pre><code class="language-bash">curl "https://pay.toss.im/api/v1/refunds" \
-H "Content-Type: application/json" \
-d '{
"apiKey":"sk_test_apikey1234567890", # 상점의 API Key (필수)
"payToken":"test_token1234567890", # 결제 고유 번호 (필수)
"amount":10000 # 환불할 금액 (필수)
"amountTaxable":5000, # 환불할 금액 중 과세금액
"amountTaxFree":4000, # 환불할 금액 중 비과세금액 (필수)
"amountVat":500, # 환불할 금액 중 부가세
"amountServiceFee":500, # 환불할 금액 중 봉사료
}'
</code></pre>
</div>
<h4 id="refund-1">결제 환불 API의 Endpoint</h4>
<div class="well">POST https://pay.toss.im/api/v1/refunds</div>
<h4 id="refund-2">필수 Parameters</h4>
<p>'결제 취소'와 필수 파라미터는 4가지 입니다. '어느 가맹점'에서 '어떤 결제건'을 환불하는지만 알려주세요!</p>
<ol>
<li><strong>상점 API Key</strong> : 결제를 생성한 상점의 API key가 필요합니다.</li>
<li><strong>결제 고유 토큰 (payToken)</strong> : 결제 생성 완료 후 받은 결제 고유번호</li>
<li><strong>환불할 금액 (amount)</strong> : 환불 할 금액</li>
<li><strong>환불할 비과세 금액 (amountTaxFree)</strong> : 환불할 금액중 비과세 금액</li>
</ol>
<h4 id="refund-3">환불할 금액</h4>
<p>
총 결제 금액 중 일부만 환불하고자 하는 경우, 이 파라미터 값을 설정해주세요. 금액을 설정하지 않으면 결제 금액 전액을 환불합니다.
<br> (단, 에스크로 보호 중인 결제는 전체 금액 환불만 가능합니다)
</p>
<h4 id="refund-4">복합과세 결제 환불 처리</h4>
<p>
결제 생성 시, 세부 금액 구성(과세금액/비과세금액/부가세/봉사료)을 지정했다면, 환불 요청 시에도 반드시 어떤 부분에서 환불 처리할지 지정해야 합니다.
</p>
<p>
환불 요청하는 금액은 '남은 결제 금액'보다 작거나 같아야 하고, 환불할 세부 금액들의 총합은 반드시 전체 환불 금액(amount)과 동일해야 합니다. (다를 시 에러 발생)
</p>
</div>
</div>
<div class="method" id="checkstatus">
<div class="method-description">
<h3>결제 상태 알아보기</h3>
<p>결제가 생성되고 진행됨에 따라 결제의 '상태'는 끊임없이 바뀝니다. 상점 운영을 위해선 특정 결제건이 현재 어떤 상태인지 파악할 일이 많을 것입니다. 결제가 잘 끝난 것인지, 취소된 것은 아닌지. 환불 요청에 들어왔던 주문은 잘 환불 되었는지...</p>
<p>그럴땐 망설이지 말고 '결제 상태 확인 API'를 찾아주세요. 아래 예제는 결제 상태 확인 API 호출 코드입니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
</div>
<pre><code class="language-bash">curl "https://pay.toss.im/api/v1/status" \
-H "Content-Type: application/json" \
-d '{
"apiKey":"sk_test_apikey1234567890", # 상점의 API Key (필수)
"payToken":"test_token1234567890", # 결제 고유 번호 (필수)
}'
</code></pre>
</div>
<h4 id="checkstatus-1">결제 상태 확인 API의 Endpoint</h4>
<div class="well">POST https://pay.toss.im/api/v1/status</div>
<h4 id="checkstatus-2">필수 Parameters</h4>
<p>필수 파라미터는 딱 2가지 입니다. '어느 가맹점'에서 일어난 '어떤 결제건'을 조회하고 싶은지 알려주세요.</p>
<ol>
<li><strong>상점 API Key</strong> : 결제를 생성한 상점의 API key가 필요합니다.</li>
<li><strong>결제 고유 토큰 (payToken)</strong> : 결제 생성 완료 후 받은 결제 고유번호</li>
</ol>
<p>* '결제 고유 토큰 (payToken)' 대신 '상점의 주문번호 (orderNo)'값을 사용할 수도 있습니다.</p>
<h4 id="checkstatus-3">결제 상태 확인 요청에 대한 응답</h4>
<p>결제 상태 확인 요청에 대한 응답은 아래와 같은 형태로 받게됩니다.</p>
<div class="method-example">
<pre><code class="always-visible language-bash">{
"code":0, # 응답코드
"payToken":"test_token1234567890" # 결제 고유 번호
"orderNo":"2015072012211", # 상점의 주문번호
"payStatus":"REFUND_SUCCESS", # 결제 상태
"availableActions ":["REFUND"], # 가능한 액션 목록
"hasOwner":true, # 결제할 사람의 정보 입력 여부
"metadata":"metadata" # 결제 생성 시 입력한 metadata
}
</code></pre>
</div>
<p>각 항목은 다음과 같은 의미를 가지고 있습니다.</p>
<ul>
<li><strong>응답코드</strong> : 요청에 대한 결과. 성공하면 '0' 입니다.</li>
<li><strong>결제 고유 번호</strong> : 결제 생성 완료 후 받은 결제 고유번호. '주문번호'로 상태를 조회하면 이 값을 참조하여 '결제 고유번호 값을 알 수 있습니다.</li>
<li><strong>상점의 주문번호</strong> : 상점에서 사용하는 주문번호. 'payToken'으로 상태를 조회하면 이 값을 참조하여 '주문번호'를 알 수 있습니다.</li>
<li><strong>결제 상태</strong> : 조회 당시의 결제 상태 (아래 '결제 상태 목록'을 참고하세요)</li>
<li><strong>가능한 액션 목록</strong> : 조회 당시에 가능한 액션(취소, 환불 등) 목록 (예를 들어, '결제 완료' 상태에서는 '환불'이 가능하나 '전액 환불'한 상태에서는 환불 불가)</li>
<li><strong>결제할 사람의 정보 입력 여부</strong> : 당신의 상점에서 결제를 생성하고 결제 진행 웹페이지를 구매자에게 제공하고 나면 구매자는 결제 승인에 필요한 정보를 입력합니다. 결제를 진행할 사람에 대한 정보가 올바르게 입력되면 이 값은 <span class="bg-info">true</span>가 됩니다. 반면, 아직 정보를 입력하지 않은 상태라면 <span class="bg-info">false</span> 입니다.</li>
<li><strong>결제 연관 data</strong> : 결제 생성 시 가맹점 측에서 해당 결제건과 연관된 정보를 metadata field를 통헤 기록할 수 있고, 결제 상태 조회를 통해 기록하셨던 data에 다시 접근하실 수 있습니다.</li>
</ul>
<h4 id="checkstatus-4">결제 상태 목록</h4>
<p>
결제 상태는 아래 중 하나입니다.
<br> 각 상태에 대한 자세한 설명은 <a href="api.html#state">결제 API > 결제 상태</a> 문서를 참고하세요.
</p>
<table class="table table-hover">
<tr>
<td width=50%>PAY_STANDBY</td>
<td width=50%>결제 대기 중</td>
</tr>
<tr>
<td>PAY_CANCEL</td>
<td>결제 취소</td>
</tr>
<tr>
<td>PAY_PROGRESS</td>
<td>결제 진행 중</td>
</tr>
<tr>
<td>PAY_COMPLETE</td>
<td>결제 완료</td>
</tr>
<tr>
<td>ESCROW_REQUEST</td>
<td>배송등록 대기 중 (에스크로 요청)</td>
</tr>
<tr>
<td>ESCROW_RELEASE</td>
<td>구매확정 대기 중 (에스크로 해제)</td>
</tr>
<tr>
<td>ESCROW_DENY</td>
<td>구매자 지급 거부 (에스크로 거부)</td>
</tr>
<tr>
<td>REFUND_PROGRESS</td>
<td>환불 진행 중</td>
</tr>
<tr>
<td>REFUND_SUCCESS</td>
<td>환불 성공</td>
</tr>
<tr>
<td>SETTLEMENT_COMPLETE</td>
<td>정산 완료</td>
</tr>
<tr>
<td>SETTLEMENT_REFUND_COMPLETE</td>
<td>환불 정산 완료</td>
</tr>
</table>
</div>
</div>
<div class="method" id="escrow">
<div class="method-description">
<h3>에스크로 결제 진행</h3>
<p>
에스크로 결제는 아래와 같은 흐름으로 진행됩니다.
<br>
<img src="images/flow_escrow.png" alt="에스크로 결제 흐름">
</p>
<ol>
<li>에스크로 결제 생성 및 구매자의 승인 완료</li>
<li>배송등록 대기 중 : 구매자가 결제 승인을 완료하여 구매 대금이 출금된 상태입니다. (구매 대금은 '구매 확정'될 때 까지 토스가 보관합니다) 판매자가 물품 배송을 완료한 후, <span class="bg-info">'배송 등록'</span>을 하면 '구매확정 대기 중' 상태로 변경됩니다.</li>
<li>구매확정 대기 중 : 구매자의 '구매 확정'을 기다리는 상태입니다. 이 때 구매자는 '구매 확정' 또는 '지급 거부'할 수 있습니다.
<ul>
<li>구매 확정 시 : 결제가 완료되고 판매자는 대금을 정산받습니다.</li>
<li>지급 거부 시 : '구매자 지급 거부' 상태가 되며, 대금 정산이 진행되지 않습니다. 구매자와 판매자간 합의를 거친 후, '환불'하거나 '구매확정을 다시 요청'할 수 있습니다.</li>
</ul>
</li>
</ol>
<p>위와 같은 에스크로 결제 진행 과정에서 판매자가 반드시 조치해야하는 두 가지 상황이 있습니다.</p>
<ol>
<li>'배송등록 대기 중' 상태에서 물품 배송 후 <strong>'배송 등록'하기</strong></li>
<li>'구매자 지급 거부' 상태에 빠졌을 때 문제를 해결하고 <strong>'구매확정 재요청'하기</strong></li>
</ol>
<p>위 두 상황에서 조치를 취하지 않으면 결제 및 대금 지급이 이루어지지 않으므로 잊지말고 진행해야 합니다. '배송 등록'과 '구매확정 재요청' 처리 시 사용하는 API가 지금부터 소개할 '에스크로 결제 진행 API'입니다.</p>
<p>아래 예제는 에스크로 결제 진행 API의 예제 코드입니다.</p>
<div class="method-example">
<div class="languages">
<a class="language selected" data-lang="language-bash" href="#">curl</a>
</div>
<pre><code class="language-bash">curl "https://pay.toss.im/api/v1/escrow" \
-H "Content-Type: application/json" \
-d '{
"apiKey":"sk_test_apikey1234567890", # 상점의 API Key
"payToken":"test_token1234567890" # 결제 고유 번호
}'
</code></pre>
</div>
<ul>
<li>'배송등록 대기 중' 상태인 결제 건에 대해 위 요청을 보내면 '배송 등록' 처리됩니다.</li>
<li>'구매자 지급 거부' 상태인 결제 건에 대해 위 요청을 보내면 '구매확정 재요청' 처리됩니다.</li>
</ul>
<h4 id="escrow-1">에스크로 결제 진행 API의 Endpoint</h4>
<div class="well">POST https://pay.toss.im/api/v1/escrow</div>
<h4 id="escrow-2">필수 Parameters</h4>
<ol>
<li><strong>상점 API Key</strong> : 결제를 생성한 상점의 API key가 필요합니다.</li>
<li><strong>결제 고유 토큰 (payToken)</strong> : 결제 생성 완료 후 받은 결제 고유번호</li>
</ol>
<h4 id="escrow-3">에스크로 결제 정책</h4>
<p>에스크로 결제와 관련된 자세한 정책은 아래 문서를 참고하세요.</p>
<p><a href="policy.html#escrow">토스 결제 서비스 정책 > 에스크로 결제</a></p>
</div>
</div>
<div class="method" id="maintenance">
<div class="method-description">
<h3>은행별 정기 점검시간</h3>
<p>
은행 점검시간에는 해당 은행 계좌를 통한 결제가 불가합니다.
</p>
<p>
<a href="api.html#maintenance"> 은행 점검 시간 확인</a>
</p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function() {
// hljs.configure({
// tabReplace: ' ',
// classPrefix: ''
// })
// hljs.initHighlightingOnLoad();
// language toggle
var $languages = $(".languages .language");
$languages.click(function(e) {
e.preventDefault();
var lang = $(this).data("lang");
$languages.removeClass("selected");
$(this).addClass("selected");
$("pre code").hide();
$("pre code." + lang).css("display", "block");
});
});
</script>
<script src="js/prism.js"></script>
</body>
</html>