October 10, 2024
cancel
Showing results for 
Search instead for 
Did you mean: 
Help
Ricardo
Community Manager
Community Manager

The Marqeta Core API puts the power to build payment card programs in the hands of developers. The RESTful API uses standard POST, PUT, and GET methods to operate on resources. Regardless of the language, you use to build your Marqeta-backed application, you simply need to send HTTP requests to operate on the Core API.

Core API SDKs exist for Python and Ruby, but not for JavaScript. However, working with the API inside of a Node.js application is straightforward.

This article is a “Getting Started” guide for Node.js developers building on the platform. We’ll provide a walkthrough of common first-time-use endpoints. If you’re new to Marqeta, then this is your chance to get your feet wet and begin playing with the Core API from within a Node.js application. (By the way, keep in mind that we are not talking about Marqeta.js, which is “a JavaScript library used for displaying sensitive card data in your application or webpage.”)

Are you ready? Here we go!

Setup

All of the code that we’ll use in this walkthrough can be found in this public GitHub repository. Let’s walk through our steps to get set up.

 

Create a Marqeta developer account

First, you’ll need to create a Marqeta developer account. This will give you free access to use the developer sandbox and begin sending requests to the Core API. After you create your account and sign in, you’ll see the credentials that you will need for authentication.

1 2.pngWe’ll need these token values and the Base URL soon.

 

 

 

Initialize a new project

On our local machine, let’s create a new folder and initialize a Node.js project with yarn (or npm), accepting all of the defaults.

 

 

~$ mkdir marqeta-node
~$ cd marqeta-node
~/marqeta-node$ yarn init
…
success Saved package.json
Done in 2.19s.

 

 

Our application has two dependencies: axios and dotenv. Let’s add them.

 

 

~/marqeta-node$ yarn add axios dotenv
…
Done in 0.68s.

 

 

 

Store credentials in .env file

We use dotenv to store our API credentials in a .env file. Open a new file called .env, and then paste in the API key values from your Developer Dashboard

 

 

APPLICATION_TOKEN=enter-your-token-here
ADMIN_ACCESS_TOKEN=enter-your-token-here

 

 

Make sure your .env file is ignored by your version control system.

 

Create a module for sending requests with axios

We’ll be using axios to send all of our requests. Because all our requests will have some similarities, it makes sense to factor out these commonalities into a reusable module. Create a new file called marqeta-axios.js. The code will look like this:

 

 

// FILE: marqeta-axios.js

require('dotenv').config();
const { APPLICATION_TOKEN, ADMIN_ACCESS_TOKEN } = process.env

const axios = require('axios');

const authString = Buffer.
  from(`${APPLICATION_TOKEN}:${ADMIN_ACCESS_TOKEN}`).
  toString('base64');

axios.defaults.headers.common['Authorization'] = `Basic ${authString}`;
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.headers.put['Content-Type'] = 'application/json';
axios.defaults.baseURL = 'https://sandbox-api.marqeta.com/v3';

const send = async (args = {}) => {
  const method = args.method || 'GET';
  try {
    const options = {
      method,
      url: args.endpoint
    }
    if (args.data) {
      options.data = args.data
    }
    const result = await axios(options);
    return result.data;
  } catch (e) {
    console.log(e);
  }
}

module.exports = send;

 

 

 

Briefly, this is what our module does:

  1. Use dotenv to read in environment variables from the .env file.
  2. Create the authString that we will use in our Authorization header. The Core API uses HTTP Basic Authentication, requiring a base64 encoded string that concatenates your application token with your admin access token, with a colon separating the two.
  3. Configure the default Content-Type header values for POST and PUT requests.
  4. Configure the baseURL for all requests.
  5. Define a send function that sends a request with axios based on the arguments given and then returns the response data.
  6. Export the send function as a named export.

Now that we’ve extracted axios usage to a module, we’re ready to make some API calls!

Basic querying for resources

In your project folder, open a new file called index.js. At this point, your project folder should look like this:

 

 

~/marqeta-node$ tree -aL 1
.
├── .env
├── index.js
├── marqeta-axios.js
├── node_modules
├── package.json
└── yarn.lock

1 directory, 5 files

 

 

 

List Users

