- Overview
- Countries & currencies
- Integration
- Process flows
- Testing
- Additional information
- Consumer experience
- Reporting
- FAQ
Integration
- Using MyCheckout hosted payment pages
- Installments payment (MyCheckout payment pages)
- Using your own checkout page
- Client-side encryption
- Raw data
- Installments server-to-server payment
- Customer redirection
- Delayed capture
- Refunds and cancellations
Before you begin
To follow along with this guide, please ensure that you have the following ready:
- The correct API endpoint
- A way to construct the authorization header(our API Explorer, our SDKs, etc.)
- A way to send RESTful API calls (our API Explorer, our SDKs, etc.)
Using MyCheckout hosted payment pages
- Make a POST /v1/{merchantId}/hostedcheckouts API call.
- Create the order object containing the following elements:
- amountOfMoney, including amount and currencyCode
- customer, including billingAddress and countryCode
- personalInformation, including name with firstName and surname
- contactDetails, including mobilePhoneNumber and emailAddress
Here's an example of a minimum payload:
{
"order": {
"amountOfMoney": {
"amount": 10000,
"currencyCode": "KRW"
},
"customer": {
"billingAddress": {
"countryCode": "KR"
},
"personalInformation": {
"name": {
"firstName": "진우",
"surname": "성"
}
},
"contactDetails": {
"mobilePhoneNumber": "13810366366",
"emailAddress": "example@example.org"
}
}
}
}
Installments payment
- Make a POST /v1/{merchantId}/hostedcheckouts API call.
- Create the order object containing the following elements:
- amountOfMoney, including amount and currencyCode
- customer, including billingAddress and countryCode
- personalInformation, including name with firstName and surname
- contactDetails, including mobilePhoneNumber and emailAddress
- additionalInput for installments with the set parameters for frequencyOfInstallments and numberOfInstallments
Here's an example of a minimum payload:
{
"order": {
"amountOfMoney": {
"amount": 5000000,
"currencyCode": "KRW"
},
"customer": {
"billingAddress": {
"countryCode": "KR"
},
"personalInformation": {
"name": {
"firstName": "진우",
"surname": "성"
}
},
"contactDetails": {
"mobilePhoneNumber": "13810366366",
"emailAddress": "example@example.org"
}
},
"additionalInput": {
"installments": {
"frequencyOfInstallments": "monthly",
"numberOfInstallments": 10
}
}
}
}
The API call for both payment types will return the following response:
{
"RETURNMAC": "33893c8a-1e6f-4e02-9015-9d4e34b08d41",
"hostedCheckoutId": "0634e88f-7255-71ff-860e-3f55f70978cc",
"partialRedirectUrl": "pay1.preprod.checkout.worldline-solutions.com/checkout/9960-97ae62fd118940e492f22785def1a0a6:0660433a-041e-71ff-9ad1-a28eccdd6100:433067f2f12f4e42a1a2b6ca72e44f89"
}
From the response, the important properties are:
- hostedCheckoutId – can be used in subsequent API calls to retrieve the transaction details, such as GET/v1/{merchantId}/hostedcheckouts/{hostedCheckoutId}
- partialRedirectUrl – is used to create the URL to which the customer needs to be redirected (by default, we configure every account with the subdomain payment, so you can always connect https://payment. with the partialRedirectUrl, for example:
Check out more information on how to customize MyCheckout hosted payment pages (subdomains, design, languages, etc).
The hostedCheckoutId is only valid for 2 hours, please ensure to store the createdPaymentOutput.payment.id from the GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} response to be able to retrieve data after 2 hours have elapsed via the GET /v1/{merchantId}/payments/{paymentId} API call. Alternatively, we can also optionally send a webhook event that will contain it.
Using your own checkout page
Use this integration option if you have your own checkout page. You can build a direct integration using our SDKs (or integrate our API from scratch). Depending on your integration needs, there are several options available.
Client-side encryption
Our Client API allows you to perform various actions, such as collecting card data without being PCI SAQ-D compliant. All you need is to be able to create a session via the POST /v1/{merchantId}/sessions API call, which will grant you access to the Client API.
It's highly recommended that you use our Client SDKs.
We also have reference implementations showing how to use these SDKs on GitHub.
If you choose not to use our Client SDKs, at the very least, please use the encryption methods we provide in these SDKs, as it can be a bit tricky to do a custom implementation.
Raw data
If you wish to do a direct server-to-server API call, go for this option. The difference with the other options mentioned before is that you don't need to submit an encryptedCustomerInput property.
After the customer chose to pay with Shinhan Card, you need to perform the following:
- Make a POST /v1/{merchantId}/payments API call.
- Create the order object requiring the following properties:
- amountOfMoney, including amount and currencyCode
- customer, including billingAddress and countryCode
- personalInformation, including name with firstName and surname
- contactDetails, including mobilePhoneNumber and emailAddress
3. Create the redirectPaymentMethodSpecificInput object requiring the following properties:
- paymentProductId
- redirectionData, including the returnUrl
Here's an example of a minimum payload:
{
"order": {
"amountOfMoney": {
"amount": 10000,
"currencyCode": "KRW"
},
"customer": {
"billingAddress": {
"countryCode": "KR"
},
"personalInformation": {
"name": {
"firstName": "진우",
"surname": "성"
}
},
"contactDetails": {
"mobilePhoneNumber": "13810366366",
"emailAddress": "example@example.org"
}
}
},
"redirectPaymentMethodSpecificInput": {
"paymentProductId": 8597,
"redirectionData": {
"returnUrl": "https://example.org/return"
}
}
}
Installments server-to-server payment
- Make a POST /v1/{merchantId}/payments API call.
- Create the order object requiring the following properties:
- amountOfMoney, including amount and currencyCode
- customer, including billingAddress and countryCode
- personalInformation, including name with firstName and surname
- contactDetails, including mobilePhoneNumber and emailAddress
- additionalInput for installments with the set parameters for frequencyOfInstallments and numberOfInstallments
3. Create the redirectPaymentMethodSpecificInput object requiring the following properties:
- paymentProductId
- redirectionData, including the returnUrl
Here's an example of a minimum payload
{
"order": {
"amountOfMoney": {
"amount": 5000000,
"currencyCode": "KRW"
},
"customer": {
"billingAddress": {
"countryCode": "KR"
},
"personalInformation": {
"name": {
"firstName": "진우",
"surname": "성"
}
},
"contactDetails": {
"mobilePhoneNumber": "13810366366",
"emailAddress": "example@example.org"
}
},
"additionalInput": {
"installments": {
"frequencyOfInstallments": "monthly",
"numberOfInstallments": 10
}
}
},
"redirectPaymentMethodSpecificInput": {
"paymentProductId": 8597,
"redirectionData": {
"returnUrl": "https://example.org/return"
}
}
}
Customer redirection
If you use POST /v1/{merchantId}/payments, you'll also need to care of the customer redirection (in case of MyCheckout hosted payment pages, we handle customer redirection ourselves).
We'll return a merchantAction object containing various actionType values. However, with the Shinhan Card (authenticated), we'll always return the actionType value REDIRECT. This is accompanied by a redirectData object containing a redirectURL – it's used to let customers complete the payment by following the URL address. Note that the merchantAction is only returned in the response to POST /v1/{merchantId}/payments, and will look like this:
Expand example code
{
"creationOutput": {
"additionalReference": "01010100000750700001",
"externalReference": "0101010000075070000100001"
},
"merchantAction": {
"actionType": "REDIRECT",
"redirectData": {
"RETURNMAC": "a6efc939-5891-4bb4-a4d9-768f90950b78",
"redirectURL": "https://payment.pay1.preprod.checkout.worldline-solutions.com/external/south-korea/4002b6aa-1d3a-432c-9eb7-fd048e28793c%22"
}
},
"payment": {
"id": "000000101010000075070000100001",
"paymentOutput": {
"amountOfMoney": {
"amount": 100,
"currencyCode": "KRW"
},
"references": {
"paymentReference": "101000008219"
},
"paymentMethod": "redirect",
"redirectPaymentMethodSpecificOutput": {
"paymentProductId": 8597,
"bankAccountBban": {
"accountHolderName": "성"
}
}
},
"status": "REDIRECTED",
"statusOutput": {
"isCancellable": false,
"statusCategory": "PENDING_PAYMENT",
"statusCode": 50,
"statusCodeChangeDateTime": "20221102141354",
"isAuthorized": false,
"isRefundable": false
}
}
}
The merchantAction is omitted from the GET /v1/{merchantId}/payments/{paymentId} API call and will return a response like this:
{
"id": "000000101010000075070000100001",
"paymentOutput": {
"amountOfMoney": {
"amount": 100,
"currencyCode": "KRW"
},
"references": {
"paymentReference": "101000008219"
},
"paymentMethod": "redirect",
"redirectPaymentMethodSpecificOutput": {
"paymentProductId": 8597,
"bankAccountBban": {
"accountHolderName": "성"
}
}
},
"status": "REDIRECTED",
"statusOutput": {
"isCancellable": false,
"statusCategory": "PENDING_PAYMENT",
"statusCode": 50,
"statusCodeChangeDateTime": "20221102141354",
"isAuthorized": false,
"isRefundable": false
}
}
Delayed capture
This feature allows you to choose when to perform a capture (when using the API or via configuration). To do this, you need to submit the additional requiresApproval property according to the following example:
{
"order": {
"amountOfMoney": {
"amount": 100,
"currencyCode": "KRW"
},
"customer": {
"billingAddress": {
"countryCode": "KR"
},
"personalInformation": {
"name": {
"firstName": "진우",
"surname": "성"
}
},
"contactDetails": {
"mobilePhoneNumber": "13810366366",
"emailAddress": "accept@test.com"
}
}
},
"redirectPaymentMethodSpecificInput": {
"paymentProductId": 8597,
"requiresApproval": true,
"redirectionData": {
"returnUrl": "https://example.org/return"
}
}
}
Contact us to make this setting permanent so that you don't need to send requiresApproval in the request.
After the customer finishes the payment, GET /v1/{merchantId}/payments/{paymentId} will return a response like this:
{
"id": "000000101010000075150000100001",
"paymentOutput": {
"amountOfMoney": {
"amount": 100,
"currencyCode": "KRW"
},
"references": {
"paymentReference": "101000008299"
},
"paymentMethod": "redirect",
"redirectPaymentMethodSpecificOutput": {
"paymentProductId": 8597,
"bankAccountBban": {
"accountHolderName": "성"
}
}
},
"status": "PENDING_APPROVAL",
"statusOutput": {
"isCancellable": true,
"statusCategory": "PENDING_MERCHANT",
"statusCode": 600,
"statusCodeChangeDateTime": "20221102160445",
"isAuthorized": true,
"isRefundable": false
}
}
Here's how the equivalent GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} response looks like:
Expand example code
{
"createdPaymentOutput": {
"payment": {
"id": "000000101010000075160000100001",
"hostedCheckoutSpecificOutput": {
"hostedCheckoutId": "06362876-270e-71ff-8f2a-8dbfda4ebb12"
},
"paymentOutput": {
"amountOfMoney": {
"amount": 100,
"currencyCode": "KRW"
},
"references": {
"paymentReference": "101000008309"
},
"paymentMethod": "redirect",
"redirectPaymentMethodSpecificOutput": {
"paymentProductId": 8597,
"bankAccountBban": {
"accountHolderName": "성"
}
}
},
"status": "PENDING_APPROVAL",
"statusOutput": {
"isCancellable": true,
"statusCategory": "PENDING_MERCHANT",
"statusCode": 600,
"statusCodeChangeDateTime": "20221102160635",
"isAuthorized": true,
"isRefundable": false
}
},
"paymentCreationReferences": {
"additionalReference": "00000010101000007516",
"externalReference": "000000101010000075160000100001"
},
"paymentStatusCategory": "SUCCESSFUL"
},
"status": "PAYMENT_CREATED"
}
As seen above, the status will be changed to PENDING_APPROVAL (as opposed to CAPTURED, which is the usual status of a successful payment), indicating that it requires your approval to continue. You need to send the approval with the POST /v1/{merchantId}/payments/{paymentId}/approve API call to let us perform the capture.
After we receive your approval to capture, we'll proceed with the transaction, and the status will change to CAPTURED.
Refunds and cancellations
If you wish to cancel a payment, you have 2 opportunities to do so: before the capture and after the capture. Depending on the situation, you need to send a separate API call.
The first one we will cover is POST /v1/{merchantId}/payments/{paymentId}/cancel. This can be only be performed when the status is PENDING_APPROVAL and statusOutput.isCancellable is true.
Next is the POST /v1/{merchantId}/payments/{paymentId}/refund API call, this is only possible if status is PAID. You may refund any amount equal or lower to the captured amount, and may do this up till the total captured amount has been refunded.
A basic refund payload only requires the amountOfMoney object specifying the amount and currencyCode:
{
"amountOfMoney": {
"amount": 25,
"currencyCode": "KRW"
}
}
If you'd like to see the details of your refund, you may use the GET /v1/{merchantId}/refunds/{refundId} API call.