General
You can call the Capacities API with any HTTP client. We also ship official SDKs that handle authentication headers, request validation, and typed responses.
The TypeScript SDK is published on npm as @capacities/api.
npm install @capacities/api
The client sets Authorization and X-Capacities-Api-Version on every request. Failed responses throw CapacitiesApiError with code, status, and message — see Errors.
The SDK supports two authentication methods. Both send a standard Authorization: Bearer <token> header.
The simplest option. Generate a token in Settings > Capacities API and pass it directly. Tokens do not expire.
import { CapacitiesClient } from '@capacities/api'
const client = new CapacitiesClient({
apiToken: process.env.CAPACITIES_API_TOKEN!,
})
Use this for scripts and server-side automations where a single user's credentials are acceptable. See Personal API token for how to generate one.
Use this when your product acts on behalf of end users. The SDK manages token refresh automatically. See OAuth 2.0 for the full flow and how to get a client_id.
What you receive after the OAuth flow
After a user completes the Authorization Code + PKCE flow, your server receives:
{
"access_token": "eyJ...",
"refresh_token": "abc...",
"expires_in": 3600,
"token_type": "Bearer"
}
Convert this into the OAuthTokens shape expected by the SDK:
import type { OAuthTokens } from '@capacities/api'
const tokens: OAuthTokens = {
accessToken: data.access_token,
refreshToken: data.refresh_token,
// Store expiresAt so the SDK can refresh proactively before the token expires.
expiresAt: Math.floor(Date.now() / 1000) + data.expires_in,
}
Initialising the client
import { CapacitiesClient } from '@capacities/api'
const client = new CapacitiesClient({
oauth: {
tokens,
clientId: 'your_client_id',
onTokenRefreshed: async (newTokens) => {
// Both fields can change on every refresh. Persist the full set.
await db.oauthTokens.upsert({ userId, ...newTokens })
},
},
})
How refresh works
| Trigger | Behaviour |
|---|---|
Proactive (expiresAt within 60 s) | SDK refreshes before sending the next request |
Reactive (server returns 401) | SDK refreshes and retries the request once |
| Concurrent requests | A single refresh call is shared; all waiting requests use the new token |
Refresh tokens rotate on every use: the server returns a new refresh_token each time. The onTokenRefreshed callback receives the complete replacement OAuthTokens set. Persist both accessToken and refreshToken.
Error handling
import { CapacitiesOAuthError, CapacitiesApiError } from '@capacities/api'
try {
const space = await client.space.get()
} catch (err) {
if (err instanceof CapacitiesOAuthError) {
// Refresh token expired or revoked. Re-initiate the OAuth flow.
redirectToOAuthLogin()
} else if (err instanceof CapacitiesApiError) {
// API-level error (4xx / 5xx). Inspect err.status, err.code, err.message.
console.error(err.code, err.message)
}
}
CapacitiesOAuthError is thrown when the refresh request itself fails (network error, expired refresh token, revoked connection). Treat it as a signal to start a new authorisation flow.
Restoring tokens between sessions
Store the full OAuthTokens object in your database. On each new process or request, restore it:
const stored = await db.oauthTokens.findByUserId(userId)
const client = new CapacitiesClient({
oauth: {
tokens: stored,
clientId: 'your_client_id',
onTokenRefreshed: async (newTokens) => {
await db.oauthTokens.update({ userId, ...newTokens })
},
},
})
Request examples for every endpoint live in the API Reference.
Open any operation in the reference UI and switch to the TypeScript SDK code sample. Samples use CapacitiesClient method names that mirror the REST paths (for example capacities.object.get, capacities.blocks.append).
Only the TypeScript SDK is available today. For other stacks, use the reference's examples. You can also request a client library for your language of choice on our feedback board.
Create a ticket on our feedback board. - Let us know if you have an idea for a feature, improvement or think there is something missing.
Request additions to the documentation. - If your questions are not getting answered, let us know and we will extend the documentation.