API keys
A single key for a dedicated API user in your own workspace. Best for internal scripts and back-office jobs.
OAuth apps
Each person authorizes your app themselves, with scoped, revocable, audited access. Best for integrations that other people connect to.
Sample app: FakeTax
An open-source Flask app that implements the full OAuth flow with Sign in with Campfire (OpenID Connect), onboarding, buttons, panels, navigation and events. Clone it to see a working integration end to end.
How it works
1
An admin registers the app
A workspace admin creates the app in Campfire, picks the most it may ever access (its scopes), and gets a client ID and client secret.
2
A person authorizes it
Your app sends the person to Campfire’s authorize URL. They sign in, review what the app is asking for, choose a workspace, and click Authorize.
3
Your app exchanges the code for tokens
Campfire redirects back to your app with a one-time
code. Your server exchanges it, along with the client secret, for an access token (valid for 1 hour) and a refresh token (valid for 30 days).4
Your app calls the API
Your app sends
Authorization: Bearer <access_token> on API requests. Campfire treats each request as that person in the chosen workspace, limited to the scopes they granted.Creating and managing OAuth apps requires a Campfire admin. Anyone in a workspace can authorize an app, but the app can never do more than that person is already allowed to do.
Part 1: Register your app
1
Open the Apps page
Go to Settings > Developer > Apps. If you haven’t created an app yet, you’ll see the empty state. Click Create App. Once you have at least one app, the button is New App in the top right.If you already have a manifest, click Create from Manifest (From Manifest once you have apps) and paste it instead. That sets up the details, permissions and extensions in one step.

If you don’t see Apps under Developer, contact your Campfire support team to have OAuth apps turned on for your workspace.
2
Fill in the app details
The Details tab describes your app to the people who will authorize it.



3
Choose the app's permissions
Switch to the Permissions tab and check the access your app needs. These scopes are the ceiling: the most the app can ever request. People connecting the app are still limited to their own permissions in the workspace they choose.
Permissions are grouped by module (Accounting, Revenue, Reports, Cash Management, Close Management, Organization, Ember AI). Each row is a resource, and each column is an access tier:

A higher tier includes the lower ones. For example, checking Write on Invoice Payments also checks Read and Draft. Only check what your integration actually uses. You can widen the scopes later, through a new version, without affecting existing connections.
4
Save and copy your credentials
Click Create App. Campfire shows the app’s credentials:


Your app now appears on the Apps page with its scope count and its production version. Click Manage to open it.

Part 2: Implement the authorization flow
The examples below use these endpoints:Step 1: Send the person to Campfire
Generate a randomstate value and a PKCE verifier, store both in the person’s session, then redirect them to the authorize endpoint:
Here is how to generate the PKCE pair:
Step 2: The person approves access
If the person isn’t signed in, Campfire asks them to sign in first. They then see the consent screen, which shows your app’s icon, name, tagline, and a plain-language list of what it will be able to do:
- Workspace. For a private app, the workspace is fixed to the one that created the app. For a published and approved app, the person picks one of the workspaces they belong to.
-
Authorize redirects to your
redirect_uriwithcodeandstate: -
Cancel redirects to your
redirect_uriwith an error:
state matches the value you stored. If it doesn’t, discard the code.
Step 3: Exchange the code for tokens
From your server,POST the code to the token endpoint within 5 minutes. Each code can be used only once. Authenticate with your client ID and secret, either with HTTP Basic auth (shown) or as client_id and client_secret form fields:
cfa_ and refresh tokens start with cfr_. Store both securely on your server, keyed to the person who connected. The scope field lists exactly what was granted. If the person granted openid, the response also contains an id_token.
Step 4: Call the API
Send the access token as a bearer token:permissions map is the effective access for this token: the person’s own permissions intersected with the granted scopes. The response above is shortened.
What a request can do. Each request runs as the person who authorized the app, in the workspace they chose. It can do only what both that person’s role and the granted scopes allow. An app never inherits admin privileges, even when an admin authorizes it.
When a scope is missing, Campfire returns 403 and tells you which scope you need in the WWW-Authenticate header:
Some endpoints are not available to OAuth apps and return
403 with "This endpoint is not available to OAuth apps." Account and credential management (API keys, OAuth app management, connections) is never available to app tokens.Step 5: Refresh the access token
Access tokens expire after 1 hour. Use the refresh token to get a new pair:Starting the flow from Campfire
If you set a Connect URL, people can also start from Campfire. Clicking Connect on your app’s page under Settings > Connections sends them to your Connect URL. Campfire doesn’t start the OAuth flow itself, because your app has to own thestate and PKCE values. Your Connect URL should do exactly what Step 1 does: generate state and a verifier, store them, and redirect to the authorize URL.
Campfire adds a return_to parameter with the page the person came from. After the callback, and any setup of your own, you can send them back there. Only redirect if return_to starts with Campfire’s own origin. See Onboarding after connect.
A complete example
This minimal Flask app implements the whole flow: connect, callback, calling the API, and refreshing.app.py
Sign in with Campfire (OpenID Connect)
Campfire is an OpenID Connect provider on top of the same authorization code flow. Request theopenid scope and the token response includes an ID token: a signed JWT that says who authorized your app. Use it to sign people in to your own product with their Campfire account.
1
Add the identity scopes to your app
Add
openid, plus email and/or profile if you want those claims, to the app’s allowed_scopes in its manifest or through the API, then promote the version. They grant no access to Campfire data.2
Request them with a nonce
Include the scopes in
scope and send a random nonce, stored in the session with state:3
Verify the ID token
Exchange the code as usual. The response now has an
id_token alongside the access token. Before trusting it, verify it:- The signature, with algorithm
RS256and the key named by the token’skidheader, fromhttps://api.meetcampfire.com/.well-known/jwks.json. issishttps://api.meetcampfire.com.audis your client ID.expis in the future.nonceequals the value you stored.
ID token claims
An ID token describes the person, not the workspace. To learn which workspace they chose, call the permissions endpoint with the access token.
Refreshing a connection that holds
openid returns a fresh ID token too, without a nonce. The client_credentials grant never returns one.
UserInfo endpoint
You can also read the same claims with the access token:401 with WWW-Authenticate: Bearer error="invalid_token" for an expired or revoked token, and 403 with error="insufficient_scope" if the connection was not granted openid.
Discovery
OpenID Connect libraries can configure themselves fromhttps://api.meetcampfire.com/.well-known/openid-configuration, which lists the issuer, endpoints, jwks_uri, userinfo_endpoint, and supported algorithms. Campfire signs ID tokens with RS256 and uses public subject identifiers. Cache the JWKS, and re-fetch it when a token names a kid you don’t have.
Part 3: Manage connections
Viewing connected apps
Apps connected to your account are listed under Settings > Connections. On the All Connections tab, an app with a category appears in that category’s section (and on the category’s tab) alongside Campfire’s built-in integrations; an app without one appears in the Apps section. The Active tab lists every connected app under Apps, with the last time each one was used.

