Quickstart

One curl call against the live API. No auth required while sapph1re's billing gateway is in dev mode.

curl 'https://api.imagetrustprotocol.world/v1/lookup/claim?text=biden+inauguration'

You should get back a JSON object with several PolitiFact / Logically Facts / Youturn records about Biden's inauguration. The response shape is documented below under Response shape.

Production state. The API is live; the billing gateway integration with sapph1re is still being wired in. Once it's live, calls will require an integrator account through sapph1re's MCP Billing Gateway and pricing will apply per call. See Pricing.

Authentication

Authentication is handled by sapph1re's MCP Billing Gateway, which sits in front of the API and issues integrator API keys. When billing is wired in, every authenticated request will pass through sapph1re's gateway, which adds an X-Gateway-Secret header that the API validates.

While the gateway integration is being finalized, the API runs in dev mode (open). This will change before production billing turns on. New integrators should plan for sapph1re-issued API keys.

To get on the early-integrator list, email info@skydata.one.

Base URL

https://api.imagetrustprotocol.world

All endpoints live under the /v1/ path prefix. URL path versioning is used so future breaking changes can ship as /v2/ without affecting existing integrations.

Lookup by hash

Use this when your agent or pipeline already has a 64-bit perceptual hash (pHash) of the image. Fastest path; no image bytes leave your system.

GET/v1/lookup/hash/{hash}

Path parameters

ParameterTypeDescription
hashstring (16 hex chars)64-bit pHash, formatted as exactly 16 hexadecimal characters. Lower or upper case accepted.

Example

curl 'https://api.imagetrustprotocol.world/v1/lookup/hash/abc123def4567890'

Returns a standard response object. match_quality will be one of exact (Hamming distance 0), similar (distance 1-8), or not_found (distance > 8 or no record present).

Lookup by image bytes

Use this when you have an image file but no pHash. The API computes the hash server-side using the same DCT-based algorithm and runs the same lookup as the hash endpoint.

POST/v1/lookup/image

Body

multipart/form-data with one field:

FieldTypeDescription
imagefileImage file. Maximum 10 MB. Common formats supported (JPEG, PNG, WebP, GIF, etc.).

Example

curl -X POST https://api.imagetrustprotocol.world/v1/lookup/image \
  -F "image=@/path/to/image.jpg"

What we do with the image bytes. We compute the perceptual hash and discard the bytes. Original image bytes are never stored. See the privacy policy for the full data handling description.

Lookup by claim text

Use this when you have the textual claim being asserted about an image (or about anything else). Powered by Postgres full-text search across the corpus's claim text and translated claim text.

GET/v1/lookup/claim?text={claim}

Query parameters

ParameterTypeDescription
textstringThe claim text to look up. URL-encode appropriately. There is no fixed maximum length, though very long inputs may be truncated.

Example

curl 'https://api.imagetrustprotocol.world/v1/lookup/claim?text=trump+venezuela+capture'

If the local corpus returns no matches, the API falls back to Google Fact Check Tools API as a real-time source. Records returned via the Google fallback are tagged with methodology_version: "google_fallback_v1" and metadata.fallback_source: "google_fact_check_api" on each source record so you can distinguish cached corpus matches from live fallback results.

Response shape

Every endpoint returns the same JSON object structure. Fields not relevant to a given match (e.g. image on a claim-only query) are null.

{
  "request_id": "54eb3b58-7ab5-4fe4-92c6-b92cf655a348",
  "match_quality": "similar",
  "image": {
    "hash": "abc123def4567890",
    "first_seen_at": "2025-04-12T18:33:01.000Z",
    "known_urls": ["https://example.com/article/x"]
  },
  "consensus": {
    "rating": "MOSTLY_FALSE",
    "confidence": 0.83,
    "contextual_flags": ["MISATTRIBUTED"],
    "contributing_record_count": 4
  },
  "sources": [
    {
      "publisher": "PolitiFact",
      "source_url": "https://www.politifact.com/factchecks/...",
      "publication_date": "2024-11-12",
      "rating_original": "Mostly False",
      "rating_canonical": "MOSTLY_FALSE",
      "rating_explanation": "...",
      "contextual_flags": [],
      "language": "en",
      "ifcn_signatory": true,
      "methodology_version": "v1",
      "appearance_urls": ["https://twitter.com/..."],
      "source_format": "CLAIMREVIEW",
      "media_authenticity_category": null
    }
  ],
  "total_record_count": 9,
  "metadata": {
    "response_timestamp": "2026-05-03T15:19:33.954Z",
    "api_version": "v1"
  }
}

