Issue cards

*Card issuing is currently in a closed beta and requires underwritingcontact us for more information.

Moov makes spending money in a wallet easy by enabling platforms to issue cards to their customers. This guide covers how to issue and spend on a card.

Key players

For the purposes of this guide, we’ll assume you are a developer building a platform with the following players:

  • Your Moov account: A platform that enables its customers to accept payments and monetizes the spending of those funds on business purchases
  • Customer: A business looking to make a purchase using the funds in its wallet

1. Get your access token

Assuming you’ve already completed a basic setup of your own account, you’ll need to generate an access token. You will include a new access token as the Moov Drop onboarding.token whenever you onboard a customer.

1
2
3
4
curl -X POST "https://api.moov.io/oauth2/token" \
  -u "PUBLIC_KEY:PRIVATE_KEY" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode  "scope=/accounts.write" \
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { Moov, SCOPES } from '@moovio/node';

const moov = new Moov({
  accountID: "YOUR_MOOV_ACCOUNT_ID",
  publicKey: "PUBLIC_KEY",
  secretKey: "PRIVATE_KEY",
  domain: "YOUR_DOMAIN"
});

const scopes = [SCOPES.ACCOUNTS_CREATE];
try {
  const {token} = await moov.generateToken(scopes);
  // Do something with token
} catch(err) {
  // Handle any errors
}

2. Onboard your customers

Customers looking to use their wallet as the funding source for the card will need to request both the wallet and card-issuing (beta) capabilities. These accounts will need to be verified and undergo underwriting.

The following example uses the create account POST endpoint.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
curl -X POST "https://api.moov.io/accounts" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "accountType": "business",
    "profile": {
      "business": {
        "legalBusinessName": "Whole Body Fitness LLC",
        "businessType": "llc",
      }
    }
    "capabilities": [
      "wallet", 
      "card-issuing"
    ]
  }'\

Alternative onboarding methods

Alternatively, you can onboard using the Node SDK, Moov.js with your own UI, or Moov Drops (with a pre-built UI for onboarding).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// create Moov instance with generated token
const moov = new Moov(credentialsObject);

// create Moov account, likely on form submit
const accountPayload = {
  accountType: "business",
  profile: {
    business: {
      legalBusinessName: "Whole Body Fitness LLC",
      businessType: "llc",
      website: "wbfllc.com"
    }
  },
  capabilities: ["wallet", "card-issuing"]
};

moov.accounts.create(accountPayload).then((account) => {
  console.log(account);
}).catch((err) => {
  console.error(err);
});

// Generate a new token server-side with the accountID and update the token within your frontend app. You can chain methods together
moov.setToken("new-token");

// add a representative to account
const accountID = "accountID";
const representativePayload = {
  name: {
    firstName: "George",
    lastName: "Glass"
  },
  address: {
    addressLine1: "12 Main Street",
    city: "Cabot Cove",
    stateOrProvince: "ME",
    postalCode: "04103",
    country: "US"
  },
  birthDate: {
    day: 10,
    month: 11,
    year: 1985
  },
  email: "georgeg@classbooker.dev",
  governmentID: {
    ssn: {
      full: "111111111",
      lastFour: "1111"
    }
  },
  responsibilities: {
    isController: false,
    isOwner: true,
    ownershipPercentage: 38,
    jobTitle: "CEO"
  }
}

moov.accounts.representatives.create(accountID, representativePayload);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// create Moov instance with generated token
const moov = Moov(token);

// create Moov account, likely on form submit
const accountPayload = {
  accountType: "business",
  profile: {
    business: {
      legalBusinessName: "Whole Body Fitness LLC",
      businessType: "llc",
      website: "wbfllc.com"
    }
  },
  capabilities: ["wallet", "card-issuing"]
};

moov.accounts.create({accountPayload}).then((account) => {
  console.log(account);
}).catch((err) => {
  console.error(err);
});

// Generate a new token server-side with the accountID and update the token within your frontend app. You can chain methods together
moov.setToken("new-token");

// add a representative to account
const accountID = "accountID";
const representativePayload = {
  name: {
    firstName: "George",
    lastName: "Glass"
  },
  address: {
    addressLine1: "12 Main Street",
    city: "Cabot Cove",
    stateOrProvince: "ME",
    postalCode: "04103",
    country: "US"
  },
  birthDate: {
    day: 10,
    month: 11,
    year: 1985
  },
  email: "georgeg@classbooker.dev",
  governmentID: {
    ssn: {
      full: "111111111",
      lastFour: "1111"
    }
  },
  responsibilities: {
    isController: false,
    isOwner: true,
    ownershipPercentage: 38,
    jobTitle: "CEO"
  }
};

moov.accounts.representatives.create(accountID, representativePayload);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Card issuing Moov Drop
const onboarding = document.querySelector("moov-onboarding");
// After generating a token, set it on the onboarding element
onboarding.token = "some-generated-token";

// Include your own accountID which can be found in the Moov Dashboard
onboarding.facilitatorAccountID = "your-account-id";

// Wallet and card issuing capabilities are needed for this flow
onboarding.capabilities = ["wallet", "card-issuing"];

// Funding will occur with the Moov wallet
onboarding.paymentMethodTypes = ["moov-wallet"];

// Open the onboarding flow when ready
onboarding.open = true;

3. Request a card

Once you’ve onboarded your customer and they’ve gone through business verification, you can request a card for that customer. You’ll do this through the card issuing endpoint in the Moov API. When requesting a card, you have the option to specify a spend limit as well as a descriptive memo. If you don’t specify a spend limit, the maximum amount the card can spend will be the amount of the balance held in the customer’s wallet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
curl -X POST "https://api.moov.io/issuing/{accountID}/issued-cards" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "authorizedUser": {
      "firstName": "George",
      "lastName": "Glass"
      "birthDate": {
        "day": 29,
        "month": 4,
        "year": 1958
      }
    },
    "fundingWalletID": "string",
    "formFactor": "virtual",
    "memo": "supplies purchase",
    "expiration": {
        "month": "01",
        "year": "25"
    }
  }'\

After you request the card, your customer will be provided a virtual card with a 16-digit card number, expiration date, and security code. The customer can then use the card to make purchases within the amount of their spend limit or wallet balance, depending on which is lower.

4. Get card details

Once the card has been successfully created, you can retrieve full details about the card by passing the customer’s account ID and the card ID to the GET issued card endpoint.

1
2
3
4
5
6
curl -X POST "https://api.moov.io/issuing/{accountID}/issued-cards/{issuedCardID}/details" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "accountID": "customer-account-id",
	  "issuedCardID": "card-id"
  }'\

5. View card transactions

To see card transactions associated with a particular Moov account, you can pass the account ID to the card issuing transactions GET endpoint.

1
2
3
4
5
curl -X POST "https://api.moov.io/issuing/{accountID}/transactions" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "accountID": "customer account ID"
  }'\

What’s next

Feel free to explore Moov.js, our in-browser JavaScript SDK. Or, if you’re interested in other use cases, you can dive into our guides:

Summary Beta