Skip to content

List the Watchtower answers houses contested, with the contributions behind each

GET
/v1/watchtower/contests
curl --request GET \
--url 'https://api.aerandil.com/v1/watchtower/contests?limit=50' \
--header 'Authorization: Bearer <token>'

The platform’s review queue for Watchtower, the card rail’s federated fraud network: every fraud_network_signal a desk contested (contest_fraud_network_signal), across every tenant, most recently contested first — the house it was given to, when and why it was contested, the answer’s buckets, band_floor and floor_basis — and the contributions behind it: every fraud_network_contribution carrying one of the digests the answer kept, under its salt epoch, within the two-year look-back the answer was read with. A contribution is listed whatever its status now, naming its house, outcome, status and source; counts says whether the next answer still counts it (active, its house still consenting), own_house whether it is the contesting house’s own, and after_answer whether it was contributed after the answer (so did not shape it). An answer frozen before its digests were kept (2026-11-03) lists none (traceable: false). The platform operator’s read (tenant_admin:write), cleared to read internal.restricted (markings:internal.restricted:read): 403 without either, insufficient_clearance without the second.

limit
integer
default: 50 >= 1 <= 200

At most this many contests (default 50).

The contested answers, newest contest first.

Media typeapplication/json
object
contests
required
Array<object>

An answer a house contested, the house it was given to, and the contributions behind it.

object
band_floor
string | null
Allowed values: low medium high block not_assessed
contest_reason
string | null
contested_at
required
string format: date-time
contributions
required
Array<object>

A contribution behind a contested answer, as the platform’s review reads it: whose, what, and whether it still counts.

object
after_answer
required

Contributed after the answer was given, so it did not shape it.

boolean
contributed_at
required
string format: date-time
contribution_id
required
string format: uuid
counts
required

Whether the next answer counts it: active, its house still consenting.

boolean
matched_kinds
required
Array<string>
Allowed values: card email phone
outcome
required
string
Allowed values: chargeback_lost_fraud confirmed_fraud
own_house
required

The contesting house’s own contribution.

boolean
property_code
string | null
property_id
string | null format: uuid
property_name
string | null
reference
string | null
source_reference

The processor’s dispute id, or the assessment id.

string | null
status
required
string
Allowed values: active withdrawn
tenant_id
required
string format: uuid
withdrawal_reason
string | null
withdrawn_at
string | null format: date-time
withdrawn_by
string | null
Allowed values: house platform
contributor_breadth
string | null
Allowed values: none below_cohort cohort_met
floor_basis
string | null
Allowed values: none contact card_unconfirmed card_corroborated card_own_house desk_override
issued_at
required
string format: date-time
kinds_queried
required
Array<string>
Allowed values: card email phone
match_count_bucket
string | null
Allowed values: none one few many
matched_kinds
required
Array<string>
Allowed values: card email phone
property_code
string | null
property_id
string | null format: uuid
property_name
string | null
recency_bucket
string | null
Allowed values: none within_30_days within_180_days older
reference
string | null
salt_epoch
required
integer
signal_id
required
string format: uuid
subject_id
string | null
subject_kind
string | null
tenant_id
required
string format: uuid
traceable
required

Whether the answer kept its digests (since 2026-11-03).

boolean
limit
required
integer
Example
{
"contests": [
{
"band_floor": "low",
"contributions": [
{
"matched_kinds": [
"card"
],
"outcome": "chargeback_lost_fraud",
"status": "active",
"withdrawn_by": "house"
}
],
"contributor_breadth": "none",
"floor_basis": "none",
"kinds_queried": [
"card"
],
"match_count_bucket": "none",
"matched_kinds": [
"card"
],
"recency_bucket": "none"
}
]
}
Cache-Control
string

Always no-store. Object and link state is live data and is never cacheable.

The bearer authenticated but does not hold the scope this operation requires.

Media typeapplication/json

Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.

object
error
required
object
code
required

Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).

Examplegenerated
{
"error": {
"code": "example",
"instance_id": "example",
"message": "example",
"parameters": "example"
}
}

The request parsed but a validator refused it. The envelope’s code names which rule.

Media typeapplication/json

Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.

object
error
required
object
code
required

Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).

Examplegenerated
{
"error": {
"code": "example",
"instance_id": "example",
"message": "example",
"parameters": "example"
}
}