Skip to main content
Postcard accepts a direct post URL and runs a four-stage forensic pipeline to produce a credibility report. You can submit a URL two ways: through the web UI or the REST API.

Via the web UI

1

Open Postcard

Navigate to postcard.fartlabs.org. The home page displays a URL input field.
2

Paste the post URL

Paste the full URL of the social media post you want to verify — for example, https://x.com/user/status/123.
3

Submit

Press Enter or click the submit button. Postcard redirects you to /postcards?url=<encoded-url> and the forensic pipeline starts automatically, provided your API key is configured.
4

Wait for the report

The UI polls for status every 3 seconds and displays live progress messages — scraping, corroborating, auditing, and scoring — until the report is ready.
The pipeline requires a Google Gemini API key to start a new analysis. If you haven’t set one up yet, see API key setup.

Via the REST API

Use the REST API to integrate Postcard into your own tools or pipelines.

1. Submit the URL

Send a POST request to /api/postcards with the post URL in the JSON body:
curl -s -X POST "https://postcard.fartlabs.org/api/postcards" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://x.com/user/status/123" }'
The endpoint returns HTTP 202 Accepted immediately with an analysis id:
{
  "id": "abc-123",
  "status": "processing",
  "message": "Forensic trace initialized."
}

2. Poll for results

Use the original URL to poll GET /api/postcards?url=... for status updates:
# Poll for completion
while true; do
  RESPONSE=$(curl -s "https://postcard.fartlabs.org/api/postcards?url=https://x.com/user/status/123")
  STATUS=$(echo "$RESPONSE" | jq -r '.status')

  if [ "$STATUS" = "completed" ]; then
    echo "$RESPONSE" | jq '.postcard'
    break
  elif [ "$STATUS" = "failed" ]; then
    echo "Error: $(echo '$RESPONSE' | jq -r '.error')"
    break
  fi

  echo "Progress: $(echo '$RESPONSE' | jq -r '.progress // 0')"
  sleep 3
done
While processing, the response includes a stage, message, and progress (0–1):
{
  "status": "processing",
  "stage": "corroborating",
  "message": "Searching for primary sources...",
  "progress": 0.4
}
When complete, the full forensic report is included in the response body.

Forcing re-analysis with refresh

By default, Postcard serves a cached result if the URL has been analysed before — no API key required. To force a fresh analysis regardless of the cache, set refresh: true in your POST body:
{
  "url": "https://x.com/user/status/123",
  "userApiKey": "your-gemini-api-key",
  "refresh": true
}

Cached results

When a URL has already been analysed, Postcard returns the stored report immediately with no pipeline cost — no API key needed for cached lookups. The GET endpoint (/api/postcards?url=...) also serves cached results directly. If no analysis exists for the URL yet, it returns a 404 not_found response:
{
  "status": "not_found",
  "error": "Analysis not found. Submit this URL via the Postcard UI or the POST endpoint to start a trace."
}

Error cases

ErrorCause
Login or signup wall detectedThe platform requires authentication to view the content (common on Instagram and some X posts)
Cloudflare or security check detectedThe platform blocked the scraper with a challenge page
Content too short or emptyThe page returned insufficient text for analysis
Platform not recognized or supportedThe URL resolved to a generic page with no platform signals
When any of these occur, the pipeline sets the verdict to insufficient_data and records the failure reason in the corroboration log. No API credits are consumed.

Build docs developers (and LLMs) love