If your business has ever considered adding a payment system for issuing cards—perhaps to customers or employees—then you may have avoided it because the technical hurdles seemed too difficult. In reality, getting a payment system up and running is quite straightforward. In this post, we’ll look at how to build payments into your Java application using the Core API from Marqeta.
Marqeta is a financial services company that you’ve likely already benefited from using their platform. Uber, Square, and DoorDash all have payment platforms built out using Marqeta. If your company needs to issue payment methods to customers or employees, then this platform may be exactly what you need.
We’ll walk through building out a fully functioning card payment system that starts with a bank or other financial institution and ends with a customer or employee with a card they can use for payments anywhere that a debit or credit card is accepted.
Before we get going on the technology, it’s important first to cover some of the key terms in use at Marqeta.
Marqeta partners with a bank to provide a funding source. This source will be a place from which money can be drawn any time a transaction is carried out by the user who has a card issued to them. A cardholder is any user who holds a card—which can be physical or virtual.
The rules that govern how a card is to be used are encapsulated in a card product. Card products include information related to all cards associated with them, such as whether cards are physical or virtual, single-use or multiple-use, and what is required to complete a transaction.
All of these important pieces of the Marqeta ecosystem can be managed via the Core API. In our simple Java application, we’ll create a new card product, create a user, and issue a virtual card (based on the card product we created) to the user we created—all by using the Core API. From the perspective of your cardholders, everything will be happening within the app that we’re going to build, so there’s no need for them to interact with Marqeta at all.
While there’s not an officially supported Java SDK for Marqeta, building a Java client is quite straightforward, as the Core API is documented in both Swagger v2.0 and OpenAPI v3.0. The OpenAPI documentation is in beta, but it is generated directly from the API source code. To get a Java client, all we need to do is drop the OpenAPI yaml file into editor.swagger.io, modify the servers section to use the https://sandbox-api.marqeta.com/v3
as the URL, and tell it to generate a Java client.
Once you’ve downloaded the client, you can build the client in your local Maven repository, get a Maven app started, and include the client in your pom.xml
file.
Newer versions of Java may require adding a dependency to the client’s pom.xml
:
<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
To build the client, we run this command from within the client’s folder:
$ mvn clean install
Then, in a clean working folder for our app, we run this command:
$ mvn -B archetype:generate \
-DgroupId=com.mycompany.app \
-DartifactId=my-payment-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4
You’ll now have a folder called my-payment-app
with a pom.xml
into which you can add the generated client as a dependency:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-java-client</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
Now that you’ve created your app’s skeleton, let’s look at the meat of getting started with Marqeta’s Core API. In fact, we’re going to be working through a lot of the steps of the Core API Quick Start guide. If you’d prefer to work through that guide, you won’t need to write any code at all, as it includes a built-in API Explorer. The explorer is also a great way to double check your work as you go through this article.
We can get started in the main App.java
file of the Maven-generated app by setting up our authentication and importing the classes we’ll use throughout the project.
package com.mycompany.app;
import io.swagger.client.*;
import io.swagger.client.api.*;
import io.swagger.client.model.*;
public class App
{
public static void main( String[] args )
{
String username = "your-sandbox-application-token";
String password = "your-sandbox-admin-access-token";
ApiClient apiClient = new ApiClient();
apiClient.setUsername(username);
apiClient.setPassword(password);
}
}
Of course, in a production application, you wouldn’t want to include your authentication tokens in plaintext in your code. However, for learning purposes in this demo setup, doing so will allow us to get going quickly. You can find the values you need in your Marqeta Sandbox Dashboard.
Once we have this ApiClient
object ready to go, we can create a new user record with the UsersAPI
:
...
apiClient.setPassword(password);
UsersApi usersApiInstance = new UsersApi();
usersApiInstance.setApiClient(apiClient);
CardHolderModel cardHolderBody = new CardHolderModel();
cardHolderBody.setFirstName("Marqeta");
cardHolderBody.setLastName("User");
cardHolderBody.setAddress1("180 Grand Avenue");
cardHolderBody.setAddress2("6th Floor");
cardHolderBody.setCity("Oakland");
cardHolderBody.setState("CA");
cardHolderBody.setPostalCode("94612");
String userToken = "";
try {
UserCardHolderResponse cardHolderResult = usersApiInstance.postUsers(cardHolderBody);
System.out.println(cardHolderResult);
userToken = cardHolderResult.getToken();
System.out.println("USER TOKEN: " + userToken);
} catch (ApiException e) {
System.err.println("Exception when calling UsersApi#postUsers");
e.printStackTrace();
}
...
Note that we’ve set the user’s first and last name, and we’re storing the user token that gets returned so we can use it later. We also configured the usersApiInstance
to use the APIClient
that we defined previously. We’ll continue to do that for each new API endpoint we interact with.
At this point, we can look for an appropriate card product for issuing a card to our user. Fortunately, the sandbox provides us with a card product called “Reloadable Card”, so we can search for that card product and save its token. This card product also has a funding type attached to it, so we don’t need to do anything special to create one.
...
CardProductsApi cardProductsApiInstance = new CardProductsApi();
cardProductsApiInstance.setApiClient(apiClient);
Integer count = 1;
Integer startIndex = 0;
String sortBy = "-createdTime";
String cardProductToken = "";
try {
CardProductListResponse cardProductListResult = cardProductsApiInstance.getCardproducts(count, startIndex, sortBy);
System.out.println(cardProductListResult);
cardProductToken = cardProductListResult.getData().get(0).getToken();
System.out.println("CARD PRODUCT TOKEN: " + cardProductToken);
} catch (ApiException e) {
System.err.println("Exception when calling CardProductsApi#getCardProducts");
e.printStackTrace();
}
...
At this point, we have everything we need—a user token and a card product token—to issue a new card. We make sure to tell the API not to send us the CVV or the PAN for the card upon generation, for greater security.
...
CardsApi cardsApiInstance = new CardsApi();
cardsApiInstance.setApiClient(apiClient);
CardRequest cardRequestBody = new CardRequest();
cardRequestBody.setUserToken(userToken);
cardRequestBody.setCardProductToken(cardProductToken);
Boolean showCvvNumber = false;
Boolean showPan = false;
try {
CardResponse cardResult = cardsApiInstance.postCards(cardRequestBody, showCvvNumber, showPan);
System.out.println(cardResult);
} catch (ApiException e) {
System.err.println("Exception when calling CardsApi#postCards");
e.printStackTrace();
}
...
Now that you’ve created a card for your user, you can simulate some transactions against that card. The existing card product we used already has a funding source, but you can also make API calls to make sure that a user is properly funded to make payments with their card.
Then, you can view account balances and a history of transactions in the Transaction Timeline tool in your dashboard. This will help you get a sense of what exactly goes on when transactions are carried out against a card on Marqeta.
Marqeta’s Core API also implements webhooks, which allow your application or systems to be notified whenever certain events take place. Webhooks can help you connect activity in your application (like the issuing of a card or a declined transaction) with triggers to run backend processes or notify your users.
Integrating payments into your application—whether it’s in Java, Python, JavaScript, or another language—isn’t as daunting of a task as you might think. With Marqeta’s Core API—available in OpenAPI format—coupled with its documentation and the API Explorer, building a payment application is a straightforward project you can tackle quickly.
Also published here.