Skip to content

Profiles API Reference

The Profiles API allows you to retrieve and manage connected social media profiles. Profiles represent authenticated connections to social media platforms.

MethodEndpointDescription
GET/api/profilesList all profiles
GET/api/profiles/:idGet a single profile (with latest stats)
GET/api/profiles/:id/placementsList placements for a profile
GET/api/profiles/:id/statsGet profile stats timeseries
DELETE/api/profiles/:idDelete/disconnect a profile

A profile represents a connected social media account.

FieldTypeDescription
idstringUnique profile identifier (id)
namestringDisplay name of the connected account
statusstringPlatform connection status: active, expired, inactive (might be disconnected or suspended on a platform)
platformstringPlatform identifier
profile_group_idstringID of the profile group this belongs to
expires_atstring|nullISO 8601 timestamp when the connection expires (if applicable)
post_countintegerNumber of posts made through this profile
avatar_urlstring|nullURL to the profile’s avatar image (resized, hosted by Postproxy). null if not yet downloaded
PlatformAccount type
facebookFacebook Page
instagramInstagram Business/Creator Account
tiktokTikTok Account
linkedinLinkedIn Profile or Company Page
youtubeYouTube Channel
twitterX (Twitter) Account
threadsThreads Account
pinterestPinterest Account
blueskyBluesky Account
telegramTelegram Bot (publishes to channels via placements)
google_businessGoogle Business Profile (publishes to locations via placements)

GET /api/profiles

Retrieves your profiles. Pass profile_group_id to restrict to a single group; omit it to return profiles across every group your API key or OAuth user can access.

NameTypeRequiredDefaultDescription
profile_group_idstringNo-Restrict to profiles in this group. When omitted, returns profiles across every profile group your API key or OAuth user can access.
Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"data": [
{
"id": "prof123abc",
"name": "My Company Page",
"platform": "facebook",
"status": "active",
"profile_group_id": "grp456xyz",
"expires_at": null,
"post_count": 42,
"avatar_url": "https://cdn.postproxy.dev/uploads/avatar_prof123abc.jpg"
},
{
"id": "prof789def",
"name": "@mycompany",
"platform": "instagram",
"status": "expired",
"profile_group_id": "grp456xyz",
"expires_at": "2024-03-15T00:00:00.000Z",
"post_count": 38,
"avatar_url": "https://cdn.postproxy.dev/uploads/avatar_prof789def.jpg"
},
{
"id": "prof321ghi",
"name": "John Doe",
"platform": "linkedin",
"status": "inactive",
"profile_group_id": "grp456xyz",
"expires_at": null,
"post_count": 15,
"avatar_url": null
},
{
"id": "prof654jkl",
"name": "@mycompany",
"platform": "twitter",
"status": "active",
"profile_group_id": "grp456xyz",
"expires_at": null,
"post_count": 127,
"avatar_url": "https://cdn.postproxy.dev/uploads/avatar_prof654jkl.jpg"
}
]
}

The same scoping rule applies to the :id endpoints below (GET /api/profiles/:id, /placements, /stats, and DELETE /api/profiles/:id):

profile_group_id sent?Profile ID lookup scope
YesThe profile must belong to that group
NoResolved across every profile group your API key or OAuth user can access

This mirrors the resolution rule already used by POST /api/posts.


GET /api/profiles/:id

Retrieves a single profile by its ID. The response includes the profile fields plus the latest stats snapshot per placement and (for placement networks) a summary_stats rollup.

For non-placement networks (e.g. bluesky, twitter), latest_stats contains a single entry with placement_id: null and summary_stats is null.

Snapshots are typically refreshed every 23 hours per profile. If latest_stats is empty, the profile has been connected but has not yet been polled for stats.

