Use ChronoVerify with OpenAI function calling
Give an OpenAI model a single tool, chronoverify_verify_image, so it can check a photo's capture time and provenance before acting on it. The definitions below are copy-paste ready for both the Chat Completions and the Responses API.
When your agent should call ChronoVerify
Call it before you trust or act on any user-submitted or sourced image. Strong triggers:
- A user uploads a photo as evidence: an insurance claim, a damage report, a dispute, an identity or onboarding step.
- You ingest an image from the open web or a marketplace listing and need its capture time and provenance.
- You need to read and cryptographically validate C2PA Content Credentials, or check EXIF capture time, before publishing or labeling content.
- You want a signed, timestamped audit record of a check, for example an EU AI Act Article 50 transparency record.
Branch on the verdict and confidence it returns; treat anything below your bar as needing human review.
1. Define the tool
Chat Completions API (the definition nests under function):
{
"type": "function",
"function": {
"name": "chronoverify_verify_image",
"description": "Verify a photo's capture time and provenance: cryptographic C2PA Content Credentials validation against the official trust list, EXIF and XMP metadata consistency, and classical pixel forensics. Returns one verdict (provenance_confirmed, consistent, inconclusive, metadata_anomaly, or manipulation_indicated) with a 0 to 100 confidence. Provenance-first, NOT a deepfake or AI-generation detector; results are investigative triage, not proof. Calls ChronoVerify POST https://chronoverify.com/v1/verify. Provide exactly one of url, file_path, or image_base64.",
"parameters": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "Public HTTPS URL of the image to verify."
},
"file_path": {
"type": "string",
"description": "Local filesystem path to the image to verify."
},
"image_base64": {
"type": "string",
"description": "Base64-encoded image bytes (no data: prefix)."
}
},
"required": [],
"additionalProperties": false
}
}
}
Responses API (flattened, no function wrapper):
{
"type": "function",
"name": "chronoverify_verify_image",
"description": "Verify a photo's capture time and provenance: cryptographic C2PA Content Credentials validation against the official trust list, EXIF and XMP metadata consistency, and classical pixel forensics. Returns one verdict (provenance_confirmed, consistent, inconclusive, metadata_anomaly, or manipulation_indicated) with a 0 to 100 confidence. Provenance-first, NOT a deepfake or AI-generation detector; results are investigative triage, not proof. Calls ChronoVerify POST https://chronoverify.com/v1/verify. Provide exactly one of url, file_path, or image_base64.",
"parameters": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "Public HTTPS URL of the image to verify."
},
"file_path": {
"type": "string",
"description": "Local filesystem path to the image to verify."
},
"image_base64": {
"type": "string",
"description": "Base64-encoded image bytes (no data: prefix)."
}
},
"required": [],
"additionalProperties": false
}
}
2. Run the call when the model asks for it
When the model emits a call to chronoverify_verify_image, POST the arguments to the API and feed the JSON back as the tool result:
import base64, io, requests
def chronoverify_verify_image(url=None, file_path=None, image_base64=None):
headers = {"Authorization": "Bearer cv_live_..."} # omit to use the free public path
if url:
r = requests.post("https://chronoverify.com/v1/verify", data={"url": url}, headers=headers)
else:
blob = open(file_path, "rb") if file_path else io.BytesIO(base64.b64decode(image_base64))
r = requests.post("https://chronoverify.com/v1/verify", files={"file": blob}, headers=headers)
r.raise_for_status()
return r.json()
What comes back
One JSON object, the same in the browser and the API. The verdict is one of provenance_confirmed, consistent, inconclusive, metadata_anomaly, or manipulation_indicated.
{
"schema_version": "v1",
"verdict": "consistent",
"confidence": 61,
"headline": "Metadata is internally consistent. No manipulation signals fired.",
"capture_time": {
"value": "2026-05-18T14:32:10",
"source": "exif",
"consistent": null
},
"capture_device": {
"make": "Canon",
"model": "EOS R6",
"software": "Firmware 1.8.1"
},
"c2pa": {
"present": false,
"validated": null,
"validation_state": null,
"signer": null
},
"integrity": {
"sha256": "1313339a...",
"sha512": "93a81e4a...",
"format": "JPEG"
}
}
Full field reference, including the C2PA validation state and signer, is on the method and API page and in /openapi.json.
What it does and does not tell you
ChronoVerify validates provenance and metadata and flags possible editing for human review. It is not a deepfake or AI-generation detector, and a verdict is investigative triage, not proof. A clean result means a file's saved data is internally consistent, not that the scene it shows is real. Never use a verdict as the sole basis for an automated decision about a person.
Common questions
Do I need an API key?
No, not to try it: omit the Authorization header to use the free, rate-limited public path. For metered, higher-volume use, send Authorization: Bearer cv_live_....
Is this a deepfake detector?
No. ChronoVerify is provenance-first and returns investigative triage, not an AI-or-real score.
Which verdict should gate an action?
Treat manipulation_indicated and metadata_anomaly as review flags, and use the confidence value plus your own threshold; never auto-decide about a person on a verdict alone.
The fastest way to see it is to run a photo through it.
Try the free verifier