Public social data API
6 platforms livePublic social media data. One API, one schema.
SocialTap returns public social media data from the major platforms, normalized into one JSON schema per resource. One API key, one credit balance, and you only pay for requests that succeed.
curl -G 'https://staging-fly.socialtap.dev/v1/tiktok/profile' \
--data-urlencode 'handle=https://www.tiktok.com/@nasa' \
-H "x-api-key: $SOCIALTAP_API_KEY"const params = new URLSearchParams({
handle: "https://www.tiktok.com/@nasa",
});
const res = await fetch(`https://staging-fly.socialtap.dev/v1/tiktok/profile?${params}`, {
headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, meta } = body;
console.log(data, meta.credits_charged);import os
import requests
res = requests.get(
"https://staging-fly.socialtap.dev/v1/tiktok/profile",
params={"handle": "https://www.tiktok.com/@nasa"},
headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, meta = body["data"], body["meta"]
print(data, meta["credits_charged"])package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
)
func main() {
q := url.Values{}
q.Set("handle", "https://www.tiktok.com/@nasa")
req, err := http.NewRequest("GET", "https://staging-fly.socialtap.dev/v1/tiktok/profile?"+q.Encode(), nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
var body struct {
Data json.RawMessage `json:"data"`
Meta map[string]any `json:"meta"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
log.Fatal(err)
}
if body.Error != nil {
log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
}
fmt.Println(string(body.Data), body.Meta["credits_charged"])
}<?php
$query = http_build_query([
'handle' => 'https://www.tiktok.com/@nasa',
]);
$ch = curl_init('https://staging-fly.socialtap.dev/v1/tiktok/profile?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;require "json"
require "net/http"
uri = URI("https://staging-fly.socialtap.dev/v1/tiktok/profile")
uri.query = URI.encode_www_form('handle' => 'https://www.tiktok.com/@nasa')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) throws Exception {
String query = "handle=" + encode("https://www.tiktok.com/@nasa");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://staging-fly.socialtap.dev/v1/tiktok/profile?" + query))
.header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
if (response.statusCode() >= 400) throw new RuntimeException(response.body());
System.out.println(response.body());
}
static String encode(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
}using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));
var query = string.Join("&",
"handle=" + Uri.EscapeDataString("https://www.tiktok.com/@nasa"));
var res = await http.GetAsync("https://staging-fly.socialtap.dev/v1/tiktok/profile?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
var error = body.RootElement.GetProperty("error");
throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::blocking::Client::new()
.get("https://staging-fly.socialtap.dev/v1/tiktok/profile")
.query(&[("handle", "https://www.tiktok.com/@nasa")])
.header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
.send()?;
let ok = res.status().is_success();
let body: serde_json::Value = res.json()?;
if !ok {
return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
}
println!("{} {}", body["data"], body["meta"]["credits_charged"]);
Ok(())
}handle takes any form. TikTok username with or without the @ (nasa, @nasa), a profile URL (tiktok.com/@nasa, m.tiktok.com/@nasa, with or without query parameters), or a numeric user ID (tiktok.com/share/user/<id> or the bare ID). Usernames are case-insensitive.
{
"data": {
"approximate_fields": [],
"avatar_url": "https://p16-common-sign.tiktokcdn-us.com/tos-useast5-avt-0068-tx/e5143212a59c09a008bf50f487d54d1f~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=9640&refresh_token=9341391e&x-expires=4070908800&x-signature=SCRUBBED&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=useast5",
"banner_url": null,
"bio": "Making the seemingly impossible, possible.✨",
"category": null,
"country_code": null,
"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": 2140425,
"following_count": 23,
"post_count": 60,
"total_like_count": 11385816,
"total_view_count": null
},
"platform": "tiktok",
"platform_specific": {},
"type": "organization",
"unknown_fields": [],
"url": "https://www.tiktok.com/@nasa",
"username": "nasa"
},
"meta": {
"request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
"platform": "tiktok",
"source": "page",
"is_cached": false,
"credits_charged": 1,
"latency_ms": 0,
"fetched_at": "2026-10-25T12:00:00Z",
"input": {
"kind": "profile",
"id": "7664638705177150477",
"url": "https://www.tiktok.com/@nasa"
},
"credits_remaining": 9999,
"client_request_id": null,
"warnings": [],
"mode": "live"
}
}curl -G 'https://staging-fly.socialtap.dev/v1/facebook/post' \
--data-urlencode 'url=https://www.facebook.com/reel/4075684206061398/' \
-H "x-api-key: $SOCIALTAP_API_KEY"const params = new URLSearchParams({
url: "https://www.facebook.com/reel/4075684206061398/",
});
const res = await fetch(`https://staging-fly.socialtap.dev/v1/facebook/post?${params}`, {
headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, meta } = body;
console.log(data, meta.credits_charged);import os
import requests
res = requests.get(
"https://staging-fly.socialtap.dev/v1/facebook/post",
params={"url": "https://www.facebook.com/reel/4075684206061398/"},
headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, meta = body["data"], body["meta"]
print(data, meta["credits_charged"])package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
)
func main() {
q := url.Values{}
q.Set("url", "https://www.facebook.com/reel/4075684206061398/")
req, err := http.NewRequest("GET", "https://staging-fly.socialtap.dev/v1/facebook/post?"+q.Encode(), nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
var body struct {
Data json.RawMessage `json:"data"`
Meta map[string]any `json:"meta"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
log.Fatal(err)
}
if body.Error != nil {
log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
}
fmt.Println(string(body.Data), body.Meta["credits_charged"])
}<?php
$query = http_build_query([
'url' => 'https://www.facebook.com/reel/4075684206061398/',
]);
$ch = curl_init('https://staging-fly.socialtap.dev/v1/facebook/post?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;require "json"
require "net/http"
uri = URI("https://staging-fly.socialtap.dev/v1/facebook/post")
uri.query = URI.encode_www_form('url' => 'https://www.facebook.com/reel/4075684206061398/')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) throws Exception {
String query = "url=" + encode("https://www.facebook.com/reel/4075684206061398/");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://staging-fly.socialtap.dev/v1/facebook/post?" + query))
.header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
if (response.statusCode() >= 400) throw new RuntimeException(response.body());
System.out.println(response.body());
}
static String encode(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
}using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));
var query = string.Join("&",
"url=" + Uri.EscapeDataString("https://www.facebook.com/reel/4075684206061398/"));
var res = await http.GetAsync("https://staging-fly.socialtap.dev/v1/facebook/post?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
var error = body.RootElement.GetProperty("error");
throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::blocking::Client::new()
.get("https://staging-fly.socialtap.dev/v1/facebook/post")
.query(&[("url", "https://www.facebook.com/reel/4075684206061398/")])
.header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
.send()?;
let ok = res.status().is_success();
let body: serde_json::Value = res.json()?;
if !ok {
return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
}
println!("{} {}", body["data"], body["meta"]["credits_charged"]);
Ok(())
}url takes any form. Facebook post, photo, video or reel URL: /<page>/posts/<id>, permalink.php and story.php links, /photo/?fbid= and /<page>/photos/… links, reel, watch, video.php and /<page>/videos/… links, fb.watch and /share/p|v|r/ share links (m., mbasic. and web. hosts too), or a numeric post, photo or video ID.
{
"data": {
"approximate_fields": [],
"author": {
"avatar_url": "https://scontent-atl3-2.xx.fbcdn.net/v/t39.30808-1/243095782_416661036495945_3843362260429099279_n.png?stp=cp0_dst-png&cstp=mx800x800&ctp=s80x80&_nc_cat=1&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=24&_nc_ht=scontent-atl3-2.xx&_nc_gid=SCRUBBED&_nc_ss=7b…",
"display_name": "NASA - National Aeronautics and Space Administration",
"id": "100044561550831",
"is_verified": true,
"url": "https://www.facebook.com/NASA",
"username": "NASA"
},
"coauthors": [],
"duration_ms": 39381,
"hashtags": [],
"id": "1670768087751894",
"is_nsfw": null,
"is_pinned": null,
"is_sponsored": null,
"language": null,
"media": [
{
"alt_text": null,
"duration_ms": 39381,
"expires_at": "2026-10-25T18:00:00Z",
"height": 2160,
"thumbnail_url": "https://scontent-atl3-2.xx.fbcdn.net/v/t15.5256-10/877658791_1832631854542515_4430770165954872904_n.jpg?stp=dst-jpg_tt6&cstp=mx1920x1080&ctp=s960x960&_nc_cat=101&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=23&_nc_ht=scontent-atl3-2.xx&_nc_gid=SCRUBBED&_n…",
"type": "video",
"url": "https://video-atl3-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQMS1Kmor5hpvEHAtxe3lVPcxOt4prhHPFgKMLcPxvBSvELFTPbkpMPfDvKx8gg5c4VOCCZrgCV0tzqv9ahLzz1s3O0N2Cdf2DaUFGeUSO0WTA.mp4?_nc_cat=106&_nc_sid=SCRUBBED&_nc_ht=video-atl3-1.xx.fbcdn.net&_nc_ohc=SCRUBBED&efg=SCRUBBED&ccb=SCRUBBED&vs=SCRUBBE…",
"width": 3840
}
],
"mentions": [
"CanadianSpaceAgency",
"ISS"
],
"metrics": {
"comment_count": 55,
"like_count": 574,
"quote_count": null,
"repost_count": null,
"save_count": null,
"share_count": null,
"view_count": 52713
},
"platform": "facebook",
"platform_specific": {
"facebook": {
"feedback_id": "ZmVlZGJhY2s6MTY3MDc2ODA4Nzc1MTg5NA==",
"link": null,
"reactions": [
{
"count": 476,
"type": "like"
},
{
"count": 70,
"type": "love"
},
{
"count": 13,
"type": "care"
}
],
"shared_post": null,
"video_id": "4075684206061398"
}
},
"platform_type": "reel",
"published_at": "2026-10-29T11:48:37Z",
"text": "NASA astronaut Anil Menon and Canadian Space Agency astronaut Joshua Kutryk are getting ready to head out of the International Space Station!\n \nAt this point, they have donned spacesuits called Extravehicular Mobility Units (EMUs), which contain all the protections and life suppo…",
"thumbnail_url": "https://scontent-atl3-2.xx.fbcdn.net/v/t15.5256-10/877658791_1832631854542515_4430770165954872904_n.jpg?stp=dst-jpg_tt6&cstp=mx1920x1080&ctp=s960x960&_nc_cat=101&ccb=SCRUBBED&_nc_sid=SCRUBBED&_nc_ohc=SCRUBBED&_nc_oc=SCRUBBED&_nc_zt=23&_nc_ht=scontent-atl3-2.xx&_nc_gid=SCRUBBED&_n…",
"title": null,
"type": "video",
"unknown_fields": [],
"url": "https://www.facebook.com/reel/4075684206061398/"
},
"meta": {
"request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
"platform": "facebook",
"source": "page",
"is_cached": false,
"credits_charged": 1,
"latency_ms": 0,
"fetched_at": "2026-10-25T12:00:00Z",
"input": {
"kind": "video",
"id": "1670768087751894",
"url": "https://www.facebook.com/reel/4075684206061398/"
},
"credits_remaining": 9999,
"client_request_id": null,
"warnings": [],
"mode": "live"
}
}curl -G 'https://staging-fly.socialtap.dev/v1/instagram/transcript' \
--data-urlencode 'url=https://www.instagram.com/p/De1S3KpCXf0/' \
-H "x-api-key: $SOCIALTAP_API_KEY"const params = new URLSearchParams({
url: "https://www.instagram.com/p/De1S3KpCXf0/",
});
const res = await fetch(`https://staging-fly.socialtap.dev/v1/instagram/transcript?${params}`, {
headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, meta } = body;
console.log(data, meta.credits_charged);import os
import requests
res = requests.get(
"https://staging-fly.socialtap.dev/v1/instagram/transcript",
params={"url": "https://www.instagram.com/p/De1S3KpCXf0/"},
headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, meta = body["data"], body["meta"]
print(data, meta["credits_charged"])package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
)
func main() {
q := url.Values{}
q.Set("url", "https://www.instagram.com/p/De1S3KpCXf0/")
req, err := http.NewRequest("GET", "https://staging-fly.socialtap.dev/v1/instagram/transcript?"+q.Encode(), nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
var body struct {
Data json.RawMessage `json:"data"`
Meta map[string]any `json:"meta"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
log.Fatal(err)
}
if body.Error != nil {
log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
}
fmt.Println(string(body.Data), body.Meta["credits_charged"])
}<?php
$query = http_build_query([
'url' => 'https://www.instagram.com/p/De1S3KpCXf0/',
]);
$ch = curl_init('https://staging-fly.socialtap.dev/v1/instagram/transcript?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;require "json"
require "net/http"
uri = URI("https://staging-fly.socialtap.dev/v1/instagram/transcript")
uri.query = URI.encode_www_form('url' => 'https://www.instagram.com/p/De1S3KpCXf0/')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) throws Exception {
String query = "url=" + encode("https://www.instagram.com/p/De1S3KpCXf0/");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://staging-fly.socialtap.dev/v1/instagram/transcript?" + query))
.header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
if (response.statusCode() >= 400) throw new RuntimeException(response.body());
System.out.println(response.body());
}
static String encode(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
}using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));
var query = string.Join("&",
"url=" + Uri.EscapeDataString("https://www.instagram.com/p/De1S3KpCXf0/"));
var res = await http.GetAsync("https://staging-fly.socialtap.dev/v1/instagram/transcript?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
var error = body.RootElement.GetProperty("error");
throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::blocking::Client::new()
.get("https://staging-fly.socialtap.dev/v1/instagram/transcript")
.query(&[("url", "https://www.instagram.com/p/De1S3KpCXf0/")])
.header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
.send()?;
let ok = res.status().is_success();
let body: serde_json::Value = res.json()?;
if !ok {
return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
}
println!("{} {}", body["data"], body["meta"]["credits_charged"]);
Ok(())
}url takes any form. Instagram reel/post URL (instagram.com/reel/…, /reels/…, /p/…, /tv/…, instagr.am, instagram.com/share/… links) or a raw shortcode. For carousel posts, ?img_index=N selects the item; default is the first video.
{
"data": {
"available_languages": [],
"duration_ms": 23745,
"id": "De1S3KpCXf0",
"is_auto_generated": true,
"language": "en",
"platform": "instagram",
"platform_specific": {},
"segments": [
{
"end_ms": 3580,
"start_ms": 0,
"text": "You are looking at nudibranchs. You ever seen anything that crazy looking?"
},
{
"end_ms": 9220,
"start_ms": 3800,
"text": "Every color in the rainbow. These are marine snails basically that have lost their shells"
},
{
"end_ms": 13480,
"start_ms": 9220,
"text": "over time and developed these elaborate colors. Usually brightly colored animals are toxic."
}
],
"source": "asr",
"text": "You are looking at nudibranchs. You ever seen anything that crazy looking? Every color in the rainbow. These are marine snails basically that have lost their shells over time and developed these elaborate colors. Usually brightly colored animals are toxic. Some of these are, some…",
"url": "https://www.instagram.com/reel/De1S3KpCXf0/"
},
"meta": {
"request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
"platform": "instagram",
"source": "asr",
"is_cached": false,
"credits_charged": 4,
"latency_ms": 4125,
"fetched_at": "2026-10-25T12:00:00Z",
"input": {
"kind": "video",
"id": "De1S3KpCXf0",
"url": "https://www.instagram.com/reel/De1S3KpCXf0/"
},
"credits_remaining": 9996,
"client_request_id": null,
"warnings": [],
"mode": "live"
}
}curl -G 'https://staging-fly.socialtap.dev/v1/rumble/comments' \
--data-urlencode 'url=https://rumble.com/shorts/v7h29za' \
-H "x-api-key: $SOCIALTAP_API_KEY"const params = new URLSearchParams({
url: "https://rumble.com/shorts/v7h29za",
});
const res = await fetch(`https://staging-fly.socialtap.dev/v1/rumble/comments?${params}`, {
headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, page, meta } = body;
console.log(data, meta.credits_charged);import os
import requests
res = requests.get(
"https://staging-fly.socialtap.dev/v1/rumble/comments",
params={"url": "https://rumble.com/shorts/v7h29za"},
headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, page, meta = body["data"], body["page"], body["meta"]
print(data, meta["credits_charged"])package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
)
func main() {
q := url.Values{}
q.Set("url", "https://rumble.com/shorts/v7h29za")
req, err := http.NewRequest("GET", "https://staging-fly.socialtap.dev/v1/rumble/comments?"+q.Encode(), nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
var body struct {
Data json.RawMessage `json:"data"`
Page json.RawMessage `json:"page"`
Meta map[string]any `json:"meta"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
log.Fatal(err)
}
if body.Error != nil {
log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
}
fmt.Println(string(body.Data), body.Meta["credits_charged"])
}<?php
$query = http_build_query([
'url' => 'https://rumble.com/shorts/v7h29za',
]);
$ch = curl_init('https://staging-fly.socialtap.dev/v1/rumble/comments?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;require "json"
require "net/http"
uri = URI("https://staging-fly.socialtap.dev/v1/rumble/comments")
uri.query = URI.encode_www_form('url' => 'https://rumble.com/shorts/v7h29za')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) throws Exception {
String query = "url=" + encode("https://rumble.com/shorts/v7h29za");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://staging-fly.socialtap.dev/v1/rumble/comments?" + query))
.header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
if (response.statusCode() >= 400) throw new RuntimeException(response.body());
System.out.println(response.body());
}
static String encode(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
}using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));
var query = string.Join("&",
"url=" + Uri.EscapeDataString("https://rumble.com/shorts/v7h29za"));
var res = await http.GetAsync("https://staging-fly.socialtap.dev/v1/rumble/comments?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
var error = body.RootElement.GetProperty("error");
throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::blocking::Client::new()
.get("https://staging-fly.socialtap.dev/v1/rumble/comments")
.query(&[("url", "https://rumble.com/shorts/v7h29za")])
.header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
.send()?;
let ok = res.status().is_success();
let body: serde_json::Value = res.json()?;
if !ok {
return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
}
println!("{} {}", body["data"], body["meta"]["credits_charged"]);
Ok(())
}url takes any form. Rumble video, short or live stream URL (rumble.com/v…-title.html, /shorts/v…, /share/v…, /embed/v…/) or a video ID (v…).
{
"data": [
{
"approximate_fields": [
"published_at"
],
"author": {
"avatar_url": "https://hugh.cdn.rumble.cloud/video/z0/e/b/M/g/ebMgr.asF.1-4qu5ac-tnkdxy.jpeg",
"display_name": "inshallakhan",
"id": null,
"is_verified": false,
"url": "https://rumble.com/user/inshallakhan",
"username": "user/inshallakhan"
},
"edited_at": null,
"id": "620403472",
"is_by_post_author": false,
"is_edited": null,
"is_liked_by_author": null,
"is_pinned": null,
"metrics": {
"like_count": 0,
"reply_count": 0
},
"parent_id": null,
"platform": "rumble",
"platform_specific": {
"rumble": {
"author_badges": [],
"dislike_count": 0
}
},
"post_id": "v7h29za",
"published_at": "2026-10-23T03:31:00Z",
"text": "oh 😯😯",
"unknown_fields": [],
"url": "https://rumble.com/shorts/v7h29za#comment-620403472"
},
{
"approximate_fields": [
"published_at"
],
"author": {
"avatar_url": "https://hugh.cdn.rumble.cloud/video/z0/C/E/l/b/CElbr.asF-4pzq1o-ti0cx0.jpeg",
"display_name": "CassandraB89",
"id": null,
"is_verified": false,
"url": "https://rumble.com/user/CassandraB89",
"username": "user/CassandraB89"
},
"edited_at": null,
"id": "620356964",
"is_by_post_author": false,
"is_edited": null,
"is_liked_by_author": null,
"is_pinned": null,
"metrics": {
"like_count": 0,
"reply_count": 0
},
"parent_id": null,
"platform": "rumble",
"platform_specific": {
"rumble": {
"author_badges": [],
"dislike_count": 0
}
},
"post_id": "v7h29za",
"published_at": "2026-10-22T13:01:00Z",
"text": "🐈👌🏻🧡",
"unknown_fields": [],
"url": "https://rumble.com/shorts/v7h29za#comment-620356964"
},
{
"approximate_fields": [
"published_at"
],
"author": {
"avatar_url": null,
"display_name": "SkyeWalker0504",
"id": null,
"is_verified": false,
"url": "https://rumble.com/user/SkyeWalker0504",
"username": "user/SkyeWalker0504"
},
"edited_at": null,
"id": "620301964",
"is_by_post_author": false,
"is_edited": null,
"is_liked_by_author": null,
"is_pinned": null,
"metrics": {
"like_count": 1,
"reply_count": 0
},
"parent_id": null,
"platform": "rumble",
"platform_specific": {
"rumble": {
"author_badges": [],
"dislike_count": 0
}
},
"post_id": "v7h29za",
"published_at": "2026-10-21T15:29:00Z",
"text": "Looks like a Minecraft cat.",
"unknown_fields": [],
"url": "https://rumble.com/shorts/v7h29za#comment-620301964"
}
],
"page": {
"has_more": false,
"next_cursor": null,
"next_cursor_expires_at": null,
"end_reason": "end"
},
"meta": {
"request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
"platform": "rumble",
"source": "api",
"is_cached": false,
"credits_charged": 1,
"latency_ms": 0,
"fetched_at": "2026-10-25T12:00:00Z",
"input": {
"kind": "video",
"id": "v7h29za",
"url": "https://rumble.com/v7h29za"
},
"credits_remaining": 9999,
"client_request_id": null,
"warnings": [],
"mode": "live"
}
}Coverage
Every platform. The same JSON, field for field.
How it works
One integration. Learn a schema once, then add platforms without new parsing code.
One key, one URL pattern
Send x-api-key on every request, the same way for every platform.
One schema per resource
Ads, Comments, Posts, Profiles and Transcripts have the same fields on every platform. null means unknown, never zero.
Pay only for success
Prepaid credits, one balance. Errors cost nothing. Cache hits cost nothing.
For agents
Built for coding agents. Paste one prompt, ship the integration.
Integrate the SocialTap API (https://staging-fly.socialtap.dev) into this project.
1. Read https://staging-fly.socialtap.dev/llms.txt first, then the Markdown docs page of the endpoint you need (linked there). Use only endpoints and parameters documented there.
2. Send the API key in the x-api-key header, read from the SOCIALTAP_API_KEY environment variable. Never hard-code it; if it is not set, ask me for it.
3. Branch on error.code: retry only the retryable codes the docs list, with backoff. On list endpoints follow page.next_cursor while page.has_more is true.
4. Verify with one real request before building on it, for example:
curl -G 'https://staging-fly.socialtap.dev/v1/tiktok/profile' \
--data-urlencode 'handle=https://www.tiktok.com/@nasa' \
-H "x-api-key: $SOCIALTAP_API_KEY"
and check that data is not empty.
5. Tell me which endpoint you used, what meta.credits_charged was, and any error code you saw.claude mcp add --transport http socialtap https://staging-fly.socialtap.dev/mcp --header "authorization: Bearer $SOCIALTAP_API_KEY"{
"mcpServers": {
"socialtap": {
"type": "http",
"url": "https://staging-fly.socialtap.dev/mcp",
"headers": {
"authorization": "Bearer ${SOCIALTAP_API_KEY}"
}
}
}
}{
"mcpServers": {
"socialtap": {
"url": "https://staging-fly.socialtap.dev/mcp",
"headers": {
"authorization": "Bearer ${env:SOCIALTAP_API_KEY}"
}
}
}
}codex mcp add socialtap --url https://staging-fly.socialtap.dev/mcp --bearer-token-env-var SOCIALTAP_API_KEY[mcp_servers.socialtap]
url = "https://staging-fly.socialtap.dev/mcp"
bearer_token_env_var = "SOCIALTAP_API_KEY"Endpoints
Call them today. Each has a docs page, a playground and live status.
GET /v1/facebook/post1 creditFacebook Ad Library Search APIBetaAdGET /v1/facebook/search_ads1 credit / pageFacebook Video Transcript APIBetaTranscriptGET /v1/facebook/transcriptFrom 1 creditInstagram Post APIBetaPostGET /v1/instagram/post1 creditInstagram Posts APIBetaPostGET /v1/instagram/posts1 credit / pageInstagram Profile APIBetaProfileGET /v1/instagram/profile1 creditInstagram Reels Transcript APIBetaTranscriptGET /v1/instagram/transcriptFrom 1 creditRumble Comments APIBetaCommentGET /v1/rumble/comments1 credit / pageRumble Video APIBetaPostGET /v1/rumble/post1 creditRumble Channel Videos APIBetaPostGET /v1/rumble/posts1 credit / pageRumble Channel APIBetaProfileGET /v1/rumble/profile1 creditRumble Search APIBetaPostGET /v1/rumble/search_posts1 credit / pageRumble Transcript APIBetaTranscriptGET /v1/rumble/transcriptFrom 1 creditThreads Profile APIBetaProfileGET /v1/threads/profile1 creditTikTok Comments APIBetaCommentGET /v1/tiktok/comments1 credit / pageTikTok Post APIBetaPostGET /v1/tiktok/post1 creditTikTok Posts APIBetaPostGET /v1/tiktok/posts1 credit / pageTikTok Profile APIBetaProfileGET /v1/tiktok/profile1 creditTikTok Transcript APIBetaTranscriptGET /v1/tiktok/transcriptFrom 1 creditYouTube Comments APIBetaCommentGET /v1/youtube/comments1 credit / pageYouTube Video APIBetaPostGET /v1/youtube/post1 creditYouTube Channel Videos APIBetaPostGET /v1/youtube/posts1 credit / pageYouTube Channel APIBetaProfileGET /v1/youtube/profile1 creditYouTube Transcript APIBetaTranscriptGET /v1/youtube/transcriptFrom 1 creditPricing
Prepaid credits. From $0.75 per 1,000, and they never expire.
$29
$1.45 per 1,000 credits
$99
$1.24 per 1,000 credits
$399
$1.00 per 1,000 credits
$1,499
$0.75 per 1,000 credits