GET /v1/bloggers
Returns a paginated list of the accounts (blogger records) in your organization, with their aggregated video statistics. Supports filtering, exact-campaign matching and sorting.
An account is one tracked (or previously tracked) social account. To see accounts grouped under a named creator entity, use GET /v1/creators instead — every account here may belong to zero, one or several creators.
To start tracking a new account, use POST /v1/bloggers/track first and poll GET /v1/bloggers/jobs/{job_id} until succeeded.
📋 Overview
🔐 Headers
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
📝 Query Parameters
tracked and creator_id intersect: ?tracked=true&creator_id=<uuid> returns only accounts that are actively tracked and linked to that creator, never the union.
Example Request
# Actively-tracked TikTok accounts, biggest audience first
curl -X GET "https://api.influtics.com/v1/bloggers?tracked=true&platform=tiktok&sort=number_of_subscribers&sort_order=desc&limit=25" \
-H "Authorization: Bearer YOUR_API_KEY"
# Every account linked to one creator (campaign names must be exact and encoded)
curl -X GET "https://api.influtics.com/v1/bloggers?creator_id=1f0c9a5e-6b2d-4a17-9c3e-7d8b2f4a1c90&campaign=%D0%90%D0%B2%D0%B8%D1%82%D0%BE%20%D0%9D%D0%B5%D0%B4%D0%B2%D0%B8%D0%B6" \
-H "Authorization: Bearer YOUR_API_KEY"
# Second page
curl -X GET "https://api.influtics.com/v1/bloggers?limit=50&offset=50" \
-H "Authorization: Bearer YOUR_API_KEY"
📤 Response
{
"success": true,
"data": {
"accounts": [
{
"id": "1b7c4e90-3a55-4d21-9f08-6c2ad5b19e34",
"channel_name": "Kate Comfortt",
"channel_username": "katecomfortt",
"channel_thumbnail": "https://xhrjtpcqcdqwcdiqrhfw.supabase.co/storage/v1/object/public/avatars/katecomfortt.jpg",
"url": "https://www.instagram.com/katecomfortt",
"platform": "instagram",
"is_tracked": true,
"tracking_id": "8c3f2b71-0d64-4a92-b1f7-2e5c9a4d6b13",
"tracked_at": "2026-02-14T09:31:00Z",
"last_scraped_at": "2026-10-19T22:00:00Z",
"campaign": "Авито Недвиж",
"budget_per_video": 12000,
"daily_videos_count": 3,
"video_count": 42,
"number_of_subscribers": 128400,
"total_views": 18732000,
"median_views": 312000,
"avg_views": 446000,
"created_at": "2026-01-08T11:02:41Z",
"updated_at": "2026-10-19T22:03:12Z"
},
{
"id": "5e2d8a13-7c40-4b96-8f51-2d9a6e3b7c02",
"channel_name": "Блогер без статистики",
"channel_username": null,
"channel_thumbnail": null,
"url": null,
"platform": "vk",
"is_tracked": false,
"tracking_id": "1a9d4e77-6b02-4c58-8f31-7d0e2b4a6c95",
"tracked_at": "2026-06-02T14:12:09Z",
"last_scraped_at": "2026-09-28T03:10:44Z",
"campaign": null,
"budget_per_video": null,
"daily_videos_count": 0,
"video_count": 0,
"number_of_subscribers": 0,
"total_views": 0,
"median_views": 0,
"avg_views": 0,
"created_at": "2026-05-30T08:44:00Z",
"updated_at": "2026-09-28T03:10:44Z"
}
],
"pagination": {
"total": 387,
"limit": 50,
"offset": 0,
"has_more": true
}
},
"meta": {
"request_id": "9f7e8d4c-1a2b-4c3d-8e5f-6a7b8c9d0e1f"
}
}
account fields
pagination fields
Pagination lives inside data, not in meta.
An empty page is not an empty result set: total is computed over the whole filtered set independently of offset, so paging past the end still reports the real total and has_more: false.
⚠️ Error Responses
All errors share the standard envelope { success: false, error: { code, message, request_id, ... } }. The table below lists every documented code and the conditions that trigger it.
A 403 means the key was recognised and can no longer be used — a revoked or deactivated credential — which is a different client-side fix from a 401, where the Authorization: Bearer header never arrived or was malformed. The two are deliberately distinct: a credential that never arrived versus one that arrived and is unusable.
An unknown id in a by-id path, or a path that matches no route at all, returns 404 NOT_FOUND.
📌 Notes
is_tracked means actively tracking, not "known to you"
This is the single most misread field on this endpoint. is_tracked is true only while tracking is running. An account you started tracking and later paused reads is_tracked: false — the same value as an account you never tracked. The response never distinguishes the two.
So:
?tracked=falsereturns paused and never-tracked accounts together, not just the paused ones.- An account can appear in an unfiltered list with
is_tracked: falsewhile its videos are still being fetched. - Filtering by
is_trackedto build a "currently tracked" roster is correct; treating it as "is in our database" will over-report.
avg_views, not average_views
The published field name is avg_views. It is the account's mean views per video (ROUND(AVG(views))). median_views is the 50th percentile, and total_views the sum.
avg_likes, avg_comments and avg_reposts are not returned
These three fields are deliberately absent from this endpoint. The statistics view behind it aggregates views only — it has no columns that could produce an engagement average — so there is no correct value to send. They are omitted rather than emitted as 0.
If you need engagement averages, use GET /v1/bloggers/by-username/{username}, which computes avg_likes, avg_comments and avg_reposts through a different query. There, 0 means "no video data to average". Treat the absence here as "not computable", and the 0 there as "genuinely zero" — do not unify them.
avg_views itself is present on both endpoints with the same meaning, so the two responses can be compared field-for-field apart from those three.
⚠️ campaign is an exact match, not a substring
?campaign=Авито does not match Авито Недвиж. The value is compared for equality against the stored campaign name. If you need a prefix or substring match, fetch and filter client-side.
Two consequences that look like bugs but are not:
- Filtering by campaign legitimately returns a very small result set.
campaignis set on only about 3% of accounts and isnullon the other 97%. The rate varies by organization — a campaign-heavy organization can be far higher — but globally expect to filter away nearly everything. A handful of results, or none, is the filter working, not a broken endpoint. - There is no way to ask for "accounts with no campaign." An unset campaign is stored as
null, and no filter expressesnull. Omittingcampaignreturns everyone; supplying it returns only the named ones.
Campaign names are arbitrary user text and may be Cyrillic. Percent-encode them — Авито Недвиж becomes
%D0%90%D0%B2%D0%B8%D1%82%D0%BE%20%D0%9D%D0%B5%D0%B4%D0%B2%D0%B8%D0%B6.
total counts view rows, so an account can be counted twice
The statistics view groups by tracking row, so a blogger with two tracking rows produces two rows. pagination.total counts rows, and so can over-report the number of distinct accounts — about four such duplicate pairs exist at present. The same account can also appear twice in accounts[], and can straddle a page boundary.
Deduplicate on id before counting or paging if your workflow depends on exact account counts. has_more is computed against the same row count, so it stays internally consistent.
Sorting, clamping and defaults are silent
Three query parameters are normalized rather than rejected:
Only sort, platform, tracked and an empty campaign produce a 400. Check the echoed pagination.limit and pagination.offset if the exact page size matters to you.
nullsFirst: false is applied to every sort, so accounts with no value for the sort key (for example avg_views on an account with no videos) always appear last, in both directions.
Other characteristics
- The response is scoped to the calling organization. An account belonging to another organization is not visible and returns
404 NOT_FOUNDfrom the by-id endpoint. - These endpoints only read tables the organization already pays for and call no platform API, so they cost
0credits. - Statistics are as of the last platform refresh, which is what
last_scraped_atreports — not the moment of this request.
Related: Account by ID → | Creator Lookup by Username → | List Creators → | Track an Account →