Skip to content
× FreshBooks App Logo
FreshBooks
Official App
Free - Google Play
Get it
You're currently on our US site. Select your regional site here:

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

customeridstringThis will be the Cardholder’s name i.e. Dominic Schiavo
create_datestringCreated day of the invoice profile 2020-07-20
frequencystringthe 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)
numberRecurringintegerThe number of invoices that will be generated, 0 for infinite
linesarray of objectsdescription of industry client is in
namestringName of the item i.e. shoes
qtystringHow many items you are adding to the invoice. This will multiply the unit_cost of the items
unit_costobject 
amountstringCost 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_systemidcustomerid, 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 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: 

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

namestringThis will be the Cardholder’s name Dominic Schiavo

Yes

card_numberstringThe 13-19 (usually 16) digits of the credit card 1234567890123456 Yes
expiry_monthstringThe two digits associated with the expiry month on the credit card 02

Yes

expiry_yearintegerThe four digits associated with the expiry year on the credit card 2022Yes
api_keyarray of objectsThe 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

countrystringCountry Code, should only be 2 characters long i.e. CA or US

FBPay

postal_codestringPostal or zip code associated with the credit card i.e.02134or M6P3T1

FBPay

emailobjectCC owner’s email address i.e.[email protected]

FBPay

cvv string3-4 digit CVV number, usually found on the back of the card 123FBPay

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_methodstringThe 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_systemidcustomerid, 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_cardobjectAll credit card information associated with customer profile
saved_to_system_idstringThe 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_idintegerID associated with the owner of the invoice profile.
(Can also be identified as customerid)
accessobjectThe four digits associated with the expiry year on the credit card 2022
systembooleanWhen 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.
clientbooleanCredit card is being saved by the Client (this prevents the system from being able to reuse the credit card).
invoice_profilesarray of integersFor each invoice profile you want to add the credit card to, separate profileId by commas. 
credit_card_tokensarray of objectsDetails of tokenized credit card information
payment_method_idstringCredit card token received from Step 1.
i.e.
FBPay 12345678901
Stripe pm_1H4OnEsY2TwOsYsAnD3sYs
gateway_namestringPayment gateway name i.e. fbpay or stripe
is_primarybooleanSets 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": {}
}