Layers
ApiReferenceSocial accounts

GET /v1/social-accounts/:accountId/health

Content-health snapshot — score, tier, engagement buckets, and a tailored recommendation.

View as Markdown
GET/v1/social-accounts/:accountId/health
Phase 1stable
Auth
Bearer
Scope
social:read

Returns the latest content-health snapshot for a connected social account. Layers refreshes this every 30 minutes via a Temporal cron — partners read; they don't compute.

The response is purpose-built for surfacing two things to a creator:

  1. Where am I? — a continuous score (0–100) and a coarse tier label (shadowbanned | new | cold | warming_up | warm | hot).
  2. What should I do? — a single human-readable recommendation string ("this is your state, this is what you should do"). Deterministic — generated from a finite template set with the account's actual numbers interpolated. No LLM, no hallucination.

Health is computed from post metrics only — view counts, comment/save/share counts, posting cadence. It does not use follower count and has no audience denominator. Engagement is judged with absolute counts against tier-relative thresholds, not ratios — so a 1M-view post with 50 comments and a 100-view post with 1 comment can both read as healthy at their respective scales.

Path
  • accountId
    stringrequired
    Prefixed social account id (e.g. `sa_9c1e42a0-b7f3-4e5d-a2c1-8b4f5e6c7d8e`).

Example request

curl "https://api.layers.com/v1/social-accounts/sa_9c1e42a0-b7f3-4e5d-a2c1-8b4f5e6c7d8e/health" \
  -H "Authorization: Bearer lp_..."
const health = await layers.social.getHealth({
  accountId: "sa_9c1e42a0-b7f3-4e5d-a2c1-8b4f5e6c7d8e",
});

if (health.tier === "shadowbanned") {
  showBanner({
    severity: health.shadowbanSeverity,
    message: health.recommendation,
  });
}
health = layers.social.get_health(
    account_id="sa_9c1e42a0-b7f3-4e5d-a2c1-8b4f5e6c7d8e",
)

if health["tier"] == "shadowbanned":
    show_banner(severity=health["shadowbanSeverity"], message=health["recommendation"])

Response

200Latest health snapshot
{
  "socialAccountId": "sa_9c1e42a0-b7f3-4e5d-a2c1-8b4f5e6c7d8e",
  "score": 73,
  "tier": "warm",
  "isShadowBanned": false,
  "shadowbanSeverity": null,
  "coldStart": false,
  "managedDistribution": false,
  "engagementHealth": {
    "comments": "par",
    "saves": "above_par",
    "shares": "par"
  },
  "signals": {
    "medianRecentViews": 4200,
    "averageRecentViews": 5100,
    "totalRecentViews": 51000,
    "postsAnalyzed": 10,
    "daysSinceLastPost": 1,
    "daysOfHistory": 60,
    "postingFrequency": 0.8,
    "postingVariance": 1.2,
    "medianRecentComments": 12,
    "medianRecentSaves": 25,
    "medianRecentShares": 6
  },
  "recommendation": "You're pulling 4,200 median views with healthy engagement — breaking through. Push to 2 posts per day (not back-to-back) and double down on the formats that are working. Homogeneity is fine right now. Spend 10 minutes a day leaving substantive comments on 5–10 peer creators in your niche. We can't measure this from the platform APIs but it's a leading indicator of algorithmic lift.",
  "analyzedAt": "2026-05-07T14:30:00Z"
}

Cold start vs new

The new tier covers two states the partner often needs to distinguish:

StatetiercoldStartsignals.postsAnalyzedWhat it means
Pre-launchnewtrue0Account hasn't posted yet — there is no signal at all. Don't render any progress UI.
Early runnewfalse14Posts exist but too few (< 5) or too short a history (< 14 days) to read meaningfully.

Score is 0 for cold-start accounts; the recommendation tells the user (or the distribution layer, for managed accounts) to keep posting.

Managed Social Distribution accounts

