Detection Feedback

Tell Resemble whether a detection verdict was right — and when it wasn’t, what it should have been.

Every answer is stored alongside a snapshot of what the model said at the time it was submitted (verdict, score, media type, and the raw per-modality metrics). That snapshot is what makes the data usable as training signal later: it stays interpretable even if the detect is re-run, re-finalized, or deleted.

MethodPathPurpose
POST/detect/{uuid}/feedbackSubmit or revise your answer
GET/detect/{uuid}/feedbackRead your answer
DELETE/detect/{uuid}/feedbackRetract your answer

Access and scoping

  • The authenticated user needs Detect access. Without it, every call returns 400 — not 403. Resemble’s v2 API surfaces entitlement errors as 400, so don’t branch on 403.
  • Calls are scoped to your team. A detect belonging to another team returns 404, the same as one that doesn’t exist — the endpoint never confirms whether a UUID you can’t reach is real.
  • Feedback is per user, not per team. GET and DELETE only ever see your own row; a teammate’s answer on the same detect is invisible to you.
  • Requests are rate-limited to 50 per second per IP, across all Resemble APIs.

Submit feedback

POST https://app.resemble.ai/api/v2/detect/{uuid}/feedback

Upserts on (detect, user): re-posting edits your existing answer rather than adding a second one. There is no separate update call.

FieldTypeRequiredDescription
typestringYesWhat the verdict should have been. See below.
commentstringNoFree text, up to 1000 characters. Trimmed; blank becomes null.
sourcestringNoWhere the answer came from. Defaults to api. Truncated to 64 characters rather than rejected.

type values

ValueMeaning
correctThe verdict was right.
should_be_ai_generatedWe said authentic; it is AI-generated.
should_be_authenticWe said AI-generated; it is genuine and unaltered.
should_be_non_aiNo model generated it — but it may still be edited, spliced, or a human impersonation.
should_be_neutralNeither call is right; this one is genuinely ambiguous.
skippedThe verdict was wrong, but the reviewer didn’t say how.

correct maps to a thumbs-up; every other value, including skipped, maps to a thumbs-down.

Use skipped rather than withholding feedback when a reviewer knows the verdict is wrong but can’t say what it should be — “wrong, unspecified” is still signal, and it’s distinguishable from the four specific corrections.

should_be_authentic vs should_be_non_ai

These are different claims, and the distinction matters — sending the stronger one when you mean the weaker teaches the model that “not synthetic” implies “not manipulated”.

  • Use should_be_authentic when you can vouch for the media: it is a genuine recording of what it appears to be.
  • Use should_be_non_ai when you only know that no model generated it. A human impersonator, a spliced-together real recording, and a heavily edited but human-performed clip are all non-AI without being authentic.

When in doubt, should_be_non_ai is the safer answer.

Example

$curl --request POST 'https://app.resemble.ai/api/v2/detect/DETECT_UUID/feedback' \
> -H 'Authorization: Bearer YOUR_API_TOKEN' \
> -H 'Content-Type: application/json' \
> --data '{
> "type": "should_be_authentic",
> "comment": "Verified with the speaker — this is their real voice.",
> "source": "acme-moderation"
> }'

Response

1{
2 "success": true,
3 "item": {
4 "detect_uuid": "3f1a9c4e7b2d5081",
5 "type": "should_be_authentic",
6 "vote": "down",
7 "verdict": "ai_generated",
8 "score": 0.92,
9 "media_type": "audio",
10 "comment": "Verified with the speaker — this is their real voice.",
11 "credit": 0,
12 "source": "acme-moderation",
13 "created_at": "2026-08-06T18:22:04.000Z",
14 "updated_at": "2026-08-06T18:22:04.000Z"
15 }
16}

Response fields

FieldTypeDescription
item.detect_uuidstringThe detect this answer is attached to.
item.typestringWhat you sent.
item.votestringup or down, derived from type. Never independent of it.
item.verdictstring | nullWhat the model said: ai_generated, authentic, or null.
item.scorenumber | nullThe model’s headline confidence, 0.01.0, or null.
item.media_typestringaudio, video, image, or text, copied from the detect.
item.commentstring | nullYour comment, or null.
item.creditintegerCredits awarded for this answer. Written by Resemble, never by the submitter; 0 on a fresh row.
item.sourcestringThe attribution string recorded for this answer.
item.created_atstringWhen the answer was first submitted.
item.updated_atstringMoves when you revise an answer; created_at does not.

Resemble records more against each answer than it returns — a frozen copy of the raw per-modality metrics the verdict came from, plus internal review state. None of that is part of this response or of any forward contract. The interpreted form of the snapshot (verdict, score, media_type) is what you get.

When verdict is null, the detection landed somewhere indeterminate — a neutral or uncertain label, or a label we can’t map to either class. You can still submit a correction; that’s arguably when it’s most useful.

score for video is the higher of the audio and video confidences, since the more confident modality is what drives the displayed verdict. For a detect where only one modality was requested, it’s that modality’s score.

should_be_neutral and should_be_non_ai never appear in verdict. That field records only the two decided model outcomes; those two assertions live solely in type.

Read your feedback

GET https://app.resemble.ai/api/v2/detect/{uuid}/feedback

Returns the same item shape as POST.

$curl --request GET 'https://app.resemble.ai/api/v2/detect/DETECT_UUID/feedback' \
> -H 'Authorization: Bearer YOUR_API_TOKEN'

Returns 404 when you haven’t answered this detect, even if the detect exists and a teammate has answered it.

Retract your feedback

DELETE https://app.resemble.ai/api/v2/detect/{uuid}/feedback

$curl --request DELETE 'https://app.resemble.ai/api/v2/detect/DETECT_UUID/feedback' \
> -H 'Authorization: Bearer YOUR_API_TOKEN'

Idempotent: returns 200 { "success": true } whether or not a row existed. Only your own row is removed; a teammate’s answer on the same detect is untouched.

Integration notes

Wait for the detect to complete

The most common integration snag. A detect that is still processing — or that errored — rejects feedback with 400. Poll GET /detect/{uuid} until status is completed before offering a reviewer the choice.

$curl --request GET 'https://app.resemble.ai/api/v2/detect/DETECT_UUID' \
> -H 'Authorization: Bearer YOUR_API_TOKEN' | jq -r '.item.status'

DELETE is exempt: you can always retract, even from a detect that later failed.

One row per reviewer

If several people in your organization review the same detect, give each of them their own Resemble user. Feedback is keyed on (detect, user), so a shared service account collapses all of their answers into one row, each overwriting the last.

Attribute your surface

Set source to something stable and specific — a product or queue name, not a per-request identifier. It’s how we weigh a one-click reaction against a considered review, so its value is in being aggregatable.

Deleted detects

Feedback outlives the detect it describes, but the endpoints don’t: once a detect is deleted, all three calls return 404. Retract before deleting if you need to.

Errors

Every error uses the same envelope:

1{ "success": false, "message": "..." }
StatusReason
400Unknown or missing type; comment over 1000 characters; the detect hasn’t finished processing or it failed; the team doesn’t have Detect access.
401Missing or invalid credentials.
404No such detect for your team, or (on GET) you haven’t answered it.

An explicitly supplied invalid type is always an error — it never silently falls back to anything else.