NameTypeRequiredDescription
idstringYesProfile id
FieldTypeDescription
latest_statsarrayLatest snapshot per placement. One entry for non-placement networks (with placement_id: null). Empty array if no snapshots have been recorded yet.
latest_stats[].placement_idstring|nullPlatform-specific placement ID. null for non-placement networks.
latest_stats[].statsobjectPlatform-specific metrics. See Stats fields by network.
latest_stats[].recorded_atstringISO 8601 timestamp when the snapshot was captured.
summary_statsobject|nullFor placement networks: numeric values summed across the latest snapshot of every placement. null for non-placement networks and when no snapshots exist. Non-numeric values (e.g. channel_title) are omitted from the summary.
summary_stats.statsobjectSummed metrics.
summary_stats.recorded_atstringISO 8601 timestamp of the most recent placement snapshot included in the summary.
Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles/prof123abc" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"id": "prof_li_001",
"name": "Acme Inc",
"platform": "linkedin",
"status": "active",
"profile_group_id": "grp456xyz",
"expires_at": null,
"post_count": 42,
"avatar_url": "https://cdn.postproxy.dev/uploads/avatar_prof_li_001.jpg",
"latest_stats": [
{
"placement_id": "108520199",
"stats": {
"followerCount": 4567,
"shareCount": 10,
"likeCount": 99,
"allPageViews": 12728,
"overviewPageViews": 6348,
"aboutPageViews": 1533,
"careersPageViews": 1378,
"peoplePageViews": 3370,
"insightsPageViews": 99
},
"recorded_at": "2026-05-11T08:00:00Z"
},
{
"placement_id": "110131347",
"stats": {
"followerCount": 1200,
"shareCount": 4,
"likeCount": 22,
"allPageViews": 3100
},
"recorded_at": "2026-05-11T08:00:01Z"
}
],
"summary_stats": {
"stats": {
"followerCount": 5767,
"shareCount": 14,
"likeCount": 121,
"allPageViews": 15828,
"overviewPageViews": 6348,
"aboutPageViews": 1533,
"careersPageViews": 1378,
"peoplePageViews": 3370,
"insightsPageViews": 99
},
"recorded_at": "2026-05-11T08:00:01Z"
}
}

GET /api/profiles/:id/placements

Retrieves the available placements for a profile. For Facebook profiles, placements are business pages. For LinkedIn profiles, placements include the personal profile and organizations. For Pinterest profiles, placements are boards. For Telegram profiles, placements are the channels the bot has been added to. For Google Business profiles, placements are the locations associated with the connected Business Profile account(s).

This endpoint is available for facebook, linkedin, pinterest, telegram, and google_business profiles.

If no placement is specified when creating a post:

  • LinkedIn: defaults to the personal profile
  • Facebook: it fails — page_id is always required
  • Pinterest: it fails
  • Telegram: it fails — chat_id is always required
  • Google Business: it fails — location_id (the location resource path) is always required

For Telegram, each placement is a channel the bot has been added to. The placement id is the Telegram chat_id you pass as chat_id when creating a post. The list is empty until the user adds the bot as administrator to a channel — Telegram pushes a my_chat_member event for each one and we record it. Poll this endpoint after connecting Telegram until the expected channels appear.

For Google Business, each placement is a location resource managed by the connected account(s). The placement id is the full Business Profile resource path (e.g. accounts/123456789/locations/987654321) you pass as location_id when creating a post. Listing locations issues one call per Google Business account on the profile, so responses may be slower than other networks when many accounts/locations are linked.

NameTypeRequiredDescription
idstringYesProfile id
FieldTypeDescription
idstring|nullPlatform-specific placement ID. null for personal profile (LinkedIn)
namestringDisplay name of the placement
Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles/prof123abc/placements" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"data": [
{
"id": null,
"name": "Personal Profile"
},
{
"id": "108520199",
"name": "Acme Marketing"
},
{
"id": "110131347",
"name": "Acme Labs"
}
]
}

GET /api/profiles/:id/stats

Retrieves the full stats timeseries for a profile. Mirrors Post Stats in shape (records[].stats + recorded_at) — use this to plot follower growth and engagement trends over time.

Snapshots are captured roughly every 23 hours. For networks with multiple placements (Facebook pages, LinkedIn organizations, Telegram channels), each placement has its own timeseries — placement_id is required so the response is scoped to a single placement.

