Skip to content

Approve or reject an item, or correct a rejection reason

PATCH
/v1/review-items/{id}
curl --request PATCH \
--url https://beta-api.plune.ai/v1/review-items/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "state": "rejected", "rejectionCategory": "duplicate", "note": "Цей самий сценарій уже покриває кейс «Оформлення замовлення з порожнім кошиком»." }'
id
required
string format: uuid
Media type application/json
One of:
RejectWithReason
object
state
required
string
Allowed values: rejected
rejectionCategory
required

Why a proposal or a result was turned down. A closed list of six: each value maps to one correction the generating agent can act on, which is what makes the reasons aggregatable instead of a pile of prose. Wire values are these English keys; the Ukrainian labels live in the SPA and never reach a machine client.

string
Allowed values: duplicate incorrect out-of-scope low-value not-testable other
note
required

The nuance the category cannot hold. Trimmed first, then measured: 10 to 2000 characters. The bounds are a product number reviewed without a migration, so they are enforced on the route rather than in the database.

string
>= 10 characters <= 2000 characters
Examples

Reject with the full pair

{
"state": "rejected",
"rejectionCategory": "duplicate",
"note": "Цей самий сценарій уже покриває кейс «Оформлення замовлення з порожнім кошиком»."
}

Updated

Media type application/json

One entry of the review queue. Always starts pending; a reviewer moves it on.

object
schemaVersion
required
integer
Allowed values: 1
id
required
string format: uuid
resultId

Present on an entry disputing a RESULT. Exactly one of resultId, proposedCase and discoveredTest is present: an entry with two asks two questions at once, and one with none asks nothing.

string format: uuid
proposedCase

Present on an entry proposing a new case. Mutually exclusive with the other two.

object
stableId
required

Content-derived identity; the dedup key.

string
title
required
string
<= 300 characters
execution
required
string
Allowed values: auto manual
steps
required
Array<string>
>= 1 items <= 20 items
expected
required
string
<= 2000 characters
origin
required
object
runId
required
string
mode
required
string
Allowed values: explore design api
target
required
string
technique
string
<= 32 characters
priority
string
source
object
kind
required
string
Allowed values: url openapi-operation requirement
value
required
string
>= 1 characters <= 100 characters
rationale
string
>= 1 characters <= 400 characters
runCost
object
tokens
required
integer
cases
required
integer
verdict

Absent means never executed — NOT “no result yet”.

string
Allowed values: passed failed
externalKeys

What a match resolves through. Absent is a normal proposal, not a degraded one: an agent that names no key gets an entry with no comparison, which is exactly what a genuinely new case gets.

Array<object>
<= 32 items

An identifier another tool already uses for this test, so a report can find its case without anyone typing a Plune id. The order of kind is load-bearing: it is the ranking that decides which key wins when several match different cases.

object
kind
required
string
Allowed values: playwright-id path-title allure-history cairn-stable eval-id qase testrail
value
required
string
<= 1024 characters
discoveredTest

Present on an entry reporting a test the caller RUNS and this project has no case for. Mutually exclusive with the other two.

object
keys
required

The identity. Order does not matter — the server ranks them and the highest-ranked kind is what deduplication reads, so two adapters sending the same keys in a different order do not produce two entries about one test.

Array<object>
>= 1 items <= 8 items

An identifier another tool already uses for this test, so a report can find its case without anyone typing a Plune id. The order of kind is load-bearing: it is the ranking that decides which key wins when several match different cases.

object
kind
required
string
Allowed values: playwright-id path-title allure-history cairn-stable eval-id qase testrail
value
required
string
<= 1024 characters
title
required
string
<= 300 characters
source
required

The reporter that found it, e.g. playwright.

string
<= 32 characters
specRef
required

Where the test lives, e.g. e2e/checkout.spec.ts:12. Required while everything descriptive is optional: an approved discovery becomes an automated case, and that shape needs a spec to point at.

string
<= 400 characters
rawStatus

What it did on this run, in the reporter’ own word.

string
<= 64 characters
platformRunId

The run that turned it up, once stored.

string
state
required
string
Allowed values: pending approved rejected
rejectionCategory

Present on every item rejected after R4, and absent forever on rejections stored before it — those are never migrated and must keep reading without error. An item that is pending or approved usually has none, but MAY still carry one: a rejection returned to review keeps the pair in the row as a draft, and the next move to rejected must supply it in the request anyway. Read it as “meaningful only while state is rejected”, not as “absent otherwise”.

string
Allowed values: duplicate incorrect out-of-scope low-value not-testable other
note
string
createdAt
required
string format: date-time
updatedAt
required
string format: date-time
Example
{
"schemaVersion": 1,
"proposedCase": {
"execution": "auto",
"origin": {
"mode": "explore"
},
"source": {
"kind": "url"
},
"verdict": "passed",
"externalKeys": [
{
"kind": "playwright-id"
}
]
},
"discoveredTest": {
"keys": [
{
"kind": "playwright-id"
}
]
},
"state": "pending",
"rejectionCategory": "duplicate"
}

Invalid body, unknown state, or an incomplete reason on a write that leaves the item rejected. Each missing half is named separately, and an unknown category is answered with the list of allowed ones.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No / invalid token or session

Not found or not yours

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Rate-limited: either the per-route throttle or a tenant quota. Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over