ml-connector
FreshBooksPayPal

FreshBooks and PayPal integration

FreshBooks handles your accounting, invoicing, and client records. PayPal processes your customer payments. Connecting them keeps your receivables ledger in sync with PayPal captures so you see real cash received without re-keying. Each time a customer pays a FreshBooks invoice via PayPal, the payment record flows back into FreshBooks automatically, matched to the correct invoice and customer. ml-connector bridges the two different authentication models and prevents duplicate postings even if webhooks retry.

How FreshBooks works

FreshBooks exposes clients, invoices, payments, expenses, bills, journal entries, and chart of accounts through a REST API at https://api.freshbooks.com with two namespaces: /accounting/account/<accountId> for accounting records and /timetracking/business/<businessId> for time tracking. Authentication uses user-delegated OAuth 2.0 (not Client Credentials), so ml-connector needs permission from a FreshBooks user to act on their behalf. FreshBooks supports webhooks for invoice, payment, bill, client, and other events, posting events as application/x-www-form-urlencoded payloads signed with HMAC-SHA256. Webhook delivery ranges from seconds to several minutes and is not guaranteed real-time, and callbacks that do not return 2xx within 10 seconds are retried and eventually disabled if they continue to fail.

How PayPal works

PayPal exposes orders, authorizations, captures, refunds, invoices, transactions, subscriptions, and payouts through REST APIs at https://api-m.paypal.com (production) and https://api-m.sandbox.paypal.com (sandbox), with v1 and v2 path prefixes depending on the resource. Authentication uses OAuth 2.0 Client Credentials: a base64-encoded CLIENT_ID and CLIENT_SECRET pair is sent via HTTP Basic Auth to the token endpoint, and the resulting bearer token is cached for reuse (typically 8 hours). PayPal supports push webhooks, retrying non-2xx responses up to 25 times over 3 days, and webhook signatures are verified using RSA-SHA256 (not HMAC). Refunds must be issued against captures, not orders, and invoices must be sent through a dedicated send endpoint to notify customers.

What moves between them

Payments flow from PayPal into FreshBooks. When a PayPal customer makes a payment and the capture succeeds, ml-connector receives a webhooks event, looks up the matching FreshBooks invoice by transaction ID or customer email and amount, and creates a payment record in FreshBooks tied to that invoice. The sync is one-directional; FreshBooks invoices do not flow back to PayPal, and PayPal refunds and disputes are tracked but not automatically reflected in FreshBooks as credits (manual review is required to map refunds to the original transaction).

How ml-connector handles it

ml-connector stores both credential sets encrypted. For FreshBooks, it holds the OAuth 2.0 refresh token and uses it to mint a new access token when the old one expires, since FreshBooks uses user-delegated grant and does not support Client Credentials. For PayPal, it caches the bearer token (typically 8 hours per spec) and refreshes it when a call returns 401, and it verifies every incoming webhook using PayPal's RSA-SHA256 signature. On the integration side, ml-connector receives a PayPal capture.complete or similar event from the webhook, extracts the transaction ID and amount, searches FreshBooks' invoices for a matching customer and amount, and posts a payment record. If a webhook arrives twice or is delayed, ml-connector deduplicates by transaction ID so the same payment is not posted twice. FreshBooks' webhook events are received and stored for audit, though the main flow is pull-based from PayPal. Every record carries a full audit trail of when it was received, matched, and posted.

A real-world example

A small e-commerce business uses FreshBooks to track invoices and receivables, and uses PayPal to accept customer payments. Before the integration, the owner exported PayPal transaction reports weekly and manually entered each captured payment into FreshBooks, matching them to invoices by customer name and amount. With FreshBooks and PayPal connected, each captured payment flows into FreshBooks automatically and is matched to the right invoice, so the cash-in column of the receivables report is always current. Month-end reconciliation between the PayPal bank statement and the FreshBooks invoice ledger no longer requires manual matching.

What you can do

  • Create FreshBooks payment records for each PayPal capture, matched to the correct invoice and customer.
  • Handle FreshBooks' user-delegated OAuth model and PayPal's Client Credentials model without manual token rotation.
  • Verify PayPal webhook signatures using RSA-SHA256 and confirm every incoming payment event.
  • Deduplicate payments by transaction ID so retried or out-of-order webhooks do not create duplicate records.
  • Maintain a full audit trail of each payment from capture to posting, including matched invoice and any deduplication actions.

Questions

Which direction does data move between FreshBooks and PayPal?
Payments move from PayPal into FreshBooks. When a PayPal capture succeeds, ml-connector creates a corresponding payment record in FreshBooks tied to the matching invoice. FreshBooks invoices and adjustments do not flow back to PayPal, and refunds must be reviewed manually to determine how to reflect them in FreshBooks.
How does ml-connector handle FreshBooks' user-delegated OAuth and PayPal's Client Credentials?
ml-connector stores both credential sets encrypted. For FreshBooks, it holds the OAuth refresh token and mints a new access token when the old one expires (user-delegated grant). For PayPal, it uses Client Credentials to obtain and cache a bearer token (reused for 8 hours), and refreshes it when a call returns 401. Webhook signatures are verified separately for each platform using their respective algorithms (HMAC-SHA256 for FreshBooks, RSA-SHA256 for PayPal).
What happens if a PayPal webhook is delayed or retried?
ml-connector deduplicates by transaction ID so the same payment is not posted twice. If a webhook arrives out of order or a PayPal retry is received after the payment is already in FreshBooks, the duplicate is detected and skipped. Every deduplication action is recorded in the audit trail.

Related integrations

Connect FreshBooks and PayPal

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started