NameTypeRequiredDescription
idstringYesProfile id
NameTypeRequiredDescription
placement_idstringConditionalRequired for facebook, linkedin, and telegram profiles. The platform-specific ID returned by List placements. Omit (or ignored) for other networks.
fromstringNoISO 8601 timestamp — only include snapshots recorded at or after this time.
tostringNoISO 8601 timestamp — only include snapshots recorded at or before this time.
Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles/prof_li_001/stats?placement_id=108520199&from=2026-04-01T00:00:00Z" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"data": {
"profile_id": "prof_li_001",
"platform": "linkedin",
"placement_id": "108520199",
"records": [
{
"stats": {
"followerCount": 4500,
"shareCount": 8,
"likeCount": 80,
"allPageViews": 12000
},
"recorded_at": "2026-05-09T08:00:00Z"
},
{
"stats": {
"followerCount": 4520,
"shareCount": 9,
"likeCount": 90,
"allPageViews": 12400
},
"recorded_at": "2026-05-10T08:00:00Z"
},
{
"stats": {
"followerCount": 4567,
"shareCount": 10,
"likeCount": 99,
"allPageViews": 12728
},
"recorded_at": "2026-05-11T08:00:00Z"
}
]
}
}
FieldTypeDescription
data.profile_idstringProfile ID.
data.platformstringNetwork name (facebook, linkedin, bluesky, etc.).
data.placement_idstring|nullThe placement filter that was applied (echo of the request). null for non-placement networks.
data.recordsarraySnapshots ordered by recorded_at ascending.
records[].statsobjectPlatform-specific metrics. See Stats fields by network.
records[].recorded_atstringISO 8601 timestamp when the snapshot was captured.

Missing placement_id for a placement network (400):

{
"error": "placement_id is required for linkedin profiles"
}

Profile not found (404):

{
"error": "Not found"
}

The stats object’s keys come straight from each platform’s API — they are not normalized into a common schema, so each network exposes a different set.

NetworkPlacement-scoped?Typical fields
facebookYes (per page)fan_count, followers_count, plus daily page insights (e.g. page_impressions, page_views_total, page_fan_adds, page_fan_removes)
linkedinYes (per organization)followerCount, shareCount, likeCount, commentCount, clickCount, engagement, allPageViews, overviewPageViews, aboutPageViews, careersPageViews, peoplePageViews, insightsPageViews
telegramYes (per channel)followers_count, channel_title, channel_username
instagramNofollowers_count, follows_count, media_count, plus per-window insights suffixed with _1d, _7d, _14d, _30d: reach_*, profile_views_*, accounts_engaged_*, total_interactions_*, website_clicks_*, follower_count_*
threadsNofollowers_count, views, likes, replies, reposts, quotes
youtubeNosubscriberCount, viewCount, videoCount
twitterNofollowers_count, following_count, tweet_count, listed_count, like_count
tiktokNofollower_count, following_count, likes_count, video_count
pinterestNofollower_count, following_count, pin_count, board_count, monthly_views, analytics_30d (nested 30-day rollup)
blueskyNofollowersCount, followsCount, postsCount

Notes:

  • LinkedIn page-view metrics are filtered down to the rollups (we drop redundant mobile/desktop splits and dead sections like productsPageViews / lifeAtPageViews).
  • Non-numeric fields (e.g. Telegram’s channel_title) appear in latest_stats[].stats but are omitted from summary_stats.stats, which sums numeric values only.
  • A stats key only appears in a snapshot if the platform returned a value for it on that polling cycle, so fields can come and go between records.

DELETE /api/profiles/:id

Disconnects and removes a profile from the account. This does not affect posts already published through this profile.

NameTypeRequiredDescription
idstringYesProfile id
Terminal window
curl -X DELETE "https://api.postproxy.dev/api/profiles/prof123abc" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"success": true
}

Some platforms issue access tokens that expire. The expires_at field indicates when the connection will expire and require re-authentication.

BehaviorDescription
expires_at: nullToken does not expire or has a refresh token
expires_at: "2024-..."Token expires at the specified time

When a token expires:

  • Posts to that profile will fail
  • The user needs to reconnect the profile through the web dashboard
  • Use the Initialize Connection endpoint to generate a new connection URL

Profiles cannot be created directly via the API. To connect a new social media account:

  1. Use the Initialize Connection endpoint to get an OAuth URL
  2. Redirect the user to that URL to authenticate
  3. User is redirected back to your redirect_url after authentication
  4. The profile is automatically created and associated with the profile group

When creating posts, reference profiles by:

  1. Profile ID: Use the id id directly
  2. Platform name: Use the platform string (e.g., "twitter") to automatically select the profile for that platform
{
"profiles": ["prof123abc", "twitter", "linkedin"]
}

If multiple profiles exist for the same platform in a profile group, using the platform name selects the first one. Use the profile ID for explicit selection.