× Freshbooks App Logo
FreshBooks
Official App
Free - Google Play
Get it

Tokenizing Credit Cards

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:

https://api.freshbooks.com/payments/<account_id>/gateway

 

It will be returned to you as a publishable_key somehwere in the response payload. You do NOT need a publishable_key for FBPay requests

 

Now I'm going to make an authenticated POST call to: 

https://paid.freshbooks.com/gateway/stripe/payment-method

For FBPay, make your POST call to: 

https://paid.freshbooks.com/gateway/fbpay/tokenize

field

type

description

Required

name string This will be the Cardholder's name Dominic Schiavo

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 —> 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.02134or M6P3T1

FBPay

email object

CC owner's email address i.e.mushparker@freshbooks.com

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: 

https://api.freshbooks.com/payments/account/<ACCOUNT_ID>/gateway/stripe/credit-card/token

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 newapi@freshbooks.com. 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": "john.doe@abcorp.com",
// FBPay Only 
        "country": "CA",
        "postal_code": "M6P3T1",
        "email": "dominic.schiavo@freshbooksexample.com",
        "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": {}
}