When managedDistribution: true, the account is part of Layers' Managed Social Distribution program — content publishes via an upstream provider (DS, SSH, HA, FM, TP) with vendor-defined per-day caps. The customer cannot unilaterally change cadence on these accounts.

The recommendation language is softened accordingly:

  • Customer-controlled accounts get prescriptive language: "Push to 2 posts per day."
  • Managed accounts get observation-style language: "If your distribution provider supports a higher cadence, request it."

UI guidance: don't render "post more" or "schedule a post" controls for managed accounts — render the linked distribution-layer status instead. The managedDistribution flag exists exactly so partners can branch their UX without parsing the recommendation text.

Tier ladder

The five non-special tiers are ordered for psychological progress — each step up reads as visible improvement.

TierMedian views (last 10 posts)What it meansRecommended cadence
shadowbannedRecent posts pulling 0 viewsPlatform is throttling reach. See shadowbanSeverity for severity.Pause posting (24h or 48h depending on severity).
new< 5 posts OR < 14 days of historyToo early to read signal.1 post/day for 2 weeks; we'll re-evaluate.
cold< 100We don't have enough signal yet.1 post/day, experiment broadly with formats.
warming_up100 – 1,000Some format is starting to land.1 post/day, narrow your experiments toward what's working.
warm1,000 – 10,000Breaking through.2 posts/day (not back-to-back), double down.
hot≥ 10,000You've broken through. Algorithm is lifting you.3 posts/day, expect "what app is this?" comments.

Shadowban severity

shadowbanSeverityTriggerRecommendation
possibleMost-recent post has 0 views and is more than 1 hour old.Wait about a day before posting again. Stay out of the feed.
definite≥ 2 consecutive recent posts have 0 views.Pause posting and feed engagement for 48 hours. Resume with a single test post.
nullNot shadowbanned.

Shadowban detection is gated by a new-account guard — accounts with fewer than 5 posts or less than 14 days of history can't be classified as shadowbanned (small audiences look identical to throttled ones).

Engagement health

Per-axis (comments, saves, shares), each post is bucketed against absolute thresholds for its view tier — not a ratio. The medians of those per-post buckets across the recent window become the field values.

tierpar commentspar savespar shares
cold000
warming_up110
warm10205
hot5010030

A bucket value of above_par means the median count is at least 2× par; par is between par and 2× par; below_par is below par. When a platform doesn't expose saves on a given post (TikTok historically didn't on some surfaces), saves reports par rather than below_par — neutrality, not penalty.

Score formula

viewMomentum    = log10(medianRecentViews + 1) / log10(100_000)         # 0..1
engagementHealth = avg of {comments, saves, shares} bucket scores       # 0..1
consistency     = blend of postingFrequency and daysSinceLastPost       # 0..1

score = round(100 × (0.5·viewMomentum + 0.3·engagementHealth + 0.2·consistency))
score -= 30 if shadowbanned
score = clamp(score, 0, 100)

The score is informational — tier and recommendation are what to render in your UI. Score is most useful for ranking accounts within a portfolio or trending an account over time.

Recommendation

recommendation is a single string, deterministic, and personalised by interpolating the account's actual numbers. It always covers two layers:

  1. Primary line — state + cadence action ("you're at X median views — do Y").
  2. Optional appendices — flagged when the data warrants it: spotty distribution (high postingVariance), and a peer-engagement nudge (suppressed when shadowbanned/new).

Render it as one block of text. It's safe to show verbatim.

When the snapshot doesn't exist

Returns 404 if the account hasn't been analyzed yet — typically the case for the first ~30 minutes after the Account Health Monitor system layer was provisioned for the account. Poll back, or call again after the first scheduled run.

Errors

StatusCodeWhen
401UNAUTHENTICATEDMissing or invalid key.
403FORBIDDEN_SCOPEKey lacks social:read.
404NOT_FOUNDAccount not in your organization, or no analysis row exists yet.
429RATE_LIMITEDRead budget exhausted.

See also

On this page