Get started

Quickstart

Make your first request in a minute: one API key, one HTTP call, one JSON shape for every platform.

  1. Get an API key

    Every request is authenticated with an API key in the x-api-key header. To try SocialTap right now, use this public test key:

    st_test_docs_mZkmkl5JiSWvVgL4v3DLolbtSsjxXm11

    It works right now, with no signup: every endpoint answers from recorded responses, free. It can't reach an account or spend credits. For live data, use your own key.

    Keep keys out of source control, for example in an environment variable:

    Shell
    export SOCIALTAP_API_KEY="st_test_docs_mZkmkl5JiSWvVgL4v3DLolbtSsjxXm11"
  2. Make a request

    Endpoints are plain HTTPS GET requests with query parameters. This calls the TikTok Profile API with its documented example input:

    cURL
    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"
    Node.js
    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);
    Python
    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"])
    Go
    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
    <?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;
    Ruby
    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"]
    Java
    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);
        }
    }
    .NET
    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"));
    Rust
    // 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(())
    }
  3. Read the response

    A successful response is a JSON object with two keys: data, the item in its resource's shared schema, and meta, which describes how the request was served. List endpoints add a third key with what you need to fetch the next page.

    200 OK
    {
      "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"
      }
    }
    FieldTypeDescription
    meta.request_idstringUnique request ID; include it when contacting support.
    meta.platformstringPlatform ID of the endpoint (youtube, tiktok, …).
    meta.sourcestringWhich upstream strategy produced the data.
    meta.is_cachedbooleanTrue when served from the cache (free); see max_age.
    meta.credits_chargedintegerCredits charged for this request (0 for errors and cache hits).
    meta.latency_msintegerTime SocialTap spent on the request, in milliseconds.
    meta.fetched_atstring (date-time)When the data was fetched from the platform, RFC 3339 UTC (older than the request for cache hits).
    meta.inputobject or nullWhat the request's url or handle resolved to: kind, platform ID and canonical URL, so you can confirm what was fetched; null for searches.
    meta.input.kindstringWhat the input points to (profile, video, post, …). New values may be added; treat unknown values as other.
    meta.input.idstring or nullPlatform-native ID of the item; null when it is only known after the fetch and the request failed.
    meta.input.urlstring or nullCanonical URL of the item; null when unknown.
    meta.credits_remaininginteger or nullAccount balance after this request (the x-credits-remaining header); for a busy account an estimate that may not yet subtract concurrent requests (about a second of usage), never below the real balance; null when SocialTap could not read it.
    meta.client_request_idstring or nullYour x-client-request-id, echoed; null when you sent none.
    meta.warningsobject[]Things to act on that did not fail the request: a deprecated endpoint, partial data. [] when none.
    meta.warnings[].codestringMachine-readable warning code (see the warnings list). New codes may be added.
    meta.warnings[].messagestringWhat to do about it.
    meta.warnings[].doc_urlstringWhere to read more (the changelog entry, the endpoint's docs).
    meta.warnings[].fieldsstring[]partial_data: the output fields (catalog paths such as metrics.view_count) that are null or [] because part of the data could not be fetched; absent for other codes.
    meta.modestring or nulllive, or test for a test key's answer: a recorded response (fixture), free and deterministic; null when SocialTap could not tell. New values may be added.
    One of live, test

Errors

A failed request returns a non-2xx status and an error object with a stable code:

400 response
{
  "error": {
    "code": "invalid_input",
    "message": "unknown parameter \"username\"; did you mean \"handle\"? This endpoint accepts: handle, max_age, fields.",
    "request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
    "status": 400,
    "retryable": false,
    "param": "username",
    "remediation": "Fix the parameter named in param (the message says how); for a link of the wrong kind, call the endpoint the message names.",
    "doc_url": "https://staging-fly.socialtap.dev/docs/errors/#invalid_input",
    "details": {
      "accepted_params": [
        "handle",
        "max_age",
        "fields"
      ],
      "suggestion": "handle"
    },
    "charged": false
  }
}

Branch on code, never on message. The error reference lists every code and whether it is safe to retry.

Next steps

All endpoints

Facebook

Instagram

Rumble

Threads

TikTok

YouTube

Last updated