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

# Metrics

> Pull a compact analytics summary, trigger a fresh LinkedIn sync.

## GET /api/v1/metrics/summary

Compact KPI snapshot + top N posts by impressions.

**Query params**

| Param | Type | Default | Values |
| - | - | - | - |
| `period` | string | `30d` | `1d`, `7d`, `30d`, `90d`, `180d`, `365d`, `all` |
| `top_n` | int | `5` | Clamped 1–20 |

```bash theme={null}
curl "https://api.magicpost.in/api/v1/metrics/summary?period=30d&top_n=5" \
  -H "Authorization: Bearer mp_xxx"
```

**Response**

```json theme={null}
{
  "period": "30d",
  "profile": {
    "name": "Naïlé Titah",
    "headline": "CEO @MagicPost",
    "followers_total": 24174
  },
  "access": {
    "linkedin_connected": true,
    "impressions_access": true,
    "followers_data_available": true
  },
  "followers": {
    "current_total": 24174,
    "gained": 327,
    "available_range_gained": 327,
    "data_available": true,
    "data_points": 30,
    "daily": [
      { "date": "2026-07-26", "gained": 9 },
      { "date": "2026-07-27", "gained": 14 }
    ],
    "coverage": {
      "complete": true,
      "date_from": "2026-06-28",
      "date_to": "2026-07-27"
    }
  },
  "totals": {
    "posts_count": 10,
    "impressions": 56147,
    "likes": 740,
    "comments": 319,
    "reposts": 11
  },
  "averages_per_post": {
    "impressions": 5614.7,
    "likes": 74.0,
    "comments": 31.9,
    "reposts": 1.1
  },
  "top_posts": [
    {
      "linkedin_share_urn": "urn:li:share:...",
      "post_url": "https://linkedin.com/feed/update/urn:li:...",
      "posted_at": "2026-05-12T07:30:00Z",
      "text_preview": "First 200 chars of the post...",
      "num_impressions": 12500,
      "num_likes": 180,
      "num_comments": 45,
      "num_reposts": 3
    }
  ]
}
```

`followers.gained` is the sum of LinkedIn's follower snapshots only when the
whole selected period is covered. It is `null`, not `0`, when coverage is
partial or unavailable. `followers.available_range_gained` contains the sum
for the explicit `coverage.date_from` to `coverage.date_to` range.

Use `coverage.complete` and `data_available` to distinguish full coverage,
partial history, missing data, and measured zero growth. The `all` period
cannot guarantee lifetime coverage and therefore returns `gained: null`.

`followers.daily` contains the profile's total followers gained for each
available day. These values are not attributed to individual posts. For a
daily roll-up, request a multi-day period such as `7d` or `30d` once and use
the returned points instead of making one `1d` request per day.

## GET /api/v1/linkedin-post-metrics

List per-post metrics for the connected LinkedIn profile over an inclusive
date range. This includes posts published natively on LinkedIn and posts
published through MagicPost once they have been imported into MagicPost
analytics.

**Query params**

| Param | Type | Default | Values |
| - | - | - | - |
| `date_from` | string | required | ISO date (`YYYY-MM-DD`), inclusive |
| `date_to` | string | required | ISO date (`YYYY-MM-DD`), inclusive |
| `limit` | int | `50` | Clamped 1–100 |
| `cursor` | string | — | Opaque cursor returned by the previous page |

```bash theme={null}
curl "https://api.magicpost.in/api/v1/linkedin-post-metrics?date_from=2026-05-01&date_to=2026-06-30&limit=50" \
  -H "Authorization: Bearer mp_xxx"
```

The response does not run an exact count over the LinkedIn posts table.
Follow `next_cursor` while `has_more` is `true`.

```json theme={null}
{
  "date_from": "2026-05-01",
  "date_to": "2026-06-30",
  "timezone": "UTC",
  "limit": 50,
  "has_more": false,
  "next_cursor": null,
  "posts": [
    {
      "linkedin_activity_id": "7457337929711902720",
      "linkedin_post_id": "7457337929711902720",
      "post_url": "https://www.linkedin.com/feed/update/urn:li:activity:...",
      "posted_at": "2026-06-12T07:30:00Z",
      "text_preview": "First 200 characters...",
      "impressions": 12500,
      "impressions_available": true,
      "reactions": 180,
      "comments": 45,
      "reposts": 3,
      "impressions_updated_at": "2026-06-12T08:00:00Z",
      "advanced_metrics_available": true,
      "advanced_metrics_updated_at": "2026-06-15T07:30:00Z",
      "reach": 8400,
      "saves": 21,
      "link_clicks": 64,
      "premium_cta_clicks": 0,
      "profile_views": 37,
      "sends": 12,
      "followers_gained": 9
    }
  ]
}
```

`linkedin_activity_id` is the stable identifier used by the MagicPost LinkedIn
analytics store. `linkedin_post_id` can be null for some native or company
posts. Neither identifier is a MagicPost post UUID. `impressions_available`
distinguishes an uncollected impression count (`null`) from a measured value
of `0`.

The extended metrics (`reach`, `saves`, `link_clicks`, `premium_cta_clicks`,
`profile_views`, `sends`, `followers_gained`) are `null` until LinkedIn has
been asked for them (`advanced_metrics_available`). `sends` and
`followers_gained` are collected from October 2026 onward, so older posts
return `null`. On a company page, LinkedIn does not measure `saves`,
`premium_cta_clicks`, `profile_views`, `sends` or `followers_gained`: they are
`null` and listed in `advanced_metrics_unavailable_for_profile_type`.

## GET /api/v1/metrics/freshness

Check the latest stored LinkedIn post-metrics timestamp without triggering a
refresh. Use this endpoint before `/refresh-posts`.

```bash theme={null}
curl "https://api.magicpost.in/api/v1/metrics/freshness?max_age_minutes=60" \
  -H "Authorization: Bearer mp_xxx"
```

**Response**

```json theme={null}
{
  "last_metrics_updated_at": "2026-08-05T08:12:00Z",
  "checked_at": "2026-08-05T08:42:00Z",
  "age_seconds": 1800,
  "max_age_minutes": 60,
  "data_available": true,
  "is_fresh": true,
  "should_refresh": false
}
```

Skip the refresh when `should_refresh` is `false`. If no metrics timestamp is
available, `data_available` is `false` and `should_refresh` is `true`.

## POST /api/v1/refresh-posts

Trigger a fresh pull of LinkedIn data. **Rate-limited at 5 req/min.**

```bash theme={null}
curl -X POST https://api.magicpost.in/api/v1/refresh-posts \
  -H "Authorization: Bearer mp_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
```

**Response**

```json theme={null}
{ "success": true, "job_id": "uuid", "status": "pending" }
```

Use the returned `job_id` to poll the status endpoint until completion.

## GET /api/v1/refresh-posts/\<job\_id>

Poll refresh job status.

```bash theme={null}
curl https://api.magicpost.in/api/v1/refresh-posts/uuid \
  -H "Authorization: Bearer mp_xxx"
```

**Response**

```json theme={null}
{
  "job_id": "uuid",
  "processed": 50,
  "total": 50,
  "status": "finished",
  "error": null
}
```

`status` is one of `pending`, `running`, `finished`, `success`, `error`.
Returns 404 if the job doesn't exist OR was started by another user.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.