@trillboards/api-client
v0.3.0
Published
Official TypeScript SDK for the Trillboards DOOH Partner API
Maintainers
Readme
@trillboards/api-client
Official TypeScript SDK for the Trillboards DOOH Partner API.
Installation
npm install @trillboards/api-clientRequires Node.js 18+ (uses native fetch and crypto). Zero runtime dependencies.
Quick Start
import { TrillboardsClient } from '@trillboards/api-client';
const client = new TrillboardsClient({
apiKey: 'trb_partner_xxxxx',
});
// List screens
const { data: screens } = await client.screens.list({ limit: 10 });
// Get analytics
const { data: analytics } = await client.analytics.get({ period: 'week' });
// Get earnings
const { data: earnings } = await client.earnings.get({ period: 'month' });Resources
| Resource | Methods |
|----------|---------|
| client.screens | list, get, create, delete |
| client.devices | list, get, create, delete, heartbeat |
| client.impressions | create, createBatch |
| client.analytics | get |
| client.earnings | get |
| client.webhooks | list, create, update, delete, test |
| client.fleet | pushCommand, listCommands |
| client.audience | getLive, getHeatmap, getStats |
| client.data | getVenueIntelligence, getUsage |
| client.errors | list, get |
| client.billing | get, getStripeStatus, requestPayout |
Error Handling
import { TrillboardsClient, TrillboardsError } from '@trillboards/api-client';
try {
await client.screens.get('nonexistent');
} catch (err) {
if (err instanceof TrillboardsError) {
console.log(err.code); // 'screen_not_found'
console.log(err.statusCode); // 404
console.log(err.docsUrl); // 'https://api.trillboards.com/docs/errors#screen_not_found'
if (err.isRateLimited) {
const retryAfter = err.retryAfter; // seconds from Retry-After header
}
}
}Webhook Verification
Trillboards webhooks carry a Stripe-style compound signature header
X-Trillboards-Signature: t=<timestamp>,v0=<hex>,v1=<hex> and a separate
X-Trillboards-Timestamp: <unix_seconds> for redundancy.
The verifier accepts either format and rejects payloads outside a 300-second replay window by default.
import { Webhooks } from '@trillboards/api-client';
// Use express.raw for the webhook route so req.body is the exact signed bytes
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = Webhooks.constructEvent(
req.body, // raw Buffer or string (NOT JSON.parsed)
req.headers, // IncomingHttpHeaders — case-insensitive lookup
process.env.WEBHOOK_SECRET!,
);
console.log('Event:', event.type, event.data);
res.sendStatus(200);
} catch (err) {
// TrillboardsError with code "webhook_signature_invalid"
res.sendStatus(401);
}
});Override the replay-window tolerance (default 300s):
const event = Webhooks.constructEvent(req.body, req.headers, secret, {
tolerance: 600, // 10 minutes
});Upgrading from 0.2.0: the 0.2.0 call shape
Webhooks.constructEvent(payload, signatureString, secret)produced verification failures against the production server because the server signs${timestamp}.${payload}while the 0.2.0 verifier signedpayloadonly. The 0.3.0 verifier handles both formats AND adds replay protection. Migrate to the newWebhooks.constructEvent(payload, req.headers, secret)call shape. The 0.2.0 shape is preserved asWebhooks.constructEventLegacyfor one minor version (logs a deprecation warning).
Full webhook contract: https://api.trillboards.com/docs/integrations/webhook-signature-verification.md
Configuration
const client = new TrillboardsClient({
apiKey: 'trb_partner_xxxxx', // Required
baseUrl: 'https://api.trillboards.com', // Optional, defaults to production
version: '2024-01-15', // Optional, sent as Trillboards-Version header
});License
MIT
