{
  "openapi": "3.0.0",
  "info": {
    "title": "Proof of Human API",
    "description": "The Proof of Human API verifies credentialed audio by itself or a legacy audio + `.poh` pair.\nA valid result confirms PoH's signature and binds its account of the editing PoH witnessed to\nthe exact export. The structured evidence report is **report-only**; your screening policy stays\nyours. Legacy calibration values are not authorship percentages.\n\n## Authentication surfaces\n\nThe published partner API uses `x-api-key`; keep that credential server-side and never ship it\nin a browser or app bundle. Every non-public operation in this partner contract—including\nproof-id reads—requires that key. The PoH macOS app uses a separate App API and authorization\nboundary that is deliberately outside the published partner contract. Health is public.\n\n## Quickstart\n\n```bash\nnpm install @proof-of-human/ts-sdk\n```\n\n```ts\nimport { PoHClient } from \"@proof-of-human/ts-sdk\";\nconst poh = new PoHClient({ apiKey: process.env.POH_API_KEY! });\n\nconst upload = await poh.createUpload();        // presigned slot — POST the audio to it\nconst result = await poh.verify({ uploadId: upload.uploadId }); // credentialed audio\n// Legacy sidecar: poh.verify({ uploadId: upload.uploadId, poh: pohBase64 })\nresult.verdict;   // \"valid\" when the proof is PoH's AND matches the audio\nresult.evidenceReport; // observed facts, inferences, creator statements, and coverage limits\n```\n\n## What a proof attests\n\nA `valid` proof attests **PoH's signature** and the **binding to the exact audio file** — a\nrecorded process account, not an \"AI-free\" certification.\n\n## Idempotency & retries\n\nEvery `GET` is safe to retry. `DELETE /proofs/{proofId}` is idempotent and reports its outcome —\na repeat returns `already_erased`. `POST /verify` has no side effects. `POST /uploads` mints a\nfresh short-lived slot each call, so retrying a failed call is safe (unused slots expire on\ntheir own). `POST /partner/keys/rotate` requires an `Idempotency-Key` header: retrying with the\nsame key within 24 hours replays the original result — same key, same secret — instead of\nminting again (the TypeScript SDK sends one automatically). Proof issuance keeps that header\noptional for the shipped app; the server binds retries to the complete request and returns 409\nif the same replay identity is reused with changed request data.\n\n## Errors\n\nEvery error response is `{ \"error\": string, \"code\": string }`. `error` is a human-readable\nmessage; `code` is a stable slug to branch on (`invalid_request`, `forbidden`, `not_found`,\n`conflict`, `unprocessable`, `rate_limited`, `internal`, plus a few endpoint-specific codes).\nThe same shape is returned whether a handler or the API gateway rejected the call. Treat an\nunrecognized `code` as its HTTP status class.\n\n## Request IDs\n\nEvery response carries an `X-Request-Id` header — a stable id for that exact call, shared with\nour logs (it also appears as the AWS `x-amzn-requestid`). Quote it when reporting a problem so we\ncan trace the request end to end. The TypeScript SDK surfaces it on failures as\n`PoHError.requestId`.\n\n## Timestamps\n\nEvery timestamp this API returns is **unix epoch seconds** — `createdAt`, `issuedAt`,\n`deployedAt`, and the `X-RateLimit-Reset` header alike. A list or verify result's `issuedAt` is\nthe same value as that proof's canonical `ProofDocument.createdAt`.\n\n## Rate limits\n\nEvery key is rate-limited and metered by its plan; `GET /partner/usage` shows your limits and\nper-day consumption. Partner self-service responses under `/partner` carry\n`X-RateLimit-Limit` (your monthly quota) and `X-RateLimit-Reset` (unix seconds until the quota\nwindow resets); `GET /partner/usage` also\nreturns `X-RateLimit-Remaining` (the live quota headroom — the authoritative source, since\nlimiting is metered at the edge). Exceeding a limit returns `429` with `Retry-After` and the\n`{ error, code: \"rate_limited\" }` body — back off and retry (the SDK does this automatically).\nKey rotation runs in its own deliberately low throttle lane.\n\n## Integration monitoring\n\nPoll `GET /health` for public reachability and `GET /partner/usage` for the same quota counters\nused by the gateway. In your client, record HTTP status, latency, `X-Request-Id`, and the\n`X-RateLimit-*` / `Retry-After` headers — never the API key, uploaded audio, or `.poh` body.\nAlert on sustained 5xx responses, latency regression, repeated 429s, and quota headroom below\nyour operating threshold. PoH separately monitors end-to-end availability, per-client outcomes,\nverification verdict distribution, C2PA embedding failures, latency, and background-job health.\n\n## Use with AI agents\n\nPoint your coding agent (Cursor, Claude Code, Copilot, …) at the context files:\n[llms.txt](https://proofofhuman.fm/llms.txt) is a concise map of every endpoint, and\n[llms-full.txt](https://proofofhuman.fm/llms-full.txt) inlines each endpoint's parameters. Or use\nthe **Generate MCP** action in this reference to expose the API to an agent over MCP.\n\n## Model-first\n\nEvery route, type, example, and code sample on this page is generated from one TypeSpec model,\nso what the docs say, the API enforces.",
    "version": "2.7.0"
  },
  "tags": [
    {
      "name": "Verify",
      "description": "Verify one credentialed WAV by itself, or a legacy audio + `.poh` pair. The core partner flow."
    },
    {
      "name": "Proofs",
      "description": "Read, list, interpret, and erase issued proofs."
    },
    {
      "name": "Reviews",
      "description": "Bind registered proofs to partner records, request supporting evidence, and track the partner's own review outcome."
    },
    {
      "name": "API keys",
      "description": "Self-service key rotation, inventory, and usage — authenticated by your own key."
    },
    {
      "name": "System",
      "description": "Health, the download redirect, and content-free product telemetry."
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "health",
        "description": "Public deployment health/version stamp. No API key or device signature is required.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "System"
        ],
        "security": [
          {}
        ],
        "x-poh-auth-surface": "public",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"https://api.proofofhuman.fm/v1/health\"   # { \"ok\": true, \"version\": \"…\", \"commit\": \"…\" }"
          }
        ]
      }
    },
    "/partner/keys": {
      "get": {
        "operationId": "listPartnerKeys",
        "description": "List the caller's API keys (metadata only — never secrets). The calling key identifies the\npartner; there is nothing to pass.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "page size; omit both limit and cursor to return the complete legacy inventory",
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100
            },
            "explode": false
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "opaque `nextCursor` from the preceding response; activates bounded pagination",
            "schema": {
              "type": "string"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable partner 200 response with request-correlation and rate-limit headers.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerKeysResponse"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "API keys"
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "const { keys } = await poh.partner.listKeys();\nfor (const k of keys) console.log(k.keyId, k.status, k.name); // never a secret"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"https://api.proofofhuman.fm/v1/partner/keys\" -H \"x-api-key: $POH_API_KEY\""
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/keys/rotate": {
      "post": {
        "operationId": "rotatePartnerKey",
        "description": "Rotate the caller's API key: mints a new key on the same plan and returns its secret — the only\ntime it is ever visible. The key that made this call keeps working for a grace window\n(`previousKeyExpiresAt`, 72h) so integrations cut over with zero downtime, then expires\nautomatically. Rotations are audit-logged.\n\nSend an `Idempotency-Key` header (the SDK does automatically): if the response is lost to a\nnetwork failure, retrying with the same key within 24 hours replays the original result — same\nkey id, same secret — instead of minting a second key. Without it, a retry after a completed\nrotation is refused (409), because the caller's key is already in its grace window.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "a unique high-entropy string — a UUID is ideal (16–128 chars); reuse it to safely retry this exact rotation for 24h",
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "201": {
            "description": "The request has succeeded and a new resource has been created as a result.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "idempotency-replayed": {
                "required": false,
                "description": "`true` when the original rotation response was replayed",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RotatedKeyResponse"
                },
                "examples": {
                  "Rotate with a zero-downtime cutover": {
                    "summary": "Rotate with a zero-downtime cutover",
                    "description": "The new secret is returned exactly once; the old key keeps working until `previousKeyExpiresAt`. Retrying with the same Idempotency-Key within 24h replays this exact result.",
                    "value": {
                      "apiKey": "poh_live_<returned-once>",
                      "keyId": "7b2mk9p4za",
                      "name": "acme-2026-07-07",
                      "previousKeyExpiresAt": 1783719200
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state of the server.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "API keys"
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "// mint a new key; the old one keeps working for 72h so you can cut over with no downtime.\n// The SDK sends an Idempotency-Key automatically, so a retried call can never double-mint.\nconst rotated = await poh.partner.rotateKey();\nconsole.log(rotated.apiKey); // the new secret — shown ONCE, store it now\n// old key stops working at rotated.previousKeyExpiresAt (unix seconds)"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST \"https://api.proofofhuman.fm/v1/partner/keys/rotate\" \\\n  -H \"x-api-key: $POH_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\"   # retry with the SAME value to replay, never double-mint"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/reviews": {
      "post": {
        "operationId": "createPartnerReview",
        "description": "Create a metadata-only review case for a registered PoH proof. The four business identifiers\nare partner assertions: this endpoint does not independently verify creator identity and does\nnot replace `POST /verify` for exact-audio verification.",
        "parameters": [],
        "responses": {
          "201": {
            "description": "Reusable partner 201 response with request-correlation and rate-limit headers.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerReviewCase"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state of the server.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePartnerReviewRequest"
              }
            }
          }
        },
        "x-poh-auth-surface": "partner-api-key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/reviews/{reviewId}": {
      "get": {
        "operationId": "getPartnerReview",
        "description": "Read one review case scoped to the calling partner, including its evidence requests.",
        "parameters": [
          {
            "name": "reviewId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable partner 200 response with request-correlation and rate-limit headers.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerReviewCase"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "x-poh-auth-surface": "partner-api-key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/reviews/{reviewId}/evidence-requests": {
      "post": {
        "operationId": "createPartnerEvidenceRequest",
        "description": "Request supporting source evidence, a source licence, or creator clarification. Each review can\nopen each kind once (three rows maximum). PoH stores only state and opaque references; the\npartner remains the custodian of the actual material.",
        "parameters": [
          {
            "name": "reviewId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Reusable partner 201 response with request-correlation and rate-limit headers.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerReviewCase"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state of the server.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePartnerEvidenceRequest"
              }
            }
          }
        },
        "x-poh-auth-surface": "partner-api-key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/reviews/{reviewId}/evidence-requests/{requestId}": {
      "patch": {
        "operationId": "updatePartnerEvidenceRequest",
        "description": "Advance an evidence request through supplied → accepted/declined; terminal states are immutable.",
        "parameters": [
          {
            "name": "reviewId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
              "minLength": 1,
              "maxLength": 128
            }
          },
          {
            "name": "requestId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable partner 200 response with request-correlation and rate-limit headers.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerReviewCase"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state of the server.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePartnerEvidenceRequest"
              }
            }
          }
        },
        "x-poh-auth-surface": "partner-api-key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/reviews/{reviewId}/resolve": {
      "post": {
        "operationId": "resolvePartnerReview",
        "description": "Record the integrating partner's final policy outcome. Open evidence requests must be completed\nfirst. The outcome belongs to the partner; it is not a PoH claim of authorship or rights.",
        "parameters": [
          {
            "name": "reviewId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable partner 200 response with request-correlation and rate-limit headers.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerReviewCase"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state of the server.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResolvePartnerReviewRequest"
              }
            }
          }
        },
        "x-poh-auth-surface": "partner-api-key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/partner/usage": {
      "get": {
        "operationId": "getPartnerUsage",
        "description": "The caller's request usage against its quota, per UTC day — the observability half of key\nself-service. Data comes from the metering plan itself, so it matches exactly what billing\nand throttling see.",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "how many days back to include (default 30)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 90
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "`GET /partner/usage` success — carries the full rate-limit header trio.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUsageResponse"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "API keys"
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "const usage = await poh.partner.usage({ days: 30 });\nconsole.log(usage.plan.quotaLimit, usage.plan.quotaPeriod);\nfor (const d of usage.days) console.log(d.date, d.used, d.remaining);"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"https://api.proofofhuman.fm/v1/partner/usage?days=30\" -H \"x-api-key: $POH_API_KEY\""
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/proofs": {
      "get": {
        "operationId": "listProofs",
        "description": "List the caller's issued proofs, newest first — the restore path for a reinstalled app. The\nenrolled device key IS the library identity: a machine that still holds its key can rebuild its\nproof library with no local data. Tenant-scoped; pending (incomplete) proofs are excluded.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100
            },
            "explode": false
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListProofsResponse"
                },
                "examples": {
                  "First page of the caller's library": {
                    "summary": "First page of the caller's library",
                    "description": "Pass `nextCursor` back as `?cursor=` for the next page; it is absent on the last page.",
                    "value": {
                      "items": [
                        {
                          "proofId": "87c16563-a9d9-4bb8-81c7-62b83fce841b",
                          "song": "Midnight Take",
                          "issuedAt": 1783460000,
                          "classification": "human",
                          "hasFeedback": true
                        }
                      ],
                      "nextCursor": "eyJwayI6IlBST09GIzg3YzE2NTYzIn0="
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Proofs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "const page = await poh.listProofs({ limit: 50 });\nfor (const p of page.items) {\n  // Render evidenceReport, not legacy classification/grade calibration fields.\n  console.log(p.proofId, p.song, p.evidenceReport?.status ?? \"report_unavailable\");\n}\nif (page.nextCursor) {\n  const next = await poh.listProofs({ cursor: page.nextCursor });\n}"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"https://api.proofofhuman.fm/v1/proofs?limit=50\" -H \"x-api-key: $POH_API_KEY\""
          }
        ]
      }
    },
    "/proofs/{proofId}": {
      "get": {
        "operationId": "getProof",
        "description": "Fetch one proof's restorable artifact: the stored proof record plus its sealed `.poh`. Returns\nONLY the shareable proof file and display fields — never the retained audio or behavioral trace.\nTenant-scoped: another tenant's proofId reads as 404.",
        "parameters": [
          {
            "name": "proofId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetProofResponse"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Proofs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "const proof = await poh.getProof(\"87c16563-a9d9-4bb8-81c7-62b83fce841b\");\nconsole.log(proof.song, proof.evidenceReport);\n// proof.poh is the base64 .poh — identical to what issuance produced"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"https://api.proofofhuman.fm/v1/proofs/87c16563-a9d9-4bb8-81c7-62b83fce841b\" -H \"x-api-key: $POH_API_KEY\""
          }
        ]
      },
      "delete": {
        "operationId": "eraseProof",
        "description": "Erase a proof's retained data and record (GDPR/CCPA right-to-erasure) and return a receipt.\nIdempotent and safe to retry blindly: the call that removes the proof reports `erased`; a repeat\n— or a proofId with nothing behind it — reports `already_erased` with the same 200. Tenant-scoped:\na caller can only ever erase data held under its own API key, and erasure always converges on\n\"gone\".",
        "parameters": [
          {
            "name": "proofId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EraseProofResponse"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Proofs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "const receipt = await poh.eraseProof(\"87c16563-a9d9-4bb8-81c7-62b83fce841b\");\nconsole.log(receipt.outcome); // \"erased\" — or \"already_erased\" on a repeat (idempotent)"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X DELETE \"https://api.proofofhuman.fm/v1/proofs/$PROOF_ID\" -H \"x-api-key: $POH_API_KEY\"\n# → { \"proofId\": \"…\", \"outcome\": \"erased\", \"erasedAt\": 1783460000 }"
          }
        ]
      }
    },
    "/proofs/{proofId}/asset": {
      "get": {
        "operationId": "getEmbeddedAsset",
        "description": "Fetch a short-lived download URL for this proof's one-file C2PA audio artifact.",
        "parameters": [
          {
            "name": "proofId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddedAssetResponse"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Proofs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-poh-auth-surface": "partner-api-key"
      }
    },
    "/proofs/{proofId}/interpretation": {
      "get": {
        "operationId": "getInterpretation",
        "description": "Fetch the async evidence-selected process note for a proof, by id — the poll endpoint the\nverifier UI hits while a summary is still generating. Returns `pending` (poll again shortly),\n`ready` with the summary, or `unavailable`. Keyed by the unguessable proofId and report-only.\nV1 policy decision: proofId is the lookup capability, but it is NOT sufficient authentication\non its own. The body is tenant-data-free, yet the deployed gateway still requires a partner API\nkey or enrolled-device signature; this preserves the current anti-abuse boundary without\nwidening access. 404 only when no proof with that id exists.",
        "parameters": [
          {
            "name": "proofId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Interpretation"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Proofs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "// Poll for at most two minutes; a pending result can be checked again later.\nconst deadline = Date.now() + 120_000;\nlet interp = await poh.getInterpretation(proofId);\nwhile (interp.status === \"pending\" && Date.now() < deadline) {\n  await new Promise((r) => setTimeout(r, (interp.retryAfterSeconds ?? 2) * 1000));\n  interp = await poh.getInterpretation(proofId);\n}\nif (interp.status === \"ready\") console.log(interp.text);"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"https://api.proofofhuman.fm/v1/proofs/$PROOF_ID/interpretation\" -H \"x-api-key: $POH_API_KEY\""
          }
        ]
      }
    },
    "/records/{proofId}": {
      "get": {
        "operationId": "getProofRecord",
        "description": "Get the shareable record for a proof id. Same access doctrine as `getInterpretation`: any valid\ncaller holding a proofId reads it without re-presenting the audio — proofIds are unguessable\nUUIDs, the id travels only where the artist (or their file) carries it, and the body is\nreport-only. The legacy calibration FIELDS (`grade`/`classification`) are never on this surface:\nthe record exists to be shown publicly, and those percentages are withheld from public display\neverywhere. The `evidenceReport` itself is the SAME account `verifyProof` returns for this proof\n— including its withheld-percentage `legacy_human_assessment` fact and any declaration conflicts.\nThat parity is deliberate: pruning report facts here would dangle the conflicts built on them,\nand a creator-contradicted proof would read CALMER on its share page than on the verifier.\nA proof that was erased, never issued, or not fully written (any lifecycle status) is a uniform\n404 — the response never distinguishes \"deleted\" from \"never existed\".",
        "parameters": [
          {
            "name": "proofId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProofRecordResponse"
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The server cannot find the requested resource.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Verify"
        ],
        "x-poh-auth-surface": "partner-api-key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/uploads": {
      "post": {
        "operationId": "createUpload",
        "description": "Get a short-lived, size-bounded presigned upload URL for audio or a sealed capture trace.",
        "parameters": [
          {
            "name": "purpose",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UploadPurpose"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadResponse"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Verify"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { readFile } from \"node:fs/promises\";\nimport { PoHClient } from \"@proof-of-human/ts-sdk\";\nconst poh = new PoHClient({ apiKey: process.env.POH_API_KEY! });\n\n// 1. ask for a short-lived, presigned upload slot\nconst upload = await poh.createUpload();\n\n// 2. POST the audio bytes to it (multipart/form-data: every field, then the file)\nconst bytes = await readFile(\"song.wav\");\nconst form = new FormData();\nfor (const [k, v] of Object.entries(upload.fields)) form.append(k, v);\nform.append(\"file\", new Blob([new Uint8Array(bytes)], { type: \"audio/wav\" }), \"song.wav\");\nconst posted = await fetch(upload.url, { method: \"POST\", body: form });\nif (!posted.ok) throw new Error(`audio upload failed: ${posted.status}`);\n// upload.uploadId now points at the stored audio — pass it to verify()"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "UPLOAD=$(curl -fsS -X POST \"https://api.proofofhuman.fm/v1/uploads?purpose=verify\" -H \"x-api-key: $POH_API_KEY\")\nUPLOAD_ID=$(jq -r .uploadId <<<\"$UPLOAD\")\nUPLOAD_URL=$(jq -r .url <<<\"$UPLOAD\")\nFORM_FIELDS=()\nwhile IFS=$'\\t' read -r key value; do FORM_FIELDS+=( -F \"$key=$value\" ); done \\\n  < <(jq -r '.fields | to_entries[] | [.key, .value] | @tsv' <<<\"$UPLOAD\")\ncurl -fsS -X POST \"$UPLOAD_URL\" \"${FORM_FIELDS[@]}\" -F \"file=@song.wav;type=audio/wav\"\n# pass $UPLOAD_ID to POST /verify"
          }
        ]
      }
    },
    "/verify": {
      "post": {
        "operationId": "verifyProof",
        "description": "Verify either an uploaded one-file C2PA/PoH audio asset or a legacy uploaded audio + proof pair.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Reusable 200 response with the standard request-correlation header.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                },
                "examples": {
                  "Verify a credentialed WAV with one file": {
                    "summary": "Verify a credentialed WAV with one file",
                    "description": "Post the WAV to the presigned slot from POST /uploads, then send only its uploadId. For a legacy sidecar, add the base64 `.poh` as `poh`. `valid` means the proof is PoH's and bound to exactly these bytes.",
                    "value": {
                      "good": true,
                      "verdict": "valid",
                      "proofId": "87c16563-a9d9-4bb8-81c7-62b83fce841b",
                      "song": "Midnight Take",
                      "classification": "human"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The server could not understand the request due to invalid syntax.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "The caller's API key is missing/invalid for this action, or the device is not enrolled / revoked.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "The caller exceeded its rate limit or quota — wait `Retry-After` seconds and retry.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "required": false,
                "description": "seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Shaped internal failure. Gateway and Lambda failures use the same ApiError body.",
            "headers": {
              "X-Request-Id": {
                "required": false,
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "tags": [
          "Verify"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              },
              "examples": {
                "Verify a credentialed WAV with one file": {
                  "summary": "Verify a credentialed WAV with one file",
                  "description": "Post the WAV to the presigned slot from POST /uploads, then send only its uploadId. For a legacy sidecar, add the base64 `.poh` as `poh`. `valid` means the proof is PoH's and bound to exactly these bytes.",
                  "value": {
                    "uploadId": "9f3a2c7e-5b14-4d2a-8e6f-1c2b3a4d5e6f"
                  }
                }
              }
            }
          }
        },
        "x-poh-auth-surface": "partner-api-key",
        "x-codeSamples": [
          {
            "lang": "TypeScript",
            "label": "SDK",
            "source": "import { PoHClient } from \"@proof-of-human/ts-sdk\";\nconst poh = new PoHClient({ apiKey: process.env.POH_API_KEY! });\n\n// Credentialed WAV: one file, so no sidecar field.\nconst result = await poh.verify({ uploadId: upload.uploadId });\n\n// Legacy fallback: poh.verify({ uploadId: upload.uploadId, poh: pohFileBase64 });\n\nif (result.good && result.verdict === \"valid\") {\n  // signature checks out AND the proof is bound to exactly this audio\n  console.log(result.evidenceReport); // observations, inferences, declarations, conflicts, limits\n}"
          },
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST \"https://api.proofofhuman.fm/v1/verify\" \\\n  -H \"x-api-key: $POH_API_KEY\" \\\n  -H \"content-type: application/json\" \\\n  -d \"{\\\"uploadId\\\":\\\"$UPLOAD_ID\\\"}\"\n# Legacy fallback: include \"poh\":\"<base64 .poh>\" in the JSON body."
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": [
          "ok",
          "version",
          "commit",
          "deployedAt"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "version": {
            "type": "string",
            "minLength": 1,
            "description": "deployed API/SDK semantic version; matches `info.version` in the production OpenAPI"
          },
          "commit": {
            "type": "string",
            "minLength": 1
          },
          "deployedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds of the last deploy (same unit as every other timestamp in this API)"
          }
        },
        "description": "Public, non-sensitive deployment stamp for smoke tests and source-to-deploy verification."
      },
      "ApiError": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "violations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldViolation"
            },
            "description": "Machine-readable field failures for a 400 produced by operation request validation."
          }
        },
        "description": "A structured error. `error` is a human-readable message (may change); `code` is a STABLE,\nmachine-readable slug you can branch on. Common codes: `invalid_request` (400), `forbidden`\n(403), `not_found` (404), `conflict` (409), `unprocessable` (422), `rate_limited` (429),\n`internal` (5xx). A few endpoints return more specific codes — e.g. rotation returns\n`key_rotating`, `rotation_in_progress`, or `idempotency_key_reused`. New codes may be added over\ntime, so treat an unrecognized code as its HTTP status class."
      },
      "PartnerKeysResponse": {
        "type": "object",
        "required": [
          "partner",
          "keys"
        ],
        "properties": {
          "partner": {
            "type": "string",
            "description": "your partner account slug"
          },
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartnerKey"
            },
            "description": "every key on this page (metadata only — never a secret), including expired and revoked keys"
          },
          "nextCursor": {
            "type": "string",
            "description": "opaque cursor for the next page; absent when this is the final page"
          }
        },
        "example": {
          "partner": "acme",
          "keys": [
            {
              "keyId": "3n7kp2q9xa",
              "name": "acme-2026-07-07",
              "createdAt": 1783460000,
              "status": "active"
            }
          ]
        }
      },
      "RotatedKeyResponse": {
        "type": "object",
        "required": [
          "apiKey",
          "keyId",
          "name",
          "previousKeyExpiresAt"
        ],
        "properties": {
          "apiKey": {
            "type": "string",
            "description": "the NEW secret — store it now, it is never returned again"
          },
          "keyId": {
            "type": "string",
            "description": "the new key's id (safe to log)"
          },
          "name": {
            "type": "string",
            "description": "the new key's display name"
          },
          "previousKeyExpiresAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds until which the previous key keeps working — the zero-downtime cutover window (72h)"
          }
        },
        "description": "The one-time result of a rotation. Store `apiKey` now — it is never retrievable again.",
        "example": {
          "apiKey": "poh_live_<returned-once>",
          "keyId": "7b2mk9p4za",
          "name": "acme-2026-07-07",
          "previousKeyExpiresAt": 1783719200
        }
      },
      "PartnerReviewCase": {
        "type": "object",
        "required": [
          "reviewId",
          "proofId",
          "bindings",
          "bindingAssurance",
          "identityStatus",
          "status",
          "createdAt",
          "updatedAt",
          "expiresAt",
          "requests"
        ],
        "properties": {
          "reviewId": {
            "type": "string"
          },
          "proofId": {
            "type": "string"
          },
          "bindings": {
            "$ref": "#/components/schemas/PartnerReviewBindings"
          },
          "bindingAssurance": {
            "$ref": "#/components/schemas/PartnerBindingAssurance"
          },
          "identityStatus": {
            "$ref": "#/components/schemas/PartnerIdentityStatus"
          },
          "status": {
            "$ref": "#/components/schemas/PartnerReviewStatus"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          },
          "updatedAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          },
          "expiresAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "hard metadata-retention deadline; DynamoDB TTL deletion is eventual"
          },
          "requests": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartnerEvidenceRequest"
            },
            "maxItems": 3,
            "description": "At most one request of each kind; bounded to keep one review cheap and readable."
          },
          "resolution": {
            "$ref": "#/components/schemas/PartnerReviewResolution"
          }
        }
      },
      "CreatePartnerReviewRequest": {
        "type": "object",
        "required": [
          "proofId",
          "bindings"
        ],
        "properties": {
          "proofId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "a registered PoH proof; creating a case does not re-verify an audio file"
          },
          "bindings": {
            "$ref": "#/components/schemas/PartnerReviewBindings"
          }
        }
      },
      "CreatePartnerEvidenceRequest": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "$ref": "#/components/schemas/PartnerEvidenceRequestKind"
          },
          "requestReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "optional opaque ticket/reference in the partner's own evidence system"
          }
        }
      },
      "UpdatePartnerEvidenceRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/PartnerEvidenceResponseStatus"
          },
          "responseReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "required by partner policy when status is `supplied`; omitted for a decline"
          }
        }
      },
      "ResolvePartnerReviewRequest": {
        "type": "object",
        "required": [
          "outcome"
        ],
        "properties": {
          "outcome": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PartnerReviewOutcome"
              }
            ],
            "description": "the partner's own Accept / Hold / Reject policy result"
          }
        }
      },
      "PartnerUsageResponse": {
        "type": "object",
        "required": [
          "partner",
          "plan",
          "days"
        ],
        "properties": {
          "partner": {
            "type": "string",
            "description": "your partner account slug"
          },
          "plan": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PartnerUsagePlan"
              }
            ],
            "description": "the plan's throttle + quota limits"
          },
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartnerDayUsage"
            },
            "description": "per-day request counts, oldest first, over the requested window"
          }
        },
        "example": {
          "partner": "acme",
          "plan": {
            "rateLimit": 10,
            "burstLimit": 20,
            "quotaLimit": 50000,
            "quotaPeriod": "MONTH"
          },
          "days": [
            {
              "date": "2026-07-06",
              "used": 1420,
              "remaining": 48580
            },
            {
              "date": "2026-07-07",
              "used": 1893,
              "remaining": 46687
            }
          ]
        }
      },
      "ListProofsResponse": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProofListItem"
            },
            "description": "the caller's proofs, newest first"
          },
          "nextCursor": {
            "type": "string",
            "description": "opaque page cursor; pass it back as `?cursor=` to fetch the next page. Absent on the last page"
          }
        },
        "example": {
          "items": [
            {
              "proofId": "87c16563-a9d9-4bb8-81c7-62b83fce841b",
              "song": "Midnight Take",
              "issuedAt": 1783460000,
              "classification": "unknown",
              "evidenceReport": {
                "version": "poh-evidence-report-1",
                "scope": "observed_session",
                "status": "evidence_conflict",
                "legacyPercentagesWithheld": true,
                "facts": [
                  {
                    "code": "legacy_human_assessment",
                    "basis": "rule_inference"
                  },
                  {
                    "code": "render_observed",
                    "basis": "system_observation"
                  },
                  {
                    "code": "creator_external_material",
                    "basis": "creator_declaration"
                  },
                  {
                    "code": "creator_contribution_under_twenty",
                    "basis": "creator_declaration"
                  },
                  {
                    "code": "creator_declared_no_ai_generated_material",
                    "basis": "creator_declaration"
                  },
                  {
                    "code": "creator_reported_assessment_too_lenient",
                    "basis": "creator_declaration"
                  },
                  {
                    "code": "source_identity_unverified",
                    "basis": "unverifiable"
                  },
                  {
                    "code": "final_output_coverage_unverified",
                    "basis": "unverifiable"
                  }
                ],
                "conflicts": [
                  {
                    "code": "legacy_human_score_vs_creator_declaration",
                    "systemFact": "legacy_human_assessment",
                    "creatorFact": "creator_contribution_under_twenty"
                  }
                ]
              },
              "hasFeedback": true
            }
          ],
          "nextCursor": "eyJwayI6IlBST09GIzg3YzE2NTYzIn0="
        }
      },
      "GetProofResponse": {
        "type": "object",
        "required": [
          "proofId",
          "song",
          "issuedAt",
          "hasFeedback",
          "poh"
        ],
        "properties": {
          "proofId": {
            "type": "string",
            "minLength": 1
          },
          "song": {
            "type": "string",
            "minLength": 1
          },
          "issuedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds at issuance — the same value as this proof's canonical `ProofDocument.createdAt`"
          },
          "classification": {
            "$ref": "#/components/schemas/Classification"
          },
          "grade": {
            "allOf": [
              {
                "$ref": "#/components/schemas/GradeBreakdown"
              }
            ],
            "description": "Legacy normalized behavioral evidence masses. Kept for wire compatibility; prefer\n`evidenceReport` for every user-facing report."
          },
          "evidenceReport": {
            "$ref": "#/components/schemas/EvidenceReport"
          },
          "hasFeedback": {
            "type": "boolean",
            "description": "whether the post-export survey was completed — a restored library must not re-ask"
          },
          "embeddedCredential": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EmbeddedCredential"
              }
            ],
            "description": "present when a self-contained C2PA audio artifact is available for this proof"
          },
          "poh": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Base64"
              }
            ],
            "description": "base64 of the sealed `.poh` — identical in content to what issuance returned"
          },
          "interpretation": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Interpretation"
              }
            ],
            "description": "the async evidence-selected process note, if one has been generated for this proof"
          }
        },
        "description": "A proof's restorable artifact: the library row plus the sealed `.poh` bytes."
      },
      "EraseProofResponse": {
        "type": "object",
        "required": [
          "proofId",
          "outcome",
          "erasedAt"
        ],
        "properties": {
          "proofId": {
            "type": "string",
            "minLength": 1,
            "description": "the proofId the erasure addressed"
          },
          "outcome": {
            "$ref": "#/components/schemas/EraseOutcome"
          },
          "erasedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds when this erasure pass completed"
          }
        },
        "description": "The receipt for a right-to-erasure call.",
        "example": {
          "proofId": "87c16563-a9d9-4bb8-81c7-62b83fce841b",
          "outcome": "erased",
          "erasedAt": 1783460000
        }
      },
      "EmbeddedAssetResponse": {
        "type": "object",
        "required": [
          "url",
          "expiresAt",
          "bytes",
          "sha256",
          "format",
          "publiclyTrusted"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "expiresAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          },
          "bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 1
          },
          "sha256": {
            "$ref": "#/components/schemas/Sha256"
          },
          "format": {
            "type": "string",
            "minLength": 1
          },
          "publiclyTrusted": {
            "type": "boolean"
          }
        },
        "description": "A short-lived download for the self-contained C2PA audio artifact."
      },
      "Interpretation": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/InterpretationStatus"
          },
          "text": {
            "type": "string",
            "maxLength": 1500,
            "description": "the high-level summary — present only when `status` is `ready`."
          },
          "generatedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds when the summary was generated (present when `ready`)."
          },
          "policyVersion": {
            "type": "string",
            "minLength": 1,
            "description": "renderer policy that produced `text`; clients must fail closed on unknown or absent values."
          },
          "retryAfterSeconds": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "description": "suggested delay before the next poll; present when `status` is `pending`"
          }
        },
        "description": "A high-level account of the editing PoH witnessed — a report-only companion to `grade`, produced\nASYNCHRONOUSLY after issuance from content-free behavioral features. A model selects only\napproved evidence IDs through structured output; fixed server\ntemplates render the public text. The model never writes public prose and receives no raw capture,\nexact percentages, names, identifiers, paths, audio, or musical content.\n`pending` while still generating (poll after `retryAfterSeconds`, for at most two minutes per\nforeground polling session); `ready` carries the summary; `unavailable`\nwhen it permanently failed or the proof predates the feature. NON-GATING — never affects\n`good`/`verdict`/issuance.",
        "example": {
          "status": "ready",
          "text": "The clearest observed pattern was that an audio source entered the session and was rearranged. No recording activity or MIDI note entry was observed; the relationship to the final rendered audio remains unverifiable.",
          "policyVersion": "poh-interpretation-policy-3.0.0",
          "generatedAt": 1700000000
        }
      },
      "ProofRecordResponse": {
        "type": "object",
        "required": [
          "proofId",
          "song",
          "issuedAt",
          "audioSha256"
        ],
        "properties": {
          "proofId": {
            "type": "string"
          },
          "song": {
            "type": "string"
          },
          "issuedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds when the proof was issued"
          },
          "audioSha256": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Sha256"
              }
            ],
            "description": "SHA-256 of the exact audio this proof is bound to"
          },
          "evidenceReport": {
            "$ref": "#/components/schemas/EvidenceReport"
          },
          "interpretation": {
            "$ref": "#/components/schemas/Interpretation"
          },
          "embeddedCredential": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EmbeddedCredential"
              }
            ],
            "description": "present when the proof was delivered as C2PA-credentialed audio"
          }
        },
        "description": "The registered, shareable account of one proof. Deliberately NOT a verification: nothing here\nsays the reader's audio matches — it is the record PoH holds for this id, so an artist can hand\nsomeone a link instead of a file. `audioSha256` names the exact audio the record is bound to;\nconfirming a candidate file still requires `POST /verify` with the file itself."
      },
      "UploadPurpose": {
        "type": "string",
        "enum": [
          "source",
          "verify",
          "activity"
        ]
      },
      "UploadResponse": {
        "type": "object",
        "required": [
          "uploadId",
          "url",
          "fields",
          "expiresAt",
          "maxBytes"
        ],
        "properties": {
          "uploadId": {
            "type": "string",
            "minLength": 1,
            "description": "the id you pass back to `POST /verify` once the file is uploaded"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "presigned upload endpoint — send a multipart/form-data POST here"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "form fields (policy, signature, key, …) to send verbatim, with the file as the last part"
          },
          "expiresAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds when this presigned upload policy expires"
          },
          "maxBytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "description": "maximum size accepted by this slot (64 MiB source, 65 MiB verification, or 16 MiB capture trace)"
          }
        },
        "description": "A presigned upload: POST the audio as multipart/form-data to `url`, carrying every entry of\n`fields` plus the file. The presigned policy pins a size limit and a server-owned object key, so\nan oversized or misnamed upload is rejected before it is ever stored.",
        "example": {
          "uploadId": "9f3a2c7e-5b14-4d2a-8e6f-1c2b3a4d5e6f",
          "url": "https://uploads.proofofhuman.fm/",
          "fields": {
            "key": "uploads/9f3a2c7e-5b14-4d2a-8e6f-1c2b3a4d5e6f.audio",
            "policy": "eyJleHBpcmF0aW9uIjoiMjAyNi0wNy0wN1QyMzo1OTo1OVoiLCJjb25kaXRpb25zIjpbXX0=",
            "signature": "a1b2c3d4e5f60718293a4b5c6d7e8f90"
          },
          "expiresAt": 1783460900,
          "maxBytes": 67108864
        }
      },
      "VerifyResponse": {
        "type": "object",
        "required": [
          "good",
          "verdict"
        ],
        "properties": {
          "good": {
            "type": "boolean"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "detail": {
            "type": "string"
          },
          "proofId": {
            "type": "string"
          },
          "song": {
            "type": "string"
          },
          "document": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProofDocument"
              }
            ],
            "description": "The verified signed public proof document. Present for every valid credential so clients can\nrender the same receipt for one-file and legacy audio + `.poh` verification without parsing\neither credential format in an untrusted client."
          },
          "classification": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Classification"
              }
            ],
            "description": "The legacy behavioral-calibration classification recorded at issuance. It is not an authorship,\nlabor-contribution, or final-audio-origin measure. NON-GATING: `good`/`verdict` are the\ncredential check and never depend on this. Returned to anyone presenting the matching\ncredentialed audio or legacy audio + `.poh` pair — possession is the access token. Absent on\nproofs issued before grading shipped."
          },
          "grade": {
            "$ref": "#/components/schemas/GradeBreakdown"
          },
          "evidenceReport": {
            "$ref": "#/components/schemas/EvidenceReport"
          },
          "decision": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VerificationDecisionEnvelope"
              }
            ],
            "description": "Stable partner decision + evidence envelope. Additive for compatibility; returned on every check."
          },
          "sourceDetailReport": {
            "allOf": [
              {
                "$ref": "#/components/schemas/SourceDetailReport"
              }
            ],
            "description": "Private source explainability, returned only when `includeSourceDetails` was requested by an\nexplicitly approved partner. Never present for ordinary API keys or public verification."
          },
          "sourceDetailReportV2": {
            "allOf": [
              {
                "$ref": "#/components/schemas/SourceDetailReportV2"
              }
            ],
            "description": "Expanded private source explainability, returned only when the approved partner explicitly\nrequests `sourceDetailReportVersion=poh-source-detail-2` and the stored proof collected v2.\nKeeping this additive field separate preserves the original v1 response for existing clients."
          },
          "interpretation": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Interpretation"
              }
            ],
            "description": "The async evidence-selected process note recorded for this proof, if any. `pending` while the\nselection job is still running (poll `getInterpretation` by `proofId`), `ready` with the summary,\n`unavailable` / absent on proofs that predate the feature. Report-only like `grade`."
          },
          "embeddedCredential": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EmbeddedCredential"
              }
            ],
            "description": "present when verification used a proof embedded in a C2PA audio asset"
          }
        },
        "example": {
          "good": true,
          "verdict": "valid",
          "proofId": "87c16563-a9d9-4bb8-81c7-62b83fce841b",
          "song": "Fixture Song",
          "classification": "unknown",
          "evidenceReport": {
            "version": "poh-evidence-report-1",
            "scope": "observed_session",
            "status": "insufficient_source_evidence",
            "legacyPercentagesWithheld": true,
            "facts": [
              {
                "code": "render_observed",
                "basis": "system_observation"
              },
              {
                "code": "source_identity_unverified",
                "basis": "unverifiable"
              },
              {
                "code": "final_output_coverage_unverified",
                "basis": "unverifiable"
              }
            ]
          }
        }
      },
      "VerifyRequest": {
        "type": "object",
        "required": [
          "uploadId"
        ],
        "properties": {
          "uploadId": {
            "type": "string",
            "minLength": 1,
            "description": "the `uploadId` returned by `POST /uploads`, after you've posted the audio bytes to it"
          },
          "poh": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Base64"
              }
            ],
            "description": "The `.poh` proof file, base64-encoded. Omit it when the uploaded audio carries PoH's C2PA\nassertion; the verifier extracts the nested proof after validating the C2PA binding and signer."
          },
          "includeSourceDetails": {
            "type": "boolean",
            "description": "Ask for the private, source-by-source DAW placement report. This fails with 403 unless the\ncalling partner account is active and PoH has explicitly granted its `source-detail:read`\ncapability. The report is returned only after the uploaded audio verifies exactly."
          },
          "sourceDetailReportVersion": {
            "type": "string",
            "enum": [
              "poh-source-detail-2"
            ],
            "description": "Opt in to the expanded v2 report. Omit this field for the original v1 response contract. If\nthe proof predates v2 collection, the available v1 report is returned in `sourceDetailReport`.\nThis is meaningful only when `includeSourceDetails` is true."
          }
        },
        "example": {
          "uploadId": "9f3a2c7e-5b14-4d2a-8e6f-1c2b3a4d5e6f"
        }
      },
      "UnixSeconds": {
        "type": "integer",
        "format": "int64",
        "minimum": 0,
        "description": "Whole unix epoch seconds. Kept numeric on the wire for v1 compatibility."
      },
      "FieldViolation": {
        "type": "object",
        "required": [
          "field",
          "rule",
          "message"
        ],
        "properties": {
          "field": {
            "type": "string",
            "description": "Request location plus field path, e.g. `body.consent.acceptedAt` or `query.days`."
          },
          "rule": {
            "type": "string",
            "description": "Stable schema rule that failed, e.g. `required`, `minimum`, or `pattern`."
          },
          "message": {
            "type": "string",
            "description": "Human-readable description of the violated rule."
          }
        },
        "description": "One invalid request field, derived from the operation's generated OpenAPI schema."
      },
      "PartnerKey": {
        "type": "object",
        "required": [
          "keyId",
          "name",
          "createdAt",
          "status"
        ],
        "properties": {
          "keyId": {
            "type": "string",
            "description": "the key's id (safe to log/display — this is NOT the secret)"
          },
          "name": {
            "type": "string",
            "description": "display name, e.g. `acme-2026-07-08`"
          },
          "createdAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds when the key was created"
          },
          "status": {
            "$ref": "#/components/schemas/PartnerKeyStatus"
          },
          "expiresAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds when an `expiring` key stops working (rotation grace deadline)"
          }
        },
        "description": "One API key on the caller's partner account. Metadata only — the secret is returned exactly once, at rotation."
      },
      "PartnerReviewBindings": {
        "type": "object",
        "required": [
          "creatorId",
          "accountId",
          "submissionId",
          "trackId"
        ],
        "properties": {
          "creatorId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "opaque creator id from the partner's system — never a name or email address"
          },
          "accountId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "opaque account id from the partner's system"
          },
          "submissionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "opaque submission id from the partner's system"
          },
          "trackId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "opaque track id from the partner's system"
          }
        },
        "description": "Partner-owned identifiers that bind a PoH proof to one concrete catalog submission."
      },
      "PartnerBindingAssurance": {
        "type": "string",
        "enum": [
          "registered_proof_partner_asserted_context"
        ],
        "description": "PoH registered the proof, while the business identifiers remain assertions by the partner."
      },
      "PartnerIdentityStatus": {
        "type": "string",
        "enum": [
          "not_verified_by_poh"
        ],
        "description": "PoH does not independently identify the creator through this workflow."
      },
      "PartnerReviewStatus": {
        "type": "string",
        "enum": [
          "open",
          "evidence_requested",
          "evidence_received",
          "ready_for_review",
          "resolved"
        ]
      },
      "PartnerEvidenceRequest": {
        "type": "object",
        "required": [
          "requestId",
          "kind",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "requestId": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/PartnerEvidenceRequestKind"
          },
          "status": {
            "$ref": "#/components/schemas/PartnerEvidenceRequestStatus"
          },
          "requestReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "optional opaque ticket/reference in the partner's own evidence system"
          },
          "responseReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
            "description": "optional opaque reference to the supplied response; PoH does not store the material itself"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          },
          "updatedAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          }
        }
      },
      "PartnerReviewResolution": {
        "type": "object",
        "required": [
          "outcome",
          "basis",
          "resolvedAt"
        ],
        "properties": {
          "outcome": {
            "$ref": "#/components/schemas/PartnerReviewOutcome"
          },
          "basis": {
            "$ref": "#/components/schemas/PartnerReviewOutcomeBasis"
          },
          "resolvedAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          }
        }
      },
      "PartnerEvidenceRequestKind": {
        "type": "string",
        "enum": [
          "source_evidence",
          "source_licence",
          "creator_clarification"
        ]
      },
      "PartnerEvidenceResponseStatus": {
        "type": "string",
        "enum": [
          "supplied",
          "accepted",
          "declined"
        ],
        "description": "Status values a partner can submit after the initial request has been created."
      },
      "PartnerReviewOutcome": {
        "type": "string",
        "enum": [
          "accepted",
          "held",
          "rejected"
        ],
        "description": "The integrating partner's policy outcome — this is not an authorship finding by PoH."
      },
      "PartnerUsagePlan": {
        "type": "object",
        "properties": {
          "rateLimit": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "steady-state requests/second the plan allows"
          },
          "burstLimit": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "description": "burst ceiling"
          },
          "quotaLimit": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "the quota amount per period (absent if unlimited)"
          },
          "quotaPeriod": {
            "allOf": [
              {
                "$ref": "#/components/schemas/QuotaPeriod"
              }
            ],
            "description": "the quota period: `DAY`, `WEEK`, or `MONTH`"
          }
        }
      },
      "PartnerDayUsage": {
        "type": "object",
        "required": [
          "date",
          "used"
        ],
        "properties": {
          "date": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
            "description": "the UTC day, `yyyy-mm-dd`"
          },
          "used": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "requests counted against the quota that day"
          },
          "remaining": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "requests left in the quota that day (absent if the plan has no quota)"
          }
        },
        "description": "One UTC day of request usage against the partner's quota."
      },
      "ProofListItem": {
        "type": "object",
        "required": [
          "proofId",
          "song",
          "issuedAt",
          "hasFeedback"
        ],
        "properties": {
          "proofId": {
            "type": "string",
            "minLength": 1
          },
          "song": {
            "type": "string",
            "minLength": 1
          },
          "issuedAt": {
            "allOf": [
              {
                "$ref": "#/components/schemas/UnixSeconds"
              }
            ],
            "description": "unix seconds at issuance — the same value as this proof's canonical `ProofDocument.createdAt`"
          },
          "classification": {
            "$ref": "#/components/schemas/Classification"
          },
          "grade": {
            "allOf": [
              {
                "$ref": "#/components/schemas/GradeBreakdown"
              }
            ],
            "description": "Legacy normalized behavioral evidence masses. Kept for wire compatibility; prefer\n`evidenceReport` for every user-facing report."
          },
          "evidenceReport": {
            "$ref": "#/components/schemas/EvidenceReport"
          },
          "hasFeedback": {
            "type": "boolean",
            "description": "whether the post-export survey was completed — a restored library must not re-ask"
          },
          "embeddedCredential": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EmbeddedCredential"
              }
            ],
            "description": "present when a self-contained C2PA audio artifact is available for this proof"
          }
        },
        "description": "One proof in the caller's library."
      },
      "Classification": {
        "type": "string",
        "enum": [
          "human",
          "ai",
          "unknown"
        ],
        "description": "A legacy behavioral-calibration classification over the captured session: `human` only when\nwitnessed hands-on evidence dominates; `ai` only on positive generative, bulk-appearance, or\nAI-provenance evidence; `unknown` whenever the trace is too thin to judge. The separate\n`high_risk_import` category is a review flag and does not by itself produce `ai`. Absence of\nevidence is never read as `ai`. Report-only: issuance is not gated on it, and public clients must\nrender `EvidenceReport` instead."
      },
      "GradeBreakdown": {
        "type": "object",
        "required": [
          "human",
          "ai",
          "unknown",
          "riskCategory",
          "rubricVersion"
        ],
        "properties": {
          "human": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "maximum": 100
          },
          "ai": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "maximum": 100
          },
          "unknown": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "maximum": 100
          },
          "riskCategory": {
            "$ref": "#/components/schemas/WorkflowRiskCategory"
          },
          "rubricVersion": {
            "type": "string",
            "minLength": 1
          }
        },
        "description": "Legacy normalized behavioral evidence masses summing to 100, plus the rubric that produced them.\nThey are retained for reproducibility and calibration, not as an authorship or final-audio\ncontribution estimate. Public clients must render `EvidenceReport` instead."
      },
      "EvidenceReport": {
        "type": "object",
        "required": [
          "version",
          "scope",
          "status",
          "legacyPercentagesWithheld",
          "facts"
        ],
        "properties": {
          "version": {
            "type": "string",
            "enum": [
              "poh-evidence-report-1"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "observed_session"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/EvidenceAssessmentStatus"
          },
          "legacyPercentagesWithheld": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Always true while the legacy behavioral masses lack a validated final-audio denominator. Clients\nmust not present `grade.human`, `grade.ai`, or `grade.unknown` as authorship percentages."
          },
          "facts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvidenceFact"
            },
            "minItems": 1,
            "maxItems": 32
          },
          "conflicts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvidenceConflict"
            },
            "maxItems": 8
          },
          "declarations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreatorDeclaration"
            },
            "maxItems": 20,
            "description": "Raw creator answers with version, time, subject, and honest post-issuance binding status."
          }
        },
        "description": "A versioned, expandable account of what PoH directly observed, inferred, was told by the creator,\nand could not verify. Unlike the legacy `grade`, this is not a percentage estimate of authorship.\nIt describes only the captured session and never claims that a DAW timeline share equals a share\nof the final audio."
      },
      "EmbeddedCredential": {
        "type": "object",
        "required": [
          "container",
          "format",
          "publiclyTrusted"
        ],
        "properties": {
          "container": {
            "type": "string",
            "enum": [
              "c2pa"
            ]
          },
          "format": {
            "type": "string",
            "minLength": 1
          },
          "publiclyTrusted": {
            "type": "boolean",
            "description": "true only after PoH's production signer chains to the public C2PA Trust List"
          }
        },
        "description": "The portable credential carried inside a C2PA-enabled audio file."
      },
      "Base64": {
        "type": "string",
        "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
        "description": "Standard base64-encoded bytes with complete 4-character quanta and valid terminal padding."
      },
      "EraseOutcome": {
        "type": "string",
        "enum": [
          "erased",
          "already_erased"
        ],
        "description": "What an erasure call found: `erased` when this call removed the proof, `already_erased` when there was nothing left to remove."
      },
      "Sha256": {
        "type": "string",
        "pattern": "^[0-9a-f]{64}$",
        "description": "A lowercase hex SHA-256 digest."
      },
      "InterpretationStatus": {
        "type": "string",
        "enum": [
          "pending",
          "ready",
          "unavailable"
        ],
        "description": "Whether the async evidence-selected process note is still generating, ready, or won't be produced."
      },
      "Verdict": {
        "type": "string",
        "enum": [
          "valid",
          "tampered",
          "audioChanged",
          "unregistered",
          "unreadable",
          "local_seal"
        ],
        "description": "The outcome of a verification — `valid` only when the proof is PoH's and matches the audio.\nTreat any verdict you don't recognize as a failed verification: new failure verdicts may be\nadded over time (`local_seal` was added after v1 shipped)."
      },
      "ProofDocument": {
        "type": "object",
        "required": [
          "version",
          "id",
          "createdAt",
          "song",
          "audio",
          "session",
          "statement"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "format": "int32",
            "minimum": 1
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          },
          "song": {
            "type": "string",
            "minLength": 1
          },
          "audio": {
            "$ref": "#/components/schemas/ProofAudio"
          },
          "session": {
            "$ref": "#/components/schemas/ProofSession"
          },
          "statement": {
            "type": "string",
            "minLength": 1
          }
        },
        "description": "The proof document — the canonical bytes that get signed.",
        "example": {
          "version": 1,
          "id": "87c16563-a9d9-4bb8-81c7-62b83fce841b",
          "createdAt": 1700000000,
          "song": "Fixture Song",
          "audio": {
            "name": "song.wav",
            "format": "WAV",
            "bytes": 44144,
            "sha256": "17718abea891e9406634e02d7a53c8be00bdeb16b41ccece7a1923c4860107a9"
          },
          "session": {
            "sessionId": "fixture1",
            "durationSeconds": 300,
            "noteCount": 48,
            "editCount": 1,
            "commandCount": 0,
            "saveCount": 1
          },
          "statement": "PoH bound a scoped evidence account from a captured session in the artist's DAW to this exact audio file and applied its signature. The signature verifies the account bytes and audio binding; it does not independently certify authorship, source identity, or that the music is AI-free."
        }
      },
      "VerificationDecisionEnvelope": {
        "type": "object",
        "required": [
          "status",
          "reasons",
          "carrier",
          "sourceCoverage",
          "declarationCount",
          "conflictCount",
          "unknownFactCount",
          "recommendedAction"
        ],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/VerificationDecisionStatus"
          },
          "reasons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VerificationDecisionReason"
            },
            "minItems": 1,
            "maxItems": 4
          },
          "carrier": {
            "$ref": "#/components/schemas/VerificationCarrier"
          },
          "sourceCoverage": {
            "$ref": "#/components/schemas/VerificationSourceCoverage"
          },
          "declarationCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "conflictCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "unknownFactCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "recommendedAction": {
            "$ref": "#/components/schemas/VerificationRecommendedAction"
          }
        },
        "description": "Normalized, policy-neutral envelope for partner automation. It separates cryptographic validity\nfrom source-evidence review and exposes no legacy authorship percentages."
      },
      "SourceDetailReport": {
        "type": "object",
        "required": [
          "version",
          "scope",
          "coverage",
          "daw",
          "derivedFromVerifiedTrace",
          "finalAudioAttributionVerified",
          "limitations",
          "sources"
        ],
        "properties": {
          "version": {
            "type": "string",
            "enum": [
              "poh-source-detail-1"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "private_daw_source_map"
            ]
          },
          "coverage": {
            "$ref": "#/components/schemas/SourceDetailCoverage"
          },
          "daw": {
            "type": "string",
            "enum": [
              "ableton",
              "logic",
              "flstudio",
              "unknown"
            ]
          },
          "derivedFromVerifiedTrace": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "finalAudioAttributionVerified": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "limitations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceDetailLimitation"
            },
            "maxItems": 8
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceDetailItem"
            },
            "maxItems": 64
          }
        },
        "description": "Approved-vendor-only source explainability derived from the verified, device-signed capture\ntrace. It is stored in the encrypted private corpus and is never placed in the public proof,\nC2PA assertion, shareable record, public verifier, or interpretation."
      },
      "SourceDetailReportV2": {
        "type": "object",
        "required": [
          "version",
          "scope",
          "coverage",
          "daw",
          "derivedFromVerifiedTrace",
          "finalAudioAttributionVerified",
          "limitations",
          "sources"
        ],
        "properties": {
          "version": {
            "type": "string",
            "enum": [
              "poh-source-detail-2"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "private_daw_source_map"
            ]
          },
          "coverage": {
            "$ref": "#/components/schemas/SourceDetailCoverage"
          },
          "daw": {
            "type": "string",
            "enum": [
              "ableton"
            ]
          },
          "derivedFromVerifiedTrace": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "finalAudioAttributionVerified": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "sourceMapObservedAtSessionSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "latest completed source-map observation, measured on the signed capture timeline"
          },
          "limitations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceDetailLimitationV2"
            },
            "maxItems": 10
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceDetailItemV2"
            },
            "maxItems": 64
          }
        },
        "description": "Consent-v6 source explainability. This extends v1 with DAW-native beat positions, anonymous\nplacement/track grouping, last-observed source/placement flags, and source-linked edit summaries. It still contains\nno source bytes, names, paths, hashes, notes, automation values, or final-mix attribution claim."
      },
      "PartnerKeyStatus": {
        "type": "string",
        "enum": [
          "active",
          "expiring",
          "expired",
          "revoked"
        ],
        "description": "A key's complete lifecycle state, including terminal states retained for credential history."
      },
      "PartnerEvidenceRequestStatus": {
        "type": "string",
        "enum": [
          "requested",
          "supplied",
          "accepted",
          "declined"
        ]
      },
      "PartnerReviewOutcomeBasis": {
        "type": "string",
        "enum": [
          "partner_policy"
        ]
      },
      "QuotaPeriod": {
        "type": "string",
        "enum": [
          "DAY",
          "WEEK",
          "MONTH"
        ]
      },
      "WorkflowRiskCategory": {
        "type": "string",
        "enum": [
          "strong_human",
          "high_risk_import",
          "mixed_assisted",
          "insufficient_evidence",
          "insufficient_data"
        ],
        "description": "The ordered workflow-risk category from the legacy rules cascade — a review flag over behavioral\ncalibration signals, not an authorship or source verdict. `high_risk_import` means \"finished\ncontent arrived with no witnessed human process; needs review\"; the `insufficient_*` categories\nmean \"we did not see enough\" and must never be presented as \"judged AI\"."
      },
      "EvidenceAssessmentStatus": {
        "type": "string",
        "enum": [
          "consistent",
          "evidence_conflict",
          "insufficient_source_evidence",
          "needs_review"
        ],
        "description": "Whether the source account is internally consistent, contradicted by a creator declaration, or\nstill missing the evidence needed to make a source claim. This status never affects whether a\ncryptographic proof is valid."
      },
      "EvidenceFact": {
        "type": "object",
        "required": [
          "code",
          "basis"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/EvidenceFactCode"
          },
          "basis": {
            "$ref": "#/components/schemas/EvidenceBasis"
          },
          "value": {
            "type": "number",
            "format": "double",
            "minimum": 0
          },
          "unit": {
            "$ref": "#/components/schemas/EvidenceValueUnit"
          }
        }
      },
      "EvidenceConflict": {
        "type": "object",
        "required": [
          "code",
          "systemFact",
          "creatorFact"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/EvidenceConflictCode"
          },
          "systemFact": {
            "$ref": "#/components/schemas/EvidenceFactCode"
          },
          "creatorFact": {
            "$ref": "#/components/schemas/EvidenceFactCode"
          }
        }
      },
      "CreatorDeclaration": {
        "type": "object",
        "required": [
          "surveyVersion",
          "submittedAt",
          "submissionId",
          "subject",
          "dimension",
          "option",
          "authentication",
          "bindingStatus"
        ],
        "properties": {
          "surveyVersion": {
            "type": "integer",
            "format": "int32",
            "minimum": 1
          },
          "submittedAt": {
            "$ref": "#/components/schemas/UnixSeconds"
          },
          "submissionId": {
            "type": "string",
            "minLength": 1
          },
          "subject": {
            "$ref": "#/components/schemas/CreatorDeclarationSubject"
          },
          "dimension": {
            "$ref": "#/components/schemas/CreatorDeclarationDimension"
          },
          "option": {
            "$ref": "#/components/schemas/CreatorDeclarationOption"
          },
          "authentication": {
            "type": "string",
            "enum": [
              "device_signed_request"
            ]
          },
          "bindingStatus": {
            "type": "string",
            "enum": [
              "authenticated_post_issuance_record"
            ]
          }
        },
        "description": "One creator answer with its provenance. It is authenticated by the enrolled device request and\nrecorded after issuance; it is not misrepresented as part of the original proof signature."
      },
      "ProofAudio": {
        "type": "object",
        "required": [
          "name",
          "format",
          "bytes",
          "sha256"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "format": {
            "type": "string",
            "minLength": 1
          },
          "bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "duration": {
            "type": "number",
            "format": "double",
            "minimum": 0
          },
          "sha256": {
            "$ref": "#/components/schemas/Sha256"
          }
        },
        "description": "The audio a proof is bound to."
      },
      "ProofSession": {
        "type": "object",
        "required": [
          "sessionId",
          "durationSeconds",
          "noteCount",
          "editCount",
          "commandCount",
          "saveCount"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "minLength": 1
          },
          "durationSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0
          },
          "noteCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "editCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "commandCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "saveCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "evidence": {
            "allOf": [
              {
                "$ref": "#/components/schemas/SessionEvidenceSummary"
              }
            ],
            "description": "Present on server-notarized proofs issued after canonical trace replay shipped."
          }
        },
        "description": "Content-free counters from the captured session. They describe supported observed activity and\nmust not be interpreted as proof of authorship or source ownership."
      },
      "VerificationDecisionStatus": {
        "type": "string",
        "enum": [
          "verified_binding",
          "needs_review",
          "invalid_proof"
        ],
        "description": "Partner-facing decision state. It never labels a track as human or AI."
      },
      "VerificationDecisionReason": {
        "type": "string",
        "enum": [
          "exact_audio_binding_verified",
          "structured_evidence_clear",
          "source_evidence_needs_review",
          "source_evidence_incomplete",
          "credential_unreadable",
          "credential_integrity_mismatch",
          "signature_invalid",
          "audio_binding_mismatch",
          "proof_unregistered",
          "device_local_seal_only"
        ],
        "description": "Stable reasons behind the partner decision envelope."
      },
      "VerificationCarrier": {
        "type": "string",
        "enum": [
          "embedded_c2pa",
          "legacy_sidecar",
          "unverified_one_file_input"
        ]
      },
      "VerificationSourceCoverage": {
        "type": "string",
        "enum": [
          "public_structured_evidence",
          "approved_private_source_detail_v1",
          "approved_private_source_detail_v2",
          "source_detail_unavailable"
        ]
      },
      "VerificationRecommendedAction": {
        "type": "string",
        "enum": [
          "accept_exact_audio_binding",
          "review_structured_evidence",
          "request_additional_source_evidence",
          "reject_invalid_credential",
          "request_registered_proof"
        ]
      },
      "SourceDetailCoverage": {
        "type": "string",
        "enum": [
          "complete_source_map",
          "partial_source_map",
          "position_unavailable",
          "not_collected"
        ],
        "description": "Whether the detailed source map covers the latest successfully completed DAW observation.\n`complete` means the adapter completed that bounded observation; it does not mean the observation\nwas synchronized to export or that PoH proved how much of each source is audible in the mix."
      },
      "SourceDetailLimitation": {
        "type": "string",
        "enum": [
          "daw_arrangement_not_final_audio_attribution",
          "tempo_automation_may_shift_seconds",
          "logic_visible_regions_only",
          "source_identity_unavailable",
          "source_position_unavailable",
          "source_map_truncated",
          "legacy_capture_did_not_collect_source_detail"
        ],
        "description": "Stable limitation codes let an approved vendor render precise, non-misleading explanations."
      },
      "SourceDetailItem": {
        "type": "object",
        "required": [
          "sourceId",
          "observedDuringCapture",
          "presentAtExport",
          "classification",
          "placements"
        ],
        "properties": {
          "sourceId": {
            "type": "string",
            "pattern": "^source-[1-9][0-9]{0,2}$",
            "description": "report-local opaque identifier; never a path, file name, track name, clip name, or hash"
          },
          "observedDuringCapture": {
            "type": "boolean",
            "description": "true only when PoH observed this source first appear after capture began"
          },
          "presentAtExport": {
            "type": "boolean",
            "description": "Legacy v1 field retained for schema compatibility. Current readers withhold v1 source rows\nbecause older capture did not synchronize its final scan to export; request v2 for explicitly\nlast-observed semantics."
          },
          "classification": {
            "$ref": "#/components/schemas/SourceClassification"
          },
          "placements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourcePlacement"
            },
            "maxItems": 256,
            "description": "DAW placement observations. They describe arrangement/session placement, not causal or audible\ncontribution to the rendered master."
          }
        }
      },
      "SourceDetailLimitationV2": {
        "type": "string",
        "enum": [
          "daw_arrangement_not_final_audio_attribution",
          "tempo_automation_may_shift_seconds",
          "placement_identity_inferred_after_daw_object_replacement",
          "source_identity_restarted_after_daw_reconnect",
          "source_map_not_export_synchronized",
          "logic_visible_regions_only",
          "source_identity_unavailable",
          "source_position_unavailable",
          "source_map_truncated",
          "capture_event_gap",
          "legacy_capture_did_not_collect_source_detail"
        ],
        "description": "v2 adds one explicit limitation for conservatively inferred placement continuity."
      },
      "SourceDetailItemV2": {
        "type": "object",
        "required": [
          "sourceId",
          "observedDuringCapture",
          "presentAtLastObservation",
          "classification",
          "editSummary",
          "placements"
        ],
        "properties": {
          "sourceId": {
            "type": "string",
            "pattern": "^source-[1-9][0-9]{0,2}$",
            "description": "report-local opaque identifier; never a path, file name, track name, clip name, or hash"
          },
          "observedDuringCapture": {
            "type": "boolean"
          },
          "presentAtLastObservation": {
            "type": "boolean",
            "description": "whether the latest completed DAW source-map observation contained this source"
          },
          "firstObservedAtSessionSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "first time this source appeared after capture began, relative to session start"
          },
          "classification": {
            "$ref": "#/components/schemas/SourceClassification"
          },
          "editSummary": {
            "$ref": "#/components/schemas/SourceEditSummary"
          },
          "placements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourcePlacementV2"
            },
            "maxItems": 256
          }
        }
      },
      "EvidenceFactCode": {
        "type": "string",
        "enum": [
          "legacy_human_assessment",
          "audio_regions_appeared",
          "audio_import_observed",
          "imported_source_reused",
          "imported_asset_count",
          "imported_timeline_coverage",
          "dominant_audio_timeline",
          "audio_clip_editing_observed",
          "arrangement_change_observed",
          "recording_observed",
          "recording_not_observed",
          "midi_authorship_observed",
          "midi_authorship_not_observed",
          "render_observed",
          "source_identity_unverified",
          "final_output_coverage_unverified",
          "creator_external_material",
          "creator_imported_finished",
          "creator_contribution_under_twenty",
          "creator_no_manual_work",
          "creator_declared_no_ai_generated_material",
          "creator_reported_assessment_too_lenient",
          "creator_declared_from_scratch",
          "creator_declared_ai_material",
          "creator_declared_prior_project",
          "creator_declared_other_origin",
          "creator_declared_ai_share_small",
          "creator_declared_ai_share_about_half",
          "creator_declared_ai_share_most",
          "creator_declared_ai_share_almost_all",
          "creator_declared_manual_work",
          "creator_declared_contribution_partial",
          "creator_declared_contribution_majority",
          "creator_disputed_assessment",
          "session_summary_reconciled"
        ],
        "description": "Stable, localization-safe evidence facts. Values are optional and interpreted by `unit`."
      },
      "EvidenceBasis": {
        "type": "string",
        "enum": [
          "system_observation",
          "rule_inference",
          "creator_declaration",
          "unverifiable"
        ],
        "description": "Where one evidence fact came from. The report never silently merges these categories."
      },
      "EvidenceValueUnit": {
        "type": "string",
        "enum": [
          "count",
          "ratio",
          "seconds"
        ]
      },
      "EvidenceConflictCode": {
        "type": "string",
        "enum": [
          "legacy_human_score_vs_creator_declaration",
          "observed_source_vs_creator_declaration",
          "observed_import_vs_creator_origin_declaration"
        ],
        "description": "Stable conflict codes let clients localize the explanation without trusting generated prose."
      },
      "CreatorDeclarationSubject": {
        "type": "object",
        "required": [
          "proofId",
          "sessionId"
        ],
        "properties": {
          "proofId": {
            "type": "string",
            "minLength": 1
          },
          "sessionId": {
            "type": "string",
            "minLength": 1
          }
        },
        "description": "What the authenticated declaration is bound to."
      },
      "CreatorDeclarationDimension": {
        "type": "string",
        "enum": [
          "how_made",
          "ai_share",
          "ai_part",
          "manual_work",
          "contribution",
          "assessment"
        ],
        "description": "Which survey field one raw creator declaration came from."
      },
      "CreatorDeclarationOption": {
        "type": "string",
        "enum": [
          "from_scratch",
          "external_material",
          "ai_material",
          "imported_finished",
          "old_project",
          "other",
          "none",
          "small",
          "about_half",
          "most",
          "almost_all",
          "full_track",
          "backing",
          "vocals",
          "stems",
          "loops",
          "midi_ideas",
          "mastering",
          "rearranged",
          "recorded_audio",
          "wrote_midi",
          "heavy_editing",
          "mixing",
          "nothing",
          "lt20",
          "20_40",
          "40_60",
          "60_80",
          "gt80",
          "accurate",
          "too_strict",
          "too_lenient",
          "wrong"
        ],
        "description": "Raw, stable survey options. These values preserve the answer without converting it to prose."
      },
      "SessionEvidenceSummary": {
        "type": "object",
        "required": [
          "version",
          "source",
          "semanticsVersion",
          "traceSha256",
          "eventCount",
          "metrics",
          "clientSummaryMatched"
        ],
        "properties": {
          "version": {
            "type": "string",
            "enum": [
              "poh-session-evidence-1"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "verified_trace_replay"
            ]
          },
          "semanticsVersion": {
            "type": "string",
            "enum": [
              "poh-session-metrics-1"
            ]
          },
          "traceSha256": {
            "$ref": "#/components/schemas/Sha256"
          },
          "eventCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 1
          },
          "metrics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionMetric"
            },
            "minItems": 4,
            "maxItems": 4
          },
          "clientSummaryMatched": {
            "type": "boolean",
            "description": "False when at least one legacy client summary field differed from the replayed trace."
          }
        },
        "description": "Traceable, versioned activity summary signed inside the proof. Each verified trace row is counted\nonce by its authenticated sequence position; no client-provided counter is used as evidence."
      },
      "SourceClassification": {
        "type": "object",
        "required": [
          "origin",
          "materialType",
          "basis"
        ],
        "properties": {
          "origin": {
            "$ref": "#/components/schemas/SourceOrigin"
          },
          "materialType": {
            "$ref": "#/components/schemas/SourceMaterialType"
          },
          "basis": {
            "$ref": "#/components/schemas/SourceClassificationBasis"
          },
          "reviewSignals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceReviewSignal"
            },
            "maxItems": 4
          }
        }
      },
      "SourcePlacement": {
        "type": "object",
        "required": [
          "context",
          "precision"
        ],
        "properties": {
          "context": {
            "$ref": "#/components/schemas/SourcePlacementContext"
          },
          "precision": {
            "$ref": "#/components/schemas/SourcePlacementPrecision"
          },
          "startSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "estimated offset in the DAW arrangement, in seconds"
          },
          "durationSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "estimated placed duration, in seconds"
          },
          "startBar": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "one-indexed DAW bar position when seconds are unavailable"
          },
          "durationBars": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "placed duration measured in DAW bars"
          }
        }
      },
      "SourceEditSummary": {
        "type": "object",
        "required": [
          "timingChanges",
          "trimChanges",
          "loopChanges",
          "gainChanges",
          "pitchChanges",
          "warpChanges",
          "automationChanges",
          "muteChanges",
          "trackChanges"
        ],
        "properties": {
          "timingChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "trimChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "loopChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "gainChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "pitchChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "warpChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "automationChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "muteChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "trackChanges": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        },
        "description": "Bounded, source-linked edit dimensions. Counts are observations, not authorship weights."
      },
      "SourcePlacementV2": {
        "type": "object",
        "required": [
          "placementId",
          "context",
          "precision"
        ],
        "properties": {
          "placementId": {
            "type": "string",
            "pattern": "^placement-[1-9][0-9]{0,2}$"
          },
          "trackId": {
            "type": "string",
            "pattern": "^track-[1-9][0-9]{0,3}$"
          },
          "context": {
            "$ref": "#/components/schemas/SourcePlacementContext"
          },
          "precision": {
            "$ref": "#/components/schemas/SourcePlacementPrecisionV2"
          },
          "identityInferred": {
            "type": "boolean",
            "description": "True only when the DAW replaced its clip object and PoH conservatively carried placement\ncontinuity across scans using a unique local source/state match. This is never emitted for an\nambiguous match and does not strengthen the source classification."
          },
          "startSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "estimated offset in the DAW arrangement, in seconds"
          },
          "durationSeconds": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "estimated placed duration, in seconds"
          },
          "startBar": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "one-indexed DAW bar position when seconds are unavailable"
          },
          "durationBars": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "placed duration measured in DAW bars"
          },
          "startBeats": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "exact musical-time offset reported by the DAW"
          },
          "durationBeats": {
            "type": "number",
            "format": "double",
            "minimum": 0,
            "description": "exact placed length in DAW beats"
          },
          "clipMuted": {
            "type": "boolean"
          },
          "trackMuted": {
            "type": "boolean"
          },
          "looped": {
            "type": "boolean"
          },
          "warped": {
            "type": "boolean"
          },
          "gainAdjusted": {
            "type": "boolean"
          },
          "transposed": {
            "type": "boolean"
          },
          "hasAutomation": {
            "type": "boolean"
          },
          "editSummary": {
            "allOf": [
              {
                "$ref": "#/components/schemas/SourceEditSummary"
              }
            ],
            "description": "source-linked edits observed for this placement while it remained identifiable"
          }
        },
        "description": "A content-free Ableton placement for the v2 private report. IDs are report-local and cannot be\nresolved to a DAW name, path, or another proof. Optional state flags are emitted only when the\nDAW exposed that property; absence means unknown, never false."
      },
      "SessionMetric": {
        "type": "object",
        "required": [
          "name",
          "status",
          "coverage"
        ],
        "properties": {
          "name": {
            "$ref": "#/components/schemas/SessionMetricName"
          },
          "status": {
            "$ref": "#/components/schemas/SessionMetricStatus"
          },
          "coverage": {
            "$ref": "#/components/schemas/SessionMetricCoverage"
          },
          "value": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "description": "Present only when the adapter supports this surface. Zero means supported and not observed."
          }
        },
        "description": "One server-replayed metric from the verified, sequence-numbered capture trace."
      },
      "SourceOrigin": {
        "type": "string",
        "enum": [
          "human",
          "ai",
          "mixed",
          "unknown"
        ],
        "description": "The observed origin of one imported source. `ai` is used only when machine-readable provenance\nor the creator's explicit declaration supports it. A heuristic signal never changes this field\nfrom `unknown`."
      },
      "SourceMaterialType": {
        "type": "string",
        "enum": [
          "recording",
          "sample",
          "generated_audio",
          "stem",
          "finished_track",
          "unknown"
        ],
        "description": "How an imported source was used, kept separate from origin so an AI-generated sample is valid."
      },
      "SourceClassificationBasis": {
        "type": "string",
        "enum": [
          "device_observed_content_credential",
          "creator_declaration",
          "heuristic_review_signal",
          "unverified"
        ],
        "description": "The strongest basis supporting the source classification."
      },
      "SourceReviewSignal": {
        "type": "string",
        "enum": [
          "container_pattern",
          "spectral_pattern"
        ],
        "description": "Private review signals are evidence to inspect, never an AI verdict."
      },
      "SourcePlacementContext": {
        "type": "string",
        "enum": [
          "arrangement",
          "session_clip",
          "visible_region"
        ],
        "description": "Where the DAW exposed a source placement."
      },
      "SourcePlacementPrecision": {
        "type": "string",
        "enum": [
          "tempo_snapshot_estimate",
          "daw_bars",
          "position_unavailable"
        ],
        "description": "How to interpret a reported position. Ableton's musical timeline is converted with the tempo\nobserved alongside the periodic source map, so its seconds are an estimate when tempo automation\nexists and are not an export-time claim. Logic exposes\nvisible bar spans rather than absolute seconds. A session clip has duration but no arrangement\nstart."
      },
      "SourcePlacementPrecisionV2": {
        "type": "string",
        "enum": [
          "tempo_snapshot_estimate",
          "daw_beats_with_tempo_snapshot_estimate",
          "daw_bars",
          "position_unavailable"
        ]
      },
      "SessionMetricName": {
        "type": "string",
        "enum": [
          "notes",
          "edits",
          "commands",
          "saves"
        ],
        "description": "Stable metric names; clients localize these values instead of rendering backend prose."
      },
      "SessionMetricStatus": {
        "type": "string",
        "enum": [
          "observed",
          "not_observed",
          "unsupported",
          "unknown"
        ],
        "description": "Whether one content-free activity metric was seen, absent, unsupported, or could not be classified."
      },
      "SessionMetricCoverage": {
        "type": "string",
        "enum": [
          "complete",
          "partial",
          "unsupported",
          "unknown"
        ],
        "description": "How completely the active DAW adapter can observe one activity surface."
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    }
  },
  "servers": [
    {
      "url": "https://api.proofofhuman.fm/v1",
      "description": "Production",
      "variables": {}
    }
  ],
  "x-poh-auth-surfaces": {
    "partner": "x-api-key on the production partner API",
    "app": "ECDSA-P256 enrolled-device signature in the x-poh-* request headers on the App API",
    "public": "No credential for health, download, and content-free telemetry",
    "proofIdReads": "Capability-addressed but still gateway-authenticated in v1; never anonymous"
  },
  "x-poh-contract": "partner-api"
}
