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.comProtocol
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":
- —Queries use
GETwith input URL-encoded in theinputquery parameter:?batch=1&input={"0":{...}} - —Mutations use
POSTwith input in the JSON body:{"0": {...}} - —Responses are arrays indexed to match:
[{"result": {"data": ...}}]
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}}}
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:
bashnpm 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:
| Token | Lifetime | Purpose |
|---|---|---|
| Access token | 1 hour | Sent as Bearer token in Authorization header |
| Refresh token | 30 days | Used 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:
bashcurl -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"
SDK Authentication Pattern
For SDK users, obtain a token via the CLI and refresh it before each API call:
typescriptimport { 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.
bashcurl -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
bashcurl 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:
bashcurl -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
typescriptimport { 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.
bashnpm install @chapter-two-music/sdk
Client Methods
| Method | Description |
|---|---|
| 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
typescriptimport { 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
typescriptimport { 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:
bashc2 endpoints # List all endpoints c2 endpoints --groups # Grouped by namespace c2 describe rightsholder.list # Detailed info for an endpoint