Credit Card Tokenization
Tokenizing Credit Cards
So you’re looking to tokenize a credit card and add it to a recurring profile or invoice, eh? Well you’ve come to the right spot.
To get started you will need:
- FreshBooks account with Advanced Payments
- FreshBooks Payments or Stripe account
- Postman or know your way around a cURL request
Let’s make a quick example of why you would need to use this tutorial? Let’s say you own a mountain biking rental business and people reach out to you seeing if they can rent directly from you or your site. Of course they can!
You want to be able to lead them to your website, have them enter in their credit card information and save it to an invoice profile in your FreshBooks account.
The problem with mountain biking rentals is that they can get a little tricky. One customer wants a full-suspension bike while another just wants a cruiser to travel around town. Dominic needs to rent a helmet but Lucy brought her own. Furthermore, if Dominic brings back his full-suspension bike in three separate pieces, you’re likely going to need to charge him for the damages to the bike and you don’t want to have to send another invoice hoping Dom willingly pays for his damages. BUT! you don’t want to have to store a credit card on a piece of paper because that’s incredibly dangerous (ahem, and not PCI-compliant). We need to give FreshBooks the client’s credit card number and save it to an invoice profile so it can be stored securely and used easily with consent.
In this tutorial, we’re going to assume you’ve already made the interface with the customer and are just looking for a place to send the customer’s credit card information.
NOTE: You will need Advanced Payments on New FreshBooks to enable this. If you don’t have it you can click on Add-on’s in the left side panel, look for “Advanced Payments” and click “Get Add-on” or you can call our friendly account managers at 1.833.333.1128
We’re going to follow four basic steps with two payment processors (FreshBooks Payments and Stripe).
1. Setting up an Invoice Profile
You will need to create an invoice profile (and a client for that profile) before you can apply a payment to it.
In this case, I’m making a simple invoice profile that starts today, recurs monthly and will continue to recur for 3 months since Dom wants to rent the bike for the summer. I am only going to put two line items on the invoice. You can edit the invoice profile at a later date if Dom comes back for a mid-month tune-up (one-time payment) or wants to rent knee pads (recurring) and wants you to just charge his card.
I’m going to make a POST request to:
https://api.freshbooks.com/accounting/account/<ACCOUNT_ID>
/invoice_profiles/invoice_profiles
field |
type |
description |
---|---|---|
customerid | string | This will be the Cardholder’s name i.e. Dominic Schiavo |
create_date | string | Created day of the invoice profile 2020-07-20 |
frequency | string | the frequency the invoice will be created. In the form of xy where x is an integer and y is either d,w,m,y . (example: Every two weeks would be 2w ) |
numberRecurring | integer | The number of invoices that will be generated, 0 for infinite |
lines | array of objects | description of industry client is in |
name | string | Name of the item i.e. shoes |
qty | string | How many items you are adding to the invoice. This will multiply the unit_cost of the items |
unit_cost | object | |
amount | string | Cost per each item i.e. 15.00 |
NOTE: When adding your invoice profile, you should also make sure that you have the proper bill_gateway
added to your POST request. For Stripe, use stripe and for FreshBooks Payments, use fbpay
. It’s not necessary if you already have it set up in the past, however, I did notice I ran into an issue trying to add a credit card via Stripe tokenization when previous invoices (via the UI) were set to FBPay.
Keep note of accounting_systemid
, customerid
, and profileid
from the response because you’re going to need those later!
You can check your successfully made invoice profile on FreshBooks by clicking Invoices on the side bar and then Recurring Templates.
Here is the one that I just made:
Now that we have an invoice profile we’re going to add a credit card to it in the next three steps. Let’s go!
2. Creating a Payment Method (Tokenizing the Credit Card)
In this step, you’re going to be sending the customer’s credit card information (along with Stripe’s publishable key) and you will get back a token (Stripe: payment_method_id
FBPay: cc_token
) that we’re going to use in lieu of any credit card information moving forward.
You can get the Stripe publishable_key
in one of two ways:
1. Login to your Stripe account and get it from your Stripe dashboard. Follow the directions here.
2. You can make an authenticated GET request using the following endpoint:
It will be returned to you as a publishable_key
somewhere in the response payload. You do NOT need a publishable_key
for FBPay requests
Ensure the keys you retrieve for Stripe are live keys. They would typically have the prefix “pk_live_*****”.
Now I’m going to make an authenticated POST
call to:
For FBPay, make your POST
call to:
field |
type |
description |
Required |
---|---|---|---|
name | string | This will be the Cardholder’s name
|
Yes |
card_number | string | The 13-19 (usually 16) digits of the credit card 1234567890123456 | Yes |
expiry_month | string | The two digits associated with the expiry month on the credit card 02 |
Yes |
expiry_year | integer | The four digits associated with the expiry year on the credit card 2022 | Yes |
api_key | array of objects | The API key from Stripe can be found by logging into your Stripe account —> Developers —> Live API Keys —> Publishable Key or by making a GET call to the https://api.freshbooks.com/payments/account/<account_id>/gateway endpoint |
Stripe |
country | string | Country Code, should only be 2 characters long i.e. CA or US |
FBPay |
postal_code | string | Postal or zip code associated with the credit card i.e.02134 or M6P3T1 |
FBPay |
object | CC owner’s email address i.e.[email protected] |
FBPay | |
cvv | string | 3-4 digit CVV number, usually found on the back of the card 123 | FBPay |
You should receive back your credit card token which will be used in the subsequent calls.
In my case it was: “payment_method_id”: pm_1H4OnEsY2TwOsYsAnD3sYs
, for FBPay it will be something like: “cc_token”: 23954867299
Since there is no swiping, or chip involved in this process, it it likely to be considered a Card-Not-Present transaction, which sometimes amount to marginally higher fees. If you’re curious or concerned about these rates, don’t hesitate to reach out to our Payments team directly at 1.833.333.1128. Don’t worry, a real human will answer within a few rings between normal business hours (try me 🙂).
3. Create “Setup Intent” using the Payment Method key
*If you’re using FreshBooks Payments, you can move on to the next step.
Great! Now you’ve tokenized the customer’s credit card! Now the next step is to let Stripe know that we’re going to be using this token for Mail Order Telephone Order (MOTO) transactions. Although, this seems like a relatively frivolous step, it’s important to inform Stripe that you will be using this credit card for transactions via FreshBooks. You will not get the token to work if you don’t do this step. Again, this is not required if are tokenizing via FBPay.
For more information on what a MOTO transaction is, check out Stripe’s website.
I’m going to make my third authenticated POST
call to:
field |
type |
description |
---|---|---|
payment_method | string | The token you received from your last call pm_1H4OnEsY2TwOsYsAnD3sYs |
And you should get back this response, I took out most of the client_secret
for obvious reasons:
On the off-chance that requires_action
comes back true
, the card cannot be used to save on a recurring profile because it has to go through 3D authentication by Stripe. We currently don’t support the ability to fulfill the 3D authentication by Stripe so it’s best to try another card, if possible.
Awesome, so you’ve got your successful 201 - Created
back, it’s time to apply this credit card token to your invoice profile. Should be a breeze since you’ve already created it above. Don’t forget to bring your accounting_systemid
, customerid
, and profileid
along.
4. Save Payment Method to Recurring Profile
To add the credit card to a recurring invoice profile, we need to take our payment method key (our newly tokenized credit card) and update the invoice profile with it.
It doesn’t matter whether you’ve received back your FBPay or Stripe token, you’re going to use them in the same way (under token
), you will just need to change the gateway_name
based on which one you received.
field |
type |
description |
---|---|---|
credit_card | object | All credit card information associated with customer profile |
saved_to_system_id | string | The ID associated with the business you are saving the profile to. NOTE: You may find this ID as accounting_systemid when grabbing it from your invoice profile response. It can also be seen as your accountid when hitting the /me identity endpoint |
card_holder_user_id | integer | ID associated with the owner of the invoice profile. (Can also be identified as customerid ) |
access | object | The four digits associated with the expiry year on the credit card 2022 |
system | boolean | When credit card is being saved by the admin. If true , the credit card will be saved to the client profile and available to be used again, if false the admin cannot reuse the credit card. |
client | boolean | Credit card is being saved by the Client (this prevents the system from being able to reuse the credit card). |
invoice_profiles | array of integers | For each invoice profile you want to add the credit card to, separate profileId by commas. |
credit_card_tokens | array of objects | Details of tokenized credit card information |
payment_method_id | string | Credit card token received from Step 1. i.e. FBPay 12345678901 Stripe pm_1H4OnEsY2TwOsYsAnD3sYs |
gateway_name | string | Payment gateway name i.e. fbpay or stripe |
is_primary | boolean | Sets the credit card as the primary credit card on file for the specified client.true or false |
So I will make a fourth authenticated POST call. This time to:
https://api.freshbooks.com/payments/account/<ACCOUNT_ID>/credit-card
And would you look at that! We got back a successful response.
You should now see that your Client’s profile is updated on your FreshBooks account. Because you set system
to true
you’ll notice that the credit card is available for reuse on the client profile. Of course, if you set it to false you won’t be able to re-use it.
So now that we have Dom’s credit card attached to the invoice profile on file, FreshBooks will automatically charge him based on the frequency details set in the first step. You will now also be able to go check out his Client profile and if you’ve done everything correctly, you’ll also see his credit card saved in a PCI-compliant manner. If you’d like to read more about our Security and Reliability Safeguards you can do so by clicking here.
If you still have questions for us or something isn’t working as you’d like it to, don’t hesitate to reach out to [email protected]. We’ll try to respond to your request as quickly as we can!
Create Invoice Profile
Request: POST https://api.freshbooks.com/accounting/account/<account_id>/invoice_profiles/invoice_profiles
{
"invoice_profile": {
"customerid": 5756778,
"create_date": "2020-07-13",
"frequency": "m",
"numberRecurring": "3",
"lines": [
{
"name":"[Monthly Rental] - Santa Bruz Mountain Bike",
"qty": "1",
"unit_cost": {
"amount": "175.00"
}
},
{
{
"name":"[Monthly Rental] - Humpty Helmet"
"qty": "1",
"unit_cost": {
"amount": "25.00"
}
}
]
}
}
Response:
{
"response": {
"result": {
"invoice_profile": {
"code": "",
"create_date": "2020-07-13",
"send_email": true,
"street": "",
"ownerid": 1,
"bill_gateway": null,
"vat_number": "",
"numberRecurring": 3,
"id": 716,
"city": "",
"send_gmail": false,
"lname": "Schiavo",
"ext_archive": null,
"fname": "Dominic",
"vis_state": 0,
"province": "",
"updated": "2020-07-13 12:51:19",
"terms": null,
"description": "",
"vat_name": "",
"street2": "",
"currency_code": "CAD",
"disable": false,
"discount_total": {
"amount": "0.00",
"code": "CAD"
},
"address": "",
"customerid": 5756778,
"accounting_systemid": "7RgXv",
"organization": "EoS",
"occurrences_to_date": 0,
"due_offset_days": 0,
"language": "en",
"po_number": null,
"country": "Canada",
"notes": "",
"include_unbilled_time": false,
"profileid": 716,
"amount": {
"amount": "0.00",
"code": "CAD"
},
"frequency": "m",
"payment_details": "",
"discount_value": "0",
"auto_bill": false
}
}
}
}
Create Payment Method
Request: POST https://paid.freshbooks.com/gateway/<gateway>/payment-method
{
"cc_info": {
"name": "Dominic Schiavo",
"card_number": "1234567890123456",
"expiry_month": "expiry_month",
"expiry_year": "[email protected]",
// FBPay Only
"country": "CA",
"postal_code": "M6P3T1",
"email": "[email protected]",
"cvv": "123"
},
// Stripe Only
"api_key": "pk_live_ThisIsAVeRyLonGKeYpRobAblyLonGeRthaNthis"
}
Response:
{
"payment_method": "pm_1H4OnEsY2TwOsYsAnD3sYs"
}
Create "Setup Intent" using Payment Method Key
Only necessary for Stripe transactions
Request: POST https://api.freshbooks.com/payments/account/<account_id>/gateway/<gateway>/credit-card/token
{
"payment_method": "pm_1H4OnEsY2TwOsYsAnD3sYs"
}
Response:
{
"setup_intent": {
"client_secret": "seti_1H4AnoTHErReallYLonGSecreT",
"requires_action": false
}
}
Save Payment Method to Recurring Profile
Request: PUT https://api.freshbooks.com/accounting/account/<accountid>/users/clients/<id>
{
"client": {
"vis_state": 1
}
}
Response:
{
"response": {}
}