billing key
corresponding to the card.What is Billing Key?
REST API
(NICE
and JTNet
)general payment window
(JTNet
, Inicis
, Danal-Credit card
, Danal-Mobile
and Mobilians
)REST API
NICE
, the billing key is acquired through the REST API provided by Iamport. When a merchant server sends card information to the Iamport server through Iamport REST API, the Iamport server calls PG’s API. The Iamport server here is responsible for passing the card information to the PG company. The card information is not recorded during this process.There are pros and cons in this method:card number
, card expiration date
, date of birth
, and the first 2 digits of the password
. In the case of a corporate card (except the card issued to a employee with his or her name on it
), enter the 10 digits business number
in the birth field. <form action="https://www.myservice.com/subscription/issue-billing" method="post">
<div>
<label for="card_number">Card number XXXX-XXXX-XXXX-XXXX</label>
<input id="card_number" type="text" name="card_number">
</div>
<div>
<label for="expiry">Card expiration date YYYY-MM</label>
<input id="expiry" type="text" name="expiry">
</div>
<div>
<label for="birth">Date of birth YYMMDD</label>
<input id="birth" type="text" name="birth">
</div>
<div>
<label for="pwd_2digit">First 2 digits of card password XX</label>
<input id="pwd_2digit" type="text" name="pwd_2digit">
</div>
<input hidden type="text" value="johndoe_0001_1234" name="customer_uid">
<input type="submit" value="Pay">
</form>
card number
, card expiration date
, date of birth
, and the first 2 digits of the password
. The POST
request for /subscription/issue-billing
is generated to pass the contents of the form when clicking on the pay button. The value pointing to user’s card (customer_uid
) is also passed together at this point.customer_uid property
customer_uid
attribute is used as a unique key and stored in the Iamport server. In other words, the customer_uid
value corresponds 1:1 to the billing key (per card).
If you are registering multiple cards from a customer, you should configure one customer_uid
for each card. For example, if the customer’s unique key is johndoe_0001 and the last 4 digits of the card number is 1234, the value of the customer_uid
attribute can be specified as johndoe_0001_1234 to point to a specific card for a specific customer.
// Handle POST request to "/subscription/issue-billing"
app.post("/subscriptions/issue-billing", async (req, res) => {
try {
const {
card_number, // Card number
expiry, // Card expiration date
birth, // Date of birth
pwd_2digit, // First 2 digits of card password
customer_uid, // The id that corresponds 1:1 to the card (billing key)
} = req.body; // Extract the card information from the request body
...
} catch (e) {
res.status(400).send(e);
}
});
POST
requests to /subscription/issue-billing
. card_number
, expiry
, birth
, pwd_2digit
, customer_uid
were extracted from the HTTP request body.https:\//api.iamport.kr/subscribe/customers/{customer_uid}
to acquire a billing key. // Handle POST request to "/subscription/issue-billing"
app.post("/subscriptions/issue-billing", async (req, res) => {
try {
const {
card_number, // Card number
expiry, // Card expiration date
birth, // Date of birth
pwd_2digit, // First 2 digits of card password
customer_uid, // The id that corresponds 1:1 to the card (billing key)
} = req.body; // Extract the card information from the request body
...
// Acquire access token
const getToken = await axios({
url: "https://api.iamport.kr/users/getToken",
method: "post", // POST method
headers: { "Content-Type": "application/json" }, // "Content-Type": "application/json"
data: {
imp_key: "imp_apikey", // REST API key
imp_secret: "ekKoeW8RyKuT0zgaZsUtXXTLQ4AhPFW3ZGseDA6bkA5lamv9OqDMnxyeB9wqOsuO9W3Mx9YSJ4dTqJ3f" // REST API Secret
}
});
const { access_token } = getToken.data.response; // Authentication token
...
// Request a billing key
const issueBilling = await axios({
url: \`https://api.iamport.kr/subscribe/customers/\${customer_uid}\`,
method: "post",
headers: { "Authorization": access_token }, // Append the authentication token to Authorization header
data: {
card_number, // Card number
expiry, // Card expiration date
birth, // Date of birth
pwd_2digit, // First 2 digits of card password
}
});
...
const { code, message } = issueBilling.data;
if (code === 0) { // Billing key was issued successfully
res.send({ status: "success", message: "Billing has successfully issued" });
} else { // Failed to acquire a billing key
res.send({ status: "failed", message });
}
} catch (e) {
res.status(400).send(e);
}
});
REST API Key
and REST API Secret
issued on Iamport account to retrieve payment information. The authentication token request was sent to https:\//api.iamport.kr/users/getToken
using POST
method, with application/json
as Content-Type
, imp_key: REST API key, and imp_secret: REST API Secret
in the body. When the server response to the request, it stores the access_token
, which is the authentication token included in the response data. Then, customer_uid
was binded to https:\//api.iamport.kr/subscribe/customers/${customer_uid}
, the issued authentication token access_token was specified in Authorization
, and requested as POST
method with the card information including card number
, expiry
, birth
and pwd 2digit
to acquire the billing key;.If the return value of code
property in the response is 0
, the issuance of the billing key is successful. Generate appropriate server responses based on the results.Payment upon issuance
/subscribe/payments/onetime
, to request the billing key and the payment at the same time.
general payment window
JTNet
, Inicis
, Danal-Credit card
, Danal-Mobile
and Mobilians
, the billing key is acquired from the general payment window. The payment process is performed by the customer entering the card information in the general payment window provided by PG.There are pros and cons in this method:.IMP.request_pay(param, callback)
in iamport.payment.js
. You can find how to install the code in Implementing General Payments page. It can be implemented through the following steps.IMP.request_pay(param, callback)
. Include attributes and values that are required for the payment request, in the first argument of the function param
. The billing key is issued in this step. // Call IMP.request_pay(param, callback)
IMP.request_pay({ // param
pg: "html5_inicis",
pay_method: "card", // Only "card" is supported
merchant_uid: "issue_billingkey_monthly_0001", // The order number to acquire the billing key
customer_uid: "johndoe_0001_1234", // The id that corresponds 1:1 to the card (billing key)
name: "The initial authenticated payment",
amount: 0, // Set to 0 to acquire only the billing key
buyer_email: "johndoe@gmail.com",
buyer_name: "John Doe",
buyer_tel: "010-4242-4242",
buyer_addr: "Shinsa-dong, Gangnam-gu, Seoul",
buyer_postcode: "01181"
}, function (rsp) { // callback
if (rsp.success) {
// Billing key was issued successfully
} else {
// Failed to acquire a billing key
}
});
IMP.request_pay(param, callback)
is called, the payment module window of the designated PG company appears in the PC environment. On the other hand, some PG companies provide a different process that redirects to PG’s website in a mobile environment.
There are requirements for the properties of param
attribute when calling IMP.request_pay
to acquire the billing key.pay_method
property should be set to card
: Set it to card
because recurring payments can only be made with credit/debit card.amount
property should be set to 0
: Set it to 0
because this is not an actual payment but this is to issue the billing key.customer_uid
attribute property: As a value corresponding 1:1 to the billing key, a unique customer number should be used because it will attempt recurring payments with the value specified in the attribute.Mobile web environment
KG Inicis
, LG U+
, NHN KCP
, NICE
, JTNet
, and KICC
provide a payment process for mobile web environments that redirects to the website of each PG service. Therefore, when using one of the PG services, additional work is required, such as specifying m_redirect_url
. More details can be found in Implementing General Payments > Step 7. Support mobile web environment Differences in the configuration across PG services
customer_uid
to the server. The server can request the payment later on with the customer_uid
. // Call IMP.request_pay(param, callback)
IMP.request_pay({ // param
/* ...code omitted here... */
}, function (rsp) { // callback
if (rsp.success) {
// Billing key was issued successfully
// HTTP request using jQuery
jQuery.ajax({
url: "https://www.myservice.com/billings/", // URL of the web service
method: "POST",
headers: { "Content-Type": "application/json" },
data: {
customer_uid: "johndoe_0001_1234", // The id that corresponds 1:1 to the card (billing key)
}
});
} else {
// Failed to acquire a billing key
}
});
customer_uid
from the client. // Handle POST request for "/billings"
app.post("/billings", async (req, res) => {
try {
const { customer_uid } = req.body; // Extract customer_uid from req body
...
} catch (e) {
res.status(400).send(e);
}
});
customer_uid
that corresponds 1:1 to the billing key. The API Endpoint was created on the server side to receive that value. The payment will be requested later with customer_uid
along with the order information.https:\//api.iamport.kr/subscribe/payments/again
to attempt the payment. // The controller to handle POST request for "/billings"
app.post("/billings", async (req, res) => {
try {
const { customer_uid } = req.body; // Extract customer_uid from req body
// Acquire access token
const getToken = await axios({
url: "https://api.iamport.kr/users/getToken",
method: "post", // POST method
headers: { "Content-Type": "application/json" }, // "Content-Type": "application/json"
data: {
imp_key: "imp_apikey", // REST API key
imp_secret: "ekKoeW8RyKuT0zgaZsUtXXTLQ4AhPFW3ZGseDA6bkA5lamv9OqDMnxyeB9wqOsuO9W3Mx9YSJ4dTqJ3f" // REST API Secret
}
});
const { access_token } = getToken.data.response; // Authentication token
...
// Request (re)payment
const paymentResult = await axios({
url: \`https://api.iamport.kr/subscribe/payments/again\`,
method: "post",
headers: { "Authorization": access_token }, // Append the authentication token to Authorization header
data: {
customer_uid,
merchant_uid: "order_monthly_0001", // The order number for the newly created (re)payment
amount: 8900,
name: "Recurring payments for monthly subscription"
}
});
...
const { code, message } = paymentResult;
if (code === 0) { // Successful communication with the card company (additional check is required to confirm whether the payment was successful)
if ( paymentResult.status === "paid" ) { // The payment was approved
res.send({ ... });
} else { // Failed to approve the payment (e.g. Customer card limit exceeded, suspended card, insufficient balance, etc.)
// paymentResult.status: failed is returned
res.send({ ... });
}
res.send({ ... });
} else { // The payment was not approved by the card company (paymentResult is null)
res.send({ ... });
}
} catch (e) {
res.status(400).send(e);
}
});
customer_uid
corresponding to the billing key was extracted.
Then, the authentication token was issued using the REST API key and REST API Secret issued on Iamport account for the authentication. The authentication token request was sent to https:\//api.iamport.kr/users/getToken
using POST
method, with application/json
as Content-Type
, imp_key: {REST API key}, and imp_secret: {REST API Secret}
in the body.
When the server responses to the request, it stores the access_token
, which is the authentication token included in the response data. Then, the access token access_token
was specified in Authorization for https:\//api.iamport.kr/payments/again
, and the payment request was made as POST
method with the values including customer_uid
, merchant_uid
, amount
, and name
./subscribe/payments/schedule
of Iamport’s REST API, to schedule payments at specific time in the further./subscribe/payments/schedule
, to schedule the payment. The customer number corresponding to the billing key is assigned to the customer_uid
property, and the schedules
property is specified with the order and scheduling information. Multiple order information can be included in one request as the schedules
attribute is an array
type.
The merchant_uid
, schedule_at
, and amount
properties must be specified in each item of schedules
. // Schedule a payment
axios({
url: \`https://api.iamport.kr/subscribe/payments/schedule\`,
method: "post",
headers: { "Authorization": access_token }, // Append the authentication token to Authorization header
data: {
customer_uid: "johndoe_0001_1234", // The id that corresponds 1:1 to the card (billing key)
schedules: [
{
merchant_uid: "order_monthly_0001", // order number
schedule_at: 1519862400, // Time of payment attempt in Unix timestamp. e.g. The 1st of the next month
amount: 8900,
name: "Recurring payments for monthly subscription",
buyer_name: "John Doe",
buyer_tel: "01012345678",
buyer_email: "johndoe@gmail.com"
}
]
}
});
/subscribe/payments/schedule
with POST
method. The customer number was specified in customer_uid
property and an order was specified in the schedules
property in the request body.
In order element, the unique order number was specified in the merchant_uid
property and the payment attempt time was specified in the scheduled_at
property in Unix timestamp. Also, the amount
of payment request was specified in the amount property, and customer information was specified./subscribe/payments/schedule
/subscribe/payments/schedule
, in Iamport API documentation.
imp_uid
and merchant_uid
to specified callback URL. The merchant server inquires the payment information from the Iamport server with the received imp_uid
, and trigger the defined logic based on the payment status.Iamport Webhook
POST
request generated when Iamport Webhook is called. // Handle POST request for "/iamport-callback/schedule"
app.post("/iamport-callback/schedule", async (req, res) => {
try {
const { imp_uid, merchant_uid } = req.body;
...
} catch (e) {
res.status(400).send(e);
}
});
POST
request for /iamport-webhook/iamport-callback
. imp_uid
and merchant_uid
were extracted from the HTTP request body.
Then, payment information was retrieved with imp_uid
. If the payment is successfully made, the payment information is stored in the database.
Node.js // Handle POST request for "/iamport-callback/schedule"
app.post("/iamport-callback/schedule", async (req, res) => {
try {
const { imp_uid, merchant_uid } = req.body;
// Acquire access token
const getToken = await axios({
url: "https://api.iamport.kr/users/getToken",
method: "post", // POST method
headers: { "Content-Type": "application/json" }, // "Content-Type": "application/json"
data: {
imp_key: "imp_apikey", // REST API key
imp_secret: "ekKoeW8RyKuT0zgaZsUtXXTLQ4AhPFW3ZGseDA6bkA5lamv9OqDMnxyeB9wqOsuO9W3Mx9YSJ4dTqJ3f" // REST API Secret
}
});
const { access_token } = getToken.data.response; // Authentication token
// Query payment information from Iamport with imp_uid
const getPaymentData = await axios({
url: \`https://api.iamport.kr/payments/\${imp_uid}\`, // pass imp_uid
method: "get", // GET method
headers: { "Authorization": access_token } // Append the authentication token to Authorization header
});
const paymentData = getPaymentData.data.response; // Query result
const { status } = paymentData;
if (status === "paid) { // Payment complete
// Store the payment information in the database
await Orders.findByIdAndUpdate(merchant_uid, { $set: paymentData }); // Mongoose
...
} else {
// Reattempt the payment
}
} catch (e) {
res.status(400).send(e);
}
});
REST API Key
and REST API Secret
issued for Iamport account for the authentication. The access token request was sent to https:\//api.iamport.kr/users/getToken
using POST
method, with application/json
as Content-Type
, imp_key: REST API key, and imp_secret: REST API Secret
in the body.
When the server responses to the request, it stores the access_token
, which is the access token included in the response data. Then, the URL https:\//api.iamport.kr/payments/{imp_uid}
was built with imp_uid
, the issued access token access_token
was added to Authorization
, and finally the payment information was queried by sending a request using GET
method.
Then, the payment status is checked through the payment status
of the retrieved payment information, and when the payment is completed, the payment data is synchronized to the merchant’s database./subscribe/payments/schedule
allows you to schedule a payment attempt at desired time, it is possible to implement recurring payments using Iamport Webhook. Whenever the scheduled payment is attempted, Webhook is called, and the merchant server receives payment information through the callback url and confirms that the payment was successful to schedule the next payment. In this way, the recurring payments can be implemented.
Following STEP 3, schedule a new payment after confirming that the payment is successful. // Handle POST request for "/iamport-callback/schedule"
app.post("/iamport-callback/schedule", async (req, res) => {
try {
const { imp_uid, merchant_uid } = req.body;
// Acquire access token
/* ...code omitted here ... */
// Query payment information from Iamport with imp_uid
/* ...code omitted here ... */
const paymentData = getPaymentData.data.response; // Query result
const { status } = paymentData;
if (status === "paid) { // Payment complete
// Store the payment information in the database
await Orders.findByIdAndUpdate(merchant_uid, { $set: paymentData }); // Mongoose
...
// Schedule a new payment
axios({
url: \`https://api.iamport.kr/subscribe/payments/schedule\`,
method: "post",
headers: { "Authorization": access_token }, // Append the authentication token to Authorization header
data: {
customer_uid: "johndoe_0001_1234", // The id that corresponds 1:1 to the card (billing key)
schedules: [
{
merchant_uid: "order_monthly_0001", // order number
schedule_at: 1519516800, // Time of payment attempt in Unix timestamp. e.g. The 1st of the next month
amount: 8900,
name: "Recurring payments for monthly subscription",
...
}
]
}
});
} else {
// Reattempt the payment
}
} catch (e) {
res.status(400).send(e);
}
});
status === "paid"
), the payment result was stored in the database, and the time to attempt the next payment was specified in the scheduled_at
attribute in Unix timestamp.