Disconnecting an app
Click Disconnect on the app’s connection page and confirm. The app’s tokens stop working immediately, and it has to be authorized again to reconnect.
401:
401 on a refresh, or on a request made right after a refresh, as a lost connection and prompt the person to reconnect.
When access ends automatically
Besides an explicit disconnect, Campfire revokes a connection’s tokens when:
Widening an app’s permissions never changes existing connections. People keep what they originally granted until they authorize again.
Part 4: Manage your app
On Settings > Developer > Apps, click Manage on an app’s card to open its page. The tabs are:
Versions and approval
An app’s details and permissions are versioned, so you can change them without affecting the people who already use your app. The versioned fields are: name, tagline, category, description, icon, redirect URLs, Connect URL, Manage URL, and permissions.- Production is the version people authorize, and it’s what the app uses in every workspace.
- Development is your draft. There’s at most one. The first time you save a change on the Details or Permissions tab (or in the manifest’s
appsection), Campfire copies production into a new development version and saves your change there. Later saves update the same draft.


Testing a development version
You can authorize the development version before it goes live. Add a redirect URL that only the draft has, for example your staging callback, and start the flow with thatredirect_uri. Campfire picks the version from the redirect URL:
- If production registers the
redirect_uri, the person authorizes production. Production always wins when both match. - If only the development version registers it, the person authorizes the draft, with the draft’s name, details and permissions. Development authorizations are limited to your own workspace.
- If neither does, the request is rejected.
Promoting
Click Promote vN to make the draft live.
- Private apps are promoted immediately.
- Published or approved apps are submitted to Campfire for review. The button becomes Submit for approval, and the badge shows vN · Pending approval. You can keep testing the draft while it waits. Saving another change withdraws it from review, so you’ll need to submit again.
- If Campfire approves it, the draft becomes production.
- If Campfire requests changes, the badge shows vN · Changes requested, and the app page shows a banner with the reviewer’s message. Edit the draft and submit it again.
Not versioned: allowed domains, the signing secret, buttons, panels, navigation, event subscriptions, and the Published toggle. These take effect as soon as you save.
Rotating the client secret
Choose Actions > View credentials. After the first time, the secret is hidden. Click Rotate secret to generate a new one, which is shown once.
Deleting
Actions > Delete app asks for confirmation. The app’s credentials stop working immediately and every connection is removed. This cannot be undone.Private vs. published apps
Publishing is a two-step process. Turn on Published on the Details tab, then contact your Campfire support team to request a review. Until Campfire approves the app, it behaves like a private app. Turning Published off, or losing approval, disconnects every workspace other than your own.
Scopes reference
Scopes have the form<resource>:<tier>, for example invoices:read or bills:write. Request them space-separated in the scope parameter. A higher tier includes lower tiers (write includes draft and read). approve is separate and only covers itself.
Accounting
Accounting
Revenue
Revenue
Reports
Reports
Cash Management
Cash Management
Close Management
Close Management
Organization
Organization
Ember AI
Ember AI
Identity (OpenID Connect)
Identity (OpenID Connect)
These scopes have no tiers and grant no access to Campfire data. They only control what the ID token and UserInfo endpoint return.
Errors and troubleshooting
Authorize endpoint
If theclient_id or redirect_uri is invalid, Campfire can’t safely redirect back to you. It responds with 400 and a JSON detail instead:
All other problems redirect back to your
redirect_uri with error, error_description, and your state:
The consent screen itself can also show Authorization unavailable. This happens if the request expired (the person took more than 10 minutes), was already used, or the person doesn’t belong to the workspace a private app is locked to. Start the flow again from your app.
Token endpoint
Errors follow the OAuth 2.0 format:{"error": "...", "error_description": "..."}.
API requests
Security checklist
- Keep the client secret on your server. Never put it in front-end code, mobile apps, or source control.
- Always send and verify
state. - Use PKCE (
S256) on every authorization. - When you use OpenID Connect, send a
nonce, verify every ID token before trusting it, and key accounts onsub, not email. - Request the fewest scopes you need. Prefer
draftoverwritewhen a human should review changes. - Store tokens encrypted, and save each new refresh token before using the new access token.
- Handle
401by refreshing once, then prompting the person to reconnect. - Rotate the secret immediately if it may have leaked. This also revokes every existing token.
Need help? Contact your Campfire support team and we’re happy to help you build your integration.