In-page checkout

1. Set up MoneyCollect

Use our official libraries for access to the MoneyCollect API from your application:

<dependency>
  <groupId>com.moneycollect</groupId>
  <artifactId>moneycollect-java</artifactId>
  <version>{VERSION}</version>
</dependency>

2. Create a Payment

MoneyCollect uses a Payment object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process.

Handle any next actions

Add an endpoint on your server that creates a Payment. A Payment tracks the customer’s payment life cycle, keeping track of any failed payment attempts and ensuring the customer is only charged once. Return the Payment’s client secret in the response to finish the payment on the client.

package com.moneycollect.sample;

import com.alibaba.fastjson.JSONObject;
import com.moneycollect.Moneycollect;
import com.moneycollect.model.Payment;
import com.moneycollect.param.PaymentCreateParams;
import lombok.Data;
import java.nio.file.Paths;
import static spark.Spark.*;

public class Server {
    private static JSONObject json = new JSONObject();
    @Data
    static class CreatePaymentResponse {
        private String id;
        private String clientSecret;
        public CreatePaymentResponse(String id,String clientSecret) {
            this.id = id;
            this.clientSecret = clientSecret;
        }
    }

    public static void main(String[] args) {
        port(5050);

        staticFiles.externalLocation(Paths.get("public").toAbsolutePath().toString());

        // This is a sample test API key.
        MoneyCollect.apiKey = "test_pr_K***";

        post("/create-payment", (request, response) -> {
            response.type("application/json");

            PaymentCreateParams params =
                    PaymentCreateParams.builder()
                            .setAmount(14*100L)
                            .setCurrency("USD")
                            .setOrderNo("MC"+System.currentTimeMillis())
                            .build();
            Payment payment =  Payment.create(params);
            CreatePaymentResponse paymentResponse  = new CreatePaymentResponse(payment.getId(),payment.getClientSecret());
            return json.toJSONString(paymentResponse);
        });
    }
}

3. Build a checkout page on the client

Load MoneyCollect.js Use McPayment.js to remain PCI compliant by ensuring that payment details are sent directly to MoneyCollect without hitting your server. Always load MoneyCollect.js from static.moneycollect.com to remain compliant. Don’t include the script in a bundle or host it yourself.

Define the payment form

Add an empty placeholder div to your checkout form. MoneyCollect inserts an iframe into this div that securely collects payment information.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Accept a payment</title>
    <meta name="description" content="A demo of a payment on MoneyCollect" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="checkout.css" />
</head>
<body>
<div class="sr-root" style="margin: auto;">
    <div  class="payment-view" >
        <!-- Display a payment form -->
        <form id="payment-form">
            <div id="card-element" class="ab-element">
                <!--MoneyCollect.js injects the Payment Element-->
            </div>
            <div class="sr-field-error" id="card-errors" role="alert"></div>
            <button id="submit">
                <div class="spinner hidden" id="spinner"></div>
                <span id="button-text">Pay now</span>
            </button>
            <div id="payment-message" class="hidden" style="color:#ff0000"></div>
        </form>
    </div> 
</div>
<script src="https://static.moneycollect.com/jssdk/js/MoneyCollect.js"></script>
<script src="checkout.js" defer></script>
</body>
</html>

Initialize MoneyCollect.js

Initialize MoneyCollect.js with your publishable API keys. You will use MoneyCollect.js to create the Payment Element and complete the payment on the client.

Fetch a Payment

Immediately make a request to the endpoint on your server to create a new Payment as soon as your checkout page loads. The clientSecret,id returned by your endpoint is used to complete the payment.

Initialize MoneyCollect Elements

Initialize the MoneyCollect Elements UI library with the client secret. Elements manages the UI components you need to collect payment details.

// A reference to MoneyCollect.js initialized with a fake API key.
var apikey = "API Public key";
var moneyCollect;

// The items the customer wants to buy
var items = [{ id: "xl-tshirt" }];

initialize();

// Fetches a payment intent and captures the client secret
async function initialize() {
    const response = await fetch("/create-payment", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ items }),
    });
    var paymentResponse  = await response.json();

    setupElements();

    document.querySelector("#payment-form")
        .addEventListener("submit", function(evt) {
        evt.preventDefault();
        // Initiate payment
        handleSubmit(paymentResponse);
    });
}

async function setupElements()  {
    moneyCollect = MoneycollectPay(apikey);
    let params = {
        formId: 'payment-form', // form id
        frameId: 'PrivateFrame', // generated IframeId
        mode: "test",
        customerId: "",
        needCardList: true,
        autoValidate: true,
        modelType: "normal",
        lang: 'ko', // Form display and verification information language
        layout: {
            pageMode: "inner", // Style mode of the page   inner | block
            style: {
                frameMaxHeight: "50", //  The max height of iframe
                input: {
                    FontSize: "", // Collect the size of the font
                    FontFamily: "",  // Specify a prioritized list of one or more font family names 
                    FontWeight: "",  // Collect the weight (or boldness) of the font
                    Color: "", // Collect the foreground color value of an element's text
                    ContainerBorder: "",  //Collect the name of the font
                    ContainerBg: "",  // Collect the weight (or boldness) of the font
                    ContainerSh: "" //Collect the color of the font
                }
            }
        }
    }
    moneyCollect.elementInit("payment_steps", params);
}
// Billing Address
let paymentMethodsData = {
    billingDetails: {
        address: {
            city: "Hong Kong",
            country: "CN",
            line1: "193 Prince Edward Road",
            line2: "",
            postalCode: "421455",
            state: "Hong Kong"
        },
        email: "customer@gmail.com",
        firstName: "su",
        lastName: "diana",
        phone: "19112454541"
    }
}
async function handleSubmit(paymentResponse) {
    setLoading(true);
    moneyCollect.confirmPayment({
        paymentMethod: paymentMethodsData,
        autoJump: false,
        payment_id: paymentResponse.id,
        clientSecret: paymentResponse.clientSecret,
        confirmDetail: {} //Confirm parameters
    }).then((result) => { 
        if(result.data.code === "success"){
            orderComplete(result.data.data);
        } else { 
            showMessage(result.data.msg);
        }
    });

    setLoading(false);
}

