> ## Documentation Index
> Fetch the complete documentation index at: https://docs.propal.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Automate reporting

> Build custom dashboards and automated reports with the Metrics API.

This guide shows how to use the Propal Metrics API to build automated reports and custom dashboards.

## Overview

The Metrics API provides read-only access to your organization's analytics:

| Endpoint                     | What it returns                                             |
| ---------------------------- | ----------------------------------------------------------- |
| `/metrics/overview`          | Global KPIs — total proposals, total value, conversion rate |
| `/metrics/pipeline`          | Proposals by deal status (pending, approved, denied)        |
| `/metrics/conversion`        | Conversion rate and funnel data                             |
| `/metrics/sales`             | Sales data by period (daily, weekly, hourly)                |
| `/metrics/team-performance`  | Performance per team member                                 |
| `/metrics/proposal-timing`   | Average time to close, first view                           |
| `/metrics/rejection-reasons` | Why proposals get rejected                                  |

## Quick example: weekly report

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
async function generateWeeklyReport(client) {
  const [overview, pipeline, conversion, sales, timing] = await Promise.all([
    client.request('/metrics/overview').then(r => r.json()),
    client.request('/metrics/pipeline').then(r => r.json()),
    client.request('/metrics/conversion').then(r => r.json()),
    client.request('/metrics/sales?period=weekly').then(r => r.json()),
    client.request('/metrics/proposal-timing').then(r => r.json()),
  ]);

  return {
    generatedAt: new Date().toISOString(),
    kpis: overview.data,
    pipeline: pipeline.data,
    conversionRate: conversion.data,
    weeklySales: sales.data,
    averageClosingTime: timing.data,
  };
}
```

## Building a Slack report bot

Send a weekly summary to Slack every Monday:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import cron from 'node-cron';

const client = new PropalClient(process.env.PROPAL_API_KEY);

// Every Monday at 9 AM
cron.schedule('0 9 * * 1', async () => {
  const report = await generateWeeklyReport(client);

  const message = formatSlackMessage(report);
  await sendToSlack(process.env.SLACK_WEBHOOK_URL, message);
});

function formatSlackMessage(report) {
  const kpis = report.kpis;
  return {
    blocks: [
      {
        type: 'header',
        text: { type: 'plain_text', text: 'Weekly Propal Report' },
      },
      {
        type: 'section',
        fields: [
          { type: 'mrkdwn', text: `*Total Proposals*\n${kpis?.total_proposals ?? 0}` },
          { type: 'mrkdwn', text: `*Conversion Rate*\n${report.conversionRate?.conversion_rate ?? 'N/A'}%` },
          { type: 'mrkdwn', text: `*Avg. Close Time*\n${report.averageClosingTime?.avg_closing_time ?? 'N/A'} days` },
        ],
      },
    ],
  };
}
```

## Building a custom dashboard

Fetch all metrics and display them in your own dashboard:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// API client for your dashboard backend
async function getDashboardData(client) {
  const endpoints = [
    { key: 'overview', path: '/metrics/overview' },
    { key: 'pipeline', path: '/metrics/pipeline' },
    { key: 'conversion', path: '/metrics/conversion' },
    { key: 'dailySales', path: '/metrics/sales?period=daily' },
    { key: 'weeklySales', path: '/metrics/sales?period=weekly' },
    { key: 'teamPerformance', path: '/metrics/team-performance' },
    { key: 'timing', path: '/metrics/proposal-timing' },
    { key: 'rejections', path: '/metrics/rejection-reasons' },
  ];

  const results = await Promise.all(
    endpoints.map(async ({ key, path }) => {
      const response = await client.request(path);
      const { data } = await response.json();
      return [key, data];
    })
  );

  return Object.fromEntries(results);
}
```

## Combining metrics with proposals

For richer reports, combine metrics with actual proposal data:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
async function getTopPerformingProposals(client) {
  const { data: proposals } = await client
    .request('/proposals?status=approved&limit=10')
    .then(r => r.json());

  return proposals.map(p => ({
    title: p.title,
    lead: p.lead_name,
    value: p.opportunity,
    currency: p.currency,
    acceptedAt: p.accepted_at,
    daysToClose: p.accepted_at && p.proposal_created_at
      ? Math.round(
          (new Date(p.accepted_at) - new Date(p.proposal_created_at)) /
          (1000 * 60 * 60 * 24)
        )
      : null,
  }));
}
```

## Exporting to Google Sheets

Use the Google Sheets API to push your Propal data into a spreadsheet:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
async function exportToSheets(client, spreadsheetId) {
  // Fetch all proposals
  const proposals = await fetchAllProposals(client);

  // Format as rows
  const rows = proposals.map(p => [
    p.title,
    p.lead_name,
    p.deal_status,
    p.opportunity,
    p.currency,
    p.proposal_created_at,
    p.accepted_at || '',
  ]);

  // Push to Google Sheets using their API
  await sheets.spreadsheets.values.update({
    spreadsheetId,
    range: 'Proposals!A2',
    valueInputOption: 'RAW',
    resource: { values: rows },
  });
}
```

## Best practices

* **Cache metrics.** Most metrics don't change frequently. Cache them for 5-15 minutes to reduce API calls.
* **Use parallel requests.** Fetch multiple metric endpoints simultaneously with `Promise.all()`.
* **Required scope.** All metrics endpoints require the `metrics:read` scope. You don't need write access.
* **Time ranges.** Some endpoints support `period` parameters (daily, weekly, hourly) to control the granularity.
