Skip to content

feat(freshbooks): add the FreshBooks API module (v1) - #240

Merged
d-klotz merged 1 commit into
nextfrom
feat/freshbooks-v1
Oct 29, 2026
Merged

d-klotz merged 1 commit into
nextfrom
feat/freshbooks-v1

Conversation

@d-klotz

@d-klotz d-klotz commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds @friggframework/api-module-freshbooks under packages/v1-ready/freshbooks (Frigg v2, @friggframework/core ^2.0.0-next.126). packages/needs-updating/freshbooks is git mv'd and its v0 files (manager, models, mocks, old tests) are removed.

Supersedes #156.

Why

This is a port of the FreshBooks module that runs in production in lefthookhq/freshbooks-integrations (backend/src/api-modules/freshbooks/). Once it's published, the app can depend on it instead of carrying its own copy.

Behaviour

  • Single-use grants: FreshBooks authorization codes and refresh tokens are single-use, and refresh tokens rotate. Token POSTs are sent exactly once and are never retried on 401, 429, 5xx or network errors. A 401 on a token request does not start a nested refresh. Other requests keep core's backoff.
  • Entity: keyed by the business account_id, with the business name in details.name. A user with several businesses must pass account_id; the module throws and lists the choices.
  • Credential: keyed by the FreshBooks user id. It persists access_token, refresh_token and freshbooksUserId.
  • redirect_uri: ${REDIRECT_URI}/freshbooks
  • API methods:
    • users/me
    • clients: list, get, find by email, create, update
    • invoices: get, list a client's invoices
    • payments: get, list a client's payments
    • callbacks: list, get, create, verify, resend, delete
  • Helpers: webUrls, invoiceStatusName

Differences from the production copy

  • 401 on a token POST: new guard (_refreshAuthOnce override). In the production copy, a 401 on a direct getTokenFromCode or refreshAccessToken triggered core's refresh and posted a second grant.
  • defaultConfig.json: adds logoUrl.

Everything else is unchanged apart from prettier formatting.

Tests

79 tests, all mocked with nock, no network.

  • Single-use grants: a failed token POST is sent once for both grants on 401, 429, 5xx and network errors. Removing the override makes these tests fail.
  • Core Module flows: rotation persistence, concurrent 401s sharing one refresh, adopting a newer credential after invalid_grant.
  • Definition: redirect_uri, entity keying and business name.

Other checks: prettier --check is clean (apart from the auto-generated CHANGELOG), and npm ci --dry-run passes with the updated lockfile.

Left in the app

App-specific logic stays in the app: HubSpot sync, webhook routing (freshbooksWebhooks.js), cutover scripts and the cards. None of it is in this module.

🤖 Generated with Claude Code

📦 Published PR as canary version: Canary Versions

✨ Test out this PR locally via:

npm install @friggframework/api-module-freshbooks@1.1.0-canary.240.b16c133.0
# or 
yarn add @friggframework/api-module-freshbooks@1.1.0-canary.240.b16c133.0

Version

Published prerelease version: @friggframework/api-module-freshbooks@1.1.0-next.0

Changelog

🚀 Enhancement

  • @friggframework/api-module-freshbooks
    • feat(freshbooks): add the FreshBooks API module (v1) #240 (@d-klotz)

🐛 Bug Fix

  • @friggframework/api-module-microsoft-teams, @friggframework/api-module-slack, @friggframework/api-module-42matters, @friggframework/api-module-asana, @friggframework/api-module-attio, @friggframework/api-module-clio, @friggframework/api-module-connectwise, @friggframework/api-module-contentful, @friggframework/api-module-contentstack, @friggframework/api-module-crossbeam, @friggframework/api-module-deel, @friggframework/api-module-fathom, @friggframework/api-module-fireflies, @friggframework/api-module-frigg-scale-test, @friggframework/api-module-frontify, @friggframework/api-module-gong, @friggframework/api-module-google-calendar, @friggframework/api-module-google-drive, @friggframework/api-module-helpscout, @friggframework/api-module-hubspot, @friggframework/api-module-ironclad, @friggframework/api-module-linear, @friggframework/api-module-otter, @friggframework/api-module-pipedrive, @friggframework/api-module-quo, @friggframework/api-module-reevo, @friggframework/api-module-salesforce, @friggframework/api-module-stripe, @friggframework/api-module-unbabel-projects, @friggframework/api-module-unbabel, @friggframework/api-module-zoho-crm, @friggframework/api-module-zoom
    • fix(hubspot): use OAuth 2026-03 token and introspect endpoints (v1 shutdown 16 Feb 2027) #236 (@d-klotz)

Authors: 1

Promote packages/needs-updating/freshbooks to packages/v1-ready/freshbooks as
@friggframework/api-module-freshbooks on @friggframework/core ^2.0.0-next.126,
ported from the module running in production in
lefthookhq/freshbooks-integrations.

- token requests (authorization_code and refresh_token) are sent once and never
  retried on 401/429/5xx/network errors; FreshBooks grants are single-use
- entity keyed by business account_id with the business name in details
- redirect_uri is ${REDIRECT_URI}/freshbooks
- clients, invoices, payments, users/me and callback methods
- nock transport tests, including core Module refresh/rotation flows

Supersedes #156.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@d-klotz d-klotz added prerelease This change is available in a prerelease. release labels Oct 28, 2026
@d-klotz
d-klotz merged commit 9f5e5c6 into next Oct 29, 2026
4 checks passed
@d-klotz
d-klotz deleted the feat/freshbooks-v1 branch October 29, 2026 16:43
@seanspeaks

Copy link
Copy Markdown
Contributor

🚀 PR was released in @friggframework/api-module-freshbooks@1.1.0-next.0 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

prerelease This change is available in a prerelease. release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants