Create a Checkout Page via API
In this quickstart guide, you will learn how to create and pay into an Invoice created through the Invoice API. Use the Invoice API to quickly create a Checkout page without having to code your own. This guide is useful for use cases such as building an E-Commerce website with a checkout option.
This example is in Test mode and will not collect an actual payment.
Before you begin
- Register for a Xendit account by visiting our dashboard
- Generate a Secret API Key for development in Test mode here or by visiting Settings > Developers > API Keys on the dashboard
- Make sure to set "Write" permissions to your API Key for Money-In products. For more details, please visit this guide
1. Create an Invoice by making a POST request to the Invoice API
This example uses the Axios library to perform a POST request to Xendit in JavaScript by defining a createInvoice()
function.
In this example, the customer has made a fast food purchase with delivery. Each item the customer has ordered together with the delivery fees is specified in this request. This is an ideal user experience since Xendit can display these items on the Checkout page right before your customer completes payment.
This example also specifies the customer's email and phone number to allow notifications to be sent to both these channels upon successful payment.
import axios from 'axios';
const authToken = Buffer.from('xnd_development_xxxx:').toString('base64');
async function createInvoice() {
try {
const { data, status } = await axios.post('https://api.xendit.co/v2/invoices',
{
external_id: 'xendit_test_id_1',
amount: 110000,
currency: 'IDR',
customer: {
given_names: 'Ahmad',
surname: 'Gunawan',
email: 'ahmad_gunawan@example.com',
mobile_number: '+6287774441111',
},
customer_notification_preference: {
invoice_paid: ['email', 'whatsapp']
},
success_redirect_url: 'example.com/success',
failure_redirect_url: 'example.com/failure',
items: [
{
name: 'Double Cheeseburger',
quantity: 1,
price: 7000,
category: 'Fast Food'
},
{
name: 'Chocolate Sundae',
quantity: 1,
price: 3000,
category: 'Fast Food'
}
],
fees: [
{
type: "Delivery",
value: 10000
}
]
},
{
headers: {
'Authorization': `Basic ${authToken}`
}
}
)
}
The table below gives an explanation of each parameter in the request and the reason for specifying it. Make sure to replace the secret key in the example with your own secret key.
Parameter | Required | Description |
---|---|---|
external_id | Yes | A unique ID defined by you that you can use to identify each Invoice |
amount | Yes | The total amount that will be accepted as payment by Xendit |
currency | Yes | Currency of the payment to be accepted. In this case, we will use IDR |
customer.given_names | No | The given name of the customer. Use this field if you would like to send notifications to the customer |
customer.surname | No | The surname of the customer |
customer.email | No | The email to which the customer will receive a confirmation of their payment |
customer.mobile_number | No | The phone number to which the customer will receive a confirmation of their payment |
customer_notification_preference.invoice_paid | No | Channels to which notifications will be sent to the customer. In this example, we will send both Email and WhatsApp notifications |
success_redirect_url | No | A page to redirect to after successful payment. This page should be built and hosted by you |
failure_redirect_url | No | A page to redirect to after failed payment. This page should be built and hosted by you |
items.name | No | Name of the item the customer has purchased. This will appear on the checkout page. |
items.quantity | No | Quantity of the item the customer has purchased. This will appear on the checkout screen. |
items.price | No | Price of the item the customer has purchased. This, together with the value of the fees, should add up to the Invoice amount value. |
items.category | No | Category, defined by you, of which the item belongs to. In this example, we have defined this as fast food. |
fees.type | No | Type of fees to be collected as part of this invoice. Use this if you would like to collect an additional shipping or admin fee. |
fees.value | No | Amount of the fees to be charged to the customer |
After successful Invoice creation, Xendit responds to you with multiple parameters one of which is the Invoice URL. To view this, you can log the url parameter in the console.
console.log(`Response returned with a status of ${status}`);
const { invoice_url } = data;
console.log(`Invoice created! Visit ${invoice_url} to complete payment`)
For an E-Commerce use case, you should redirect the user to this page after Invoice creation. Putting it all together, your final script should look like this:
import axios from 'axios';
const authToken = Buffer.from('xnd_development_xxxx:').toString('base64');
async function createInvoice() {
try {
const { data, status } = await axios.post('https://api.xendit.co/v2/invoices',
{
external_id: 'xendit_test_id_1',
amount: 110000,
currency: 'IDR',
customer: {
given_names: 'Ahmad',
surname: 'Gunawan',
email: 'ahmad_gunawan@example.com',
mobile_number: '+6287774441111',
},
customer_notification_preference: {
invoice_paid: ['email', 'whatsapp']
},
success_redirect_url: 'example.com/success',
failure_redirect_url: 'example.com/failure',
items: [
{
name: 'Double Cheeseburger',
quantity: 1,
price: 7000,
category: 'Fast Food'
},
{
name: 'Chocolate Sundae',
quantity: 1,
price: 3000,
category: 'Fast Food'
}
],
fees: [
{
type: "Shipping",
value: 10000
}
]
},
{
headers: {
'Authorization': `Basic ${authToken}`
}
}
)
console.log(`Response returned with a status of ${status}`);
const { invoice_url } = data;
console.log(`Invoice created! Visit ${invoice_url} to complete payment`)
} catch (error) {
console.log("Request failed")
}
}
createInvoice()
After running this code (you may use NodeJS or Express to do this), you should see the Checkout page's URL being logged after successful Invoice creation.
> Response returned with a status of 200
> Invoice created! Visit https://checkout-staging.xendit.co/web/XXXXc3844c0c9828d96006a to complete payment
2. Handle the Callback for Successful Payment
Once the Invoice is paid by the customer, Xendit will send you a callback notifying successful payment. In this step, you will define a function to handle this callback sent from Xendit.
In the script below, a simple express server serves a POST endpoint /receive_callback
. This is the endpoint Xendit will send the callback to.
app.post('/receive_callback', async(req, res) => {
const { body } = req;
if (body.status === 'PAID') {
console.log(`Invoice successfully paid with status ${body.status} and id ${body.id}`)
}
res.sendStatus(200).end()
})
Parameter | Always Present | Description |
---|---|---|
status | Yes | Status of the payment. Will equal "PAID" when payment is successful |
id | Yes | ID of the Invoice. Can be used for Refunds via dashboard or to uniquely identify each invoice |
For a detailed list of parameters provided in the Invoice callback, please visit our API reference page. This page also provides additional details on how to handle failed payment callbacks.
3. Set the Callback URL on the Xendit Dashboard
Now that you have defined your callback handler, it is time to set the callback URL on Xendit's Dashboard. Ideally, this URL would lead to a production deployment of your server. For this example, it is possible to use the free tool ngrok to publicly host a localhost server.
> ngrok http 3000
Session Status online
Account abc@gmail.com (Plan: Free)
Update update available (version 3.3.0-beta, Ctrl-U to update)
Version 3.0.4
Region Asia Pacific (ap)
Latency 22ms
Web Interface http://127.0.0.1:4040
Forwarding https://XXXX-121-6-44-41.ngrok-free.app -> http://localhost:3000
You can then set the callback URL (https://XXXX-121-6-44-41.ngrok-free.app
in this case) on the Xendit Dashboard. Click here and navigate to Invoices > Invoices Paid to Test and Save this URL.
4. Simulate a payment made to your Invoice
Open the Invoice link you previously created. This will lead you to Xendit's checkout page.
In the staging environment, you're able to select any payment method and simulate payment by clicking the link in the red header.
Let's select OVO and simulate a payment by clicking the link in the red banner.
You've now successfully paid your invoice!
5. Verify that Callback was received
Now, if you go back to the server that you've been running (and perhaps hosting through ngrok), you should see a console log indicating a successful payment.
> Invoice successfully paid with status PAID and id 64759740b3adfe825417816a
6. Set success and failure URLs (Optional)
Xendit is able to redirect your customer to a success or failure page you've created on your website after successful payment or in the event of a failed payment. For this example, the following lines of code in Express will be a simple demonstration.
app.get('/success', async(req, res) => {
res.status(200).send('Success!')
})
app.get('/failure', async(req, res) => {
res.status(200).send('Failed!')
})
After this, you can provide these URLs in our Invoice creation POST request. Since this example is hosted through ngrok, the URLs have been updated to the ngrok domain that was assigned. Do note that only the relevant part of the request has been included in this example.
...
success_redirect_url: 'https://XXXX-121-6-44-41.ngrok-free.app/success',
failure_redirect_url: 'https://XXXX-121-6-44-41.ngrok-free.app/failure',
...
Wrapping Up
You've managed to successfully integrate to Xendit by creating a Checkout page and simulating payment. You've also managed to verify successful payment by verifying a successful callback sent by Xendit.
Feel free to explore the following for further reading,
- Customising Your Checkout Page
- Read the documentation on customising Docs
- Change the Xendit Checkout page according to your brand on the dashboard
- Invoice API Reference
- Enabling Payment Methods
Last Updated on 2023-06-16
- Before you begin
- 1. Create an Invoice by making a POST request to the Invoice API
- 2. Handle the Callback for Successful Payment
- 3. Set the Callback URL on the Xendit Dashboard
- 4. Simulate a payment made to your Invoice
- 5. Verify that Callback was received
- 6. Set success and failure URLs (Optional)
- Wrapping Up