{ "$id": "https://raw.githubusercontent.com/civic-interconnect/civic-ptag-core-schema/main/schema/ptag.privacy.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "$comment": "Canonical spec: https://civic-interconnect.github.io/civic-transparency-ptag-spec/en/spec/schemas/ptag.schema.json", "title": "Civic Transparency PTag (Privacy Profile)", "description": "Per-post privacy-preserving provenance tags for social content. Values are bucketed/categorical — no PII or direct identifiers.", "$defs": { "AcctAge": { "$anchor": "AcctAge", "title": "Account Age Bucket", "description": "Privacy-preserving account age categories. Bucketed to prevent precise age correlation while enabling analysis of account maturity patterns.", "type": "string", "enum": ["0-7d", "8-30d", "1-6m", "6-24m", "24m+"] }, "AcctType": { "$anchor": "AcctType", "title": "Account Type", "description": "Declared or verified account identity type. Reflects the account's stated purpose or verified status on the platform.", "type": "string", "enum": [ "person", "org", "media", "public_official", "unverified", "declared_automation" ] }, "AutomationFlag": { "$anchor": "AutomationFlag", "title": "Automation Flag", "description": "Posting method classification with clear boundaries: manual (direct user interaction), scheduled (user-configured delayed posting), api_client (third-party tools like Buffer/Hootsuite), declared_bot (automated systems with explicit bot declaration).", "type": "string", "enum": ["manual", "scheduled", "api_client", "declared_bot"] }, "PostKind": { "$anchor": "PostKind", "title": "Post Kind", "description": "Content relationship type indicating how this post relates to other content: original (new content), reshare (repost/retweet), quote (repost with commentary), reply (response to another post).", "type": "string", "enum": ["original", "reshare", "quote", "reply"] }, "ClientFamily": { "$anchor": "ClientFamily", "title": "Client Family", "description": "Application class used to create the post: web (browser-based), mobile (native mobile app), third_party_api (external tools and integrations).", "type": "string", "enum": ["web", "mobile", "third_party_api"] }, "MediaProvenance": { "$anchor": "MediaProvenance", "title": "Media Provenance", "description": "Embedded authenticity metadata for attached media: c2pa_present (C2PA content credentials found), hash_only (perceptual hash available), none (no provenance metadata).", "type": "string", "enum": ["c2pa_present", "hash_only", "none"] }, "ISO3166CountryOrSubdivision": { "$anchor": "ISO3166CountryOrSubdivision", "title": "ISO 3166 Country or Subdivision", "description": "Uppercase ISO-3166-1 alpha-2 country code, optionally with ISO-3166-2 subdivision for populations >1M (e.g., US, US-CA). Limited to country-level for privacy.", "type": "string", "pattern": "^[A-Z]{2}(-[A-Z]{1,3})?$" }, "HexHash": { "$anchor": "HexHash", "title": "Hex Hash", "description": "Privacy-preserving rolling hash for duplicate detection. Fixed 8-character hex values for standard implementations, with optional platform-configurable length (8-16 characters) for high-volume environments to reduce collision probability, salted daily to prevent cross-dataset correlation.", "type": "string", "pattern": "^[a-f0-9]{8,16}$", "minLength": 8, "maxLength": 16 } }, "type": "object", "properties": { "acct_age_bucket": { "description": "Account age bucketed for privacy: e.g., '0-7d', '8-30d', '1-6m', '6-24m', '24m+'.", "allOf": [{ "$ref": "#/$defs/AcctAge" }] }, "acct_type": { "description": "Declared identity account type.", "allOf": [{ "$ref": "#/$defs/AcctType" }] }, "automation_flag": { "description": "Posting method with clear boundaries: manual (direct user interaction), scheduled (user-configured delayed posting), api_client (third-party tools like Buffer/Hootsuite), declared_bot (automated systems with explicit bot declaration).", "allOf": [{ "$ref": "#/$defs/AutomationFlag" }] }, "post_kind": { "description": "Content relationship: original, reshare, quote, reply.", "allOf": [{ "$ref": "#/$defs/PostKind" }] }, "client_family": { "description": "Application class: web, mobile, third_party_api.", "allOf": [{ "$ref": "#/$defs/ClientFamily" }] }, "media_provenance": { "description": "Embedded authenticity: c2pa_present, hash_only, none.", "allOf": [{ "$ref": "#/$defs/MediaProvenance" }] }, "dedup_hash": { "description": "Privacy-preserving rolling hash for duplicate detection (8-16 hex characters, salted daily to prevent cross-dataset correlation).", "allOf": [{ "$ref": "#/$defs/HexHash" }] }, "content_digest": { "allOf": [{ "$ref": "#/$defs/HexHash" }], "description": "Optional privacy-preserving content similarity hash for near-duplicate detection. Fixed 12-character hex values for standard implementations, with platform-configurable length (8-16 characters). Salted daily to prevent cross-dataset correlation. Field may be omitted for platforms preferring exact-match detection." }, "origin_hint": { "description": "Optional geographic origin limited to country-level (ISO country codes) or major subdivisions only for populations >1M, e.g., 'US', 'US-CA', where lawful.", "allOf": [{ "$ref": "#/$defs/ISO3166CountryOrSubdivision" }] } }, "required": [ "acct_age_bucket", "acct_type", "automation_flag", "post_kind", "client_family", "media_provenance", "dedup_hash" ], "additionalProperties": false, "examples": [ { "acct_age_bucket": "0-7d", "acct_type": "person", "automation_flag": "api_client", "post_kind": "reshare", "client_family": "mobile", "media_provenance": "hash_only", "dedup_hash": "9a4b2c1d", "content_digest": "a1b2c3d4e5f6", "origin_hint": "US-CA" } ] }