Top-level fields

FieldTypeDescription
request_idstring (uuid)Per-call identifier. Use this when contacting support about a specific request.
match_qualitystringOne of exact, similar, not_found. See Match quality.
imageobject | nullImage record (hash, first-seen timestamp, known URLs) when an image was matched. null for claim-only matches.
consensusobject | nullAggregated verdict computed across the contributing records. null when the corpus has no records that aggregate, or when no consensus exists yet for this image.
sourcesarrayUp to 20 contributing fact-check records, sorted by publication date descending.
total_record_countintegerTotal number of contributing records (the sources array may be capped at 20; total_record_count reflects the true count).
metadataobjectResponse timestamp and API version.

Source record fields

FieldTypeDescription
publisherstringName of the fact-checking publisher (e.g. PolitiFact, AFP).
source_urlstringURL of the original fact-check article.
publication_datestring (ISO date) | nullWhen the publisher published the fact-check.
rating_originalstringThe publisher's own rating string (e.g. "Pants on Fire", "Verdadero").
rating_canonicalstringNormalized rating. See Rating values.
rating_explanationstring | nullThe publisher's short rationale for the rating, when present.
contextual_flagsarrayOrthogonal flags. See Contextual flags.
languagestring (ISO 639-1) | nullLanguage of the original claim text.
ifcn_signatorybooleanWhether the publisher is a current International Fact-Checking Network signatory. Used as a credibility weight in consensus aggregation.
methodology_versionstringVersion of our normalization methodology applied to this record. Allows reprocessing if mappings change.
appearance_urlsarrayURLs where the claim was seen (social posts, etc.) when the publisher recorded them.
source_formatstringCLAIMREVIEW or MEDIAREVIEW. MediaReview records carry image-specific manipulation assessment.
media_authenticity_categorystring | nullMediaReview-specific category (e.g. "transformedContent"). null for ClaimReview records.

Match quality

ValueMeaning
exactHamming distance 0. The image hash matches a corpus record bit-for-bit.
similarHamming distance 1-8. Visually similar (cropped, recompressed, lightly edited) but not identical. Best match returned; multiple-match support is on the v2 roadmap.
not_foundHamming distance > 8, or no record in the corpus. image, consensus, and sources will be empty.

For claim-text lookups, match_quality reflects the strength of the full-text search match. exact for direct phrase matches, similar for partial matches, not_found when nothing matches. The Google fallback may return matches even when local FTS does not.

Rating values

Each publisher has its own rating vocabulary (PolitiFact uses "Pants on Fire," AFP uses "False," Maldita uses "Falso"). We normalize all of them into a six-value canonical scale to support consensus math:

ValueMeaning
TRUEClaim is supported by evidence.
MOSTLY_TRUESubstantially supported, with caveats.
MIXEDClaim has both true and false elements, or is partly accurate.
MOSTLY_FALSESubstantially contradicted, with some elements that hold.
FALSEClaim is contradicted by evidence.
UNVERIFIEDNo evidence yet supports or contradicts the claim. Used for "no evidence" / "unsupported" / "needs context" verdicts.

The original publisher rating string is always preserved in rating_original so integrators that want maximum fidelity can read it directly.

Contextual flags

Orthogonal labels that ride alongside the truth-axis verdict. Multiple flags can apply to one record. Aggregated as a union across all contributing records.

FlagMeaning
SATIREContent originally published as satire or parody.
OUTDATEDOnce accurate, no longer reflects current state.
MISATTRIBUTEDReal content presented in a false context (wrong date, wrong location, wrong attribution).
IMPOSTOR_CONTENTContent fraudulently presented as from a different source.
OPINION_PIECEEditorial or opinion content treated as factual reporting.
ALTEREDImage or media has been digitally altered.

