Developer Guide • Updated September 15, 2026
How the Claude API Signs Files With C2PA Content Credentials
Quick Reference: Claude API C2PA Signing
| What gets signed | Supported image, video, and audio files Claude produces in the code execution sandbox, signed when downloaded through the Files API. |
| Where it works | Documented for the Claude API (platform.claude.com) only. The code execution tool also runs on Claude Platform on AWS and Microsoft Foundry, but Anthropic's docs do not state that files downloaded there are signed. Not available on Amazon Bedrock or Google Cloud. |
| Signer | Anthropic, PBC, via a private certificate authority: Anthropic Content Credentials Root CA. Not yet on the official C2PA Trust List. |
| What it proves | Anthropic delivered the file. It does not assert AI-generated pixels: no digitalSourceType, origin-confidence is marked unknown. |
| Samples on this page | A real Claude-signed PNG and JPG, produced September 15, 2026 with claude-fable-5-1, download links below. |
When a Claude API call uses the code execution tool to produce an image, video, or audio file and you download it through the Files API, Anthropic signs that file with C2PA Content Credentials before it reaches you. No extra flag, no beta header, no change to your request. This article shows what that signed file actually contains, lets you download two real examples, and walks through the code that produces one.
This is the developer companion to our earlier piece on Anthropic's watermarking and C2PA announcement. That article covered the policy and rollout. This one opens the manifest.
Download real Claude-signed sample files
These two files were generated through the Claude API on September 15, 2026, using claude-fable-5-1 and the code execution tool, then downloaded through the Files API. Both carry a live, valid C2PA manifest signed by Anthropic. Nothing about them has been edited or re-saved, since either action would strip the credential.

