API Reference

The ChapterTwo API provides programmatic access to the music royalty management platform. You can manage rightsholders, query royalty analytics, upload statements, and more.

Base URL

https://api.prod.chaptertwo.com

Protocol

The API uses tRPC over HTTP. All endpoints are accessed via the /trpc/{procedure} path using tRPC's HTTP batch protocol.

tRPC Batch Format

Every request uses the ?batch=1 query parameter. This enables tRPC's batching protocol, where inputs and outputs are indexed by number. For a single procedure call, your input is keyed as "0":

Organization Scoping

Most procedures require an organizationId field inside the input body. This is how the server resolves which organization you are acting on. The SDK and CLI inject this automatically. For raw HTTP calls, include it in your input:

json
{"0": {"organizationId": "your-org-uuid", "pagination": {"page": 1, "limit": 10}}}
The x-organization-id header is accepted for convenience but the server reads organizationId from the procedure input. Always include it in the input body for raw HTTP calls.

Authentication

OAuth 2.0 (recommended)

The easiest way to authenticate is via the CLI, which handles the full OAuth 2.0 + PKCE flow automatically:

bash
npm install -g @chapter-two-music/cli c2 auth login

After login, you can retrieve a fresh access token at any time with c2 auth token for use in scripts or the SDK.

Token Lifecycle

The OAuth flow issues two tokens:

TokenLifetimePurpose
Access token1 hourSent as Bearer token in Authorization header
Refresh token30 daysUsed to obtain new access tokens without re-login

Access tokens must be refreshed before they expire. The CLI handles this automatically. For custom integrations, call the token endpoint with grant_type=refresh_token:

bash
curl -X POST https://mcp.chaptertwo.com/api/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN"
Refresh tokens rotate on each use — the response includes a new refresh token that replaces the previous one. After 30 days, the user must re-authenticate.

SDK Authentication Pattern

For SDK users, obtain a token via the CLI and refresh it before each API call:

typescript
import { createClient } from '@chapter-two-music/sdk'; // Option 1: Use a token from the CLI // Run: c2 auth token const client = createClient({ apiUrl: 'https://api.prod.chaptertwo.com', token: process.env.C2_TOKEN!, // from `c2 auth token` orgId: 'your-org-uuid', }); // Option 2: Implement refresh in your app async function getFreshToken(refreshToken: string) { const res = await fetch('https://mcp.chaptertwo.com/api/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, }), }); const data = await res.json(); // data.access_token (1hr), data.refresh_token (rotated) return data; }

API Key

For service-to-service integrations, API keys provide long-lived access without token refresh. API keys must be requested from ChapterTwo — contact support@chaptertwo.com.

bash
curl -H "x-api-key: YOUR_API_KEY" \ -H "x-organization-id: YOUR_ORG_ID" \ https://api.prod.chaptertwo.com/trpc/health

Examples

Check API Health

bash
curl https://api.prod.chaptertwo.com/trpc/health

List Rightsholders

bash
# organizationId goes in the input, keyed as "0" for tRPC batch curl -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ "https://api.prod.chaptertwo.com/trpc/rightsholder.list?batch=1&input=$(python3 -c "import urllib.parse, json; print(urllib.parse.quote(json.dumps({'0': {'organizationId': '$ORG_ID', 'pagination': {'page': 1, 'limit': 10}}})))")"

Or with the input URL-encoded by hand:

bash
curl -H "Authorization: Bearer $TOKEN" \ "https://api.prod.chaptertwo.com/trpc/rightsholder.list?batch=1&input=%7B%220%22%3A%7B%22organizationId%22%3A%22YOUR_ORG_ID%22%2C%22pagination%22%3A%7B%22page%22%3A1%2C%22limit%22%3A10%7D%7D%7D"

Using the SDK

typescript
import { createClient } from '@chapter-two-music/sdk'; const client = createClient({ apiUrl: 'https://api.prod.chaptertwo.com', token: process.env.C2_TOKEN!, orgId: 'your-org-uuid', }); // List rightsholders const result = await client.query('rightsholder.list', { pagination: { page: 1, limit: 10 }, }); // Create a rightsholder const created = await client.mutate('rightsholder.create', { name: 'New Artist', }); // Auto-detect query vs mutation const detail = await client.call('rightsholder.getById', { id: 'uuid-here', });

Using the CLI

bash
# List rightsholders c2 rightsholder.list # Query with input c2 api rightsholder.getById -i '{"id": "uuid-here"}' # Export data c2 api export.trigger -i '{"type": "earnings"}'

SDK

The TypeScript SDK (@chapter-two-music/sdk) provides a typed client for the API.

bash
npm install @chapter-two-music/sdk

Client Methods

MethodDescription
client.query(procedure, input?)Call a query procedure (GET)
client.mutate(procedure, input?)Call a mutation procedure (POST)
client.call(procedure, input?)Auto-detect query vs mutation
client.setToken(token)Update the bearer token (e.g. after refresh)
client.setOrgId(orgId)Switch organization context

Endpoint Discovery

typescript
import { ENDPOINTS, listEndpoints, getEndpointMeta, isValidEndpoint, } from '@chapter-two-music/sdk'; // All available endpoints console.log(ENDPOINTS); // Endpoints in a namespace console.log(listEndpoints('rightsholder')); // Check if an endpoint exists console.log(isValidEndpoint('rightsholder.list')); // true // Get endpoint metadata const meta = getEndpointMeta('rightsholder.list');

Error Handling

typescript
import { ChapterTwoError } from '@chapter-two-music/sdk'; try { await client.query('rightsholder.getById', { id: 'invalid' }); } catch (err) { if (err instanceof ChapterTwoError) { console.error(err.message); console.error(err.statusCode); } }

Available Endpoints

See the Endpoints page for the full list of available API procedures with input schemas and examples.

You can also explore endpoints via the CLI or SDK:

bash
c2 endpoints # List all endpoints c2 endpoints --groups # Grouped by namespace c2 describe rightsholder.list # Detailed info for an endpoint