Webhook Callbacks

The client supports registration and verification of FreshBooks’ API Webhook Callbacks. See FreshBooks’ documentation for more information.

FreshBooks will send webhooks as a POST request to the registered URI with form data:

name=invoice.create&object_id=1234567&account_id=6BApk&business_id=6543&identity_id=1234user_id=1

Registration

data = {
    "event": "invoice.create",
    "uri": "http://your_server.com/webhooks/ready"
}

webhook = freshBooksClient.callbacks.create(account_id, data)

assert webhook.callback_id == 2001
assert webhook.verified == False

Registration Verification

Registration of a webhook will cause FreshBooks to send a webhook to the specified URI with a verification code. The webhook will not be active until you send that code back to FreshBooks.

freshBooksClient.callbacks.verify(account_id, callback_id, verification_code)

If needed, you can ask FreshBooks to resend the verification code.

freshBooksClient.callbacks.resend_verification(account_id, callback_id)

Hold on to the verification code for later use (see below).

Verifing Webhook Signature

Each Webhook sent by FreshBooks includes a header, X-FreshBooks-Hmac-SHA256, with a base64-encoded signature generated from a JSON string of the form data sent in the request and hashed with the token originally sent in the webhook verification process as a secret.

From FreshBooks’ documentation, the signature can be generated in Python using:

# Using Flask
import base64
import hmac
import hashlib
import json

from flask import Flask, request

def signature_match(verifier, request):
   signature = request.headers.get('X-FreshBooks-Hmac-SHA256')
   data = json.dumps(request.form)

   dig = hmac.new(
      verifier.encode('utf-8'),
      msg=data.encode('utf-8'),
      digestmod=hashlib.sha256
   ).digest()
   calculated_sig = base64.b64encode(dig).decode()

   return signature == calculated_sig