Let’s start with a basic call to list all users. To do this, we would ordinarily send a GET request to https://sandbox-api.marqeta.com/v3/users. However, we’ll be taking advantage of the send function from our marqeta-axios.js module. In that function, the default method is already specified as GET, and the base URL for our sandbox is already set, too. All we really need to do is:

 

 

 

let result = await send({ endpoint: '/users' });

 

 

 

 

That’s simple! Since this endpoint is for retrieving a list, the result has a sub-object called data, which is an array. Our entire file (so far) should look like this:

 

 

 

// FILE: index.js

const send = require('./marqeta-axios.js');

(async () => {
  let result = await send({ endpoint: '/users' });
  const users = result.data;
  console.log(users);
})();

 

 

 

Because we use async/await with axios (and with our exported send function), we wrap the main code of index.js in an async function call, and we call that function immediately.

 

When we run node index.js at the command line, the result may look like this:

 

 

~/marqeta-node$ node index.js
[]

 

 

 

If you have a completely new Marqeta developer account, you won’t have any users yet, which is why the result is empty. If you’d like, you can use the Core API Explorer to create a few initial users.

As an alternative, you can skip down to the part of this walkthrough where we send a request to create a new user. Then, you can send this request to GET /users in your Node.js application again to see the new results.

For the remainder of our requests, we’ll assume that your account already has some initial data in it.

 

List cards for user

Next, let’s choose a user from the returned list, and we’ll list all cards for a user. The endpoint for this GET request is /cards/user/{token}. Let’s update our index.js file by selecting the first user returned and then generating the endpoint to get that user’s cards:

 

 

/ FILE: index.js

const send = require('./marqeta-axios.js');

(async () => {
  let result = await send({ endpoint: '/users' });
  const users = result.data;
  const user = users[0];
  console.log('USER', user);

  result = await send({ endpoint: `/cards/user/${user.token}`});
  const cards = result.data;
  console.log('CARDS', cards);
})();

 

 

 

When we run node index.js, we see our first user and the cards for that user:

 

 

USER {
  token: 'test-user-01',
  active: true,
  first_name: 'John',
  last_name: 'Doe',
  email: 'johndoe@gmailx.com',
  uses_parent_account: false,
  corporate_card_holder: false,
  created_time: '2021-12-20T16:45:51Z',
  last_modified_time: '2021-12-20T16:45:52Z',
  metadata: {},
  account_holder_group_token: 'DEFAULT_AHG',
  status: 'ACTIVE'
}
CARDS [
  {
    created_time: '2021-12-20T20:37:46Z',
    last_modified_time: '2021-12-20T20:37:46Z',
    token: 'card-01',
    user_token: 'test-user-01',
    card_product_token: 'card-product-01',
    last_four: '2517',
    pan: '111111______2517',
    expiration: '0126',
    expiration_time: '2025-12-31T23:59:59Z',
    barcode: '28295063411091980770',
    pin_is_set: false,
    state: 'ACTIVE',
    state_reason: 'New card activated',
    fulfillment_status: 'ISSUED',
    instrument_type: 'PHYSICAL_MSR',
    expedite: false,
    metadata: {}
  }
]

 

 

 

List card products

A card product resource represents the behavior and functionality of one or more cards. Every card is associated with a card product. When multiple cards all derive from the same card product, those cards will have common features (like their funding source or fulfillment specifications).

We can list all card products in our program by sending a GET request to /cardproducts. We add the following lines within our main function in index.js:

 

 

  result = await send({ endpoint: '/cardproducts' });
  const cardProducts = result.data;
  console.log('CARD PRODUCTS', cardProducts);

 

 

If you have existing card products, then your result may look something like this:

 

 

...
CARD PRODUCTS [
  {
    token: 'card-product-01',
    name: 'My card product 01',
    active: true,
    start_date: '2021-12-01',
    config: {
      poi: [Object],
      transaction_controls: [Object],
      selective_auth: [Object],
      special: [Object],
      card_life_cycle: [Object],
      clearing_and_settlement: [Object],
      jit_funding: [Object],
      digital_wallet_tokenization: [Object],
      fulfillment: [Object]
    },
    created_time: '2021-12-19T20:31:11Z',
    last_modified_time: '2021-12-19T20:36:44Z'
  }
]

 

 

 

Advanced techniques for accessing resources

So far, we’ve demonstrated some basic GET requests for retrieving a list of resources. Let’s expand on this.

 

Fetch a single resource

