Skip to content

MrRefactoring/confluence.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

101 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Confluence.js logo

NPM version NPM downloads per month build status license

Type-safe Confluence REST API client for Node.js and browsers

Documentation · Getting Started · API Reference · Русский

About

confluence.js covers both Confluence Cloud REST APIs from one package:

Both are first-class. Atlassian has not deprecated v1, and the two cover different ground: v1 still owns what v2 has no equivalent for, and v2 owns everything Atlassian has moved forward.

Every response is validated at runtime against a Zod 4 schema derived from Atlassian's OpenAPI spec, so API drift surfaces as a ZodError rather than as undefined three call frames later.

  • ESM-only, Node ≥ 22, no polyfills — the transport is the built-in fetch
  • Tree-shakable: only the endpoints you import reach your bundle
  • One runtime dependency: zod

Table of Contents

Getting Started

npm install confluence.js
import { createV2Client } from 'confluence.js';

const confluence = createV2Client({
  host: 'https://your-domain.atlassian.net',
  auth: {
    type: 'basic',
    email: 'YOUR@EMAIL.ORG',
    apiToken: 'YOUR_API_TOKEN',
  },
});

const page = await confluence.page.createPage({
  spaceId: '123456',
  title: 'Project Overview',
  body: {
    representation: 'storage',
    value: '<p>Welcome to our project documentation</p>',
  },
});

console.log(`Page created: ${page.title}`);

host is your bare site URL. The API path (/wiki/api/v2, /wiki/rest/api) belongs to the request, not to host — so one host serves both versions.

Authentication

Basic

Create an API token in Atlassian account settings:

const confluence = createV2Client({
  host: 'https://your-domain.atlassian.net',
  auth: { type: 'basic', email: 'YOUR@EMAIL.ORG', apiToken: 'YOUR_API_TOKEN' },
});

OAuth 2.0 (3LO)

Hand over your app credentials and a refresh token. The client refreshes before expiry, retries once on a 401, and resolves the cloud id itself:

const confluence = createV2Client({
  auth: {
    type: 'oauth2',
    clientId: 'YOUR_CLIENT_ID',
    clientSecret: 'YOUR_CLIENT_SECRET',
    refreshToken: 'YOUR_REFRESH_TOKEN',
    // Atlassian rotates the refresh token on every refresh — persist the new one.
    onTokenRefresh: ({ refreshToken }) => tokenStore.save(refreshToken),
  },
});

No host: 3LO tokens only work through api.atlassian.com, never on your site's own domain, so the client builds that URL from the cloud id. Pass cloudId or siteUrl if the token can reach more than one site.

confluence.js also exports the flow itself — generateAuthorizationUrl, parseCallbackUrl, exchangeAuthorizationCode, refreshOAuth2Token and getAccessibleResources. See the OAuth 2.0 guide — scopes differ between v1 and v2, and refresh tokens rotate.

For a bearer token from somewhere other than 3LO, hand over a resolver — called per request — and a hook to re-derive auth after a 401:

const confluence = createV2Client({
  host: 'https://your-domain.atlassian.net',
  auth: { type: 'bearer', getToken: () => tokenStore.current() },
  getAuthOn401: async () => ({ type: 'bearer', token: await refresh() }),
});

JWT (Atlassian Connect) is not supported in 3.x. See MIGRATION.md.

Two ways to use it

A client object — the whole API behind namespaces:

import { createV2Client } from 'confluence.js';

const confluence = createV2Client({ host, auth });

await confluence.page.getPages({ spaceId: ['123'] });
await confluence.space.getSpaces({ limit: 25 });

Flat functions — the same endpoints as standalone functions taking a client. Nothing you do not import reaches your bundle:

import { createClient } from 'confluence.js/core';
import { getPages } from 'confluence.js/v2';

const client = createClient({ host, auth });

await getPages(client, { spaceId: ['123'] });

One client drives both versions:

import { createClient } from 'confluence.js/core';
import { getPages } from 'confluence.js/v2';
import { getGroups } from 'confluence.js/v1';

const client = createClient({ host, auth });

await getPages(client, {});   // → /wiki/api/v2/pages
await getGroups(client, {});  // → /wiki/rest/api/group

Entry points

Import What it gives you
confluence.js createV1Client, createV2Client, ApiError, config types
confluence.js/v2 v2 flat functions, parameter and response types
confluence.js/v1 v1 flat functions, parameter and response types
confluence.js/core createClient, transport types, OAuth helpers

confluence.js/v1 and confluence.js/v2 are not re-exported from the root: the two versions collide on a few names (createSpace, getTasks).

Choosing between v1 and v2

Reach for v2 by default — it is where Atlassian is investing. It covers pages, blog posts, custom content, whiteboards, databases, folders, comments, attachments, labels, tasks, versions, spaces, space permissions and space roles.

Reach for v1 only for what v2 has no equivalent for: attachment upload (v2 reads attachments but cannot create them), content restrictions, watches, permission checks, content states, groups, relations, CQL search, templates, themes, settings, user properties, audit records and long-running tasks.

v1 is a complement to v2, not the old API kept alive. This package tracks Atlassian's v1 spec as published, and that spec is shrinking: 37 operations that 2.x exposed — getContent, createContent, getSpace among them — are already gone from it, and 33 of those have a v2 equivalent (the map). Expect it to narrow further, and treat a v1 call as something to move to v2 once v2 covers it.

Error handling

Every failure is one of this package's own error types — nothing leaks from fetch. Non-2xx responses throw an ApiError subclass carrying the status and the parsed body; transport faults throw a NetworkError; the OAuth flow throws an OAuthError.

import { isNotFoundError, isRateLimitError } from 'confluence.js';

try {
  await confluence.page.getPageById({ id: 42 });
} catch (error) {
  if (isNotFoundError(error)) return null;
  if (isRateLimitError(error)) await sleep(error.retryAfterMs ?? 60_000);
  throw error;
}

AuthError (401), ForbiddenError (403), NotFoundError (404), RateLimitError (429) and ServerError (5xx) all extend ApiError, so instanceof works — but prefer the isXxx predicates: they survive two copies of the package in one node_modules, where instanceof silently returns false.

A response that does not match its schema throws a ZodError instead. That means Atlassian's API drifted from its own spec, and it is worth an issue.

Retries

Off by default. When enabled, retries cover transport-layer failures only — network errors and 502/503/504:

const confluence = createV2Client({
  host,
  auth,
  retry: { maxAttempts: 3, initialDelayMs: 500, backoffFactor: 2 },
});

4xx is never retried, 429 included: rate limiting is a signal to slow down, not a transient fault to paper over.

Migrating from 2.x

3.0 reworks the public surface — class clients became factories, authentication became auth, callbacks and middlewares are gone, and the v1 surface now follows Atlassian's current spec. See MIGRATION.md for the full map; a codemod handles the mechanical parts:

npx jscodeshift -t node_modules/confluence.js/tools/codemod/v2-to-v3.ts src/

Other Products

License

MIT License © MrRefactoring See LICENSE for details.

About

confluence.js is a powerful Node.JS/Browser module that allows you to interact with the Confluence API very easily

Topics

Resources

Stars

Watchers

Forks

Releases

Used by

Contributors

Languages