New flags may be added without breaking changes. Integrators should treat unknown flags as opaque labels.

Errors

Standard HTTP status codes. Error responses include a JSON body with error code and message fields.

StatusCodeMeaning
400invalid_hashThe hash path parameter is not 16 hexadecimal characters.
400missing_textThe text query parameter is missing or empty on a claim lookup.
400missing_imagePOST /v1/lookup/image was called without an image field in the form data.
413image_too_largeThe image is larger than the 10 MB limit.
415unsupported_image_formatThe image bytes could not be decoded as a known image format.
429rate_limitedToo many requests in the current window. See Rate limits.
500internal_errorServer-side error. Use the request_id from the response when contacting support.

Rate limits

Two layers of rate limiting:

  • Sapph1re's gateway sets per-integrator-account rate limits based on your sapph1re plan. These are the primary limit you'll hit at scale.
  • Our backend applies a 100 requests / minute fallback per integrator (configurable). This is a safety net for cases where sapph1re's limiter fails open.

When rate-limited, you'll receive a 429 with a JSON body. Implement exponential backoff with a jittered initial delay (e.g., 250-500 ms) and retry up to 3 times before surfacing the error to the user.

Versioning

URL path versioning. The current version is /v1/. Breaking changes will ship as /v2/ with a published migration period; /v1/ will continue to work during that period.

Non-breaking additions (new optional response fields, new contextual flags, additional source records returned) ship within /v1/ without a version bump. Build your client to ignore unknown fields and tolerate new flag values.

Pricing

Per-call billing through sapph1re's MCP Billing Gateway. Two payment rails:

  • x402 on Base (USDC) for AI agents that natively settle on-chain. Per-call settlement, no minimum, no subscription.
  • Stripe metered billing (USD card) for human-onboarded developer accounts. Pre-purchased credits or monthly invoicing.

Specific per-call rates and any volume tiers will be published once sapph1re's gateway is wired in. Get on the early-integrator list to be notified at info@skydata.one.

MCP server

If your agent platform supports the Model Context Protocol (Claude Code, Cursor, Codex, Amp, others), the fastest path is to add Image Trust Protocol as an MCP server. The MCP wrapper exposes three tools that map directly to the three API endpoints: lookup_image_hash, lookup_image_bytes, lookup_claim.

MCP server configuration details and the canonical config snippet will be published alongside the public docs.

curl / HTTP

The API is plain HTTPS JSON. Any HTTP client works. Examples in each endpoint section use curl.

For pHash computation client-side, libraries exist in most languages: imagehash (Python), image-hash (Node), blockhash (multiple languages). Use the 64-bit DCT-based pHash variant for compatibility with our hash format.

LangChain

A LangChain Tool wrapper is on the integration roadmap. In the meantime, you can call the API directly from a custom Tool:

from langchain.tools import Tool
import requests

def lookup_image_claim(claim_text: str) -> str:
    res = requests.get(
        "https://api.imagetrustprotocol.world/v1/lookup/claim",
        params={"text": claim_text},
        timeout=10,
    )
    return res.json()

itp_tool = Tool(
    name="image_trust_protocol",
    func=lookup_image_claim,
    description="Look up fact-check verdicts for a textual claim about an image. Returns synthesized verdicts from credentialed publishers.",
)

CrewAI, AutoGen, and LlamaIndex wrappers will follow the same pattern.

AI agent prompt

For agent platforms that don't support MCP, you can paste a natural-language instruction into your agent's system prompt that teaches it when to call the API and how to surface results.

The canonical instruction set is published at imagetrustprotocol.world/agent-setup with a copy button. The same content is served as plain text at /llms.txt for AI-readable consumption.

Support

Email info@skydata.one with your request_id and a description of what you saw. Response times depend on volume; we read every message.

For bug reports, paste the request URL, response status, and response body alongside the request_id.

For pricing, billing, or sapph1re-related questions, reach out to sapph1re's support channel directly; we can route messages if needed.