Migrating from HikerAPI
Swap the base URL, swap the header, translate the paths.
Same data, fewer endpoints, lower price. HikerAPI's 154 paths collapse to 37
here, because they expose their internal transport — the same capability
appears under /v1, /v2, /v3, /gql, /g1, /g2 and /a2 — and we
pick the source internally.
Fastest path: skip to the agent prompt at the bottom.
Paste it into Claude Code, Cursor or your agent of choice and it rewrites your
client — the prompt points the agent at
llms-full.txt, so it pulls these
docs itself. Everything above is that reference, for reading by hand.
Three mechanical changes
| HikerAPI | herascrape | |
|---|---|---|
| Base URL | https://api.hikerapi.com | https://api.herascrape.com |
| Auth header | x-access-key | x-api-key |
| Paths | 154 versioned | 37 RESTful |
Then two rules: one cursor for paging, and drop the noise parameters.
Pagination
HikerAPI uses a different paging parameter on almost every endpoint. We use
one opaque cursor.
| HikerAPI | herascrape |
|---|---|
page_id, next_page_id | cursor |
max_id, next_max_id, min_id, reels_max_id | cursor |
end_cursor | cursor |
page_token | cursor |
profile_grid_items_cursor, repost_next_max_id | cursor |
Read the next token from next_cursor and loop while has_more is true. Full
details in Pagination.
Two endpoints keep Instagram's native paging instead, because the token is
structural to their response: /posts/{id}/comments
pages on min_id, and /users/{id}/posts pages on
max_id.
Parameters to delete
| HikerAPI | Why it is gone |
|---|---|
safe_int | Our ids are always strings. Always safe. |
force | Privacy handling is automatic. |
amount | Deprecated on HikerAPI too. Page with cursor. |
flat, rank_token, expand_suggestion, can_support_threading | Internal defaults. |
Responses
Read this before you touch your parsing code.
Like HikerAPI, we return Instagram's JSON as Instagram sends it. We do not
rename fields, reshape objects, or trim responses. If your code already reads
HikerAPI's v1/v2 payloads, the fields are in the same places.
The differences that will actually bite:
- List responses are wrapped. HikerAPI returns a bare array on many
endpoints; ours return
{items, next_cursor, has_more}. Readitems. - HikerAPI's
v1andv2variants of the same call return different shapes. We have one endpoint per capability, so whichever variant you were on, you land on one shape. If you were using av1route, check the fields — we generally serve the richer private-API source. - No
short/fullmodes. You always get the full object.
Addressing
Users are addressed by numeric id. The only username path is
GET /users/username/{username}, which returns the profile including pk.
Where your code called a by-username sub-resource — stories, highlights,
followers — resolve once, cache the id, then use the id endpoints. Resolving
costs double, so caching is worth real money at volume.
Posts take either the pk or the shortcode on /posts/{id}, so by-id,
by-code and by-url calls all collapse into one. Pull the code out of an
instagram.com/p/<code>/ URL and pass it.
Endpoint translation
Users
| HikerAPI | herascrape |
|---|---|
GET /v2/user/by/username, /v1/user/by/username, /a2/user, /v2/userstream/by/username | GET /users/username/{username} |
GET /v2/user/by/id, /v1/user/by/id, /gql/user/by/id, /gql/user/web_profile_info, /v2/userstream/by/id | GET /users/{id} |
GET /v1/user/by/url | Extract the username, then GET /users/username/{username} |
GET /gql/user/about, /v1/user/about | GET /users/{id}/about |
GET /g2/user/followers, /g1/user/followers, /gql/user/followers/chunk, /v2/user/followers, /v1/user/followers/chunk | GET /users/{id}/followers |
GET /g2/user/following, /g1/user/following, /gql/user/following/chunk, /v2/user/following, /v1/user/following/chunk | GET /users/{id}/following |
GET /gql/user/medias, /g2/user/medias, /v1/user/medias/chunk, /v1/user/medias/pinned | GET /users/{id}/posts — pinned posts included |
GET /v2/user/clips, /gql/user/clips, /v1/user/clips/chunk, /v1/user/videos | GET /users/{id}/reels |
GET /v2/user/tag/medias, /v1/user/tag/medias/chunk | GET /users/{id}/tagged |
GET /gql/user/reposts | GET /users/{id}/reposts |
GET /v2/user/stories, /v1/user/stories, and their /by/username variants | GET /users/{id}/stories |
GET /v2/user/highlights, /v1/user/highlights, and their /by/username variants | GET /users/{id}/highlights |
Posts and media
| HikerAPI | herascrape |
|---|---|
GET /v2/media/info/by/id, /v1/media/by/id, /v2/media/by/id, /v1/media/user | GET /posts/{id} |
GET /v2/media/info/by/code, /v1/media/by/code, /v2/media/by/code | GET /posts/{id} — pass the shortcode |
GET /v2/media/info/by/url, /v1/media/by/url, /v2/media/by/url | GET /posts/{id} — pass the shortcode from the URL |
GET /v2/media/comments, /v1/media/comments/chunk, /gql/comments, /gql/comments/chunk | GET /posts/{id}/comments?user_id= — the post owner's id |
GET /v2/media/likers, /v3/media/likers, /v1/media/likers, /gql/media/likers | GET /posts/{id}/likers?user_id= — the post owner's id |
GET /gql/media/usertags | GET /posts/{id} — usertags is on the post |
GET /gql/media/clips_metadata | GET /posts/{id} — clips_metadata is on the post |
GET /v2/media/comments/infos | GET /posts/{id} — the counts are on the post |
GET /v1/media/download/photo, /v1/media/download/video, …/by/url | GET /posts/{id} — file URLs are in image_versions2 / video_versions |
GET /v1/media/oembed | GET /oembed?url= |
GET /v1/media/pk/from/code, /v1/media/code/from/pk | GET /resolve/media — free |
GET /v1/share/by/url, /v1/share/by/code, /v1/media/pk/from/url | GET /oembed?url= |
Batch ?media_ids= endpoints have no equivalent. The slices they returned
— usertags, clips metadata, comment counts — already live inside a single
GET /posts/{id}, so we did not reproduce them. If you batched to read one
slice across many posts cheaply, each post is now its own request. At
$0.0004 that is usually still cheaper; check the arithmetic for your volume.
Comments
| HikerAPI | herascrape |
|---|---|
GET /v2/media/comments/replies, /gql/comments/threaded, /gql/comments/threaded/chunk | GET /comments/{id}/replies — media_id and user_id required |
GET /gql/comment/likers, /gql/comment/likers/chunk | GET /comments/{id}/likers |
Search
| HikerAPI | herascrape |
|---|---|
GET /v3/fbsearch/accounts, /v2/fbsearch/accounts, /v1/search/users, /v2/search/accounts | GET /search/users |
GET /v2/search/hashtags, /v1/search/hashtags, /v1/fbsearch/topsearch/hashtags | GET /search/hashtags |
GET /v3/fbsearch/places, /v2/fbsearch/places, /v1/fbsearch/places, /v2/search/places | GET /search/places |
GET /v2/search/music, /v1/search/music | GET /search/audio |
GET /v2/fbsearch/topsearch, /gql/topsearch, /v1/fbsearch/topsearch, /v3/fbsearch/topsearch | GET /search/top |
Hashtags, locations, audio, stories, highlights
| HikerAPI | herascrape |
|---|---|
GET /v2/hashtag/by/name, /v1/hashtag/by/name | GET /hashtags/{name} |
GET /v2/hashtag/medias/top, /v1/hashtag/medias/top/chunk | GET /hashtags/{name}/top |
GET /v2/hashtag/medias/recent, /v1/hashtag/medias/recent | GET /hashtags/{name}/recent |
GET /v1/hashtag/medias/clips/chunk, /v2/hashtag/medias/clips | GET /hashtags/{name}/reels |
GET /v1/location/by/id | GET /locations/{id} |
GET /v1/location/medias/top, …/top/chunk | GET /locations/{id}/top |
GET /v1/location/medias/recent, …/recent/chunk | GET /locations/{id}/recent |
GET /v1/location/search | GET /search/places?lat=&lng= |
GET /v2/track/by/id | GET /audio/{id} |
GET /v2/highlight/by/id, /v1/highlight/by/id | GET /highlights/{id} |
GET /v1/highlight/by/url | GET /oembed?url= for the reel_id, then GET /highlights/{id} |
GET /v2/story/by/url, /v1/story/by/url | GET /oembed?url= for the reel_id, then GET /stories/{reel_id} |
GET /v1/story/download, …/by/url, …/by/story/url | GET /stories/{reel_id} — file URLs are on each item |
GET /sys/balance | GET /system/balance — free |
What we do not have
Honest list, so you find out here rather than in production.
Instagram removed these, so nobody has them. Nothing to migrate to.
GET /v1/location/searchas a standalone geo search. The venue picker at/search/placescovers the common case.
Returns different data than you expect.
GET /v2/story/by/id,/v1/story/by/id— we have no fetch-one-story-by-id endpoint.GET /stories/{reel_id}takes the owner's user id and returns their whole active reel. Fetch that and match on the item'spk.
Not implemented. If one of these blocks your migration, tell us — several are small, and we prioritise by what migrating customers actually need.
| HikerAPI | Notes |
|---|---|
GET /v2/user/suggested/profiles, /v2/user/explore/businesses/by/id, /gql/user/related/profiles | Related-profile suggestions. |
GET /v1/user/guides, /v1/location/guides | Guides. |
GET /v2/media/template | Media share template. |
GET /v1/media/insight | Owner-only insights; needs the account to own the post. |
GET /v2/media/comment/offensive | Offensive-text check. |
GET /v2/fbsearch/reels, /v2/search/reels, /v3/fbsearch/reels | Reels search. /search/top and /hashtags/{name}/reels cover much of it. |
GET /v2/track/by/canonical/id, /v2/track/stream/by/id | Canonical-id lookup and stream URL. |
Before and after
- GET https://api.hikerapi.com/v2/user/followers?user_id=25025320&page_id=ABC
- x-access-key: <key>
+ GET https://api.herascrape.com/users/25025320/followers?cursor=ABC
+ x-api-key: <key>- GET https://api.hikerapi.com/v2/media/info/by/code?code=B4XpqViUFUI&safe_int=true
+ GET https://api.herascrape.com/posts/B4XpqViUFUI- GET https://api.hikerapi.com/v2/user/by/username?username=instagram
- GET https://api.hikerapi.com/v2/user/stories/by/username?username=instagram
+ GET https://api.herascrape.com/users/username/instagram # returns pk, cache it
+ GET https://api.herascrape.com/users/25025320/storiesAgent prompt
Paste this into your coding agent and point it at your repository. It fetches the docs it needs, so you do not have to attach anything.
You are migrating this codebase from HikerAPI (api.hikerapi.com) to
herascrape (api.herascrape.com).
First, read these — they are the source of truth, and this prompt alone is not
enough to do the migration correctly:
- https://herascrape.com/docs/llms-full.txt
The complete herascrape documentation as one plain-text file: every endpoint,
the pagination and error contracts, and the full HikerAPI translation tables.
- https://herascrape.com/docs/guides/hikerapi-migration
The migration guide on its own, if you want just the tables.
- https://api.herascrape.com/openapi.json
The OpenAPI (Swagger) schema, emitted by the running service. Authoritative
for paths and parameters; use the "What comes back" examples in the docs for
response field names.
Then, across the whole repo:
1. Replace the base URL https://api.hikerapi.com with
https://api.herascrape.com.
2. Rename the auth header `x-access-key` to `x-api-key`. Keep the value in
its existing environment variable.
3. Rewrite every request path using the "Endpoint translation" tables. Many
HikerAPI paths collapse onto one of ours — pick the matching row.
4. Users are addressed by numeric id (/users/{id}). The only username path is
GET /users/username/{username}, which returns the profile including `pk`.
Where the code called a by-username sub-resource (stories, highlights,
followers), resolve the username once, cache the id, then call the
id-based endpoint. Flag any place where caching is not straightforward.
5. Posts: replace by-id, by-code and by-url calls with GET /posts/{id}, which
accepts either the media pk or the shortcode. Extract the shortcode from
any instagram.com/p/<code>/ URL.
6. Replace all pagination parameters (page_id, next_page_id, max_id,
next_max_id, min_id, end_cursor, page_token, reels_max_id,
profile_grid_items_cursor, repost_next_max_id) with a single `cursor`.
Read the next token from `next_cursor` and loop while `has_more` is true.
Two exceptions: /posts/{id}/comments pages on `min_id` (branch on
`has_more`), and /users/{id}/posts pages on `cursor` taken from
`feed.profile_grid_items_cursor`.
7. Delete these parameters: safe_int, flat, force, amount, rank_token,
expand_suggestion, can_support_threading.
8. List responses are wrapped in {items, next_cursor, has_more}. Where the
old code read a bare array, read `items`. Object fields are otherwise
unchanged — both APIs return Instagram's JSON.
9. Respect the rate limit: 10 requests/second per key. If the code fans out
concurrently, cap it.
10. Do NOT invent endpoints. If a call maps to something in the "What we do
not have" section of the migration guide, leave it in place and mark it
with a TODO naming the limitation. Do the same for any field you cannot
confidently map. Never guess a path that is not in the translation tables.
Produce a summary of every call site changed, plus the list of TODOs.If your agent cannot fetch URLs, download
llms-full.txt and attach it —
it is the whole of these docs in one file.
Getting started
Free balance to trial the migration, no card required, and cheaper per call across the board. Stuck on a mapping or an endpoint you do not see here? Get in touch — we will map it, or build it.