@broadwayroyalty/sdk
v1.1.0
Published
Broadway Royalty Platform — official TypeScript SDK for the /v1 API
Maintainers
Readme
@broadwayroyalty/sdk
Official TypeScript SDK for the Broadway Royalty Platform /v1 API.
Install
npm install @broadwayroyalty/sdkRequires Node 18+.
Quick start
import { BwrpClient } from '@broadwayroyalty/sdk';
const client = new BwrpClient({
base_url: 'https://api.broadwayroyalty.example',
api_key: process.env.BWRP_API_KEY!,
});
// Evaluate a settlement from a signed box-office observation
const settlement = await client.settlements.evaluate({
observation: {
show_id: 'the_meridian',
cycle_start: '2026-04-20T00:00:00Z',
cycle_end: '2026-04-26T23:59:59Z',
gross_cents: 78_000_000,
observation_id: 'nightly-2026-04-26',
},
key_id: process.env.BWRP_SIGNING_KEY_ID!,
private_key_pem: process.env.BWRP_SIGNING_PRIVATE_PEM!,
});
console.log(settlement.settlement_id, settlement.total_distributed_cents);Review-and-countersign (Phase 6E)
When a submitting partner is opted into review, the response carries
settlement_status: "pending_review" and downstream webhooks + state-machine
events are deferred until a countersigner runs approve().
// Countersigner side
const { settlements } = await client.settlements.listPending();
for (const s of settlements) {
await client.settlements.approve({
settlement_id: s.settlement_id,
key_id: process.env.REVIEWER_KEY_ID!,
private_key_pem: process.env.REVIEWER_PRIVATE_PEM!,
notes: 'Verified against bank statement',
});
}reject() has the same signature but fires settlement.rejected so the
submitter can address and re-submit. Every decision is signed with the
reviewer's Ed25519 key; the append-only log is available via
client.settlements.listApprovals(id).
Multi-sig recoupment declaration
The state machine will not flip a show to post-recoupment unless the configured number of designated declarants have submitted signed declarations attesting recoupment has been reached.
// Each declarant (producer, lead investor, GM) runs this independently
await client.recoupment.declare({
show_id: 'the_meridian',
declared_target_cents: 1_200_000_000, // $12M capitalization
declared_cumulative_cents: 1_205_000_000, // observed to date
notes: 'Confirmed against Q2 audit',
key_id: process.env.DECLARANT_KEY_ID!,
private_key_pem: process.env.DECLARANT_PRIVATE_PEM!,
});
const status = await client.recoupment.getStatus('the_meridian');
console.log(status.threshold_met, status.approvals_count, status.threshold_count);Webhook receiver
import { verifyWebhookSignature } from '@broadwayroyalty/sdk';
app.post('/bwrp-webhook', (req, res) => {
const signature = req.header('x-bwrp-signature')!;
const raw = req.rawBody; // must be the untouched request body bytes
const ok = verifyWebhookSignature({
raw_body: raw,
header_signature: signature,
signing_secret_b64: process.env.BWRP_WEBHOOK_SECRET_B64!,
});
if (!ok) return res.status(401).send('bad signature');
const event = JSON.parse(raw);
// handle event.event_type ...
res.status(200).send('ok');
});Resources
Settlements
client.settlements.evaluate(input)— sign + submit a box-office observationclient.settlements.get(id)client.settlements.listPending()— countersigner's queueclient.settlements.approve({ settlement_id, key_id, private_key_pem, notes? })client.settlements.reject({ settlement_id, key_id, private_key_pem, notes? })client.settlements.listApprovals(settlement_id)— append-only decision log
Recoupment
client.recoupment.declare({ show_id, declared_target_cents, declared_cumulative_cents, ... })client.recoupment.listDeclarations(show_id)client.recoupment.listDeclarants(show_id)client.recoupment.getStatus(show_id, { threshold_count? })
Rules
client.rules.draft({ rule, effective_at })client.rules.listVersions(show_id)
Webhooks
client.webhooks.subscribe({ target_url, events })client.webhooks.list()/client.webhooks.unsubscribe(id)
Custody
client.custody.verify(chain_id)client.custody.replayPackage(chain_id)
Meta
client.health()/client.openapi()
Signing helpers
Standalone helpers exported for callers who want to sign without going through the client:
signObservation({ observation, key_id, private_key_pem })signApprovalDecision({ decision, key_id, private_key_pem })signRecoupmentDeclaration({ declaration, key_id, private_key_pem })canonicalize(value)— RFC 8785 JCS canonical JSON
Errors
Any non-2xx response is thrown as a BwrpApiError carrying status, code, and the parsed response body.
try {
await client.settlements.evaluate(...);
} catch (err) {
const e = err as import('@broadwayroyalty/sdk').BwrpApiError;
console.error(e.status, e.code, e.message);
}