Instead of getting a list of card products, we might want to retrieve a single card product based on its token. The endpoint for this GET request would be /cardproducts/{token}. In our JavaScript application, we would add this call:

 

 

  const cardProductToken = cardProducts[0].token;
  result = await send({ endpoint: `/cardproducts/${cardProductToken}` });
  const cardProduct = result;
  console.log('CARD PRODUCT [0]', cardProduct);

 

 

Because we are retrieving a single card product (instead of a list), notice that the card product is found in result (and not result.data, which is used for arrays).

 

Field filtering

The Core API supports field filtering, allowing you to specify which fields you want to return with your query. For example, let’s say we wanted to list all users, but we only wanted the tokens and first names for our users returned. Our endpoint would be: /users?fields=token,first_name.

 

 

 

  result = await send({ endpoint: '/users?fields=token,first_name' });
  console.log(result.data);

 

 

 

The result would look like this:

 

 

 

[
  { token: 'test-user-01', first_name: 'John' },
  { token: 'test-user-02', first_name: 'Jane' }
]

 

 

 

Sorting

Most endpoints in the Core API support sorting. We add a sort_by query parameter set equal to the name of the field by which we want to support. We can prepend a - to the field name if we want reverse ordering. Note that the Marqeta documentation clarifies that “You must sort using system field names such as lastModifiedTime and createdTime, and not by the field names appearing in response bodies such as last_modified_time or created_time.”

 

For example, the following code would sort by ascending lastModifiedTime:

 

 

 result = await send({ endpoint: '/users?sort_by=lastModifiedTime' });

 

 

 

To reverse the sort, we would add a - like this:

 

 

  result = await send({ endpoint: '/users?sort_by=-lastModifiedTime' });

 

 

 

Pagination

When requesting list endpoints, the result includes the array of resources in the data sub-object. However, the values for count, start_index, end_index, and is_more are also included.

 

When is_more is true, there are additional resources that exist for this query that are not included in the response. You can apply basic pagination techniques to set query parameters for count, start_index, and end_index to retrieve lists of resources in pages.

 

Creating and updating objects

 

Creating resources uses POST requests, while updating objects uses PUT requests. Let’s cover creating resources first.

 

Create a new user

 

To create a new user, we send a POST request to /users, and we add a JSON request body. Let’s add this example to our index.js file:

 

 

 result = await send({
    endpoint: '/users',
    method: 'POST',
    data: {
      token: 'test-user-03',
      first_name: 'Ned',
      last_name: 'Leeds'
    }
  });
  console.log(result);

 

 

When we run this code, the result looks like this:

 

 

{
  token: 'test-user-03',
  active: true,
  first_name: 'Ned',
  last_name: 'Leeds',
  uses_parent_account: false,
  corporate_card_holder: false,
  created_time: '2021-12-22T06:49:16Z',
  last_modified_time: '2021-12-22T06:49:16Z',
  metadata: {},
  account_holder_group_token: 'DEFAULT_AHG',
  status: 'ACTIVE',
  deposit_account: {
    token: '3f2fdf5c-105f-4bcf-86c4-5fd497642d1a',
    account_number: '40011903013363369',
    routing_number: '293748000',
    allow_immediate_credit: false
  }
}

 

 


Note that tokens are unique. You can specify the token for the user you are about to create, but you will only be able to make that request (with that token) one time. If you do not provide a token upon resource creation, Marqeta will generate one for you.

 

Create a funding source

To create a program funding source for Managed Just-in-Time (JIT) Funding transactions, send a POST request to /fundingsources/program. Our JavaScript code would look like this:

 

 

result = await send({
    endpoint: '/fundingsources/program',
    method: 'POST',
    data: {
      token:'funding-source-01',
      name:'My Program Funding Source',
      active: true
    }
  });
  console.log(result);

 

 


The result is:

 

 

{
  name: 'My Program Funding Source',
  active: true,
  token: 'funding-source-01',
  created_time: '2021-12-22T06:57:58Z',
  last_modified_time: '2021-12-22T06:57:58Z',
  account: '12.003.001.000000'
}

 

 

 

Creating a card product

We can create a card product by sending a POST request to /cardproducts. We’ll create a card product that uses the funding source that we created above.

