SocialTap is the social media scraper API for developers and AI agents. Send a public link, a handle or a search and get live data back in one schema. Failed requests are free.
The TypeScript SDK for the SocialTap API: a method for every endpoint, typed models and errors, retries and pagination. Generated from the SocialTap catalog (version 1.509.29). Docs: https://socialtap.dev/docs.
Install
npm install socialtap
npm pkg set type=module # the examples are ES modules (or name your file .mjs or .mts)Zero runtime dependencies (fetch); Node 20.3+, Deno, Bun and Cloudflare Workers (server-side: the API key is a secret).
ESM only: in Node, your project needs "type": "module" in its package.json (the second command above) or a
.mjs/.mts file, else Node stops at the first import ("Cannot use import statement outside a module"). Run
TypeScript directly with Node 22.18+ (node app.ts) or npx tsx app.ts. Params and models use the API's snake_case
names; SDK objects (options, credits, errors) are camelCase.
null means unknown. With fields, results are typed PartialModel<T> (every member may
be absent). A 2xx that is not the API's envelope (no data, not JSON) throws APIDecodeError; a retry-after longer than
MAX_RETRY_AFTER_S throws RetryAfterExceededError instead of retrying early. Results keep the API's objects as sent,
members this version doesn't model included. Event is a union narrowed by type; a job item's params are typed by its endpoint.
Authenticate
The client reads your API key from SOCIALTAP_API_KEY, or takes it as an option. Requests send it in the
x-api-key header. Get a key at https://socialtap.dev/signup/: every account starts with 100 free credits.
First call: Exact follower and like counts, bio and country
import { SocialTap } from "socialtap";
const client = new SocialTap(); // apiKey defaults to process.env.SOCIALTAP_API_KEY
const res = await client.tiktok.profile.get({ handle: "nasa" });
console.log(res.data);
console.log(res.credits.charged, res.meta.request_id);data is a Profile (example response, truncated):
{
"approximate_fields": [],
"avatar_url": "https://p19-common-sign.tiktokcdn-us.com/tos-useast5-avt-0068-tx/e5143212a59c09a008bf50f487d54d1f~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=9640\u0026refresh_token=29840d4e\u0026x-expires=4070908800\u0026x-signature=SCRUBBED\u0026t=4d5b0474\u0026ps=13740610\u0026shp=a5d48078\u0026shcp=81f88b70\u0026idc=useast5",
"banner_url": null,
"bio": "Making the seemingly impossible, possible.✨",
"category": null,
"country_code": "US",
"created_at": "2026-07-20T15:55:49Z",
"display_name": "NASA",
"external_links": [
{
"title": null,
"url": "https://science.nasa.gov/feature/artemis-ii-preliminary-lunar-science-report"
}
],
"id": "7664638705177150477",
"is_private": false,
"is_verified": true,
"location": null,
"metrics": {
"follower_count": 2152843,
"following_count": 23,
"post_count": 62,
"total_like_count": 11486661,
"total_view_count": null
},
"platform": "tiktok",
"platform_specific": {
"tiktok": {
"display_name_changed_at": "2026-07-20T15:58:00Z",
"friend_count": 17,
"is_business_account": false,
"is_shop_seller": false,
"language": "en",
"liked_post_count": null,
"sec_uid": "MS4wLjABAAAAU9BRVzC8oCaegVnia8IbqWhPb_-dbU7s00Y3wS1_Nx8g5RUaYvyXrpejgjdxTwd6"
}
},
"type": "organization",
"unknown_fields": [],
"url": "https://www.tiktok.com/@nasa",
"username": "nasa"
}Every result also carries the envelope meta (request ID, source, cache status, fetch time) and credits
(charged by this request, and the balance after it when the API reports it). Failed requests and cache hits are free.
Endpoints
| endpoint | method | cost |
|---|---|---|
amazon.deal_products | client.amazon.dealProducts.list() | 1 credit |
amazon.offers | client.amazon.offers.list() | 1 credit |
amazon.product | client.amazon.product.get() | 1 credit |
amazon.reviews | client.amazon.reviews.list() | 1 credit |
amazon.search_products | client.amazon.searchProducts.list() | 1 credit |
amazon.seller | client.amazon.seller.get() | 1 credit |
amazon.shop | client.amazon.shop.get() | 1 credit |
amazon.shop_lists | client.amazon.shopLists.list() | 1 credit |
amazon.shop_posts | client.amazon.shopPosts.list() | 1 credit |
amazon.top_products | client.amazon.topProducts.list() | 1 credit |
applemusic.album | client.applemusic.album.get() | 1 credit |
applemusic.artist | client.applemusic.artist.get() | 1 credit |
applemusic.search_albums | client.applemusic.searchAlbums.list() | 1 credit |
applemusic.search_artists | client.applemusic.searchArtists.list() | 1 credit |
applemusic.search_playlists | client.applemusic.searchPlaylists.list() | 1 credit |
applemusic.search_tracks | client.applemusic.searchTracks.list() | 1 credit |
applemusic.top_albums | client.applemusic.topAlbums.list() | 1 credit |
applemusic.top_playlists | client.applemusic.topPlaylists.list() | 1 credit |
applemusic.top_tracks | client.applemusic.topTracks.list() | 1 credit |
applemusic.track | client.applemusic.track.get() | 1 credit |
bluesky.comments | client.bluesky.comments.list() | 1 credit |
bluesky.post | client.bluesky.post.get() | 1 credit |
bluesky.posts | client.bluesky.posts.list() | 1 credit |
bluesky.profile | client.bluesky.profile.get() | 1 credit |
bluesky.search_posts | client.bluesky.searchPosts.list() | 1 credit |
facebook.ad | client.facebook.ad.get() | 1 credit |
facebook.ad_transcript | client.facebook.adTranscript.get() | 2 credits + 2 per started minute of media |
facebook.ads | client.facebook.ads.list() | 1 credit |
facebook.comments | client.facebook.comments.list() | 1 credit |
facebook.engagement | client.facebook.engagement.get() | 1 credit |
facebook.event | client.facebook.event.get() | 1 credit |
facebook.events | client.facebook.events.list() | 1 credit |
facebook.group | client.facebook.group.get() | 1 credit |
facebook.group_posts | client.facebook.groupPosts.list() | 1 credit |
facebook.listing | client.facebook.listing.get() | 1 credit |
facebook.photos | client.facebook.photos.list() | 1 credit |
facebook.place_events | client.facebook.placeEvents.list() | 1 credit |
facebook.post | client.facebook.post.get() | 1 credit |
facebook.posts | client.facebook.posts.list() | 1 credit |
facebook.profile | client.facebook.profile.get() | 1 credit |
facebook.reels | client.facebook.reels.list() | 1 credit |
facebook.replies | client.facebook.replies.list() | 1 credit |
facebook.search_ads | client.facebook.searchAds.list() | 1 credit |
facebook.search_advertisers | client.facebook.searchAdvertisers.list() | 1 credit |
facebook.search_events | client.facebook.searchEvents.list() | 1 credit |
facebook.search_groups | client.facebook.searchGroups.list() | 1 credit + 1 per result filled in |
facebook.search_listings | client.facebook.searchListings.list() | 1 credit |
facebook.search_places | client.facebook.searchPlaces.list() | 1 credit |
facebook.search_posts | client.facebook.searchPosts.list() | 1 credit + 1 per result filled in |
facebook.search_profiles | client.facebook.searchProfiles.list() | 1 credit + 1 per result filled in |
facebook.transcript | client.facebook.transcript.get() | 1 credit (captions) or 2 credits + 2 per started minute of media (speech-to-text) |
google.ad | client.google.ad.get() | 1 credit |
google.ads | client.google.ads.list() | 1 credit |
google.advertiser | client.google.advertiser.get() | 1 credit |
google.search_ads | client.google.searchAds.list() | 1 credit |
google.search_advertisers | client.google.searchAdvertisers.list() | 1 credit |
google.search_suggestions | client.google.searchSuggestions.list() | 1 credit |
instagram.comment | client.instagram.comment.get() | 1 credit |
instagram.comments | client.instagram.comments.list() | 1 credit |
instagram.embed | client.instagram.embed.get() | 1 credit |
instagram.engagement | client.instagram.engagement.get() | 1 credit |
instagram.hashtag | client.instagram.hashtag.get() | 1 credit |
instagram.hashtag_posts | client.instagram.hashtagPosts.list() | 1 credit |
instagram.highlights | client.instagram.highlights.list() | 1 credit |
instagram.place | client.instagram.place.get() | 1 credit |
instagram.place_posts | client.instagram.placePosts.list() | 1 credit |
instagram.playlist_stories | client.instagram.playlistStories.list() | 1 credit |
instagram.post | client.instagram.post.get() | 1 credit |
instagram.posts | client.instagram.posts.list() | 1 credit |
instagram.profile | client.instagram.profile.get() | 1 credit |
instagram.reels | client.instagram.reels.list() | 1 credit |
instagram.search_hashtags | client.instagram.searchHashtags.list() | 1 credit |
instagram.search_places | client.instagram.searchPlaces.list() | 1 credit + 1 per result filled in |
instagram.search_posts | client.instagram.searchPosts.list() | 1 credit |
instagram.search_profiles | client.instagram.searchProfiles.list() | 1 credit + 1 per result filled in |
instagram.search_sounds | client.instagram.searchSounds.list() | 1 credit + 1 per result filled in |
instagram.search_suggestions | client.instagram.searchSuggestions.list() | 1 credit |
instagram.similar_profiles | client.instagram.similarProfiles.list() | 1 credit |
instagram.sound | client.instagram.sound.get() | 1 credit |
instagram.sound_posts | client.instagram.soundPosts.list() | 1 credit |
instagram.story | client.instagram.story.get() | 1 credit |
instagram.topic | client.instagram.topic.get() | 1 credit |
instagram.transcript | client.instagram.transcript.get() | 1 credit (captions) or 2 credits + 2 per started minute of media (speech-to-text) |
instagram.trending_posts | client.instagram.trendingPosts.list() | 1 credit |
instagram.username | client.instagram.username.get() | 1 credit |
kick.post | client.kick.post.get() | 1 credit |
kick.transcript | client.kick.transcript.get() | 2 credits + 2 per started minute of media |
komi.page | client.komi.page.get() | 1 credit |
kwai.post | client.kwai.post.get() | 1 credit |
kwai.posts | client.kwai.posts.list() | 1 credit |
kwai.profile | client.kwai.profile.get() | 1 credit |
linkbio.profile | client.linkbio.profile.get() | 1 credit |
linkedin.ad | client.linkedin.ad.get() | 1 credit |
linkedin.post | client.linkedin.post.get() | 1 credit |
linkedin.profile | client.linkedin.profile.get() | 1 credit (public page or web search) or 5 credits (data partner) |
linkedin.search_ads | client.linkedin.searchAds.list() | 1 credit |
linkedin.search_posts | client.linkedin.searchPosts.list() | 1 credit + 1 per result filled in |
linkedin.search_profiles | client.linkedin.searchProfiles.list() | 1 credit + 1 per result filled in |
linkme.profile | client.linkme.profile.get() | 1 credit |
linktree.profile | client.linktree.profile.get() | 1 credit |
pillar.page | client.pillar.page.get() | 1 credit |
pinterest.board | client.pinterest.board.get() | 1 credit |
pinterest.board_pins | client.pinterest.boardPins.list() | 1 credit |
pinterest.boards | client.pinterest.boards.list() | 1 credit |
pinterest.pin | client.pinterest.pin.get() | 1 credit |
pinterest.pins | client.pinterest.pins.list() | 1 credit |
pinterest.profile | client.pinterest.profile.get() | 1 credit |
pinterest.search_pins | client.pinterest.searchPins.list() | 1 credit |
pinterest.top_trends | client.pinterest.topTrends.list() | 1 credit |
pinterest.topic | client.pinterest.topic.get() | 1 credit |
pinterest.web_page | client.pinterest.webPage.get() | 1 credit |
reddit.comments | client.reddit.comments.list() | 1 credit |
reddit.engagement | client.reddit.engagement.get() | 1 credit |
reddit.post | client.reddit.post.get() | 1 credit |
reddit.posts | client.reddit.posts.list() | 1 credit |
reddit.profile | client.reddit.profile.get() | 1 credit |
reddit.profile_comments | client.reddit.profileComments.list() | 1 credit |
reddit.search_comments | client.reddit.searchComments.list() | 1 credit |
reddit.search_posts | client.reddit.searchPosts.list() | 1 credit |
reddit.search_profiles | client.reddit.searchProfiles.list() | 1 credit |
reddit.search_subreddits | client.reddit.searchSubreddits.list() | 1 credit |
reddit.subreddit | client.reddit.subreddit.get() | 1 credit |
reddit.subreddit_posts | client.reddit.subredditPosts.list() | 1 credit |
reddit.transcript | client.reddit.transcript.get() | 1 credit (captions) or 2 credits + 2 per started minute of media (speech-to-text) |
rumble.comments | client.rumble.comments.list() | 1 credit |
rumble.engagement | client.rumble.engagement.get() | 1 credit |
rumble.post | client.rumble.post.get() | 1 credit |
rumble.posts | client.rumble.posts.list() | 1 credit |
rumble.profile | client.rumble.profile.get() | 1 credit |
rumble.search_posts | client.rumble.searchPosts.list() | 1 credit |
rumble.transcript | client.rumble.transcript.get() | 1 credit (captions) or 2 credits + 2 per started minute of media (speech-to-text) |
snapchat.comments | client.snapchat.comments.list() | 1 credit |
snapchat.profile | client.snapchat.profile.get() | 1 credit |
snapchat.spotlight | client.snapchat.spotlight.get() | 1 credit |
soundcloud.artist | client.soundcloud.artist.get() | 1 credit |
soundcloud.track | client.soundcloud.track.get() | 1 credit |
soundcloud.tracks | client.soundcloud.tracks.list() | 1 credit |
spotify.album | client.spotify.album.get() | 1 credit |
spotify.artist | client.spotify.artist.get() | 1 credit |
spotify.playlist | client.spotify.playlist.get() | 1 credit |
spotify.playlist_tracks | client.spotify.playlistTracks.list() | 1 credit |
spotify.podcast | client.spotify.podcast.get() | 1 credit |
spotify.podcast_episodes | client.spotify.podcastEpisodes.list() | 1 credit |
spotify.search_albums | client.spotify.searchAlbums.list() | 1 credit |
spotify.search_artists | client.spotify.searchArtists.list() | 1 credit |
spotify.search_playlists | client.spotify.searchPlaylists.list() | 1 credit |
spotify.search_podcasts | client.spotify.searchPodcasts.list() | 1 credit |
spotify.search_tracks | client.spotify.searchTracks.list() | 1 credit |
spotify.track | client.spotify.track.get() | 1 credit |
telegram.channel | client.telegram.channel.get() | 1 credit |
telegram.channel_posts | client.telegram.channelPosts.list() | 1 credit |
telegram.post | client.telegram.post.get() | 1 credit |
telegram.search_channels | client.telegram.searchChannels.list() | 1 credit + 1 per result filled in |
threads.comments | client.threads.comments.list() | 1 credit |
threads.post | client.threads.post.get() | 1 credit |
threads.posts | client.threads.posts.list() | 1 credit |
threads.profile | client.threads.profile.get() | 1 credit |
threads.search_posts | client.threads.searchPosts.list() | 1 credit |
threads.search_profiles | client.threads.searchProfiles.list() | 1 credit |
tiktok.ad | client.tiktok.ad.get() | 1 credit |
tiktok.comment | client.tiktok.comment.get() | 1 credit |
tiktok.comments | client.tiktok.comments.list() | 1 credit |
tiktok.download | client.tiktok.download.get() | 1 credit |
tiktok.effect | client.tiktok.effect.get() | 1 credit |
tiktok.effect_posts | client.tiktok.effectPosts.list() | 1 credit |
tiktok.engagement | client.tiktok.engagement.get() | 1 credit |
tiktok.followers | client.tiktok.followers.list() | 1 credit |
tiktok.following | client.tiktok.following.list() | 1 credit |
tiktok.hashtag | client.tiktok.hashtag.get() | 1 credit |
tiktok.hashtag_posts | client.tiktok.hashtagPosts.list() | 1 credit |
tiktok.liked_posts | client.tiktok.likedPosts.list() | 1 credit |
tiktok.live | client.tiktok.live.get() | 1 credit |
tiktok.place_posts | client.tiktok.placePosts.list() | 1 credit |
tiktok.playlist_posts | client.tiktok.playlistPosts.list() | 1 credit |
tiktok.playlists | client.tiktok.playlists.list() | 1 credit |
tiktok.post | client.tiktok.post.get() | 1 credit |
tiktok.posts | client.tiktok.posts.list() | 1 credit |
tiktok.profile | client.tiktok.profile.get() | 1 credit |
tiktok.replies | client.tiktok.replies.list() | 1 credit |
tiktok.search_ads | client.tiktok.searchAds.list() | 1 credit |
tiktok.search_hashtags | client.tiktok.searchHashtags.list() | 1 credit + 1 per result filled in |
tiktok.search_posts | client.tiktok.searchPosts.list() | 1 credit |
tiktok.search_profiles | client.tiktok.searchProfiles.list() | 1 credit + 1 per result filled in |
tiktok.search_sounds | client.tiktok.searchSounds.list() | 1 credit + 1 per result filled in |
tiktok.search_suggestions | client.tiktok.searchSuggestions.list() | 1 credit |
tiktok.search_top | client.tiktok.searchTop.list() | 1 credit + 1 per result filled in |
tiktok.sound | client.tiktok.sound.get() | 1 credit |
tiktok.sound_posts | client.tiktok.soundPosts.list() | 1 credit |
tiktok.top_ads | client.tiktok.topAds.list() | 1 credit |
tiktok.top_posts | client.tiktok.topPosts.list() | 1 credit |
tiktok.transcript | client.tiktok.transcript.get() | 1 credit (captions) or 2 credits + 2 per started minute of media (speech-to-text) |
tiktok.trending_hashtags | client.tiktok.trendingHashtags.list() | 1 credit |
tiktok.trending_posts | client.tiktok.trendingPosts.list() | 1 credit |
tiktokshop.product | client.tiktokshop.product.get() | 1 credit |
tiktokshop.products | client.tiktokshop.products.list() | 1 credit |
tiktokshop.reviews | client.tiktokshop.reviews.list() | 1 credit |
tiktokshop.search_products | client.tiktokshop.searchProducts.list() | 1 credit |
truthsocial.post | client.truthsocial.post.get() | 1 credit |
truthsocial.posts | client.truthsocial.posts.list() | 1 credit |
truthsocial.profile | client.truthsocial.profile.get() | 1 credit |
twitch.profile | client.twitch.profile.get() | 1 credit |
twitch.schedule | client.twitch.schedule.list() | 1 credit |
twitch.transcript | client.twitch.transcript.get() | 2 credits + 2 per started minute of media |
twitch.video | client.twitch.video.get() | 1 credit |
twitch.videos | client.twitch.videos.list() | 1 credit |
x.community | client.x.community.get() | 1 credit |
x.post | client.x.post.get() | 1 credit |
x.profile | client.x.profile.get() | 1 credit |
x.search_communities | client.x.searchCommunities.list() | 1 credit + 1 per result filled in |
x.search_hashtags | client.x.searchHashtags.list() | 1 credit |
x.search_posts | client.x.searchPosts.list() | 1 credit + 1 per result filled in |
x.search_profiles | client.x.searchProfiles.list() | 1 credit + 1 per result filled in |
youtube.comments | client.youtube.comments.list() | 1 credit |
youtube.engagement | client.youtube.engagement.get() | 1 credit |
youtube.post | client.youtube.post.get() | 1 credit |
youtube.posts | client.youtube.posts.list() | 1 credit |
youtube.profile | client.youtube.profile.get() | 1 credit |
youtube.transcript | client.youtube.transcript.get() | 1 credit (captions) or 2 credits + 2 per started minute of media (speech-to-text) |
Endpoints newer than this package
A version has a method for every endpoint the API had when it was released. For a newer one, update the
package, or send the request yourself: the raw request adds your key and retries and raises errors like a method,
and returns the status, headers and body (the envelope, data and meta). Each endpoint's docs page has its path
and params.
const res = await client.request({ method: "GET", path: "/v1/tiktok/profile", query: { handle: "nasa" } });
console.log(res.status, res.body);Errors
Every API error is an APIError subclass named after its code, with status, code, retryable, remediation,
requestId and creditsCharged (0: errors are free). Codes this SDK version doesn't know arrive as a plain
APIError with their code; no response at all is an APIConnectionError (APITimeoutError for timeouts).
import { APIError, NotFoundError } from "socialtap";
try {
await client.tiktok.profile.get({ handle: "nasa" });
} catch (err) {
if (err instanceof NotFoundError) {
// Check the link or ID. Do not retry.
} else if (err instanceof APIError) {
console.error(err.code, err.status, err.retryable, err.remediation, err.requestId);
} else throw err;
}| code | class | status | retried |
|---|---|---|---|
invalid_input | InvalidInputError | 400 | no |
invalid_cursor | InvalidCursorError | 400 | no |
unauthorized | UnauthorizedError | 401 | no |
forbidden | ForbiddenError | 403 | no |
insufficient_credits | InsufficientCreditsError | 402 | no |
spend_limit_reached | SpendLimitReachedError | 402 | no |
rate_limited | RateLimitedError | 429 | yes |
request_too_large | RequestTooLargeError | 413 | no |
method_not_allowed | MethodNotAllowedError | 405 | no |
endpoint_retired | EndpointRetiredError | 410 | no |
idempotency_key_reused | IdempotencyKeyReusedError | 422 | no |
idempotency_key_in_progress | IdempotencyKeyInProgressError | 409 | yes |
job_not_found | JobNotFoundError | 404 | no |
unknown_endpoint | UnknownEndpointError | 404 | no |
not_found | NotFoundError | 404 | no |
private_or_unavailable | PrivateOrUnavailableError | 403 | no |
no_transcript | NoTranscriptError | 404 | no |
no_live | NoLiveError | 404 | no |
no_media | NoMediaError | 404 | no |
upstream_blocked | UpstreamBlockedError | 503 | yes |
upstream_error | UpstreamError | 502 | yes |
overloaded | OverloadedError | 503 | yes |
internal | InternalError | 500 | yes |
Retries and timeouts
Retryable failures (the codes above, connection errors, timeouts) are retried 2 times by default with
exponential backoff and jitter, honoring retry-after. A GET retry sends max_age set to the seconds since the first
attempt: if the first response was lost in transit, the retry is served free from the cache. Timeouts are per
attempt: 60 s by default, and 300 s for endpoints that may transcribe audio (facebook.ad_transcript, facebook.transcript, instagram.transcript, kick.transcript, reddit.transcript, rumble.transcript, tiktok.transcript, twitch.transcript, youtube.transcript), because speech-to-text on long
media takes minutes, and for create-and-wait's long-polls. Most requests answer in a few seconds. A timeout you set, on the client or on one request,
applies to every endpoint, and so does maxRetries.
Pagination
List endpoints return one page (data, page.has_more, page.next_cursor). iterate() returns a Paginator (for await over items, .byPage() for pages)
with two guards, maxPages and maxCredits; afterwards pagesFetched, creditsCharged, stopReason ("end", or the guard that
stopped it) and endReason (the API's page.end_reason) say what happened.
Each page is checked against its catalog price before it is fetched, and an empty page with has_more is not the end.
const items = client.amazon.dealProducts.iterate({}, { maxPages: 10, maxCredits: 100 });
for await (const item of items) {
console.log(item);
}
console.log(items.pagesFetched, items.creditsCharged, items.stopReason, items.endReason);Account, API keys, jobs, webhooks and events
The gateway's own routes (account, usage, credit ledger, API keys, jobs, webhook endpoints, events) are free and
have methods too, named from their operation IDs (<noun>.<verb>, or <noun>.<sub>.<verb> for a sub-resource). They
answer the same envelope (data, meta, credits) with their own meta; cursor-paged list routes have iterate like
list endpoints. Every POST sends an idempotency-key header (yours, or a new UUID kept for the call's retries), so it is
retried like a GET and a retry never repeats the work; replayed says when the API answered from an earlier request
with the same key, and status is 202 when accepted work continues. Each route needs a key with the scope below (a key
never gets a scope its creator lacks).
const res = await client.account.get();
console.log(res.data, res.meta.request_id);| operation | method | scope |
|---|---|---|
account.get | client.account.get() | account:read |
account.update | client.account.update(body) | admin |
usage.list | client.usage.list(params) | account:read |
usage.rate.list | client.usage.rate.list(params) | account:read |
credit_transactions.list | client.creditTransactions.list(params) | account:read |
billing.checkout.get | client.billing.checkout.get(id) | account:read |
billing.subscription.get | client.billing.subscription.get() | account:read |
billing.auto_topup.get | client.billing.autoTopup.get() | account:read |
billing.purchases.list | client.billing.purchases.list(params) | account:read |
billing.purchases.receipt | client.billing.purchases.receipt(id) | account:read |
requests.list | client.requests.list(params) | account:read |
requests.get | client.requests.get(id) | account:read |
requests.get_response | client.requests.getResponse(id) | account:read |
api_keys.create | client.apiKeys.create(body) | admin |
api_keys.list | client.apiKeys.list(params) | account:read |
api_keys.get | client.apiKeys.get(id) | account:read |
api_keys.update | client.apiKeys.update(id, body) | admin |
api_keys.rotate_secret | client.apiKeys.rotateSecret(id, body) | admin |
api_keys.revoke | client.apiKeys.revoke(id) | admin |
jobs.create | client.jobs.create(body, params) | jobs |
jobs.list | client.jobs.list(params) | jobs:read |
jobs.get | client.jobs.get(id, params) | jobs:read |
jobs.results.list | client.jobs.results.list(id, params) | jobs:read |
jobs.cancel | client.jobs.cancel(id) | jobs |
webhook_endpoints.create | client.webhookEndpoints.create(body) | admin |
webhook_endpoints.list | client.webhookEndpoints.list(params) | account:read |
webhook_endpoints.get | client.webhookEndpoints.get(id) | account:read |
webhook_endpoints.update | client.webhookEndpoints.update(id, body) | admin |
webhook_endpoints.delete | client.webhookEndpoints.delete(id) | admin |
webhook_endpoints.rotate_secret | client.webhookEndpoints.rotateSecret(id, body) | admin |
webhook_endpoints.test | client.webhookEndpoints.test(id) | admin |
webhook_endpoints.deliveries.list | client.webhookEndpoints.deliveries.list(id, params) | account:read |
events.list | client.events.list(params) | account:read |
events.get | client.events.get(id) | account:read |
events.redeliver | client.events.redeliver(id, body) | admin |
notification_preferences.get | client.notificationPreferences.get() | account:read |
notification_preferences.update | client.notificationPreferences.update(body) | admin |
Jobs and webhooks
Many requests (or one long list walk) run as a background job at the synchronous prices; failed items are free. The create-and-wait helper creates one, long-polls it until it ends and returns every result; one Idempotency-Key covers the create's retries, so a retry never runs a job twice. Webhook deliveries are signed per Standard Webhooks: verify the raw body with your endpoint's secret before trusting it, and deduplicate on the event ID.
const { job, results } = await client.jobs.createAndWait({ requests: [{ custom_id: "row-1", endpoint: "tiktok.profile", params: { handle: "nasa" } }] });
for (const r of results) console.log(r.custom_id, r.status, r.error?.code);
// A webhook delivery: the raw body, the request headers, your endpoint's secret.
const event = await client.webhooks.verify(rawBody, request.headers, process.env.SOCIALTAP_WEBHOOK_SECRET!);Tools for AI agents
The SDK hands the SocialTap MCP server's tools to a model: each tool's name, description (its price
and rules included) and input JSON Schema, and a call that sends one stateless MCP request with your key. A tool
behaves exactly as it does for an MCP client: concise results (detail: "full" for every field), next_cursor to
continue, and failures returned as the tool's output (error with retryable and remediation) so the model can
act on them. Transport failures raise as for any request, and tools that may be repeated are retried.
// The Vercel AI SDK (ai is an optional peer dependency): the default tools (call_endpoint reaches every endpoint),
// or socialtapTools({ tools: [...] }) / socialtapTools({ tools: "all" }).
import { generateText, stepCountIs } from "ai";
import { socialtapTools } from "socialtap/ai";
// model: any AI SDK model; prompt: the task. The model calls the tools, the SDK runs them with your key.
const { text } = await generateText({ model, tools: socialtapTools(), stopWhen: stepCountIs(5), prompt });
// Any other tool-calling API: hand TOOLS (name, description, inputSchema) to the model, run its calls with callTool.
import { SocialTap, TOOLS, callTool } from "socialtap";
const r = await callTool(new SocialTap(), "find_endpoint", { query: "Exact follower and like counts, bio and country" });
console.log(r.isError, r.output);| tool | what it does |
|---|---|
find_endpoint | Find an endpoint |
get_post | Post by link |
list_posts | Posts of a profile |
get_profile | Profile by handle |
list_comments | Comments of a post |
get_transcript | Transcript by link |
get_engagement | Engagement by handle |
search | Search by query |
call_endpoint | Call any endpoint |
search_docs | Search the docs |
read_doc | Read a docs page |
get_account | Get account balance |
get_story | Story by link |
list_community_posts | Community posts |
list_hashtag_posts | Hashtag posts |
list_place_posts | Place posts |
list_playlist_posts | Playlist posts |
list_reels | Reels of a profile |
list_sound_posts | Sound posts |
list_top_posts | Top posts |
list_trending_posts | Trending posts |
list_channel_posts | Channel posts of a profile |
list_effect_posts | Effect posts |
list_liked_posts | Liked posts of a profile |
list_photos | Photos of a profile |
list_pins | Pins of a profile |
list_playlist_stories | Playlist stories |
list_playlist_tracks | Playlist tracks |
list_podcast_episodes | Podcast episodes |
list_shop_posts | Shop posts of a profile |
list_tracks | Tracks of a profile |
list_videos | Videos of a profile |
get_seller | Seller by handle |
get_shop | Shop by handle |
list_followers | Followers of a profile |
list_following | Following of a profile |
list_similar_profiles | Similar profiles of a profile |
get_comment | Comment by link |
list_replies | Replies of a post |
list_profile_comments | Profile comments |
get_ad_transcript | Ad transcript by link |
get_ad | Ad by link |
list_ads | Ads of a profile |
list_top_ads | Top ads |
get_hashtag | Hashtag by link |
list_trending_hashtags | Trending hashtags |
get_community | Community by link |
get_product | Product by link |
get_album | Album by link |
get_playlist | Playlist by link |
get_sound | Sound by link |
get_topic | Topic by link |
get_download | Download by link |
get_effect | Effect by link |
get_embed | Embed by link |
get_event | Event by link |
get_live | Live by handle |
get_place | Place by link |
get_podcast | Podcast by link |
get_username | Username by handle |
get_web_page | Web page by link |
list_reviews | Reviews of a product |
list_boards | Boards of a profile |
list_deal_products | Deal products |
list_events | Events of a profile |
list_highlights | Highlights of a profile |
list_offers | Offers of a product |
list_place_events | Place events |
list_playlists | Playlists of a profile |
list_products | Products of a profile |
list_schedule | Schedule of a profile |
list_shop_lists | Shop lists of a profile |
list_top_albums | Top albums |
list_top_playlists | Top playlists |
list_top_products | Top products |
list_top_trends | Top trends |
create_job | Create a background job |
get_job | Get a background job |
list_job_results | List a job's results |
CLI
The package's bin: every endpoint as a command (JSON on stdout; a list walk with --all prints one item per
line), the agent tools, and init, which sets up coding agents.
npx socialtap tiktok profile --handle nasa
npx socialtap endpoints # every command, its params and price
npx socialtap tool find_endpoint '{"query":"Exact follower and like counts, bio and country"}'
npx socialtap init # Claude Code, Codex, Cursor, Gemini CLI: the Agent Skill + the MCP serverinit installs the Agent Skill the site publishes (its discovery index, digest checked) into each agent's user
skills directory and registers the MCP server with your key (--api-key, or SOCIALTAP_API_KEY) in each agent's own user
config: Claude Code through claude mcp add-json, Codex's config.toml, Cursor's mcp.json, Gemini CLI's
settings.json. It sets up every agent it finds (--agent <id> to choose) and is safe to run again.
Versioning
The version is derived from the API contract: major = API version, minor = the contract's revision (it grows with every additive change, a new endpoint included), patch = the SDK generator's revision. Questions and bug reports: support@socialtap.dev.