curl --request POST \
--url https://api.vidnavigator.com/v1/tweet/statement \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"tweet_id": "1234567890123456789"
}
'import requests
url = "https://api.vidnavigator.com/v1/tweet/statement"
payload = { "tweet_id": "1234567890123456789" }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({tweet_id: '1234567890123456789'})
};
fetch('https://api.vidnavigator.com/v1/tweet/statement', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vidnavigator.com/v1/tweet/statement",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tweet_id' => '1234567890123456789'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vidnavigator.com/v1/tweet/statement"
payload := strings.NewReader("{\n \"tweet_id\": \"1234567890123456789\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vidnavigator.com/v1/tweet/statement")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"tweet_id\": \"1234567890123456789\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vidnavigator.com/v1/tweet/statement")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tweet_id\": \"1234567890123456789\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"final_statement": "<string>",
"detailed_analysis": "<string>",
"topics": [
"<string>"
],
"entities": [
"<string>"
],
"claim_type": "factual_claim",
"intent": "educate",
"tone": "serious",
"emotion": "curiosity",
"authority": "data_driven",
"tweet_text": "<string>",
"tweet_media_summary": "<string>",
"quoted_tweet_text": "<string>",
"quoted_media_summary": "<string>"
}
}{
"status": "error",
"error": "<string>",
"message": "<string>"
}{
"status": "error",
"error": "limit_exceeded",
"message": "<string>"
}{
"status": "error",
"error": "metadata_fetch_failed",
"message": "<string>"
}{
"status": "error",
"error": "<string>",
"message": "<string>"
}Tweet Claim Analysis
Fetches the tweet content (including any quoted tweet and attached media), then uses AI to extract a rich structured analysis: the core claim, classification axes, topics, entities, and raw tweet data.
Multimodal media handling: attached media is processed by type. Videos are transcribed (platform captions or speech-to-text) and summarized; images are described by a vision model — transcribed text, chart/graph data points, recognisable people and logos, and any claims they make — and folded into the analysis.
Classification axes (claim_type, intent, tone, emotion, authority) reflect only the original tweet text, not quoted content, media, or images.
Billing (consolidated, mirrors /v1/analyze/video):
- exactly one
analysis_requestcharge withquantity = ceil(total_tokens / 15000), summing tokens across the optional per-media extraction calls, the optional image vision calls, AND the main statement-extraction call. A typical tweet+quoted tweet with one video or an attached image runs several LLM calls but produces just one billing entry when the combined tokens stay under 15k. Image analysis is billed through this sameanalysis_requestmeter. - one
standard_requestper media URL whose transcript or metadata is fetched (mirrors/v1/transcript). transcription_hourproportional to the audio duration if speech-to-text runs for a media video that has no platform transcript. Waived for users withusers.free_on_cache_hit=truewhen STT was served from cache (same waiver as/v1/transcribe).
Long videos: this endpoint is synchronous and holds the connection open for the whole transcription. For media longer than ~10 minutes use POST /tweet/statement/async instead, which returns a task_id and can call your webhook when it finishes. Media longer than 10 minutes is rejected here with video_too_long (HTTP 400). The metadata fetch needed to read the video’s duration is billed (standard_request or residential_request) and is not refunded: the limit is documented, so the proxy call was spent answering a request that could not be served. No transcription_hour is charged — no audio is processed. Send long media to the async endpoint, which has no cap. See https://docs.vidnavigator.com/guides/async-jobs
curl --request POST \
--url https://api.vidnavigator.com/v1/tweet/statement \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"tweet_id": "1234567890123456789"
}
'import requests
url = "https://api.vidnavigator.com/v1/tweet/statement"
payload = { "tweet_id": "1234567890123456789" }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({tweet_id: '1234567890123456789'})
};
fetch('https://api.vidnavigator.com/v1/tweet/statement', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vidnavigator.com/v1/tweet/statement",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tweet_id' => '1234567890123456789'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vidnavigator.com/v1/tweet/statement"
payload := strings.NewReader("{\n \"tweet_id\": \"1234567890123456789\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vidnavigator.com/v1/tweet/statement")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"tweet_id\": \"1234567890123456789\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vidnavigator.com/v1/tweet/statement")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tweet_id\": \"1234567890123456789\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"final_statement": "<string>",
"detailed_analysis": "<string>",
"topics": [
"<string>"
],
"entities": [
"<string>"
],
"claim_type": "factual_claim",
"intent": "educate",
"tone": "serious",
"emotion": "curiosity",
"authority": "data_driven",
"tweet_text": "<string>",
"tweet_media_summary": "<string>",
"quoted_tweet_text": "<string>",
"quoted_media_summary": "<string>"
}
}{
"status": "error",
"error": "<string>",
"message": "<string>"
}{
"status": "error",
"error": "limit_exceeded",
"message": "<string>"
}{
"status": "error",
"error": "metadata_fetch_failed",
"message": "<string>"
}{
"status": "error",
"error": "<string>",
"message": "<string>"
}Overview
This endpoint turns a single X post into a machine-readable intelligence object. It does not just retrieve tweet text or metadata. It analyzes what the author actually meant by combining the original tweet, any quoted tweet, and any media attached to either one. That means the output reflects the full communicative intent of the post, not just the visible text. If a tweet makes sense only when read together with a quoted post, an attached video, or media inside the quoted tweet, this endpoint includes that context in the analysis. It is designed for workflows that need more than keyword monitoring or tweet retrieval, such as fact-checking pipelines, narrative tracking, social risk monitoring, and structured ingestion into dashboards or AI systems.What This Endpoint Returns
Intent-Aware Claim Extraction
final_statement that reflects what the author actually meant, not just what the raw tweet text says in isolation.Quoted Tweet Understanding
Multi-Axis Classification
claim_type, intent, tone, emotion, and authority.Multimodal Media Intelligence
Why This Endpoint Is Different
Most tweet APIs stop at text retrieval, engagement metrics, or shallow metadata. This endpoint is built for intelligence extraction.- It understands the intent behind the original tweet.
- It understands the quoted tweet as part of the message, not as unrelated metadata.
- It analyzes shared media in the original tweet — both videos (transcribed) and images (described by a vision model).
- It analyzes shared media in the quoted tweet.
- It returns a structured output that reflects the combined meaning of all of that context.
How It Works
- Send a
tweet_idfor the target X post. - VidNavigator fetches the original tweet, any quoted tweet, and media attached to both.
- If video or audio is present in either context, the system retrieves transcripts or falls back to speech-to-text when needed. Attached images are described by a vision model.
- The combined context is analyzed to determine the real claim, intent, framing, and supporting media meaning.
- The result is returned as structured JSON ready for applications and pipelines.
https://x.com/user/status/1912345678901234567, the tweet_id is 1912345678901234567.Synchronous or async?
Attached videos are transcribed in full before the claim can be extracted, so a tweet carrying a long video takes as long as that video. This endpoint therefore comes in two modes, with the same request body and the same result:| Mode | Endpoint | Attached video duration | How you get the result |
|---|---|---|---|
| Synchronous | POST /tweet/statement | Up to 10 minutes | In the HTTP response |
| Async | POST /tweet/statement/async | Any length | Poll GET /tweet/statement/{task_id} or receive a webhook |
400 video_too_long. Use the async mode — it also works for text-only tweets and short clips.Classification Axes
The classification labels below are derived from the original tweet text only, not from quoted tweets or attached media:claim_type:factual_claim,opinion,question,call_to_action,satire,news_sharing,personal_experienceintent:educate,inform,analyze,persuade,entertain,inspire,challengetone:serious,humorous,provocative,neutral,warm,skeptical,inspirationalemotion:curiosity,urgency,outrage,fear,hope_inspiration,confidence_reassurance,empathy_warmth,awe_wonderauthority:data_driven,expert_led,experience_based,speculative
Example Usage
Best For
Use this endpoint when you need to understand what a post is really saying, especially when meaning depends on:- the author’s underlying intent
- a quoted tweet that changes the framing
- attached video or audio in the original tweet
- attached video or audio in the quoted tweet
Basic Request
curl -X POST "https://api.vidnavigator.com/v1/tweet/statement" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tweet_id": "1912345678901234567"
}'
import requests
url = "https://api.vidnavigator.com/v1/tweet/statement"
headers = {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
data = {
"tweet_id": "1912345678901234567"
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
print("Final statement:", result["data"]["final_statement"])
print("Claim type:", result["data"]["claim_type"])
print("Topics:", result["data"]["topics"])
const response = await fetch('https://api.vidnavigator.com/v1/tweet/statement', {
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
tweet_id: '1912345678901234567'
})
});
const result = await response.json();
console.log(result.data.final_statement);
Example: Feeding Results into Search or Verification
When you want to take a tweet’s interpreted meaning and use it for search, fact-checking, or evidence retrieval, the structured output is ready to plug into downstream pipelines:curl -X POST "https://api.vidnavigator.com/v1/tweet/statement" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tweet_id": "1912345678901234567"
}'
final_statementfor human review or as a search/verification querydetailed_analysisfor framing and stance contexttopicsandentitiesfor clustering, tagging, or analytics
Response Example
{
"status": "success",
"data": {
"final_statement": "The author claims that a new city policy will ban gas-powered delivery scooters in the downtown area next month, arguing that the change is being rushed without enough support for affected workers.",
"detailed_analysis": "The tweet presents a concrete policy claim and frames it as both imminent and harmful to delivery workers. The author positions the decision as poorly planned and emphasizes the lack of transition support. The message appears intended to persuade the audience that the policy is unfair rather than merely to report it. The framing combines factual assertion with rhetorical pressure.",
"topics": [
"urban policy",
"delivery workers",
"transport regulation",
"labor impact"
],
"entities": [
"City Council",
"downtown"
],
"claim_type": "factual_claim",
"intent": "persuade",
"tone": "provocative",
"emotion": "urgency",
"authority": "speculative",
"tweet_text": "Next month the city is banning gas scooters downtown and nobody has explained how delivery workers are supposed to adapt this fast.",
"tweet_media_summary": "A short attached video shows several delivery riders speaking about costs, route changes, and reduced earnings if the rule takes effect.",
"quoted_tweet_text": "Official announcement: downtown clean transport rules begin next month.",
"quoted_media_summary": null
}
}
Field Guide
| Field | Description |
|---|---|
final_statement | Full normalized claim in the author’s voice, informed by the full contextual analysis |
detailed_analysis | 3-5 sentence explanation covering claim, framing, evidence, and stance |
topics | Key subjects discussed in the tweet (3-8) |
entities | Named entities such as people, organizations, or places (0-8) |
claim_type / intent / tone / emotion / authority | Classification axes derived from the original tweet text only |
tweet_text | Original text of the source tweet |
tweet_media_summary | Full content summary of media attached to the original tweet: a video transcript summary or a vision-model description of attached image(s). null when no media is attached. |
quoted_tweet_text | Text of a quoted or referenced tweet, when present |
quoted_media_summary | Full content summary of media attached to the quoted tweet (video transcript or image description). null when no media is attached. |
Intelligence Model
This endpoint should be thought of as a multi-layer interpretation pipeline:- Read the original tweet text.
- Detect whether a quoted tweet changes or completes the meaning.
- Analyze media attached to the original tweet.
- Analyze media attached to the quoted tweet.
- Produce a final claim and classification that reflect the author’s intended message as completely as possible.
Billing Notes
Billing is consolidated and mirrors/analyze/video. A single call can involve several internal LLM calls (media extraction, image vision, and the main statement extraction) but produces one billing entry per meter:
- Exactly one
analysis_requestcharge withquantity = ceil(total_tokens / 15000), summing tokens across the optional per-media extraction calls, the optional image vision calls, and the main statement-extraction call. A typical tweet + quoted tweet with one video or one attached image runs several LLM calls but produces just one billing entry when the combined tokens stay under 15k. Image analysis is billed through this sameanalysis_requestmeter. - One
standard_requestper media URL whose transcript or metadata is fetched (mirrors/transcript). transcription_hourproportional to the audio duration if speech-to-text runs for a media video with no platform transcript. Waived for users withfree_on_cache_hit=truewhen STT was served from cache.
video_too_long rejection on the synchronous endpoint still bills the metadata fetch that read the duration (not refunded), but no transcription_hour.
Use Cases
Fact-Checking
Narrative Tracking
final_statement, topics, and entities across many tweets.Reputation Monitoring
AI Product Integration
Troubleshooting
- Invalid tweet ID: Make sure you are sending only the numeric post ID, not the full X URL.
- Upstream fetch failure: If X content cannot be retrieved or parsed, the endpoint may return a
502response. - Missing media summary: If no media is attached, or media could not be processed,
tweet_media_summaryandquoted_media_summarymay benull. - Unexpected classification:
claim_type,intent,tone,emotion, andauthorityare based only on the original tweet text, whilefinal_statementand media summaries reflect the broader contextual analysis. video_too_long: the tweet or its quoted tweet carries a video longer than 10 minutes. UsePOST /tweet/statement/async.402 limit_exceeded: not enough credits. See Errors for the full list.
Authorizations
API key authentication. Include your VidNavigator API key in the X-API-Key header.
Body
The X/Twitter tweet ID (numeric string)
"1234567890123456789"

