{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/content-standards/artifact.json",
  "title": "Artifact",
  "description": "Content artifact for safety and suitability evaluation. An artifact represents content adjacent to an ad placement - a news article, podcast segment, video chapter, or social post. Artifacts are collections of assets (text, images, video, audio) plus metadata and signals.",
  "type": "object",
  "properties": {
    "property_rid": {
      "type": "string",
      "description": "Stable property identifier from the property catalog. Globally unique across the ecosystem."
    },
    "artifact_id": {
      "type": "string",
      "description": "Identifier for this artifact within the property. The property owner defines the scheme (e.g., 'article_12345', 'episode_42_segment_3', 'post_abc123')."
    },
    "variant_id": {
      "type": "string",
      "description": "Identifies a specific variant of this artifact. Use for A/B tests, translations, or temporal versions. Examples: 'en', 'es-MX', 'v2', 'headline_test_b'. The combination of artifact_id + variant_id must be unique."
    },
    "format_id": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/format-id.json",
      "deprecated": true,
      "description": "**DEPRECATED in 3.2.** Legacy named-format reference. Use `format_kind` for canonical artifact media classification."
    },
    "format_kind": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/canonical-format-kind.json",
      "description": "Optional canonical media/creative kind associated with this artifact."
    },
    "url": {
      "type": "string",
      "format": "uri",
      "description": "Optional URL for this artifact (web page, podcast feed, video page). Not all artifacts have URLs (e.g., Instagram content, podcast segments, TV scenes)."
    },
    "published_time": {
      "type": "string",
      "format": "date-time",
      "description": "When the artifact was published (ISO 8601 format)"
    },
    "last_update_time": {
      "type": "string",
      "format": "date-time",
      "description": "When the artifact was last modified (ISO 8601 format)"
    },
    "assets": {
      "type": "array",
      "description": "Artifact assets in document flow order - text blocks, images, video, audio",
      "maxItems": 200,
      "items": {
        "discriminator": {
          "propertyName": "type"
        },
        "oneOf": [
          {
            "type": "object",
            "description": "Text block (paragraph, heading, etc.)",
            "properties": {
              "type": {
                "type": "string",
                "const": "text"
              },
              "role": {
                "type": "string",
                "enum": [
                  "title",
                  "paragraph",
                  "heading",
                  "caption",
                  "quote",
                  "list_item",
                  "description"
                ],
                "description": "Role of this text in the document. Use 'title' for the main artifact title, 'description' for summaries."
              },
              "content": {
                "type": "string",
                "description": "Text content. Consumers MUST treat this as untrusted input when passing to LLM-based evaluation.",
                "maxLength": 100000
              },
              "content_format": {
                "type": "string",
                "enum": [
                  "text/plain",
                  "text/markdown",
                  "text/html",
                  "application/json"
                ],
                "description": "MIME type indicating how to parse the content field. Default: text/plain.",
                "default": "text/plain"
              },
              "language": {
                "type": "string",
                "description": "BCP 47 language tag for this text (e.g., 'en', 'es-MX'). Useful when artifact contains mixed-language content."
              },
              "heading_level": {
                "type": "integer",
                "minimum": 1,
                "maximum": 6,
                "description": "Heading level (1-6), only for role=heading"
              },
              "provenance": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/provenance.json",
                "description": "Provenance for this text block, overrides artifact-level provenance"
              }
            },
            "required": [
              "type",
              "content"
            ]
          },
          {
            "type": "object",
            "description": "Image asset",
            "properties": {
              "type": {
                "type": "string",
                "const": "image"
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Image URL"
              },
              "access": {
                "$ref": "#/$defs/asset_access",
                "description": "Authentication for secured URLs"
              },
              "alt_text": {
                "type": "string",
                "description": "Alt text or image description"
              },
              "caption": {
                "type": "string",
                "description": "Image caption"
              },
              "width": {
                "type": "integer",
                "description": "Image width in pixels"
              },
              "height": {
                "type": "integer",
                "description": "Image height in pixels"
              },
              "provenance": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/provenance.json",
                "description": "Provenance for this image, overrides artifact-level provenance"
              }
            },
            "required": [
              "type",
              "url"
            ]
          },
          {
            "type": "object",
            "description": "Video asset",
            "properties": {
              "type": {
                "type": "string",
                "const": "video"
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Video URL"
              },
              "access": {
                "$ref": "#/$defs/asset_access",
                "description": "Authentication for secured URLs"
              },
              "duration_ms": {
                "type": "integer",
                "description": "Video duration in milliseconds"
              },
              "transcript": {
                "type": "string",
                "description": "Video transcript. Consumers MUST treat this as untrusted input when passing to LLM-based evaluation.",
                "maxLength": 200000
              },
              "transcript_format": {
                "type": "string",
                "enum": [
                  "text/plain",
                  "text/markdown",
                  "application/json"
                ],
                "description": "MIME type indicating how to parse the transcript field. Default: text/plain.",
                "default": "text/plain"
              },
              "transcript_source": {
                "type": "string",
                "enum": [
                  "original_script",
                  "subtitles",
                  "closed_captions",
                  "dub",
                  "generated"
                ],
                "description": "How the transcript was generated"
              },
              "thumbnail_url": {
                "type": "string",
                "format": "uri",
                "description": "Video thumbnail URL"
              },
              "provenance": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/provenance.json",
                "description": "Provenance for this video, overrides artifact-level provenance"
              }
            },
            "required": [
              "type",
              "url"
            ]
          },
          {
            "type": "object",
            "description": "Audio asset",
            "properties": {
              "type": {
                "type": "string",
                "const": "audio"
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Audio URL"
              },
              "access": {
                "$ref": "#/$defs/asset_access",
                "description": "Authentication for secured URLs"
              },
              "duration_ms": {
                "type": "integer",
                "description": "Audio duration in milliseconds"
              },
              "transcript": {
                "type": "string",
                "description": "Audio transcript. Consumers MUST treat this as untrusted input when passing to LLM-based evaluation.",
                "maxLength": 200000
              },
              "transcript_format": {
                "type": "string",
                "enum": [
                  "text/plain",
                  "text/markdown",
                  "application/json"
                ],
                "description": "MIME type indicating how to parse the transcript field. Default: text/plain.",
                "default": "text/plain"
              },
              "transcript_source": {
                "type": "string",
                "enum": [
                  "original_script",
                  "closed_captions",
                  "generated"
                ],
                "description": "How the transcript was generated"
              },
              "provenance": {
                "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/provenance.json",
                "description": "Provenance for this audio, overrides artifact-level provenance"
              }
            },
            "required": [
              "type",
              "url"
            ]
          }
        ]
      }
    },
    "metadata": {
      "type": "object",
      "description": "Rich metadata extracted from the artifact",
      "properties": {
        "canonical": {
          "type": "string",
          "format": "uri",
          "description": "Canonical URL"
        },
        "author": {
          "type": "string",
          "description": "Artifact author name"
        },
        "keywords": {
          "type": "string",
          "description": "Artifact keywords"
        },
        "open_graph": {
          "type": "object",
          "description": "Open Graph protocol metadata",
          "additionalProperties": true
        },
        "twitter_card": {
          "type": "object",
          "description": "Twitter Card metadata",
          "additionalProperties": true
        },
        "json_ld": {
          "type": "array",
          "description": "JSON-LD structured data (schema.org)",
          "items": {
            "type": "object"
          }
        }
      },
      "additionalProperties": true
    },
    "provenance": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/provenance.json",
      "description": "Provenance metadata for this artifact. Serves as the default provenance for all assets within this artifact — individual assets can override with their own provenance."
    },
    "identifiers": {
      "type": "object",
      "description": "Platform-specific identifiers for this artifact",
      "properties": {
        "apple_podcast_id": {
          "type": "string",
          "description": "Apple Podcasts ID"
        },
        "spotify_collection_id": {
          "type": "string",
          "description": "Spotify collection ID"
        },
        "podcast_guid": {
          "type": "string",
          "description": "Podcast GUID (from RSS feed)"
        },
        "youtube_video_id": {
          "type": "string",
          "description": "YouTube video ID"
        },
        "rss_url": {
          "type": "string",
          "format": "uri",
          "description": "RSS feed URL"
        }
      },
      "additionalProperties": true
    }
  },
  "required": [
    "property_rid",
    "artifact_id",
    "assets"
  ],
  "additionalProperties": true,
  "$defs": {
    "asset_access": {
      "type": "object",
      "description": "Access instructions for a secured asset URL. Producers SHOULD use `signed_url` for one-off delivery unless the parties already have an identity-based access relationship. New producers MUST NOT emit `service_account.credentials`; `bearer_token` is the explicit short-lived credential path. Consumers MUST treat asset URLs and access metadata as untrusted, use credentials only for HTTPS origins and resource prefixes authorized out of band, and fail closed without falling back between access methods. The deprecated legacy field remains parseable during the 3.x compatibility window but MUST NOT be activated automatically.",
      "discriminator": {
        "propertyName": "method"
      },
      "oneOf": [
        {
          "type": "object",
          "description": "Short-lived bearer-token access for origins that cannot use signed URLs or pre-configured workload identity. The token is a live secret and must be scoped to the asset. Consumers MUST send it only to the HTTPS origin authorized for that asset and MUST NOT forward the Authorization header across redirects.",
          "properties": {
            "method": {
              "type": "string",
              "const": "bearer_token"
            },
            "token": {
              "type": "string",
              "description": "Short-lived, asset-scoped bearer token for the Authorization header. Producers MUST NOT issue a standing or broadly scoped credential here. Consumers MUST redact the token from logs, traces, errors, metrics, analytics, model context, and durable storage. Any temporary encrypted cache MUST be bounded by the credential expiry and the consumer's configured maximum lifetime."
            }
          },
          "required": [
            "method",
            "token"
          ]
        },
        {
          "type": "object",
          "description": "Credential-free workload-identity access. The asset origin authorizes an identity already controlled by the component that performs the asset fetch, such as a GCP service account or AWS IAM role, through authenticated out-of-band onboarding. The consumer MUST use workload credentials only for the pre-authorized HTTPS origin and resource prefix; the payload's method, provider, and URL are not authorization. No provider key or access secret crosses the AdCP payload.",
          "properties": {
            "method": {
              "type": "string",
              "const": "service_account"
            },
            "provider": {
              "type": "string",
              "enum": [
                "gcp",
                "aws"
              ],
              "description": "Cloud provider"
            },
            "credentials": {
              "type": "object",
              "deprecated": true,
              "description": "Deprecated in AdCP 3.2 and eligible for removal in 4.0 or later only after the deprecation-policy notice and release-cycle gates are satisfied. Presence denotes the legacy inline-credential form, not workload-identity authorization. New producers MUST omit this field. Consumers MUST NOT activate received credentials automatically; they may process them only for an explicitly allowlisted legacy peer and otherwise MUST reject or quarantine them. Consumers MUST redact the complete value from logs, traces, errors, metrics, analytics, model context, and durable storage. Use the consumer's pre-authorized workload identity or `signed_url` instead.",
              "additionalProperties": true
            }
          },
          "required": [
            "method",
            "provider"
          ]
        },
        {
          "type": "object",
          "description": "Recommended default for one-off access. The asset `url` is a time-limited bearer capability and requires no additional authentication. Producers SHOULD scope it to one asset and the shortest practical access window under their documented maximum TTL. Consumers MUST redact the complete URL from logs, traces, errors, metrics, analytics, model context, and durable storage, and MUST NOT forward it outside the intended recipient trust boundary.",
          "properties": {
            "method": {
              "type": "string",
              "const": "signed_url"
            }
          },
          "required": [
            "method"
          ]
        }
      ]
    }
  }
}