How does Claude actually sign a file?
Claude has no image-generation model of its own. When you ask for an image, Claude writes code, typically Python with Pillow or matplotlib, and runs it inside Anthropic's code execution sandbox. Whatever the code saves to that run's $OUTPUT_DIR gets captured at the end of the command and returned to you as a file_id.
The signing itself happens later and outside the model entirely. Per Anthropic's documentation: "supported image, video, and audio files that Claude produces in the code execution sandbox carry C2PA Content Credentials when you download them through the Files API." You call the Files API to download the file, and Anthropic's infrastructure attaches the manifest at that point, not while Claude is generating the content.
Why this matters for the manifest's contents: because signing happens at download rather than at generation, the credential records that Anthropic delivered the file, not what Claude did to produce it. That distinction shows up directly in the actions assertion later in this article.
Per Anthropic's documentation, signing requires no changes to your requests or response handling, the manifest records nothing about you, your organization, or your request, and the file's visible content is unchanged. The manifest does add a few kilobytes, so a downloaded file's size and checksum will differ from the file as it exists inside the sandbox.
Step-by-step: generate a C2PA-signed file with the Claude API
Three steps: call the Messages API with the code execution tool, pull the resulting file_id values out of the response, then download each file through the Files API. The download step is what triggers signing.
1. Enable code execution and ask for a file
Add the code execution tool to your tools array. The tool name must be code_execution, and the type can be code_execution_20250825 or a newer dated version; no beta header is required for any of them.
2. Python
from anthropic import Anthropic
from anthropic.types import Message
client = Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=4096,
messages=[
{
"role": "user",
"content": "Create a matplotlib visualization and save it as output.png",
}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
def extract_file_ids(response: Message) -> list[str]:
file_ids: list[str] = []
for item in response.content:
if item.type == "bash_code_execution_tool_result":
content_item = item.content
if content_item.type == "bash_code_execution_result":
for output_block in content_item.content:
file_ids.append(output_block.file_id)
return file_ids
for file_id in extract_file_ids(response):
file_metadata = client.files.retrieve_metadata(file_id)
file_content = client.files.download(file_id)
file_content.write_to_file(file_metadata.filename)
print(f"Downloaded: {file_metadata.filename}")3. TypeScript
import Anthropic from "@anthropic-ai/sdk";
import { writeFile } from "node:fs/promises";
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-5",
max_tokens: 4096,
messages: [{ role: "user", content: "Create a matplotlib visualization and save it as output.png" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }],
});
for (const block of response.content) {
if (block.type === "bash_code_execution_tool_result") {
const result = block.content;
if (result.type === "bash_code_execution_result") {
for (const outputBlock of result.content) {
const [fileMetadata, fileResponse] = await Promise.all([
client.files.retrieveMetadata(outputBlock.file_id),
client.files.download(outputBlock.file_id),
]);
await writeFile(fileMetadata.filename, await fileResponse.bytes());
console.log(`Downloaded: ${fileMetadata.filename}`);
}
}
}
}4. Or download with cURL once you have a file_id
curl "https://api.anthropic.com/v1/files/$FILE_ID/content" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
--output out.pngOnly files created by code execution or skills are downloadable this way; files you uploaded return an error. Downloads themselves are free. Anthropic recommends prompting Claude to copy its output into $OUTPUT_DIR and list that directory in the same command, since only files at the top level of that directory get captured and returned as file_id entries. Anything written elsewhere in the sandbox stays there and is never returned.
Once you have the file locally, verify it with the open source c2patool (c2patool out.png) or drop it into this site's inspector.
Inside the manifest: what a Claude-signed file actually contains
Running c2patool against the sample PNG above returns a full C2PA manifest. Here is the JSON, trimmed to the parts that matter, with the file's own instance IDs preserved:
{
"claim_generator_info": [
{ "name": "Anthropic Files", "version": "1.0.0", "specVersion": "2.4.0" }
],
"claim_version": 2,
"ingredients": [
{
"format": "image/png",
"relationship": "parentOf",
"label": "c2pa.ingredient.v3"
}
],
"assertions": [
{
"label": "c2pa.actions.v2",
"data": {
"actions": [
{
"action": "c2pa.opened",
"parameters": { "ingredients": [ { "url": "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" } ] }
},
{
"action": "com.anthropic.claude.provided",
"softwareAgent": { "name": "Claude" },
"parameters": { "com.anthropic.origin-confidence": "unknown" },
"description": "Claude provided this file at the request of a user and may have created or modified the file contents."
}
],
"allActionsIncluded": true
}
}
],
"signature_info": {
"alg": "Es256",
"issuer": "Anthropic, PBC",
"common_name": "Anthropic Claude Content Signing",
"cert_serial_number": "370496221669126734322377145003421948178272162560"
}
}
// validation_status (top level)
[
{
"code": "signingCredential.untrusted",
"explanation": "signing certificate untrusted"
}
]
// validation_state: "Valid"A few details are worth reading closely. The claim_generator_info names "Anthropic Files" rather than Claude itself, because the Files API is what signs the manifest, not the model. The claim_version: 2 field marks this as a C2PA 2.x claim, built against spec version 2.4.0.
There is exactly one ingredient, labeled c2pa.ingredient.v3, with relationship: "parentOf". This is the unsigned file that existed briefly inside the container before Anthropic wrapped it, with no title and no manifest of its own, meaning it carries no provenance history before Claude.
The c2pa.actions.v2 assertion carries two actions: c2pa.opened, referencing that ingredient, and a vendor-namespaced com.anthropic.claude.provided action with the exact description Anthropic's documentation quotes. Notice what is not there: no c2pa.created action, and no digitalSourceType of trainedAlgorithmicMedia. The next two sections explain why that distinction is deliberate.
Why does a verifier say the signer is untrusted?
Open the sample files in this site's inspector, in the Content Authenticity Initiative's Verify tool, or with c2patool, and all three report the same thing: the signature is cryptographically valid, but the signing certificate is untrusted. That is correct behavior, not a bug in the file or in any of the verifiers.
Anthropic signs with its own private certificate authority, Anthropic Content Credentials Root CA, rather than buying a certificate from a public CA already on an established trust list. As of this writing (September 15, 2026), that root is not present on the official C2PA Trust List or the Content Authenticity Initiative's interim list used by verify.contentauthenticity.org. The certificate itself is built correctly: it carries the Extended Key Usage OID 1.3.6.1.4.1.62558.2.1, which is the C2PA claim-signing extension, and is valid from August 7, 2026 to August 6, 2028.
This is a trust list coverage gap, not a revoked or malformed certificate. Verifiers that fetch trust lists live should start showing Claude-signed files as trusted automatically once Anthropic's root is added, with no change needed to the files themselves.
What does the credential prove, and what does it not prove?
The manifest proves that Anthropic's infrastructure delivered this specific file to you, unmodified since that delivery, at the recorded time, under a certificate Anthropic controls. That is a real, checkable provenance claim.
It does not claim the pixels were AI-generated. The action is com.anthropic.claude.provided, worded carefully as a file Claude "may have created or modified," and origin-confidence is explicitly set to unknown. Compare that to Google Gemini and OpenAI's manifests, which assert AI generation directly through a digitalSourceType of trainedAlgorithmicMedia. Anthropic's manifest makes no such assertion, which lines up with the technical reality that Claude writes code to render an image rather than running a generative image model.
For a broader look at how AI-generation claims show up in C2PA manifests across tools, see verifying AI-generated images with C2PA and SynthID.
Frequently Asked Questions
Does the Claude API attach C2PA Content Credentials to every file it generates?
No. Only files that Claude produces inside the code execution sandbox and that you then download through the Files API get signed, and only in supported formats: PNG, JPEG, GIF, WebP, TIFF, HEIC, AVIF, SVG, MP4, MOV, MP3, WAV, FLAC, and M4A. Text files, PDFs, and office documents are not signed because those formats are not supported for signing. Files you upload yourself are stored as is, including any Content Credentials they already carry.
Which Claude models produce C2PA-signed files?
Anthropic's documentation does not restrict Content Credentials to a specific model. The code execution tool that makes signing possible is supported across current Claude models, and the signing happens at download time through the Files API rather than as a property of any one model. The samples on this page were produced with claude-fable-5-1.
Why does my Claude-signed file show as "untrusted" in a C2PA verifier?
As of September 2026, Anthropic's signing certificate authority, Anthropic Content Credentials Root CA, is not yet listed on the official C2PA Trust List or the Content Authenticity Initiative's interim trust list. Verifiers correctly report the signature as cryptographically valid but the signer as untrusted, which is a trust list coverage gap rather than a defect in the file.
Does the C2PA credential prove Claude generated the image pixels?
No. The manifest's action is com.anthropic.claude.provided with the parameter origin-confidence set to unknown, and there is no digitalSourceType of trainedAlgorithmicMedia and no c2pa.created action. It attests that Anthropic delivered the file through its infrastructure, not that an AI model generated the visual content, since Claude has no image-generation model and instead writes code that renders the image.
What happens if I convert or screenshot a Claude-signed file?
The Content Credential is removed. Re-encoding, format conversion, screenshotting, and any tool that strips metadata all break the signed manifest, so a missing credential on a given file does not mean Claude never produced it.
Can I verify a Claude-signed file without writing code?
Yes. Drop the file into the C2PA Viewer inspector, or run the open source c2patool from the c2pa-rs project on it from the command line. Both read the manifest the same way this article walks through.
Inspect the Sample Files Yourself
Download the signed PNG or JPG above and drop it into the inspector to see the full manifest, the untrusted signer badge, and the actions assertion firsthand.
Open the Inspector →