---
title: "Retrieve post analytics"
method: GET
path: "/analytics/posts/{post_id}"
tags: ["Analytics"]
---

# Retrieve post analytics

`GET /analytics/posts/{post_id}`

## Request

- Base URL: `https://api.shortsync.app/v1`
- URL: `https://api.shortsync.app/v1/analytics/posts/{post_id}`
- Auth: HTTP bearer

The same shape as one row of `GET /analytics/posts`, for a specific
post. Returns `404` when the post isn't in the resolved workspace
so callers can't probe for arbitrary ids.

## Response `200`

Post analytics.

- object
  - `data` PostAnalytics, required
    - `post_id` string, uuid, required: UUID of the post row. Matches the id returned by `POST /posts`.
    - `platform` 'instagram' | 'tiktok' | 'youtube' | 'facebook' | 'snapchat' | 'pinterest' | 'threads' | 'twitter' | 'bluesky' | 'linkedin' | 'reddit' | 'telegram' | 'mastodon' | 'discord' | 'tumblr' | 'pixelfed' | 'google_business', required
    - `platform_post_id` string, nullable, required: The upstream platform's id for the post (e.g. TikTok's video_id, YouTube's videoId).
    - `connection_id` string, nullable, required
    - `published_at` string, date-time, nullable, required
    - `permalink` string, nullable, required: Best-effort URL to the post on the source platform. `null` when we can't construct one.
    - `title` string, nullable
    - `caption` string, nullable
    - `thumbnail_url` string, nullable
    - `metrics` PostAnalyticsMetrics, required: Every numeric field uses `null` (not `0`) to mean "unknown / scope missing / not applicable" and `0` to mean "genuinely zero". Don't coalesce `null` to `0` in aggregations you display.
      - `views` integer, nullable
      - `likes` integer, nullable
      - `comments` integer, nullable
      - `shares` integer, nullable
      - `saves` integer, nullable
      - `reach` integer, nullable
      - `impressions` integer, nullable
      - `watch_time_seconds` integer, nullable
      - `avg_watch_time_seconds` integer, nullable
      - `engagement_rate` number, float, nullable: Percentage engagement rate derived by ShortSync as (likes + comments) / views * 100. This is not a metric returned directly by any platform API; it is generated independently by ShortSync from the underlying public stats.
    - `fetch_status` string, required: `success` when the row has any live data; `failed` when the last sync couldn't get anything for it (post deleted on the platform, connection revoked, etc.).
    - `fetched_at` string, date-time, nullable, required

## Other responses

- `401`: Missing, malformed, or revoked token.
- `403`: Token is valid but cannot access this resource. Common cases: - `INSUFFICIENT_SCOPE` - token lacks the required scope. - `WORKSPACE_NOT_ALLOWED` - account token is allowlisted to other workspaces.
- `404`: Resource does not exist or is not visible to this token.
- `429`: Per-key sliding-window rate limit (60 req/min), per-org monthly request quota, or per-user upload cap was hit. `RATE_LIMIT_EXCEEDED` carries the window headers; `QUOTA_EXCEEDED` carries `details.quota` (which counter), `used`, `limit`, `resets_at`, and `upgrade_url`. `UPLOAD_QUOTA_EXCEEDED` (Free tier on `POST /posts` only) carries the same shape plus `details.remaining`.

---

[API](https://skmtc.dev/shortsync/apis/shortsync-api.md) · [All operations](https://skmtc.dev/shortsync/apis/shortsync-api/llms.txt) · [OpenAPI document](https://skmtc.dev/shortsync/apis/shortsync-api/revisions/71fdaef1e400?raw)
