Summary and recommendation
FreshBooks exposes a REST API at https://api.freshbooks.com using OAuth 2.0 Authorization Code flow. Identity and team-member operations live under the /auth/api/v1/ path and are distinct from the accounting resource endpoints - the API is primarily designed for invoice, client, and expense management, and user/identity capabilities are limited by comparison.
The admin:all:legacy scope is required for team member management; without it, token-authenticated calls to business member endpoints will fail. Note: FreshBooks is an entirely separate product from Freshworks - their APIs, documentation, and SCIM support are unrelated and must not be conflated when building an identity graph that maps users across your SaaS environment.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 (Authorization Code flow) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise (via Okta SWA/SAML integration; no standalone SCIM endpoint documented) |
Authentication
Auth method: OAuth 2.0 (Authorization Code flow)
Setup steps
- Register an application at https://my.freshbooks.com/#/developer to obtain a client_id and client_secret.
- Redirect the user to https://auth.freshbooks.com/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri} to obtain an authorization code.
- Exchange the authorization code for an access_token and refresh_token via POST https://api.freshbooks.com/auth/oauth/token.
- Include the access token in all API requests as: Authorization: Bearer {access_token}.
- Refresh the access token using the refresh_token before expiry via the same token endpoint.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| user:profile:read | Read the authenticated user's profile information. | GET /auth/api/v1/users/me |
| user:profile:write | Update the authenticated user's profile information. | PUT /auth/api/v1/users/me |
| admin:all:legacy | Full administrative access to account resources including team members. | Team member management endpoints |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique FreshBooks user ID. | system-assigned | immutable | Used as identity key across endpoints. |
| string | Primary email address of the user. | required | optional | Must be unique across FreshBooks accounts. | |
| first_name | string | User's first name. | required | optional | |
| last_name | string | User's last name. | required | optional | |
| business_memberships | array | List of businesses the user belongs to, including role within each. | system-assigned | managed via team member endpoints | Each entry contains business_id and role. |
| phone_numbers | array | Phone numbers associated with the user profile. | optional | optional | |
| profession | object | User's professional title and company. | optional | optional | Contains title and company fields. |
| avatar | string (URL) | URL to the user's profile avatar image. | optional | optional | |
| setup_complete | boolean | Whether the user has completed account setup. | system-assigned | read-only | |
| confirmed | boolean | Whether the user's email address has been confirmed. | system-assigned | read-only | |
| language | string | Preferred language code (e.g., 'en'). | optional | optional | |
| timezone | string | User's timezone (e.g., 'America/Toronto'). | optional | optional | |
| role | string | Role of the team member within a business (e.g., 'owner', 'admin', 'employee'). | required for team member invite | optional | Set at the business membership level, not the user level. |
| permissions | object | Granular permission flags for the team member within a business. | optional | optional | Varies by role; some permissions are role-locked. |
Core endpoints
Get current authenticated user
- Method: GET
- URL:
https://api.freshbooks.com/auth/api/v1/users/me - Watch out for: This endpoint returns the OAuth token owner only; it cannot retrieve arbitrary users by ID.
Request example
GET /auth/api/v1/users/me
Authorization: Bearer {access_token}
Response example
{
"response": {
"id": 123456,
"email": "user@example.com",
"first_name": "Jane",
"last_name": "Doe",
"confirmed": true,
"business_memberships": [{"business_id": 789, "role": "owner"}]
}
}
Update current authenticated user
- Method: PUT
- URL:
https://api.freshbooks.com/auth/api/v1/users/me - Watch out for: Only the authenticated user's own profile can be updated via this endpoint; admin cannot update other users' profiles directly.
Request example
PUT /auth/api/v1/users/me
Authorization: Bearer {access_token}
Content-Type: application/json
{"first_name": "Janet", "language": "en"}
Response example
{
"response": {
"id": 123456,
"first_name": "Janet",
"email": "user@example.com"
}
}
List team members for a business
- Method: GET
- URL:
https://api.freshbooks.com/auth/api/v1/business/{business_id}/members - Watch out for: Requires admin or owner role token for the specified business_id.
Request example
GET /auth/api/v1/business/789/members?page=1&per_page=25
Authorization: Bearer {access_token}
Response example
{
"response": {
"members": [
{"id": 1, "email": "staff@example.com", "role": "employee", "confirmed": true}
],
"pages": {"page": 1, "pages": 1, "per_page": 25, "total": 1}
}
}
Invite a team member to a business
- Method: POST
- URL:
https://api.freshbooks.com/auth/api/v1/business/{business_id}/invitations - Watch out for: Sends an email invitation; the user is not active until they accept. Cannot force-create a user without their consent.
Request example
POST /auth/api/v1/business/789/invitations
Authorization: Bearer {access_token}
Content-Type: application/json
{"email": "newstaff@example.com", "role": "employee"}
Response example
{
"response": {
"invitation": {
"id": 55,
"email": "newstaff@example.com",
"role": "employee",
"status": "pending"
}
}
}
Remove a team member from a business
- Method: DELETE
- URL:
https://api.freshbooks.com/auth/api/v1/business/{business_id}/members/{member_id} - Watch out for: Removes the member from the business but does not delete the FreshBooks user account itself.
Request example
DELETE /auth/api/v1/business/789/members/1
Authorization: Bearer {access_token}
Response example
HTTP 204 No Content
Update team member role/permissions
- Method: PUT
- URL:
https://api.freshbooks.com/auth/api/v1/business/{business_id}/members/{member_id} - Watch out for: Role changes take effect immediately; ensure downstream systems are notified.
Request example
PUT /auth/api/v1/business/789/members/1
Authorization: Bearer {access_token}
Content-Type: application/json
{"role": "admin"}
Response example
{
"response": {
"member": {
"id": 1,
"role": "admin",
"email": "staff@example.com"
}
}
}
List pending invitations
- Method: GET
- URL:
https://api.freshbooks.com/auth/api/v1/business/{business_id}/invitations - Watch out for: Only returns invitations in 'pending' state; accepted invitations appear in the members list.
Request example
GET /auth/api/v1/business/789/invitations
Authorization: Bearer {access_token}
Response example
{
"response": {
"invitations": [
{"id": 55, "email": "newstaff@example.com", "status": "pending"}
]
}
}
Revoke a pending invitation
- Method: DELETE
- URL:
https://api.freshbooks.com/auth/api/v1/business/{business_id}/invitations/{invitation_id} - Watch out for: Cannot revoke an invitation that has already been accepted.
Request example
DELETE /auth/api/v1/business/789/invitations/55
Authorization: Bearer {access_token}
Response example
HTTP 204 No Content
Rate limits, pagination, and events
- Rate limits: FreshBooks does not publicly document specific rate limit thresholds in their developer docs. Limits are enforced server-side and vary by plan.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: HTTP 429 is returned when rate limits are exceeded. Retry-After header presence is not confirmed in official docs. Implement exponential backoff on 429 responses.
- Pagination method: offset
- Default page size: 15
- Max page size: 100
- Pagination pointer: page / per_page
| Plan | Limit | Concurrent |
|---|---|---|
| All plans | Not publicly documented | 0 |
- Webhooks available: Yes
- Webhook notes: FreshBooks supports webhooks for accounting resource events (invoices, payments, clients, etc.) via callback URIs registered through the API. User/team-member lifecycle events are not explicitly listed as webhook triggers in official documentation.
- Alternative event strategy: Poll GET /auth/api/v1/business/{business_id}/members periodically to detect team member changes, as no user-lifecycle webhook events are documented.
- Webhook events: invoice.create, invoice.update, invoice.delete, payment.create, payment.update, client.create, client.update, client.delete, expense.create, expense.update
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise (via Okta SWA/SAML integration; no standalone SCIM endpoint documented)
Endpoint: Not documented
Supported operations: User provisioning via Okta SWA app, SSO via SAML through Okta
Limitations:
- No native SCIM 2.0 endpoint exposed directly by FreshBooks; SCIM-like provisioning is only available through Okta's SWA (Secure Web Authentication) connector.
- Automated deprovisioning is limited; removing a user in the IdP does not guarantee immediate removal from FreshBooks without additional workflow configuration.
- Only Okta is documented as a supported IdP for SSO/provisioning; Entra ID, Google Workspace, and OneLogin are not officially supported.
- Enterprise plan required for SSO/provisioning features.
- SSO must be configured as a prerequisite before provisioning workflows can be established.
Common scenarios
Three core identity lifecycle scenarios are supported via API, each with meaningful caveats. For onboarding, POST /auth/api/v1/business/{business_id}/invitations sends an email invitation.
the user is not active and will not appear in the members list until they accept - there is no force-activation path, which breaks synchronous provisioning assumptions.
For offboarding, DELETE /auth/api/v1/business/{business_id}/members/{member_id} removes the user from the business but does not delete their FreshBooks account or revoke SSO access; Okta deprovisioning must be coordinated separately if SSO is in use.
For role auditing, paginate GET /auth/api/v1/business/{business_id}/members with per_page=100 - the default page size is 15, and omitting pagination will silently return an incomplete member list, producing an inaccurate identity graph snapshot.
Onboard a new team member
- Authenticate via OAuth 2.0 Authorization Code flow to obtain an access token with admin scope.
- GET /auth/api/v1/users/me to retrieve the business_id from business_memberships.
- POST /auth/api/v1/business/{business_id}/invitations with the new member's email and desired role.
- Poll GET /auth/api/v1/business/{business_id}/invitations to confirm invitation status.
- Once the invitee accepts, they appear in GET /auth/api/v1/business/{business_id}/members.
Watch out for: The new user must accept the email invitation before they are active; there is no way to force-activate a user programmatically.
Offboard a departing team member
- GET /auth/api/v1/business/{business_id}/members to find the member's member_id.
- DELETE /auth/api/v1/business/{business_id}/members/{member_id} to remove them from the business.
- Verify removal by re-fetching the members list.
- If the user had a pending invitation, also DELETE /auth/api/v1/business/{business_id}/invitations/{invitation_id}.
Watch out for: This only removes the user from the specific business; their FreshBooks account remains active. Coordinate with Okta SSO deprovisioning to revoke login access if SSO is in use.
Audit current team member roles
- GET /auth/api/v1/users/me to retrieve all business_ids the token owner administers.
- For each business_id, GET /auth/api/v1/business/{business_id}/members?per_page=100 and paginate through all pages using the page parameter.
- Collect each member's email, role, and confirmed status.
- Cross-reference with IdP (Okta) user list to identify orphaned accounts or role mismatches.
Watch out for: Default page size is 15; always set per_page=100 and check the pages.pages value to ensure all members are retrieved across paginated responses.
Why building this yourself is a trap
Several API behaviors create integration risk that is not obvious from the documentation. Rate limits are not publicly documented; HTTP 429 is returned when limits are exceeded, but the Retry-After header is unconfirmed - implement exponential backoff unconditionally.
Webhooks exist for accounting events (invoices, payments, clients) but user and team-member lifecycle events are not documented as webhook triggers, meaning any identity graph that relies on FreshBooks for real-time joiner/mover/leaver signals must fall back to polling GET /auth/api/v1/business/{business_id}/members on a scheduled interval.
Additionally, the /auth/api/v1/users/me endpoint returns only the token owner - there is no admin endpoint to enumerate all FreshBooks user accounts globally, which limits the completeness of any automated identity graph built on top of this API.
SCIM 2.0 provisioning is available only through Okta's SWA connector on an Enterprise plan; no standalone SCIM endpoint is exposed directly by FreshBooks, and automated deprovisioning via IdP requires additional workflow configuration beyond a standard SCIM setup.
Automate Freshbooks workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.