// Fetches the payment intent status after payment submission
async function orderComplete(paymentIntent) {
    document.querySelectorAll(".payment-view").forEach(function(view) {
        view.classList.add("hidden");
    });
    document.querySelectorAll(".completed-view").forEach(function(view) {
        view.classList.remove("hidden");
    });
    document.querySelector(".status").textContent =  paymentIntent.status ;
    var paymentIntentJson = JSON.stringify(paymentIntent, null, 2);
    document.querySelector("pre").textContent = paymentIntentJson;
}

// ------- UI helpers -------
function showMessage(messageText) {
    const messageContainer = document.querySelector("#payment-message");

    messageContainer.classList.remove("hidden");
    messageContainer.textContent = messageText;

}

// Show a spinner on payment submission
function setLoading(isLoading) {
    if (isLoading) {
        // Disable the button and show a spinner
        document.querySelector("#submit").disabled = true;
        document.querySelector("#spinner").classList.remove("hidden");
        document.querySelector("#button-text").classList.add("hidden");
    } else {
        document.querySelector("#submit").disabled = false;
        document.querySelector("#spinner").classList.add("hidden");
        document.querySelector("#button-text").classList.remove("hidden");
    }
}

Customlize your payment page language

You can customize the page language through setting the parameterlang .

Currently supports:

Japanese(ja), Korean(ko), English(en), Traditional Chinese-Taiwan(ch-TW), German(pt_de), Spanish(pt_es), French(pt_fr), Italian(pt_it), Portuguese-Brazil(pt_Br), Portugal-Portugal(pt_PT), Russian(ru);

e.g.

lang: 'ko'// Set form language to Korean

If the current browser language is one of the supported languages, the language will be displayed; otherwise, English will be displayed by default

/* Variables */
* {
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, sans-serif;
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    display: flex;
    justify-content: center;
    align-content: center;
    height: 100vh;
    width: 100vw;
}

form {
    width: 30vw;
    min-width: 500px;
    align-self: center;
    box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1),
    0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07);
    border-radius: 7px;
    padding: 40px;
}

.hidden {
    display: none;
}

#payment-message {
    color: rgb(105, 115, 134);
    font-size: 16px;
    line-height: 20px;
    padding-top: 12px;
    text-align: center;
}

#payment-element {
    margin-bottom: 24px;
}

/* Buttons and links */
button {
    background: #5469d4;
    font-family: Arial, sans-serif;
    color: #ffffff;
    border-radius: 4px;
    border: 0;
    padding: 12px 16px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    display: block;
    transition: all 0.2s ease;
    box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07);
    width: 100%;
}
button:hover {
    filter: contrast(115%);
}
button:disabled {
    opacity: 0.5;
    cursor: default;
}

/* spinner/processing state, errors */
.spinner,
.spinner:before,
.spinner:after {
    border-radius: 50%;
}
.spinner {
    color: #ffffff;
    font-size: 22px;
    text-indent: -99999px;
    margin: 0px auto;
    position: relative;
    width: 20px;
    height: 20px;
    box-shadow: inset 0 0 0 2px;
    -webkit-transform: translateZ(0);
    -ms-transform: translateZ(0);
    transform: translateZ(0);
}
.spinner:before,
.spinner:after {
    position: absolute;
    content: "";
}
.spinner:before {
    width: 10.4px;
    height: 20.4px;
    background: #5469d4;
    border-radius: 20.4px 0 0 20.4px;
    top: -0.2px;
    left: -0.2px;
    -webkit-transform-origin: 10.4px 10.2px;
    transform-origin: 10.4px 10.2px;
    -webkit-animation: loading 2s infinite ease 1.5s;
    animation: loading 2s infinite ease 1.5s;
}
.spinner:after {
    width: 10.4px;
    height: 10.2px;
    background: #5469d4;
    border-radius: 0 10.2px 10.2px 0;
    top: -0.1px;
    left: 10.2px;
    -webkit-transform-origin: 0px 10.2px;
    transform-origin: 0px 10.2px;
    -webkit-animation: loading 2s infinite ease;
    animation: loading 2s infinite ease;
}

@-webkit-keyframes loading {
    0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
    }
}
@keyframes loading {
    0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
    }
}

@media only screen and (max-width: 600px) {
    form {
        width: 80vw;
        min-width: initial;
    }
}

4. Complete the payment on the client

Handle the submit event

Listen to the form’s submit event to know when to confirm the payment through the MoneyCollect API.

Complete the payment

Call confirmPayment(), passing along the PaymentElement and a return_url to indicate where MoneyCollect should redirect the user after they complete the payment. For payments that require authentication, MoneyCollect displays a modal for 3D Secure authentication or redirects the customer to an authentication page depending on the payment method. After the customer completes the authentication process, they’re redirected to the return_url.

5. Handle post-payment events

Use a webhook

When the notifyUrl parameter is passed, MoneyCollect will use the URL to asynchronously notify the transaction result.

And for detailed guidance on managing webhooks, processing refunds, and handling responses after the payment, please refer to the following documentation.

6. Additional testing resources

There are several test cards you can use to make sure your integration is ready for production. Use them with any CVC, postal code, and future expiration date.

Last updated