Skip to content

One page of the review queue, newest first

GET
/v1/review-items
curl --request GET \
--url 'https://beta-api.plune.ai/v1/review-items?state=pending&limit=50' \
--header 'Authorization: Bearer <token>'

BREAKING as of R3: this read is always paged. A client that read items and never looked at nextCursor now sees only the first page. A limit outside the range is clamped; an invalid cursor is REFUSED rather than answered with the start of the queue — a silent restart reads as “nothing changed”, which is how the middle of a queue disappears unnoticed.

state
string
Allowed values: pending approved rejected

Narrow to one state; omit for everything.

limit
integer
default: 50 >= 1 <= 200

Page size. The maximum equals the ceiling on items per decision, so a list built from one visible page can never exceed what a single decision accepts.

cursor
string

nextCursor from the previous page. Omit for the first page.

One page of your queue

Media type application/json
object
items
required
Array<object>

The LIST form of a queue item, deliberately lighter than the single-item form. It names WHICH fields differ from the matched case, not what they contain, and carries a proposal’s title instead of the proposal. The full comparison is unbounded in the size of the proposal it describes, so a page of them could not hold a weight ceiling — read one item to get it. All THREE kinds of entry are reduced the same way: a disputed result keeps resultId, a proposal becomes proposedTitle, and a discovered test becomes discoveredTitle with discoveredSpecRef. Exactly one group is present.

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

Present on an entry disputing a RESULT.

string format: uuid
proposedTitle

The proposal’s title alone. Present exactly where proposedCase is on the single-item read — a one-field object would have promised a structure that is not there.

string
discoveredTitle

Which test was discovered. Present exactly where discoveredTest is on the single-item read (ADR 0029). Its keys are NOT here: they are bounded at 32 x 1024 characters, which is 32 KB on one row of a 256 KB page — read one item to get them.

string
discoveredSpecRef

Where that test lives, so a page can be scanned by location without opening anything. Accompanies discoveredTitle and never appears without it.

string
source
object
kind
required
string
Allowed values: url openapi-operation requirement
value
required
string
>= 1 characters <= 100 characters
technique

Source and technique ride a row because they DIFFER between rows — a reviewer can see a whole batch made by one method without opening anything. The rationale and the run cost are NOT here: the first would not fit the page budget, and a cost repeated down twenty rows reads as the cost of each proposal. Open an item for both.

string
<= 32 characters
state
required
string
Allowed values: pending approved rejected
rejectionCategory
string
Allowed values: duplicate incorrect out-of-scope low-value not-testable other
note
string
createdTestCaseId

The case an approved proposal became. Present only on an approved proposal: an entry that disputes a result never has one, and a pending or rejected proposal does not have one yet. This is the answer to “did the decision take” — the platform creates nothing silently, and this is where it says what it created.

string format: uuid
testCaseId
string format: uuid
testCaseTitle
string
runId
string format: uuid
runAt
string format: date-time
passed
integer
failed
integer
verdictsPassed
integer
verdictsFailed
integer
match

Absent when no key matched — see CaseMatch for why the three cases are one answer.

object
testCaseId
required
string format: uuid
title
required
string
matchedBy
required

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
changedFields
required

Which fields differ. Empty means the proposal matches the case field for field; the VALUES live on the single-item read.

Array<string>
Allowed values: title steps expected execution technique priority
previousRun
object
previousResultId
required
string format: uuid
previousRunId
required
string format: uuid
previousRanAt
required
string format: date-time
previousStatus
required
string
Allowed values: passed failed broken blocked skipped
previousOutcome
required
string
Allowed values: expected unexpected flaky skipped
statusChanged
required

What happened to the test.

boolean
outcomeChanged
required

Whether it behaved as expected. Independent of statusChanged: a test can stay just as unsuccessful and still move from broken to failed, and that is exactly what changes what a reviewer does next. Both axes are reported always, changed or not, so that “the state moved and the behaviour did not” is never something to infer from a missing field.

boolean
createdAt
required
string format: date-time
updatedAt
required
string format: date-time
nextCursor
required

Pass as cursor to read the next page; null on the last one. Keyset over the same pair the queue is ordered by — "<createdAt>|<id>", the spelling the audit feed already uses — so an item on a page boundary is neither skipped nor served twice.

string
nullable
Example
{
"items": [
{
"schemaVersion": 1,
"source": {
"kind": "url"
},
"state": "pending",
"rejectionCategory": "duplicate",
"match": {
"matchedBy": {
"kind": "playwright-id"
},
"changedFields": [
"title"
]
},
"previousRun": {
"previousStatus": "passed",
"previousOutcome": "expected"
}
}
]
}

Unknown state, or a position that is not a valid cursor

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

No / invalid token or session