# Instagram reels API: usage Base URL: https://data.trendlytic.net Every call below needs your key in the header `X-Api-Key: ` (this page does not). Answers are JSON. Usernames are case-insensitive; a leading @ is accepted. ## Billing You hold a balance of tokens. Each call reserves its maximum cost up front and refunds what it did not use: you only pay for what is returned, and a failed call costs nothing. If your balance covers less than you asked for, you get less (e.g. 5 tokens left, `limit=12` → 5 reels). Every successful answer ends with `tokens_used` and `tokens_remaining`. | Call | Cost | |---|---| | reels | 1 token per reel returned, 2 with `full=true` | | subscribers | 1 token per account | ## GET /api/reels/{username} The latest reels of a public account, read from its profile like a browser would. | Parameter | Default | Meaning | |---|---|---| | `limit` | 12 | 1 to 50 reels (no pagination: ask for all you need in one call) | | `full` | false | adds the full fields below, at 2 tokens per reel | | `include_collabs` | false | also keep reels where the account is only a co-author | curl -H "X-Api-Key: $KEY" "https://data.trendlytic.net/api/reels/natgeo?limit=12" curl -H "X-Api-Key: $KEY" "https://data.trendlytic.net/api/reels/natgeo?limit=3&full=true" Profile fields: - `username`: the account you asked for, lowercased - `user_id`: Instagram numeric id (string) - `full_name`: display name - `follower_count`: followers - `following_count`: accounts it follows - `media_count`: posts on the profile - `is_verified`: blue check - `biography`: bio text - `profile_pic_url`: largest profile picture - `count`: number of reels in `reels` - `reels`: the reels, newest first, pinned ones included With `full=true`, the profile also has: - `is_business`: business account - `external_url`: website shown on the profile - `bio_links`: links in the bio: [{title, url}] - `threads_username`: Threads badge label (inferred from two profiles only, may be null) Each item of `reels`: - `shortcode`: the code in instagram.com/reel// - `media_id`: Instagram media id (string) - `owner`: username of the author - `taken_at`: publication time, unix seconds - `url`: https://www.instagram.com/reel// - `views`: play count - `ig_views`: always null (not served on the web) - `likes`: like count - `comments`: comment count - `shares`: always null (not served on the web) - `saves`: always null (not served on the web) - `caption`: caption text - `video_url`: best MP4 URL - `thumbnail_url`: largest cover image URL - `duration`: seconds - `width`: video width (px) - `height`: video height (px) - `reposts`: always null (not served on the web) - `audio_title`: sound or song title - `audio_id`: sound id - `audio_type`: e.g. original_sounds - `coauthors`: usernames of collab co-authors - `product_type`: clips for a reel With `full=true`, each reel also has: - `in_posts_grid`: false = the reel was only found in the Reels tab: caption, video, duration and the fields below are null, empty or false - `pinned`: pinned on the profile - `paid_partnership`: marked as paid partnership - `sponsors`: brand usernames of the partnership - `tagged_users`: people tagged: [{username, full_name, is_verified, x, y}] - `coauthor_profiles`: co-authors: [{username, full_name, is_verified}] - `caption_created_at`: caption time, unix seconds - `caption_edited`: caption edited after publication - `has_audio`: the video has sound - `audio_author`: username of the sound's author - `audio_explicit`: sound flagged explicit - `audio_trending`: sound trending in reels - `original_width`: uploaded width (px) - `original_height`: uploaded height (px) - `qualities`: every encoded quality: [{label, width, height, bitrate, codec, fps, bytes, url}], url = video track only, no sound - `audio_url`: the sound track alone (pair it with a `qualities` url) - `likes_hidden`: likes and views hidden by the author - `sharing_disabled`: sharing disabled by the author Media URLs are signed by Instagram's CDN and expire (about a day and a half): download them soon, do not store them as permanent links. ## GET /api/subscribers/{username} Follower and following counts of a public account, read from its profile. curl -H "X-Api-Key: $KEY" "https://data.trendlytic.net/api/subscribers/natgeo" - `username`: the account you asked for, lowercased - `user_id`: Instagram numeric id (string) - `follower_count`: followers - `following_count`: accounts it follows ## Billing fields (both calls) - `tokens_used`: tokens charged by this call - `tokens_remaining`: your balance after this call ## Errors Errors are JSON `{"detail": {"code": "...", "message": "..."}}`. None of them costs tokens. | HTTP | code | meaning | what to do | |---|---|---|---| | 401 | `invalid_api_key` | missing or unknown key | fix the X-Api-Key header | | 403 | `api_key_disabled` | key disabled | contact us | | 402 | `no_tokens` | balance empty (or below one unit) | ask for a top-up | | 404 | `user_not_found` | no such Instagram account | do not retry | | 403 | `user_private` | private account | do not retry | | 422 | `-` | invalid parameter (FastAPI body: `detail` is a list) | fix the query | | 502 | `read_failed` | the read failed (another code may appear: same meaning) | retry later | | 503 | `no_reader` | service temporarily unavailable | retry in a few minutes | | 504 | `timeout` | no answer within 240 s | retry later | ## Timing and concurrency A call takes 20 to 60 s for up to 12 reels (it browses the profile like a person would), about 20 s more per extra 12 (it scrolls), and gives up after 240 s: set your client timeout to at least 300 s and do not retry a call still running. Calls are queued and served in arrival order by a small pool of browsers; send at most 5 at a time, more only wait longer. There is no cache: asking twice for the same account reads it twice.