v1.0

Building a Syndicator Dashboard

How to build a custom dashboard for syndicators using entity-scoped API keys

This guide shows how to build a syndicator-facing dashboard that displays their portfolio, deal performance, and accounting data — all using a syndicator-scoped API key.

Overview

Syndicator-scoped API keys automatically filter all data to deals where the syndicator has participation. You don’t need to filter manually — the API enforces it.

Key concept: Create an API key with entityType: "syndicator" and entityId: "{syndicatorId}". All API responses are automatically scoped to that syndicator’s deals.

Prerequisites

  • API key with:
    • entityType: syndicator
    • entityId: the syndicator’s ID
    • Scopes: deals:read, payments:read, accounting:read, collections:read

Step 1: Fetch Portfolio Deals

const API_KEY = 'smca_live_...'; // Syndicator-scoped key

// All deals returned are automatically filtered to this syndicator's participations
const res = await fetch('https://api.smartmca.com/api/public/v1/deals?limit=50', {
  headers: { 'Authorization': `Bearer ${API_KEY}` },
});
const { data: deals, meta } = await res.json();

// Display portfolio summary
const totalFunded = deals.reduce((sum, d) => sum + d.fundedAmount, 0);
const totalOutstanding = deals.reduce((sum, d) => sum + d.outstandingBalance, 0);
console.log(`Portfolio: ${deals.length} deals, $${totalFunded} funded, $${totalOutstanding} outstanding`);

Step 2: Deal Performance Detail

async function getDealDetail(dealId) {
  const [deal, payments, schedule] = await Promise.all([
    fetch(`https://api.smartmca.com/api/public/v1/deals/${dealId}`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` },
    }).then(r => r.json()),

    fetch(`https://api.smartmca.com/api/public/v1/deals/${dealId}/payments?limit=100`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` },
    }).then(r => r.json()),

    fetch(`https://api.smartmca.com/api/public/v1/deals/${dealId}/collection-schedule`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` },
    }).then(r => r.json()),
  ]);

  return {
    deal: deal.data,
    recentPayments: payments.data,
    collectionSchedule: schedule.data,
  };
}

Step 3: Syndicator Subledger

View all accounting entries specific to this syndicator:

// Syndicator subledger — all journal entries for this syndicator's participations
const subledger = await fetch(
  `https://api.smartmca.com/api/public/v1/accounting/reports/subledger/syndicator/${syndicatorId}`,
  { headers: { 'Authorization': `Bearer ${API_KEY}` } }
).then(r => r.json());

// Per-deal accounting
const dealAccounting = await fetch(
  `https://api.smartmca.com/api/public/v1/deals/${dealId}/accounting/entries`,
  { headers: { 'Authorization': `Bearer ${API_KEY}` } }
).then(r => r.json());

Step 4: Real-Time Updates with Webhooks

Subscribe to events to keep the dashboard updated:

await fetch('https://api.smartmca.com/api/public/v1/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://your-dashboard.com/webhooks',
    events: [
      'deal.status_changed',
      'payment.received',
      'payment.failed',
    ],
    description: 'Syndicator dashboard updates',
  }),
});

Security Considerations

  • Entity scoping is enforced server-side. Even if a syndicator tries to access a deal they don’t participate in, the API returns 403.
  • Use read-only scopes. Syndicator dashboards typically only need *:read scopes.
  • Rotate keys regularly. Use the key management API to rotate keys without downtime.
  • Never expose API keys in frontend code. Use a backend proxy to make API calls.