To simplify our creation, we’ll configure this card product to have a fulfillment.payment_instrument set to VIRTUAL_PAN. If we were to use the default value (PHYSICAL_MSR), we would then also need to specify a shipping address where physical cards would be delivered as a part of fulfillment.

Our JavaScript code would look like this:

 

 

result = await send({
    endpoint: '/cardproducts',
    method: 'POST',
    data: {
      token:'card-product-01',
      name:'My Card Product',
      active: true,
      start_date: '2021-12-01',
      config: {
        card_life_cycle: {
          activate_upon_issue: true
        },
        fulfillment: {
          payment_instrument: 'VIRTUAL_PAN'
        },
        jit_funding: {
          program_funding_source: {
            funding_source_token: 'funding-source-01',
            enabled: true
          }
        }
      }
    }
  });
  console.log(result);

 

 

 

Creating a card

With a user and a card product (associated with a funding source), we can now create a card for the user. To do this, we send a POST request to /cards, including the tokens for the user and the card product:

 

 

 result = await send({
    endpoint: '/cards',
    method: 'POST',
    data: {
      token:'test-user-03-card-01',
      user_token:'test-user-03',
      card_product_token:'card-product-01'
    }
  });
  console.log(result);

 

 

 

Updating objects

When updating objects, we send a PUT request to that resource’s endpoint, along with a data payload containing only those fields (and values) to be updated. Note that the token for a resource cannot be changed. For example, to update a user, our code would look like this:

 

 

result = await send({
    endpoint: '/users/test-user-03',
    method: 'PUT',
    data: {
      first_name: 'Edward',
      middle_name: 'Ned',
      state: 'New York'
    }
  });
  console.log(result);

 

 

 

Simulating transactions

In a production environment, merchants initiate financial transactions upon sale. Within the developer sandbox, we can simulate transactions for testing purposes. To simulate an authorization type transaction, send a POST request to /simulate/authorization, making sure to include the token of the card on which the authorization is being made. The transaction amount and the merchant id (mid) are also required.

Our JavaScript code for simulating a transaction would look like this:

 

 

  result = await send({
    endpoint: '/simulate/authorization',
    method: 'POST',
    data: {
      card_token: 'test-user-03-card-01',
      amount: 49.99,
      mid: 'merchant-01'
    }
  });
  console.log(result);

 

 

The response contains a wealth of data about the transaction:

 

 

{

  transaction: {
    type: 'authorization',
    state: 'PENDING',
    identifier: '61',
    token: '207befdf-9243-49ca-9274-9ff2c1cd8038',
    user_token: 'test-user-03',
    acting_user_token: 'test-user-03',
    card_token: 'test-user-03-card-01',
    gpa: {
      currency_code: 'USD',
      ledger_balance: 49.99,
      available_balance: 0,
      credit_balance: 0,
      pending_credits: 0,
      impacted_amount: -49.99,
      balances: [Object]
    },
    gpa_order: {
      token: 'd48d34ef-3363-4a6f-8439-eb6e4961544d',
      amount: 49.99,
      state: 'PENDING',
      …
    },
    response: { code: '0000', memo: 'Approved or completed successfully' },
    network: 'DISCOVER',
    card: { last_four: '6730', metadata: {} },
    …
  },
  …
}

 

 

 

Retrieving balances

Related to transactions, we can also retrieve the general purpose account (GPA) balance for any given user or business. To do so, we send a GET request to /balances/{token}.

 

 

 result = await send({ endpoint: '/balances/test-user-03' });
  console.log(result);

 

 


With our recent (simulated) transaction for this user, we see the result of this balance inquiry meets our expectations:

 

 

{
  gpa: {
    currency_code: 'USD',
    ledger_balance: 49.99,
    available_balance: 0,

    …
  },
  …
}

 

 


That’s it! You now have a starting foundation for using JavaScript to work with the Marqeta Core API. The final version of index.js, with all of our requests, can be in the
GitHub repository.

Conclusion

JavaScript developers building applications on the Marqeta platform can send requests to the Core API by using HTTP clients like axios or node-fetch. As we demonstrated above, commonalities among requests can easily be factored out to make up reusable modules. 

Although there’s presently no JavaScript SDK for the Core API, we’ve seen how working with the Core API within a Node.js application is effortless. As you begin building your own Node.js + Marqeta application, be sure to seek out the Marqeta developer community for support. Happy coding!

Developer Newsletter