Authentication

OAuth Scopes

Understand available OAuth scopes, how access is enforced, and how to request the right permissions for your integration.

OAuth scopes define what your application is allowed to do after a user grants access. This guide explains how scope authorization works in Billabex and how to choose the right scope set.

Overview

At a high level, scopes work like this:

  1. Your app requests scopes during the OAuth authorization step.
  2. The user approves those permissions.
  3. Billabex issues tokens containing the granted scopes.
  4. Each API endpoint checks scopes before executing the request.

Key Concepts

  • Space-separated values: Scopes are requested as a space-separated string.
  • Least privilege: Request only what your integration needs.
  • Read vs write: Most resource scopes follow :read (read-only) and :all (read/write) patterns.
  • OR authorization logic: If an endpoint allows multiple scopes, having one allowed scope is enough.
  • No scope escalation on existing token: To add permissions, you must re-run OAuth and request broader scopes.

Available Scopes

OpenID Connect (OIDC)

Use these scopes when you need user identity claims.

Scope Purpose
openid Enables OIDC and ID token issuance
profile Adds profile claims and allows PUT/DELETE /users/me/avatar
email Adds email claims (email, email_verified)

Invoicing

Scope Access Level Representative Endpoints
invoices:read Read-only
  • GET /invoices
  • GET /invoices/:invoiceId
invoices:all Full access
  • POST /invoices
  • PUT /invoices/:invoiceId/paid-amount
  • PUT /invoices/:invoiceId/payment-schedule
  • DELETE /invoices/:invoiceId
credit-notes:read Read-only
  • GET /credit-notes
  • GET /credit-notes/:creditNoteId
credit-notes:all Full access
  • POST /credit-notes
  • DELETE /credit-notes/:creditNoteId
  • POST /credit-allocations
accounts:read Read-only
  • GET /accounts
  • GET /accounts/:accountId
  • GET /accounts/:accountId/contacts
accounts:all Full access
  • POST /accounts
  • PUT /accounts/:accountId
  • DELETE /accounts/:accountId
  • Contact management

Dunning & Communications

Scope Access Level Representative Endpoints
communications:read Read-only
  • GET /outgoing-email-communications
  • GET /incoming-email-communications
  • GET /accounts/:accountId/outgoing-message-communications/:communicationId
dunning:manage Full access
  • GET /accounts/:accountId/dunning
  • POST /accounts/:accountId/dunning/pause
  • POST /accounts/:accountId/dunning/resume
  • PUT /outgoing-email-communications/:communicationId
  • POST /accounts/:accountId/outgoing-message-communications/preview
  • POST /accounts/:accountId/outgoing-message-communications
  • All read communication endpoints

Account Tasks

Account tasks are created by the Billabex agent when user input is required. These scopes control access to account task endpoints.

Scope Access Level Representative Endpoints
tasks:read Read-only
  • GET /account-tasks
  • GET /account-tasks/:accountTaskId
tasks:all Full access
  • POST /account-tasks/:accountTaskId/cancel
  • POST /account-tasks/:accountTaskId/interactions

Platform

Scope Access Level Representative Endpoints
organizations:read Read-only
  • GET /organizations
  • GET /organizations/:organizationId
  • GET /organizations/:organizationId/members
organizations:all Full access
  • PUT /organizations/:organizationId
  • PUT /organizations/:organizationId/settings
  • POST /organizations/:organizationId/invitations
  • DELETE /organizations/:organizationId/members/:userId

MCP (Model Context Protocol)

These scopes are used by MCP clients connecting to the Billabex MCP server.

Scope Access Level Description
mcp:read Read-only Allow MCP tools to read invoices, accounts, and communications.
mcp:write Write access Allow MCP tools to create, update, and delete data.

See MCP Server for the full list of available tools and resources.

Write nature

Scope Access Level Description
sync None Declares this client an automated synchronization. Grants no endpoint.

sync is the one scope that does not unlock anything. It tells Billabex that the writes coming from this client are machine writes rather than a person’s, and that changes how contact data is merged:

  • A contact’s fullName and language stay with whoever typed them. If a person set either field in the web app or through any non-sync client, a sync client can no longer overwrite it. It can still seed a field nobody has set.
  • Phone numbers land in their own pile. Every number carries an origin: Manual for a number a person entered, Connector for a number written by a synchronization, which now includes yours once you hold sync. Writing phones replaces only your own pile and leaves the other intact, so a synchronization and the customer’s team stop erasing each other.
  • An unreadable number is skipped instead of failing the request. A number that cannot be normalized (no countryCode on a national number, free text such as "see Jean") is dropped and reported, rather than turning the whole update into a 400. Without sync, it stays a 400, because a person needs to be told their input is wrong.

What is refused or dropped comes back in a warnings array on the contact response, each entry naming the field, the ignored value and a reason of MANUALLY_SET or UNPARSEABLE. The key is absent when there is nothing to report. Read it: without it, a refused write is indistinguishable from a write that changed nothing, since both answer 200 with the contact as it stands.

Because sync only takes rights away, it is self-declared: request it like any other scope, no extra approval step. Do not request it for an integration a person drives by hand, or that person’s edits will be filed as machine writes.

openid email accounts:all invoices:all sync

Requesting Scopes

Include scopes in the OAuth authorization request:

const authUrl = new URL('[baseURL]/api/oauth/authorize');
authUrl.searchParams.append(
  'scope',
  'openid email invoices:read accounts:read',
);

Read-only reporting integration

openid email invoices:read credit-notes:read accounts:read

Invoice management workflow

openid email invoices:all credit-notes:all accounts:read

Dunning assistant integration

openid email invoices:read accounts:read communications:read dunning:manage

Organization administration tool

openid email organizations:all

Account task management integration

openid email tasks:all accounts:read

MCP client integration

mcp:read mcp:write

See MCP Server for available tools and resources.

Authorization Behavior

OR Logic on Endpoints

When an endpoint allows multiple scopes, any one accepted scope grants access.

Example:

  • Endpoint accepts invoices:read or invoices:all
  • Token with only invoices:read is authorized

Superset Behavior

If you already have resource:all, you don’t need resource:read separately for the same resource.

Common Scope Errors

invalid_scope

Happens when a requested scope is unknown or malformed.

{
  "error": "invalid_scope",
  "error_description": "The requested scope is invalid or unknown"
}

insufficient_scope

Happens when your token does not include a required scope for the endpoint.

{
  "statusCode": 403,
  "message": "Forbidden",
  "error": "insufficient_scope"
}

Security Best Practices

  • Request the minimum scope set required for your integration.
  • Start with read scopes and expand only when needed.
  • Re-authorize users when your app requires new permissions.
  • Audit requested scopes regularly as features evolve.

Next Steps

Support

Questions about scopes and permissions? Contact us via the website contact form.