{
  "openapi": "3.1.0",
  "info": {
    "title": "Noise or Voice file verification API",
    "version": "1.0.0-pilot",
    "description": "Implemented complete-recording POST route. Decision and confidence scores are uncalibrated. No streaming, speaker identity, availability, or signing guarantee. See https://noiseorvoice.com/privacy/ before uploading audio."
  },
  "servers": [
    {
      "url": "https://noiseorvoice.com"
    }
  ],
  "paths": {
    "/api/v1/verify": {
      "post": {
        "operationId": "verifyAudioFile",
        "summary": "Analyze a complete audio recording",
        "description": "Optional operator-issued bearer key; anonymous calls have a lower rate limit. The handler processes audio in memory and writes result metadata and an audio SHA-256 digest to D1. No raw audio is written to the audit table. Supported RIFF/WAVE inputs use PCM 8/16/24-bit or IEEE float32, 1\u20138 channels, and integer sample rates from 8,000 to 192,000 Hz; extensible WAV is limited to 16-bit PCM with its explicit PCM subtype. Chunk lengths, padding, frame alignment and declared byte rate must be consistent. Nonfinite float samples and unsupported encodings are rejected rather than reinterpreted. Headerless PCM16 must contain complete two-byte samples. Maximum input audio is 25 MiB and maximum recording duration is 30 seconds. Duration is checked before allocating decoded samples; longer recordings return HTTP 413.",
        "security": [
          {},
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "X-Sensitivity",
            "in": "header",
            "schema": {
              "type": "number",
              "minimum": 0.01,
              "maximum": 0.99,
              "default": 0.5,
              "description": "The handler clamps supplied values to 0.01-0.99; an invalid value falls back to 0.5."
            }
          },
          {
            "name": "X-Extract-Telemetry",
            "in": "header",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "requestBody": {
          "description": "Complete-recording verification. At most 25 MiB of decoded audio; JSON/form encoding has a larger transport cap. WAV supports PCM 8/16/24-bit and IEEE float32; raw PCM16 must explicitly use an audio/pcm, audio/l16, or audio/raw Content-Type. Compressed formats are not decoded.",
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "audio": {
                    "description": "WAV file, at most 25 MiB. Use the file part rather than a text field.",
                    "contentMediaType": "audio/wav"
                  },
                  "file": {
                    "description": "Alternative file part name.",
                    "contentMediaType": "audio/wav"
                  },
                  "sensitivity": {
                    "type": "number",
                    "minimum": 0.01,
                    "maximum": 0.99,
                    "default": 0.5,
                    "description": "The handler clamps supplied values to 0.01-0.99; an invalid value falls back to 0.5."
                  },
                  "extract_telemetry": {
                    "type": "boolean",
                    "default": true
                  }
                },
                "anyOf": [
                  {
                    "required": [
                      "audio"
                    ]
                  },
                  {
                    "required": [
                      "file"
                    ]
                  }
                ]
              },
              "encoding": {
                "audio": {
                  "contentType": "audio/wav"
                },
                "file": {
                  "contentType": "audio/wav"
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "audio": {
                    "type": "string",
                    "contentEncoding": "base64",
                    "description": "Base64 WAV audio, optionally data-URL prefixed."
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "HTTPS URL on an operator-configured exact host allowlist. Redirects are revalidated; unset allowlist denies URL fetches."
                  },
                  "sensitivity": {
                    "type": "number",
                    "minimum": 0.01,
                    "maximum": 0.99,
                    "default": 0.5,
                    "description": "The handler clamps supplied values to 0.01-0.99; an invalid value falls back to 0.5."
                  },
                  "extract_telemetry": {
                    "type": "boolean",
                    "default": true
                  }
                },
                "anyOf": [
                  {
                    "required": [
                      "audio"
                    ]
                  },
                  {
                    "required": [
                      "url"
                    ]
                  }
                ]
              }
            },
            "audio/wav": {},
            "application/octet-stream": {
              "description": "WAV bytes only; raw PCM16 needs an explicit PCM Content-Type."
            },
            "audio/pcm": {
              "description": "Headerless mono PCM16 sampled at 16 kHz."
            },
            "audio/l16": {
              "description": "Headerless mono PCM16 sampled at 16 kHz."
            },
            "audio/raw": {
              "description": "Headerless mono PCM16 sampled at 16 kHz."
            }
          }
        },
        "responses": {
          "200": {
            "description": "Analysis completed; an inconclusive verdict is still HTTP 200.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid payload or unsupported WAV layout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "A supplied API key is invalid or not enrolled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Remote audio URL host is not allowlisted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Audio exceeds the 25 MiB byte limit or 30-second recording limit, or the request exceeds its size limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "Recognized compressed codec is unsupported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; Retry-After header and retry_after_seconds identify the delay.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "D1 rate-limit storage is unavailable; request fails closed.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "504": {
            "description": "Remote audio fetch timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Optional operator-issued pilot key. Omit for lower-limit anonymous access."
      }
    },
    "schemas": {
      "VerificationResult": {
        "type": "object",
        "required": [
          "status",
          "verdict",
          "confidence_score",
          "decision_score",
          "score_semantics",
          "score_calibrated",
          "confidence_calibrated",
          "scoring_engine",
          "threshold_evaluated",
          "duration_seconds",
          "is_synthetic",
          "is_authentic",
          "is_conclusive",
          "flags",
          "attestation",
          "signing_status"
        ],
        "properties": {
          "status": {
            "const": "success"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "AUTHENTIC_HUMAN",
              "SYNTHETIC_DETECTED",
              "INCONCLUSIVE_SILENCE",
              "INCONCLUSIVE_NON_VOCAL"
            ]
          },
          "confidence_score": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Uncalibrated display transform, not correctness probability."
          },
          "decision_score": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Uncalibrated decision score, not a probability."
          },
          "score_semantics": {
            "const": "uncalibrated_detection_score"
          },
          "score_calibrated": {
            "const": false
          },
          "confidence_calibrated": {
            "const": false
          },
          "scoring_engine": {
            "type": "string"
          },
          "threshold_evaluated": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 0.99
          },
          "duration_seconds": {
            "type": "number",
            "minimum": 0
          },
          "is_synthetic": {
            "type": "boolean"
          },
          "is_authentic": {
            "type": "boolean"
          },
          "is_conclusive": {
            "type": "boolean"
          },
          "telemetry": {
            "type": "object",
            "description": "Present by default; omitted when extract_telemetry=false.",
            "properties": {
              "vocoder_phase_incoherence": {
                "type": "number"
              },
              "glottal_skewness": {
                "type": "number"
              },
              "glottal_jitter_variance": {
                "type": "number"
              },
              "high_frequency_floor_db": {
                "type": "number"
              },
              "phoneme_continuity_score": {
                "type": "number"
              },
              "comb_notch_depth": {
                "type": "number"
              },
              "rolloff_95_hz": {
                "type": "number"
              },
              "spectral_flatness": {
                "type": "number"
              },
              "qpc_bicoherence": {
                "type": "number"
              }
            },
            "additionalProperties": false
          },
          "flags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "attestation": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Attestation"
              }
            ],
            "description": "Null when server signing is not configured. A signature authenticates a claim against an independently trusted public key; it does not prove detector accuracy."
          },
          "signing_status": {
            "type": "string",
            "enum": [
              "signed",
              "unavailable"
            ]
          }
        }
      },
      "Attestation": {
        "type": "object",
        "required": [
          "version",
          "audio_sha256",
          "timestamp_utc",
          "verdict",
          "confidence",
          "decision_score",
          "sensitivity_threshold",
          "physical_metrics",
          "latency",
          "public_key_hex",
          "algorithm",
          "signature_hex",
          "canonical_json"
        ],
        "properties": {
          "version": {
            "const": "2.4-SPECTRA"
          },
          "audio_sha256": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "timestamp_utc": {
            "type": "string",
            "format": "date-time"
          },
          "verdict": {
            "type": "string"
          },
          "confidence": {
            "type": "number"
          },
          "decision_score": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Uncalibrated decision score, not a probability."
          },
          "sensitivity_threshold": {
            "type": "number"
          },
          "physical_metrics": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            }
          },
          "latency": {
            "type": "null"
          },
          "public_key_hex": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "algorithm": {
            "const": "Ed25519"
          },
          "signature_hex": {
            "type": "string",
            "pattern": "^[a-f0-9]{128}$"
          },
          "canonical_json": {
            "type": "string"
          }
        }
      },
      "ApiError": {
        "type": "object",
        "required": [
          "status",
          "error"
        ],
        "properties": {
          "status": {
            "const": "error"
          },
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "retry_after_seconds": {
            "type": "integer",
            "minimum": 1
          }
        }
      }
    }
  }
}
