{"openapi":"3.1.0","info":{"title":"DetectifAI Developer API","summary":"Detect AI-generated speech and verify speakers by voice.","description":"The DetectifAI developer API detects synthetic (AI-generated) speech and verifies speakers by voice.\n\n**Authentication.** Send your API key in the `Authorization` header: `Authorization: Bearer dtf_live_...`.\nKeys are created in the dashboard and shown once. Never put keys in URLs.\n\n**Credits.** Detection, enrollment and verification use credits from your account balance; your balance is\nshown in the dashboard and at `GET /v1/credits`. Only completed checks use credits: a rejected file, a busy\nservice or a failed check uses none. A verification with `detect_deepfake=true` counts as two checks.\n\n**Uploads.** Send audio as `multipart/form-data` (field `file`), up to 100 MB. The whole upload must arrive\nwithin 120 s (at no less than 64 KB/s); larger or slower uploads are rejected (`413`, `408`). When too many\nlarge uploads are in progress the API answers `503 server_busy` with `Retry-After`. Durations are checked\nafter decoding: enrollment 15-60 s with at least 10 s of speech, verification 3-60 s with at least 2 s of\nspeech, deepfake detection 0.5-120 s.\n\n**Retries.** Send an `Idempotency-Key` header (for example a new UUID) with every detection, enrollment and\nverification request, and send the same key again if you retry it. The retry returns the stored response\n(`idempotent_replay: true`, header `Idempotent-Replayed: true`) without running the check again or using\ncredits again. Keys are remembered for 24 h; results stay available for 30 days at\n`GET /v1/operations/{operation_id}`.\n\n**Errors.** Every non-2xx response uses the same envelope:\n`{\"error\": {\"type\", \"code\", \"message\", \"param\"}, \"request_id\"}`. Every response carries `X-Request-Id`.\n\n**Reading results.** `score` (0 to 1) says how likely a recording is AI-generated and `similarity` (-1 to 1)\nhow alike two voices are. Each result carries the `threshold` used for its decision. Results are strong\nsignals, not proof: try them on your own recordings before relying on them.","contact":{"name":"DetectifAI developer support","url":"https://platform.detectif.ai/docs"},"version":"1.0.0"},"servers":[{"url":"https://platform.detectif.ai","description":"Production"}],"paths":{"/v1/deepfake/detect":{"post":{"tags":["Deepfake detection"],"summary":"Detect AI-generated speech","description":"Checks whether a recording contains AI-generated speech. Send one audio file longer than 4 seconds and at most 120 seconds. Use the result's `verdict`: `real`, `fake`, or `not_sure` when the recording cannot be judged reliably (try a longer or cleaner recording). `score` (0 to 1, higher means more likely AI-generated) is kept for older clients together with `label` and `is_synthetic`. A `not_sure` verdict uses credits like any result, except when the check could not run completely: then `credits.charged` is 0. Main failures: the file is not audio or is damaged (415/422), 4 seconds or shorter or longer than 120 seconds (422), not enough credits (402), the service is busy (503, retry later). Requires scope `deepfake:detect`.","operationId":"detectDeepfake","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again.","examples":["9b1f6c1e-2c1a-4d6e-9a43-2f4f5b6f7a10"],"title":"Idempotency-Key"},"description":"Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again."}],"responses":{"200":{"description":"The check completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepfakeResponse"},"examples":{"real":{"summary":"Real","value":{"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","object":"deepfake.detection","model":{"name":"aletheia","version":"3f9c2a71b0d4"},"latency_ms":58.3,"idempotent_replay":false,"result":{"threshold":0.62,"score_semantics":"Higher means more likely AI-generated. Decide with the verdict, not the score alone.","verdict":"real","label":"genuine","is_synthetic":false,"score":0.0731,"duration_seconds":6.4,"segments":[{"start":0.0,"end":4.0,"score":0.061},{"start":2.0,"end":6.4,"score":0.085}]},"credits":{"charged":50,"balance":4950}}},"fake":{"summary":"AI-generated","value":{"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","object":"deepfake.detection","model":{"name":"aletheia","version":"3f9c2a71b0d4"},"latency_ms":58.3,"idempotent_replay":false,"result":{"threshold":0.62,"score_semantics":"Higher means more likely AI-generated. Decide with the verdict, not the score alone.","verdict":"fake","label":"synthetic","is_synthetic":true,"score":0.9127,"duration_seconds":9.1,"segments":[{"start":0.0,"end":4.0,"score":0.89},{"start":2.0,"end":6.0,"score":0.93},{"start":4.0,"end":8.0,"score":0.91},{"start":6.0,"end":9.1,"score":0.92}]},"credits":{"charged":50,"balance":4900}}},"not_sure":{"summary":"Not sure (try a longer or cleaner recording)","value":{"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","object":"deepfake.detection","model":{"name":"aletheia","version":"3f9c2a71b0d4"},"latency_ms":58.3,"idempotent_replay":false,"result":{"threshold":0.62,"score_semantics":"Higher means more likely AI-generated. Decide with the verdict, not the score alone.","verdict":"not_sure","label":"uncertain","is_synthetic":false,"score":0.7012,"duration_seconds":5.2,"segments":[{"start":0.0,"end":4.0,"score":0.69},{"start":1.2,"end":5.2,"score":0.71}]},"credits":{"charged":50,"balance":4850}}}}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Not enough credits are available for this operation.","content":{"application/json":{"example":{"error":{"type":"insufficient_credits","code":"insufficient_credits","message":"Not enough credits are available for this operation."},"request_id":"req_8f14e45fceea167a5a36dedd","credits":{"available":20,"required":50}},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"The upload did not arrive in time (the whole file within 120 seconds, at least 64 KB per second).","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"upload_timeout","message":"The upload did not arrive in time: the whole request must be received within 120 s and at no less than 64 KB/s. Retry on a faster connection.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict, for example a request with the same Idempotency-Key is still running, or the speaker already has the maximum number of samples.","content":{"application/json":{"example":{"error":{"type":"conflict","code":"operation_in_progress","message":"A request with this Idempotency-Key is still being processed; retry later or poll the operation."},"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9"},"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The upload is larger than 100 MB.","content":{"application/json":{"example":{"error":{"type":"payload_too_large","code":"file_too_large","message":"The upload exceeds the 100 MB limit.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Not a supported audio format, or the request is not multipart/form-data.","content":{"application/json":{"example":{"error":{"type":"unsupported_media","code":"unsupported_format","message":"Unsupported file format. Upload WAV, MP3, FLAC, OGG/Opus, WebM, M4A/AAC or AIFF audio.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The audio cannot be used (damaged, too short, too long, silent or too little speech; the message says what is needed), or the Idempotency-Key was already used for a different request.","content":{"application/json":{"example":{"error":{"type":"unprocessable_audio","code":"audio_too_short","message":"Audio must be longer than 4 seconds","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The check failed on our side. No credits were used; retry later.","content":{"application/json":{"example":{"error":{"type":"internal","code":"inference_failed","message":"The check failed; no credits were used. Retry later."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The service is busy, for example with many large uploads. Retry after the Retry-After seconds.","content":{"application/json":{"example":{"error":{"type":"overloaded","code":"server_busy","message":"Too many large uploads are in progress; retry shortly."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The check took too long. No credits were used; retry later.","content":{"application/json":{"example":{"error":{"type":"internal","code":"inference_timeout","message":"The check took too long; no credits were used. Retry later."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"description":"multipart/form-data with the audio in the `file` field.","content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","description":"The audio file: WAV, MP3, FLAC, OGG/Opus, WebM, M4A/AAC or AIFF, at most 100 MB."}}},"encoding":{"file":{"contentType":"audio/*, application/octet-stream"}},"example":{"file":"call-2026-10-13.wav"}}}}}},"/v1/speakers/enroll":{"post":{"tags":["Speakers"],"summary":"Enroll a voice sample","description":"Saves a voice sample for a speaker so that later recordings can be verified against it. The speaker is created on first use. Send a recording of 15-60 seconds with at least 10 seconds of clear speech from that one person. Up to 5 samples per speaker; 2-3 samples from different sessions make verification more reliable. Main failures: too short, too long or too little speech (422, the message says what is needed), the speaker already has 5 samples (409), not enough credits (402). Requires scope `speakers:enroll`.","operationId":"enrollSpeaker","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again.","examples":["9b1f6c1e-2c1a-4d6e-9a43-2f4f5b6f7a10"],"title":"Idempotency-Key"},"description":"Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again."}],"responses":{"200":{"description":"The sample was saved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollResponse"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","object":"speaker.enrollment","speaker":{"speaker_id":"customer-4711","display_name":"Ada Lovelace","samples":1,"created_at":"2026-10-13T09:30:00Z","updated_at":"2026-10-13T09:30:00Z"},"quality":{"speech_seconds":17.9,"duration_seconds":19.2},"model":{"name":"eidos","version":"8e1b6c0a92f7"},"credits":{"charged":50,"balance":4900},"latency_ms":388.1,"idempotent_replay":false}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Not enough credits are available for this operation.","content":{"application/json":{"example":{"error":{"type":"insufficient_credits","code":"insufficient_credits","message":"Not enough credits are available for this operation."},"request_id":"req_8f14e45fceea167a5a36dedd","credits":{"available":20,"required":50}},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"The upload did not arrive in time (the whole file within 120 seconds, at least 64 KB per second).","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"upload_timeout","message":"The upload did not arrive in time: the whole request must be received within 120 s and at no less than 64 KB/s. Retry on a faster connection.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict, for example a request with the same Idempotency-Key is still running, or the speaker already has the maximum number of samples.","content":{"application/json":{"example":{"error":{"type":"conflict","code":"too_many_samples","message":"This speaker already has the maximum of 5 samples.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The upload is larger than 100 MB.","content":{"application/json":{"example":{"error":{"type":"payload_too_large","code":"file_too_large","message":"The upload exceeds the 100 MB limit.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Not a supported audio format, or the request is not multipart/form-data.","content":{"application/json":{"example":{"error":{"type":"unsupported_media","code":"unsupported_format","message":"Unsupported file format. Upload WAV, MP3, FLAC, OGG/Opus, WebM, M4A/AAC or AIFF audio.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The audio cannot be used (damaged, too short, too long, silent or too little speech; the message says what is needed), or the Idempotency-Key was already used for a different request.","content":{"application/json":{"example":{"error":{"type":"unprocessable_audio","code":"audio_too_short","message":"Audio must be longer than 4 seconds","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The check failed on our side. No credits were used; retry later.","content":{"application/json":{"example":{"error":{"type":"internal","code":"inference_failed","message":"The check failed; no credits were used. Retry later."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The service is busy, for example with many large uploads. Retry after the Retry-After seconds.","content":{"application/json":{"example":{"error":{"type":"overloaded","code":"server_busy","message":"Too many large uploads are in progress; retry shortly."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The check took too long. No credits were used; retry later.","content":{"application/json":{"example":{"error":{"type":"internal","code":"inference_timeout","message":"The check took too long; no credits were used. Retry later."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"description":"multipart/form-data with the audio in the `file` field.","content":{"multipart/form-data":{"schema":{"type":"object","required":["file","speaker_id"],"properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","description":"The audio file: WAV, MP3, FLAC, OGG/Opus, WebM, M4A/AAC or AIFF, at most 100 MB."},"speaker_id":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,64}$","minLength":1,"maxLength":64,"description":"Your identifier for the speaker (1-64 characters: letters, digits, _ . : -).","examples":["customer-4711"]},"display_name":{"type":"string","maxLength":128,"description":"Optional label for the speaker, shown in the dashboard.","examples":["Ada Lovelace"]}}},"encoding":{"file":{"contentType":"audio/*, application/octet-stream"}},"example":{"file":"ada-enrollment-1.wav","speaker_id":"customer-4711","display_name":"Ada Lovelace"}}}}}},"/v1/speakers/verify":{"post":{"tags":["Speakers"],"summary":"Verify a speaker","description":"Checks whether a recording is the voice of an enrolled speaker. Send a recording of 3-60 seconds with at least 2 seconds of speech. The result has a `decision` (`match` or `no_match`), a `similarity` from -1 to 1 (higher means more alike) and the `threshold` used for the decision. Main failures: unknown speaker (404), too short or too little speech (422), not enough credits (402). Requires scope `speakers:verify`.\n\nWith `detect_deepfake=true` the same recording is also checked for AI-generated speech (needs scope `deepfake:detect`; that check needs a recording longer than 4 seconds, otherwise only it fails). The two checks are counted separately, and only completed checks use credits:\n* if the synthetic-speech check fails, you still get the verification, with `deepfake.error`;\n* if the verification fails but the synthetic-speech check completed, you get the verification's error together with `partial` (the synthetic-speech result);\n* if both fail, you get the error and no credits are used.\n\nA retry with the same `Idempotency-Key` returns the same outcome again without running or counting the checks twice.","operationId":"verifySpeaker","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again.","examples":["9b1f6c1e-2c1a-4d6e-9a43-2f4f5b6f7a10"],"title":"Idempotency-Key"},"description":"Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again."}],"responses":{"200":{"description":"The check completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResponse"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","object":"speaker.verification","speaker_id":"customer-4711","result":{"decision":"match","similarity":0.7412,"threshold":0.53,"similarity_semantics":"Higher means the two voices are more alike. Not a percentage.","duration_seconds":4.1},"model":{"name":"eidos","version":"8e1b6c0a92f7"},"credits":{"charged":50,"balance":4850},"latency_ms":301.5,"idempotent_replay":false}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Not enough credits are available for this operation.","content":{"application/json":{"example":{"error":{"type":"insufficient_credits","code":"insufficient_credits","message":"Not enough credits are available for this operation."},"request_id":"req_8f14e45fceea167a5a36dedd","credits":{"available":20,"required":50}},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"408":{"description":"The upload did not arrive in time (the whole file within 120 seconds, at least 64 KB per second).","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"upload_timeout","message":"The upload did not arrive in time: the whole request must be received within 120 s and at no less than 64 KB/s. Retry on a faster connection.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict, for example a request with the same Idempotency-Key is still running, or the speaker already has the maximum number of samples.","content":{"application/json":{"example":{"error":{"type":"conflict","code":"operation_in_progress","message":"A request with this Idempotency-Key is still being processed; retry later or poll the operation."},"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9"},"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The upload is larger than 100 MB.","content":{"application/json":{"example":{"error":{"type":"payload_too_large","code":"file_too_large","message":"The upload exceeds the 100 MB limit.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Not a supported audio format, or the request is not multipart/form-data.","content":{"application/json":{"example":{"error":{"type":"unsupported_media","code":"unsupported_format","message":"Unsupported file format. Upload WAV, MP3, FLAC, OGG/Opus, WebM, M4A/AAC or AIFF audio.","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The audio cannot be used (damaged, too short, too long, silent or too little speech; the message says what is needed), or the Idempotency-Key was already used for a different request.","content":{"application/json":{"example":{"error":{"type":"unprocessable_audio","code":"audio_too_short","message":"Audio must be longer than 4 seconds","param":"file"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The check failed on our side. No credits were used; retry later.","content":{"application/json":{"example":{"error":{"type":"internal","code":"inference_failed","message":"The check failed; no credits were used. Retry later."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The service is busy, for example with many large uploads. Retry after the Retry-After seconds.","content":{"application/json":{"example":{"error":{"type":"overloaded","code":"inference_overloaded","message":"The service is at capacity; retry shortly."},"request_id":"req_8f14e45fceea167a5a36dedd","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","partial":{"deepfake":{"verdict":"real","label":"genuine","is_synthetic":false,"score":0.08,"threshold":0.62,"score_semantics":"Higher means more likely AI-generated. Decide with the verdict, not the score alone.","duration_seconds":6.1,"segments":[{"start":0.0,"end":4.0,"score":0.08},{"start":2.0,"end":6.1,"score":0.07}],"operation_id":"op_0b9d2f4c1e7a4b6c8d0e1f2a3b4c5d6e","credits_charged":50,"model":{"name":"aletheia","version":"3f9c2a71b0d4"}},"credits":{"charged":50,"balance":4850}}},"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The check took too long. No credits were used; retry later.","content":{"application/json":{"example":{"error":{"type":"internal","code":"inference_timeout","message":"The check took too long; no credits were used. Retry later."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found. Also returned for resources that belong to another account.","content":{"application/json":{"example":{"error":{"type":"not_found","code":"speaker_not_found","message":"No speaker with this speaker_id exists in your account.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"description":"multipart/form-data with the audio in the `file` field.","content":{"multipart/form-data":{"schema":{"type":"object","required":["file","speaker_id"],"properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","description":"The audio file: WAV, MP3, FLAC, OGG/Opus, WebM, M4A/AAC or AIFF, at most 100 MB."},"speaker_id":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,64}$","minLength":1,"maxLength":64,"description":"Your identifier for the speaker (1-64 characters: letters, digits, _ . : -).","examples":["customer-4711"]},"detect_deepfake":{"type":"boolean","default":false,"description":"Also check the same recording for AI-generated speech (needs scope deepfake:detect).","examples":[true]}}},"encoding":{"file":{"contentType":"audio/*, application/octet-stream"}},"example":{"file":"incoming-call.wav","speaker_id":"customer-4711","detect_deepfake":true}}}}}},"/v1/speakers":{"get":{"tags":["Speakers"],"summary":"List speakers","description":"Lists the speakers of your account, newest first, with how many voice samples each has. Use `limit` and `cursor` to page through long lists. Requires scope `speakers:read`.","operationId":"listSpeakers","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"How many speakers to return (1-100).","examples":[20],"default":20,"title":"Limit"},"description":"How many speakers to return (1-100)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"description":"`next_cursor` from the previous page.","examples":["eyJ0IjoiMjAyNi0xMC0xMyJ9"],"title":"Cursor"},"description":"`next_cursor` from the previous page."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerList"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"list","data":[{"speaker_id":"customer-4711","display_name":"Ada Lovelace","samples":2,"created_at":"2026-10-13T09:30:00Z","updated_at":"2026-10-13T09:41:12Z"}],"has_more":false}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/speakers/{speaker_id}":{"get":{"tags":["Speakers"],"summary":"Get a speaker","description":"Returns one speaker of your account and how many voice samples it has. An unknown `speaker_id` returns 404. Requires scope `speakers:read`.","operationId":"getSpeaker","security":[{"bearerAuth":[]}],"parameters":[{"name":"speaker_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,64}$","description":"Your identifier for the speaker.","examples":["customer-4711"],"title":"Speaker Id"},"description":"Your identifier for the speaker."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerObject"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"speaker","speaker_id":"customer-4711","display_name":"Ada Lovelace","samples":2,"created_at":"2026-10-13T09:30:00Z","updated_at":"2026-10-13T09:41:12Z"}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found. Also returned for resources that belong to another account.","content":{"application/json":{"example":{"error":{"type":"not_found","code":"speaker_not_found","message":"No speaker with this speaker_id exists in your account.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Speakers"],"summary":"Delete a speaker","description":"Deletes the speaker and all of its voice samples permanently. Later verifications for this `speaker_id` return 404. Requires scope `speakers:delete`.","operationId":"deleteSpeaker","security":[{"bearerAuth":[]}],"parameters":[{"name":"speaker_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,64}$","description":"Your identifier for the speaker.","examples":["customer-4711"],"title":"Speaker Id"},"description":"Your identifier for the speaker."}],"responses":{"200":{"description":"The speaker and its voice samples were deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerDeleted"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"speaker.deleted","speaker_id":"customer-4711","deleted":true}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found. Also returned for resources that belong to another account.","content":{"application/json":{"example":{"error":{"type":"not_found","code":"speaker_not_found","message":"No speaker with this speaker_id exists in your account.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/operations/{operation_id}":{"get":{"tags":["Results"],"summary":"Get a result","description":"Returns the stored outcome of a detection, enrollment or verification by its `operation_id` (kept for 30 days), for example after your connection dropped before the response arrived. Requires the scope of the operation's type.","operationId":"getOperation","security":[{"bearerAuth":[]}],"parameters":[{"name":"operation_id","in":"path","required":true,"schema":{"type":"string","description":"The `operation_id` from a response (`op_...`).","examples":["op_6f1ed002ab5595859014ebf0951522d9"],"title":"Operation Id"},"description":"The `operation_id` from a response (`op_...`)."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationObject"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"operation","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","type":"deepfake.detect","status":"succeeded","source":"api","credits_charged":50,"created_at":"2026-10-13T09:30:00Z","completed_at":"2026-10-13T09:30:01Z","result":{"operation_id":"op_6f1ed002ab5595859014ebf0951522d9","object":"deepfake.detection","result":{"label":"genuine","score":0.0731}}}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found. Also returned for resources that belong to another account.","content":{"application/json":{"example":{"error":{"type":"not_found","code":"operation_not_found","message":"No operation with this id exists in your account.","param":"operation_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/operations/{operation_id}/feedback":{"post":{"tags":["Results"],"summary":"Say whether a result was right","description":"Tells us whether an AI-speech check (`deepfake.detect`) got it right. Send `correct`, and optionally what the recording really is (`label`: `real` or `fake`) and a short note. Only for checks of your own account; sending again replaces your earlier answer. No credits are used. We store your answer with the result, not the audio: keeping recordings for review would need your explicit consent and is not offered yet. Requires the scope of the check (`deepfake:detect`).","operationId":"sendFeedback","security":[{"bearerAuth":[]}],"parameters":[{"name":"operation_id","in":"path","required":true,"schema":{"type":"string","description":"The `operation_id` of the check (`op_...`).","examples":["op_6f1ed002ab5595859014ebf0951522d9"],"title":"Operation Id"},"description":"The `operation_id` of the check (`op_...`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"},"examples":{"wrong":{"summary":"The result was wrong","value":{"correct":false,"label":"real","note":"My own voice, recorded on a phone."}}}}}},"responses":{"200":{"description":"Your answer was saved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackObject"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"operation.feedback","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","correct":false,"label":"real","note":"My own voice, recorded on a phone.","created_at":"2026-10-13T09:30:00Z","updated_at":"2026-10-13T09:30:00Z"}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found. Also returned for resources that belong to another account.","content":{"application/json":{"example":{"error":{"type":"not_found","code":"operation_not_found","message":"No operation with this id exists in your account.","param":"operation_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict, for example a request with the same Idempotency-Key is still running, or the speaker already has the maximum number of samples.","content":{"application/json":{"example":{"error":{"type":"conflict","code":"feedback_not_applicable","message":"Feedback can only be given on a completed AI-speech check (deepfake.detect operation).","param":"operation_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/credits":{"get":{"tags":["Account"],"summary":"Get your balance","description":"Returns your plan, your available credits and the credits held by checks that are still running. On the unlimited plan `unlimited` is true and `available` is null. Requires scope `credits:read`.","operationId":"getBalance","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsObject"},"examples":{"free":{"summary":"Free plan","value":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"credits","plan":"free","unlimited":false,"available":4950,"reserved":50,"price_per_operation":50}},"unlimited":{"summary":"Unlimited plan","value":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"credits","plan":"unlimited","unlimited":true,"reserved":0,"price_per_operation":0}}}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/usage":{"get":{"tags":["Account"],"summary":"List your usage","description":"Lists your detection, enrollment and verification requests with their outcome and the credits they used, newest first. Filter by `operation` or `status`; page with `limit` and `cursor`. Requires scope `usage:read`.","operationId":"getUsage","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"How many entries to return (1-100).","examples":[20],"default":20,"title":"Limit"},"description":"How many entries to return (1-100)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"description":"`next_cursor` from the previous page.","examples":["eyJ0IjoiMjAyNi0xMC0xMyJ9"],"title":"Cursor"},"description":"`next_cursor` from the previous page."},{"name":"operation","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Only this kind of request.","examples":["deepfake.detect"],"enum":["deepfake.detect","speaker.enroll","speaker.verify"],"title":"Operation"},"description":"Only this kind of request."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Only requests with this outcome.","examples":["succeeded"],"enum":["succeeded","rejected","failed","replayed"],"title":"Status"},"description":"Only requests with this outcome."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageList"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","object":"list","data":[{"id":"use_812","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","type":"deepfake.detect","source":"api","status":"succeeded","http_status":200,"credits_charged":50,"duration_seconds":6.4,"latency_ms":412.7,"request_id":"req_8f14e45fceea167a5a36dedd","created_at":"2026-10-13T09:30:00Z"}],"has_more":true,"next_cursor":"eyJ0IjoiMjAyNi0xMC0xM1QwOTozMDowMFoiLCJpIjo4MTJ9"}}}},"400":{"description":"The request is invalid, for example a missing or malformed field.","content":{"application/json":{"example":{"error":{"type":"invalid_request","code":"invalid_speaker_id","message":"speaker_id must be 1-64 characters from A-Z, a-z, 0-9, '_', '.', ':' and '-'.","param":"speaker_id"},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"error":{"type":"authentication","code":"invalid_api_key","message":"The API key is invalid."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the required scope, the email address is not verified, or the account is suspended.","content":{"application/json":{"example":{"error":{"type":"permission","code":"insufficient_scope","message":"This API key is missing the required scope(s): deepfake:detect."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"},"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/health":{"get":{"tags":["System"],"summary":"Check service health","description":"Whether the service and its parts are up: `status` is `ok`, or `degraded` when a part is unavailable. No authentication needed.","operationId":"getHealth","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"},"example":{"request_id":"req_8f14e45fceea167a5a36dedd","status":"ok","version":"1.0.0","database":"ok","inference":"ok"}}}},"429":{"description":"Too many requests or too many operations at the same time. Wait for the number of seconds in Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"rate_limited","code":"rate_limited","message":"Model operation rate limit reached (30 per minute per account)."},"request_id":"req_8f14e45fceea167a5a36dedd"}}}},"500":{"description":"Something went wrong on our side. No credits were used.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"internal","code":"internal_error","message":"An internal error occurred."},"request_id":"req_8f14e45fceea167a5a36dedd"}}}}}}}},"components":{"schemas":{"CreditsCharged":{"properties":{"charged":{"type":"integer","title":"Charged","description":"Credits used by this request. A repeated request with the same Idempotency-Key uses none: it reports 0 here and what the original request used in `original_charge`."},"balance":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance","description":"Your available credits after this request; null on the unlimited plan."},"original_charge":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Original Charge","description":"Only on repeated requests (`charged` is then 0): the credits the original request used."},"unlimited":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Unlimited","description":"Present (true) only for accounts on the unlimited plan, where checks use no credits."}},"type":"object","required":["charged","balance"],"title":"CreditsCharged"},"CreditsObject":{"properties":{"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"credits","title":"Object"},"plan":{"type":"string","enum":["free","unlimited"],"title":"Plan","description":"Your plan."},"unlimited":{"type":"boolean","title":"Unlimited","description":"true on the unlimited plan: checks use no credits and `available` is null."},"available":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Available","description":"Credits you can use; null on the unlimited plan."},"reserved":{"type":"integer","title":"Reserved","description":"Credits held by checks that are still running."},"price_per_operation":{"type":"integer","title":"Credits per check","description":"Credits one completed check uses (0 on the unlimited plan)."}},"type":"object","required":["request_id","object","plan","unlimited","available","reserved","price_per_operation"],"title":"CreditsObject"},"DeepfakeResponse":{"properties":{"request_id":{"type":"string","title":"Request Id"},"operation_id":{"type":"string","title":"Operation Id"},"object":{"type":"string","const":"deepfake.detection","title":"Object"},"result":{"$ref":"#/components/schemas/DeepfakeResult"},"model":{"$ref":"#/components/schemas/ModelInfo"},"credits":{"$ref":"#/components/schemas/CreditsCharged"},"latency_ms":{"type":"number","title":"Latency Ms"},"idempotent_replay":{"type":"boolean","title":"Idempotent Replay"}},"type":"object","required":["request_id","operation_id","object","result","model","credits","latency_ms","idempotent_replay"],"title":"DeepfakeResponse","examples":[{"credits":{"balance":4950,"charged":50},"idempotent_replay":false,"latency_ms":412.7,"model":{"name":"aletheia","version":"3f9c2a71b0d4"},"object":"deepfake.detection","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","request_id":"req_8f14e45fceea167a5a36dedd","result":{"duration_seconds":6.4,"is_synthetic":false,"label":"genuine","score":0.0731,"score_semantics":"Higher means more likely AI-generated. Decide with the verdict, not the score alone.","segments":[{"end":4.0,"score":0.061,"start":0.0},{"end":6.0,"score":0.085,"start":2.0}],"threshold":0.62,"verdict":"real"}}]},"DeepfakeResult":{"properties":{"verdict":{"type":"string","enum":["real","fake","not_sure"],"title":"Verdict","description":"The decision: `real`, `fake` (AI-generated), or `not_sure` (try a longer or cleaner recording)."},"label":{"type":"string","enum":["synthetic","genuine","uncertain"],"title":"Label","description":"The same decision in the older wording: `synthetic` (fake), `genuine` (real), `uncertain` (not sure)."},"is_synthetic":{"type":"boolean","title":"Is Synthetic","description":"true only when the verdict is `fake`."},"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score","description":"How likely the recording is AI-generated, from 0 to 1."},"threshold":{"type":"number","title":"Threshold","description":"The main model's threshold (0.62). Informational: decide with `verdict`."},"score_semantics":{"type":"string","title":"Score Semantics","description":"A short reminder of what `score` means."},"duration_seconds":{"type":"number","title":"Duration Seconds","description":"Length of the checked audio, in seconds."},"segments":{"items":{"$ref":"#/components/schemas/Segment"},"type":"array","title":"Segments","description":"Scores for consecutive, overlapping parts of the recording."}},"type":"object","required":["verdict","label","is_synthetic","score","threshold","score_semantics","duration_seconds","segments"],"title":"DeepfakeResult"},"EmbeddedDeepfake":{"properties":{"verdict":{"type":"string","enum":["real","fake","not_sure"],"title":"Verdict","description":"The decision: `real`, `fake` (AI-generated), or `not_sure` (try a longer or cleaner recording)."},"label":{"type":"string","enum":["synthetic","genuine","uncertain"],"title":"Label","description":"The same decision in the older wording: `synthetic` (fake), `genuine` (real), `uncertain` (not sure)."},"is_synthetic":{"type":"boolean","title":"Is Synthetic","description":"true only when the verdict is `fake`."},"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score","description":"How likely the recording is AI-generated, from 0 to 1."},"threshold":{"type":"number","title":"Threshold","description":"The main model's threshold (0.62). Informational: decide with `verdict`."},"score_semantics":{"type":"string","title":"Score Semantics","description":"A short reminder of what `score` means."},"duration_seconds":{"type":"number","title":"Duration Seconds","description":"Length of the checked audio, in seconds."},"segments":{"items":{"$ref":"#/components/schemas/Segment"},"type":"array","title":"Segments","description":"Scores for consecutive, overlapping parts of the recording."},"operation_id":{"type":"string","title":"Operation Id"},"credits_charged":{"type":"integer","title":"Credits Charged"},"model":{"$ref":"#/components/schemas/ModelInfo"}},"type":"object","required":["verdict","label","is_synthetic","score","threshold","score_semantics","duration_seconds","segments","operation_id","credits_charged","model"],"title":"EmbeddedDeepfake"},"EmbeddedDeepfakeError":{"properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"},"operation_id":{"type":"string","title":"Operation Id"},"credits_charged":{"type":"integer","title":"Credits Charged","default":0}},"type":"object","required":["error","operation_id"],"title":"EmbeddedDeepfakeError"},"EnrollQuality":{"properties":{"speech_seconds":{"type":"number","title":"Speech Seconds"},"duration_seconds":{"type":"number","title":"Duration Seconds"}},"type":"object","required":["speech_seconds","duration_seconds"],"title":"EnrollQuality"},"EnrollResponse":{"properties":{"request_id":{"type":"string","title":"Request Id"},"operation_id":{"type":"string","title":"Operation Id"},"object":{"type":"string","const":"speaker.enrollment","title":"Object"},"speaker":{"$ref":"#/components/schemas/Speaker"},"quality":{"$ref":"#/components/schemas/EnrollQuality"},"model":{"$ref":"#/components/schemas/ModelInfo"},"credits":{"$ref":"#/components/schemas/CreditsCharged"},"latency_ms":{"type":"number","title":"Latency Ms"},"idempotent_replay":{"type":"boolean","title":"Idempotent Replay"}},"type":"object","required":["request_id","operation_id","object","speaker","quality","model","credits","latency_ms","idempotent_replay"],"title":"EnrollResponse","examples":[{"credits":{"balance":4900,"charged":50},"idempotent_replay":false,"latency_ms":388.1,"model":{"name":"eidos","version":"8e1b6c0a92f7"},"object":"speaker.enrollment","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","quality":{"duration_seconds":9.2,"speech_seconds":7.9},"request_id":"req_8f14e45fceea167a5a36dedd","speaker":{"created_at":"2026-10-12T09:30:00Z","display_name":"Ada Lovelace","samples":1,"speaker_id":"customer-4711","updated_at":"2026-10-12T09:30:00Z"}}]},"Error":{"properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id","description":"Also in the X-Request-Id header; quote it when contacting support."},"operation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Id","description":"Errors about a specific operation (e.g. 409 operation_in_progress): its id."},"credits":{"anyOf":[{"$ref":"#/components/schemas/RequiredCredits"},{"type":"null"}],"description":"402 insufficient_credits only."},"partial":{"anyOf":[{"$ref":"#/components/schemas/PartialOutcome"},{"type":"null"}],"description":"Verification with detect_deepfake=true only: the synthetic-speech result, when that check completed although the verification failed."},"idempotent_replay":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Idempotent Replay","description":"true when this is a stored error replayed for a retry."}},"additionalProperties":true,"type":"object","required":["error","request_id"],"title":"Error","description":"The error envelope of every non-2xx response.","examples":[{"error":{"code":"missing_file","message":"A \"file\" field with the audio is required.","param":"file","type":"invalid_request"},"request_id":"req_8f14e45fceea167a5a36dedd"}]},"ErrorDetail":{"properties":{"type":{"type":"string","enum":["invalid_request","authentication","permission","not_found","conflict","rate_limited","insufficient_credits","payload_too_large","unsupported_media","unprocessable_audio","overloaded","internal"],"title":"Type"},"code":{"type":"string","title":"Code","description":"Stable snake_case error code."},"message":{"type":"string","title":"Message","description":"Human-readable explanation. Do not parse."},"param":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Param","description":"The request field the error refers to, if any."}},"type":"object","required":["type","code","message"],"title":"ErrorDetail"},"FeedbackObject":{"properties":{"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"operation.feedback","title":"Object"},"operation_id":{"type":"string","title":"Operation Id"},"correct":{"type":"boolean","title":"Correct"},"label":{"anyOf":[{"type":"string","enum":["real","fake"]},{"type":"null"}],"title":"Label"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["request_id","object","operation_id","correct","label","note","created_at","updated_at"],"title":"FeedbackObject"},"FeedbackRequest":{"properties":{"correct":{"type":"boolean","title":"Correct","description":"Was the result right?"},"label":{"anyOf":[{"type":"string","enum":["real","fake"]},{"type":"null"}],"title":"Label","description":"Optional: what the recording really is."},"note":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Note","description":"Optional note, at most 500 characters."}},"additionalProperties":false,"type":"object","required":["correct"],"title":"FeedbackRequest","examples":[{"correct":false,"label":"real","note":"My own voice, recorded on a phone."}]},"HealthResponse":{"properties":{"request_id":{"type":"string","title":"Request Id"},"status":{"type":"string","enum":["ok","degraded"],"title":"Status"},"version":{"type":"string","title":"Version"},"database":{"type":"string","enum":["ok","unavailable"],"title":"Database"},"inference":{"type":"string","enum":["ok","unavailable"],"title":"Inference"}},"type":"object","required":["request_id","status","version","database","inference"],"title":"HealthResponse"},"ModelInfo":{"properties":{"name":{"type":"string","title":"Name","description":"Model family: `aletheia` (deepfake detection) or `eidos` (speaker verification)."},"version":{"type":"string","title":"Version","description":"Opaque model version; it changes whenever the model is updated."}},"type":"object","required":["name","version"],"title":"ModelInfo"},"OperationObject":{"properties":{"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"operation","title":"Object"},"operation_id":{"type":"string","title":"Operation Id"},"type":{"type":"string","enum":["deepfake.detect","speaker.enroll","speaker.verify"],"title":"Type"},"status":{"type":"string","enum":["pending","reserved","running","succeeded","failed"],"title":"Status"},"source":{"type":"string","enum":["api","dashboard","mcp"],"title":"Source"},"parent_operation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Operation Id"},"credits_charged":{"type":"integer","title":"Credits Charged"},"created_at":{"type":"string","title":"Created At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result","description":"The original success response body (without request_id)."},"error":{"anyOf":[{"$ref":"#/components/schemas/ErrorDetail"},{"type":"null"}]},"partial":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Partial","description":"For a failed verification whose synthetic-speech check completed: that result."}},"type":"object","required":["request_id","object","operation_id","type","status","source","parent_operation_id","credits_charged","created_at","completed_at","result","error"],"title":"OperationObject"},"PartialOutcome":{"properties":{"deepfake":{"$ref":"#/components/schemas/EmbeddedDeepfake","description":"The synthetic-speech check, which completed."},"credits":{"$ref":"#/components/schemas/CreditsCharged"}},"type":"object","required":["deepfake","credits"],"title":"PartialOutcome"},"RequiredCredits":{"properties":{"available":{"type":"integer","title":"Available","description":"Credits you have available."},"required":{"type":"integer","title":"Required","description":"Credits this request needs."}},"type":"object","required":["available","required"],"title":"RequiredCredits"},"Segment":{"properties":{"start":{"type":"number","title":"Start","description":"Start of this part of the recording, in seconds."},"end":{"type":"number","title":"End","description":"End of this part of the recording, in seconds."},"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score","description":"How likely this part is synthetic (0 to 1)."}},"type":"object","required":["start","end","score"],"title":"Segment"},"Speaker":{"properties":{"speaker_id":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,64}$","title":"Speaker Id"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"samples":{"type":"integer","title":"Samples","description":"Active enrollment samples for the current speaker model (max 5)."},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["speaker_id","display_name","samples","created_at","updated_at"],"title":"Speaker"},"SpeakerDeleted":{"properties":{"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"speaker.deleted","title":"Object"},"speaker_id":{"type":"string","title":"Speaker Id"},"deleted":{"type":"boolean","const":true,"title":"Deleted"}},"type":"object","required":["request_id","object","speaker_id","deleted"],"title":"SpeakerDeleted"},"SpeakerList":{"properties":{"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"list","title":"Object"},"data":{"items":{"$ref":"#/components/schemas/Speaker"},"type":"array","title":"Data"},"has_more":{"type":"boolean","title":"Has More"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["request_id","object","data","has_more","next_cursor"],"title":"SpeakerList"},"SpeakerObject":{"properties":{"speaker_id":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,64}$","title":"Speaker Id"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"samples":{"type":"integer","title":"Samples","description":"Active enrollment samples for the current speaker model (max 5)."},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"},"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"speaker","title":"Object"}},"type":"object","required":["speaker_id","display_name","samples","created_at","updated_at","request_id","object"],"title":"SpeakerObject"},"UsageEvent":{"properties":{"id":{"type":"string","title":"Id"},"operation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Id"},"type":{"type":"string","enum":["deepfake.detect","speaker.enroll","speaker.verify"],"title":"Type"},"source":{"type":"string","enum":["api","dashboard","mcp"],"title":"Source"},"status":{"type":"string","enum":["succeeded","rejected","failed","replayed"],"title":"Status"},"http_status":{"type":"integer","title":"Http Status"},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code"},"credits_charged":{"type":"integer","title":"Credits Charged"},"duration_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Seconds"},"latency_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latency Ms"},"request_id":{"type":"string","title":"Request Id"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","operation_id","type","source","status","http_status","error_code","credits_charged","duration_seconds","latency_ms","request_id","created_at"],"title":"UsageEvent"},"UsageList":{"properties":{"request_id":{"type":"string","title":"Request Id"},"object":{"type":"string","const":"list","title":"Object"},"data":{"items":{"$ref":"#/components/schemas/UsageEvent"},"type":"array","title":"Data"},"has_more":{"type":"boolean","title":"Has More"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["request_id","object","data","has_more","next_cursor"],"title":"UsageList"},"VerifyResponse":{"properties":{"request_id":{"type":"string","title":"Request Id"},"operation_id":{"type":"string","title":"Operation Id"},"object":{"type":"string","const":"speaker.verification","title":"Object"},"speaker_id":{"type":"string","title":"Speaker Id"},"result":{"$ref":"#/components/schemas/VerifyResult"},"deepfake":{"anyOf":[{"$ref":"#/components/schemas/EmbeddedDeepfake"},{"$ref":"#/components/schemas/EmbeddedDeepfakeError"},{"type":"null"}],"title":"Deepfake","description":"null unless detect_deepfake=true; then either the synthetic-speech result or its error."},"model":{"$ref":"#/components/schemas/ModelInfo"},"credits":{"$ref":"#/components/schemas/CreditsCharged"},"latency_ms":{"type":"number","title":"Latency Ms"},"idempotent_replay":{"type":"boolean","title":"Idempotent Replay"}},"type":"object","required":["request_id","operation_id","object","speaker_id","result","deepfake","model","credits","latency_ms","idempotent_replay"],"title":"VerifyResponse","examples":[{"credits":{"balance":4850,"charged":50},"idempotent_replay":false,"latency_ms":301.5,"model":{"name":"eidos","version":"8e1b6c0a92f7"},"object":"speaker.verification","operation_id":"op_6f1ed002ab5595859014ebf0951522d9","request_id":"req_8f14e45fceea167a5a36dedd","result":{"decision":"match","duration_seconds":4.1,"similarity":0.7412,"similarity_semantics":"Higher means the two voices are more alike. Not a percentage.","threshold":0.53},"speaker_id":"customer-4711"}]},"VerifyResult":{"properties":{"decision":{"type":"string","enum":["match","no_match"],"title":"Decision","description":"`match` when `similarity` is at or above `threshold`."},"similarity":{"type":"number","maximum":1.0,"minimum":-1.0,"title":"Similarity","description":"How alike the two voices are, from -1 to 1 (higher is more alike)."},"threshold":{"type":"number","title":"Threshold","description":"The similarity from which the decision is `match`."},"similarity_semantics":{"type":"string","title":"Similarity Semantics","description":"A short reminder of what `similarity` means."},"duration_seconds":{"type":"number","title":"Duration Seconds","description":"Length of the checked audio, in seconds."}},"type":"object","required":["decision","similarity","threshold","similarity_semantics","duration_seconds"],"title":"VerifyResult"}},"securitySchemes":{"bearerAuth":{"type":"http","description":"Your API key in the Authorization header: `Authorization: Bearer dtf_live_...`. Create keys in the dashboard; each key has scopes that limit what it can do. Keys in URLs (`?api_key=`) are rejected.","scheme":"bearer","bearerFormat":"API key (dtf_live_...)"}}},"tags":[{"name":"Deepfake detection","description":"Check recordings for AI-generated speech."},{"name":"Speakers","description":"Save voice samples of speakers and verify recordings against them."},{"name":"Results","description":"Fetch the stored outcome of an earlier request."},{"name":"Account","description":"Your balance and your usage."},{"name":"System","description":"Service status."}]}