Debit Card Issuing
Overview
Use Productfy’s APIs and services to launch a fully branded debit card program for your customers. Your customers can make purchases with physical and virtual cards using money they have deposited in a Productfy virtual account.
Manage your card program
Card design and card carrier
Work with your Productfy representative to provide the following as part of your implementation:
- Card plastic design that meets specifications
- Card carrier design that meets specifications
- Return address printed on your card envelope
Limits and controls
Below are Productfy’s risk controls for debit cards:
Control | Production Limit | QA Limit |
---|---|---|
Purchase Limit per user (Consumer accounts) | $2,500 / day | $5000 / day |
Purchase Limit per user (Business accounts) | $100,000 / day | $100,000 / day |
Card Expiration | 3 years | 3 Years |
Max Active Cards per user | 100 cards | 100 cards |
Max Transactions per card per day (Consumer accounts) | 25 | 25 |
Max Transactions per card per day (Business accounts) | 50 | 50 |
PIN Retry Limit | 5 | 5 |
Card shipping times and options
The standard delivery time frame of cards is 5-7 business days using the United States Postal Service (USPS). We offer the ability for cards to be expedited for an added fee.
Business Day 1 | Business Day 2 | Business Day 3 |
---|---|---|
Card embossing file sent to card production facility at 11:30 AM Pacific Time. | Cards are produced and prepared for shipment. Regardless of shipment type passed in the embossing file, the cards are readied for shipping on the following day. | Cards are picked up by the appropriate carrier to be shipped. |
Customer support
Customer support phone numbers are required to be shown on the back of cards. Productfy can set up a toll-free number on your behalf and work with you to establish and approve procedures for handling customer support.
Disputes and chargebacks
Productfy will handle dispute intake and all of the chargeback processing with card networks. Hours of support are 7:00 am - 7:00 pm Pacific Standard Time. In cases where provisional credit must be granted to cardholder accounts, or when disputes are won or lost with merchants, Productfy will automatically debit or credit customer accounts as needed.
Funds settlement
Daily net settlement of debit card transactions will automatically come out of your FBO Settlement account. Funds for chargebacks and provisional credit come out of your reserve account.
Compliance
See our compliance guides below for more info on disclosures and requirements of your app to stay in compliance:
Prerequisites for issuing cards
Before your customers can order debit cards and spend with them, the following functions must be implemented depending on whether you are launching consumer cards or business cards:
For consumer cards:
- Create Person - A person must be created on the Productfy system (see Getting Started for more info)
- KYC - All users opening accounts must pass Productfy’s KYC process (see the KYC guide for more info)
- Virtual Accounts - Debit cards are linked to virtual accounts, so virtual accounts must be available (see the Virtual Accounts guide for more info)
For business cards:
- Create an Organization - An organization representing the business must be created on the Productfy system (see Getting Started for more info)
- Create Person - An authorized individual must be associated with each Organization (see Getting Started for more info)
- KYC on the Person ID - The authorized individual must pass Productfy's KYC process (see the KYC guide for more info)
- Associate Person with Organization - The person to whom the card is being issued needs to be tied to the organization/business
- KYB on the Organization - The business customer must pass Productfy's KYB process (see the KYB guide for more info)
- Virtual Accounts - Debit cards are linked to virtual accounts, so virtual accounts must be available (see the Virtual Accounts guide for more info)
Prerequisites for spending with cards
For cardholders to spend with the debit card, there needs to be money in their virtual account. There are a few ways to fund the virtual account:
- A customer can link a third party bank account and transfer money in via ACH. See our Account Linking and ACH implementation guides for more information.
- A customer or company can use the account number and routing number from the virtual account on the Productfy system to deposit money from another source (like setting up direct deposit from their employer for their paycheck, or depositing funds from a company that asks for account number and routing number to initiate an ACH transaction of their own).
Step 1 - Create debit card product
A one-time setup task is needed to create card products for any physical or virtual card program you offer to customers. A card product is a group of settings under which you can issue individual cards. You must create one card product for each physical or virtual debit card product you offer. This is done by calling the APIs described below.
Physical card product
Configure the following fields when you create a physical card product:
- Card Product Name - A reference name for your product set at the card processor. For example: “ABC Physical Debit Card”.
- Description - An internal reference for your product set on the Productfy system. The description can be the same as your Card Product name.
- Card Package ID - Contains identifiers card production uses to assign the correct card plastic design and card carrier to your cards. Work with Productfy support to ensure this is set correctly.
For consumer debit physical cards:
For business debit physical cards:
Virtual card product
Configure the following fields when you create a virtual card product:
- Card Product Name - A reference name for your product set at the card processor. For example: “ABC Physical Debit Card”.
- Description - An internal reference for your product set on the Productfy system. The description can be the same as your Card Product name.
For consumer debit virtual cards:
For business debit virtual cards:
Step 2 - Open account and card
Debit cards are linked to Virtual Accounts on Productfy. Virtual Accounts are where a customer’s funds are held. There are two ways to create Virtual Accounts:
- Use the Create Virtual Account API first to create the account, then use the Issue Card API to order the card that is associated with the Virtual Account. Note: Account Usage Type must be set to B - Business if a business debit card will be issued to the virtual account, and P - Personal if a personal debit card will be issued.
- Use the Issue Card API and it will do both functions: creating the virtual account and ordering the card all in one call. For consumer cards:
For business cards:
NOTE - Virtual Accounts must be funded via ACH to have money on them which can then be used to make card purchases with. See the ACH implementation guide for details on how to use ACH Money Movement.
Step 3 - Expose virtual card details
Virtual Cards are digital representations of cards that expose the necessary information to make payments with: the full card number, CVV code and expiration date. You can choose to use this optional feature in addition to or in place of physical plastic cards.
For PCI compliant applications
If your application is PCI compliant, you can use the Payment Card Sensitive Data API to retrieve this information and display it in your app.
For Non-PCI compliant applications
If your application isn't PCI compliant, you can display virtual cards through the Javascript library below. This injects a set of configurable iframes into your HTML showing the cardholder’s card data. The iframes enable you to display a virtual card without handling sensitive card data on your servers. Instead, our card processor Marqeta hosts the data on secure, compliant servers. Here is a sample of what it looks like (Note - you can customize the style and HTML to suit your needs):
Obtain Virtual Card Access Token
Call the Get Virtual Card Access Token API to retrieve your Virtual Card access token from our card processor. This token is only valid for 5 minutes, and a new token must be requested again upon expiration.
Embed Virtual Card Library into HTML
Boilerplate
Use the following sample code to get started
<!doctype html><html><head><meta charset="utf-8"><title>Marqeta.js Tutorial</title></head><body><div><!-- div elements for displaying and copying PAN, expiration date, and CVV --><div id="card"><div id="mq-card-pan"></div><div id="mq-card-exp"></div><div id="mq-card-cvv"></div></div><div style="margin-top: 10px"><button id="copy-pan-container" style="position: relative">Copy card number</button><button id="copy-exp-container" style="position: relative">Copy expiration date</button><button id="copy-cvv-container" style="position: relative">Copy CVV</button></div></div><!-- This library URL is for QA. For production,use https://widgets.marqeta.com/marqetajs/1.1.0/marqeta.min.js --><scriptsrc="https://widgets-sandbox.marqeta.com/marqetajs/1.1.0/marqeta.min.js"type="text/javascript"></script><script>var systemFonts = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';marqeta.bootstrap({clientAccessToken: '**CLIENT ACCESS TOKEN',showPan: {cardPan: {domId: 'mq-card-pan',format: true,styles: {span: {background: 'transparent',color: 'white','font-family': systemFonts,'font-size': '28px','letter-spacing': '0px','font-weight': 'normal'},'span:hover': {background: 'transparent',color: 'white','font-family': systemFonts,'font-size': '28px','letter-spacing': '0px','font-weight': 'normal'}}},cardExp: {domId: 'mq-card-exp',format: true,styles: {span: {background: 'transparent',color: 'white','font-family': systemFonts,'font-size': '18px','letter-spacing': '0px','font-weight': 'normal'},'span:hover': {background: 'transparent',color: 'white','font-family': systemFonts,'font-size': '18px','letter-spacing': '0px','font-weight': 'normal'}}},cardCvv: {domId: "mq-card-cvv",styles: {span: {background: 'transparent',color: 'white','font-family': systemFonts,'font-size': '18px'},'span:hover': {background: 'transparent',color: 'white','font-family': systemFonts,'font-size': '18px'}}},// These relate to the copy buttons, but are optionalcopyCardPan: {domId: 'copy-pan-container',mode: 'transparent',onCopySuccess: () => alert("Copied PAN!"),onCopyFailure: error => {console.error(error);}},copyCardExp: {domId: 'copy-exp-container',mode: 'transparent',onCopySuccess: () => alert("Copied expiration date!"),onCopyFailure: error => {console.error(error);}},copyCardCvv: {domId: 'copy-cvv-container',mode: 'transparent',onCopySuccess: () => alert("Copied CVV2!"),onCopyFailure: error => {console.error(error);}}},// Specify callback functionscallbackEvents: {onSuccess: () => {console.log("Success!");},onFailure: error => {console.error(error);}}});</script><style>#card {position: relative; background-color: black; border-radius: 10px; width: 430px; height: 253px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";}#card iframe {height: 36px;}#card #mq-card-pan {position: absolute; top: 100px; left: 20px;}#card #mq-card-exp {position: absolute; bottom: 20px; left: 20px; height: 36px;}#card #mq-card-exp::before {content: 'Expiration Date'; text-transform: uppercase; font-size: 10px; color: white; display: block;}#card #mq-card-cvv {position: absolute; bottom: 20px; left: 150px; height: 36px;}#card #mq-card-cvv::before {content: 'CVV'; font-size: 10px; color: white; display: block;}</style></body></html>
Insert Client Access Token
In the boilerplate, locate **CLIENT ACCESS TOKEN**
and replace it with the value from Step 1.
Update Library URL
In the boilerplate, locate the following, and modify the URL if you are in Production.
<!-- This library URL is for QA. For production,use https://widgets.marqeta.com/marqetajs/1.1.0/marqeta.min.js --><scriptsrc="https://widgets-sandbox.marqeta.com/marqetajs/1.1.0/marqeta.min.js"type="text/javascript"></script>
Customize Look & Feel Of The Virtual Card
CSS for the account numbers
In the boilerplate, you will notice styles
fields in the bootstrap configuration. We have included within the boilerplate all the possible attributes that can be customized. (See reference for customizable attributes: Using Marqeta.js, "The showPan.cardPan and showPan.cardExp objects".)
Copy buttons
In the boilerplate, you will find the following snippets. These enable the user to copy the card numbers into their clipboard, but these are optional. Modify the onCopy
handlers to suit your needs.
<div id="copy-pan-container"><button>Copy card number</button></div><div id="copy-exp-container"><button>Copy expiration date</button></div><div id="copy-cvv-container"><button>Copy CVV</button></div>
copyCardPan: {domId: 'copy-pan-container',mode: 'transparent',onCopySuccess: () => alert("Copied PAN!"),onCopyFailure: error => {console.error(error);}},copyCardExp: {domId: 'copy-exp-container',mode: 'transparent',onCopySuccess: () => alert("Copied expiration date!"),onCopyFailure: error => {console.error(error);}},copyCardExp: {domId: 'copy-cvv-container',mode: 'transparent',onCopySuccess: () => alert("Copied CVV2!"),onCopyFailure: error => {console.error(error);}}
Step 4 - Activate card and set PIN
Both physical and virtual cards start out with a status of Inactive. Once customers receive the card they must authenticate to your app to activate the card. It is recommended that you require users to validate certain pieces of private information before activating the card. Call the Activate Card API to change the status from Inactive to Active.
All physical debit cards must have 4-digit PINs set by the customer. It is recommended that customers enter their PIN digits in twice before submitting and the PIN values should be masked when entered in. For security reasons, you should not store or transmit PIN values in the clear. NOTE: PINs need to be set for virtual cards, since customers may get prompted for PINs when using mobile payments in stores. Call the Set Card PIN API to set the PIN.
Step 5 - Fund a Card
Now we can move into funding the virtual account associated with the payment card so we can actually simulate/make transactions. To do this we will use the Create Virtual Account Transaction API
.
For convenience, you may simply paste the following query data directly into the request portion of the GraphQL Query for the API below:
mutation createVirtualAccountTransaction {createVirtualAccountTransaction(accountId: "Pfy_FinA-XXXXXXX"applyToPendingBalance: trueapplyToSettledBalance: truebalanceAssetId: "USD"balanceAssetType: "M"balanceType: "GnrcBal"deltaAmount: 1000description: "Simulated Transaction Testing"ledgerEntryType: "C"transactionCategory: "Dep"transactionType: "G") {createdTransaction {amountdescriptionidsettled}}}
If you wish to change any of these values please keep in mind these parameter recommendations:
Parameter | Recommendations |
---|---|
accountId | This is the virtual account ID associated with the card. It will start with Pfy_FinA- . |
applyToPendingBalance | This must always be true so the pending balance is credited. |
applyToSettledBalance | Again this must always be true so the balance is available for use. |
balanceAssetId | Always use "USD" for this. |
balanceAssetType | Always use "M - Money". |
balanceType | Always use "GnrcBal - Balance" |
deltaAmount | This is the amount of money to fund the account with. Please use a positive number and keep in mind your simulated transactions will draw from this balance. |
description | This is open free-form text used to give a human-readable description of the transaction purpose. |
ledgerEntryType | Always use "C - Credit" since we are trying to fund the account. If you used "D - Debit" your delta amount would subtract from the balance. |
transactionCategory | This is relatively arbitrary but "Dep - Deposit" is a good option to choose for representing that this is a funding event. |
transactionType | Use "G - Generic" here. |
Step 6 - Test transactions
Card transactions can be a tricky development area and as such you will want to do as much testing as possible before your card program goes live. Productfy provides you with the ability to do all this testing with simulated transactions. This avoids the hassles that come with making real transactions over the network so you can focus on handling the scenarios your end-users will encounter in the real world. We provide various simulated transaction APIs that will help you prepare to handle all potential card flows including authorization, clearing, advice messages, refunds, and reversals.
Prerequisites
Before cards can be issued to persons or organizations we must first do the following:
- Create a Person or Organization in the Productfy system
- Complete KYC for Person or KYB for organizations
- Create a Card Product
- Issue a Card
- Activate a Card
- Fund a Card
Test a Simulated Transaction
View Initial Balances
Assuming we have our virtual account funded we can start making simulated transactions. First things first we should take a look at our balances in the FinSight Profile API
. Use the following query with your person ID to retrieve the available, pending and settled balances:
query finsightProfile {finsightProfile(personId: "Pfy_P-XXXXXX") {financialProfile {financialAccounts {currentAvailableBalance {amount}currentPendingBalances {amount}currentSettledBalances {amount}}}}}
Directly after funding the account we expect all the balances to be exactly the same.
Simulate Card Authorization
Card authorization is the first step we need to take to kick off a card payment transaction. The authorization will subtract money from the available and pending balances but will not actually settle until it is cleared in a subsequent API call. To use this API you need to provide the paymentCardId
returned from when the card was issued as well as the amount we wish to authorize. For our purposes here we will also be setting preAuth
to true meaning we only want to get authorization for the transaction and later on clear the funds.
Please also ensure that you ask for the simulationId
in the returns so we can clear this transaction later.
Once this is done we should check on our balances again using the same FinSight Profile API
query above to confirm our expectations of only pending/available balances being changed.
Another way to confirm this status is to include financialProfile.financialAccounts.transactions.amount
and financialProfile.financialAccounts.transactions.settled
in your FinSight Profile API
query. Note that settled
is false.
An expanded sample with those fields is included below for your convenience:
query finsightProfile {finsightProfile(personId: "Pfy_P-XXXXXXX") {financialProfile {financialAccounts {currentAvailableBalance {amount}currentPendingBalances {amount}currentSettledBalances {amount}transactions {amountidsettled}}}}}
Simulate Card Clearing
Now that we confirmed the card authorization went through we can clear that transaction so it settles fully. To do that we will use the Simulate Card Clearing API
using the same information from the previous authorization call but with the addition of the simulationId
so we can match up the transactions. The forcePost
parameter does not need to be used to clear our authorization transactions.
Again let's verify our expectations in the FinSight Profile API
using the previous sample query.
We should now see all balances as exactly the same:
The transaction should also now be marked as settled:
Congratulations! You have now settled your first simulated transaction.
Additional Simulated Transactions
Here are some additional kinds of card transactions you can test.
Advice
An advice message will update the amount of an authorization. Commonly used in gas pump scenarios where $100 may be initially authorized, then an advice message is sent for the actual amount of gas pumped.
Refund
A refund occurs when a cardholder requests that the merchant return money from a previous transaction after the clearing process has completed.
Reversal
A reversal occurs when a merchant cancels a transaction after the authorization succeeds but before the clearing process occurs. NOTE - When a reversal transaction is applied, we set both the initial and the reversal transactions to AUDITING display mode, which effectively hides it from view.
PIN Transaction
For transactions where a PIN was used to authenticate the cardholder, there are not separate authorization and clearing messages, it all comes in one PIN transaction message.
Step 7 - Receive webhooks
Webhook events are triggered for card transactions (including declined transactions). This can be valuable for updating your own systems or triggering notifications to your users. Note the decline reason codes in these webhooks are defined by our processor here. Subscribe to the Card Transaction webhook in your subtenant portal. See documentation on this webhook here.
Step 8 - Display transactions
You can display transactions on Virtual Accounts by using our general-purpose Finsight Profile API. Use the PaymentCardTransaction object within the PaymentCard array within the FinancialAccount array. Common fields to display are:
- Transaction Date
- Merchant
- Merchant Category Code
- Amount
- Rolling Balance
Step 9 - Debit card certification
During your implementation project with Productfy, you will be required to go through a certification phase to ensure your app is working correctly end-to-end with the Productfy system for both successful and error scenarios.
For each test scenario below you will need to be prepared to gather the following information and provide it to us:
- Transaction ID
- Date and time
- Descriptions of the tests being performed (i.e.. card refunds, card freezing, etc.)
- Documentation (screenshots should be sufficient) substantiating you can view card transactions for the end-user
Debit Card Test Cases
The following test cases must be performed and verified before we can consider Debit Card Certification testing completed and move you into Alpa.
- Multi-Factor Authentication - Ensure that you have implemented a MFA solution in your app.
- Debit Card Issuing - Ensure that you can open a card account and activate the card. Ensure that you can set a PIN successfully.
- Debit Card Transactions (Purchase) - Ensure that you can perform real live transactions with your card (assuming the account has been funded via ACH, see previous steps). Complete a signature based transaction (non-PIN) using a physical or virtual card. Complete a PIN based transaction (PIN based transaction can only be completed via physical card).
- Debit Card Transactions (Refund) - Ensure that you can complete a refund transition which will be properly reflected in your application. and validate that the customer's account balance is also accurate. Make a purchase (see previous steps for examples), allow the purchase to fully settle/clear (ie no longer “pending”). This could take up to 3 days. After the purchase has settled/cleared, initiate a return for the item purchased. After the return has been initiated confirm the funds are returned and your balance is properly updated.
- Debit Card Freezing / Unfreeze (Optional depending on use case) - Ensure that you can freeze a card which will prevent new transactions (please ensure that a transaction decline is received from the merchant). Ensure that you can unfreeze a card that will allow new transactions (please ensure that a subsequent transaction is approved).