---
title: "Read Placement Refusals"
method: GET
path: "/api/sandboxes/admin/placement-refusals"
tags: ["sandboxes"]
---

# Read Placement Refusals

`GET /api/sandboxes/admin/placement-refusals`

Placement refusals over a window, newest first.

The kind is ``placement_refused``. Every row carries a null ``sandboxId``
by nature: the refusal is the record that no box was ever created, so there
is none to name.

**Empty is a legitimate answer, and no longer means the producer is
missing.** ``_emit_placement_refused`` in ``context_gateway.py`` has three
call sites, so an empty window means no placement walk met a refusal --
not that nothing can record one. Stated because an endpoint that returns
nothing is otherwise indistinguishable from a broken one, and because the
note this replaces said the opposite for as long as the producer was
outstanding.

A row is also not a failed acquisition. One of those three call sites emits
immediately before returning a box that started, recording only that the
walk passed over a candidate first; the other two precede the allocation
error a client is waiting on. Nothing in the payload distinguishes them.

## Query parameters

- `hours` integer
- `limit` integer

## Response `200`

Successful Response

- SandboxEvent[]
  - `eventId` integer, required
  - `occurredAt` string, required
  - `recordedAt` string, required
  - `eventKind` 'placement_refused' | 'acquired' | 'ready' | 'readiness_timeout' | 'stopped' | 'resumed' | 'deleted' | 'superseded' | 'reconciled', required — Kind of transition recorded in the append-only sandbox event log.
  - `source` 'gateway' | 'reaper' | 'reconciler' | 'drain', required — Which component wrote a ledger event. ``RECONCILER`` matters on its own: it is what keeps a cause we inferred after the fact distinguishable from a cause we actually caused. ``DRAIN`` is separate from it for the same reason, one step removed. The drain synthesizes a ``superseded`` event when a colliding acquisition proves an earlier box is gone: inferred, so not ``GATEWAY``, but inferred from something a gateway *witnessed* rather than from sweeping a provider after the fact. Folding it into ``RECONCILER`` would inflate exactly the gateway-to-reconciler ratio that ``models/sandbox_ledger.py`` calls the ledger's own trustworthiness metric, and no later migration could separate the two again -- an enum value cannot be removed, and by then the rows are indistinguishable.
  - `causeOfDeath` 'idle_reap' | 'preemption' | 'health_check_kill' | 'readiness_failed' | 'lease_released' | 'lease_expired' | 'age_limit' | 'explicit_teardown' | 'superseded' | 'unknown_reconciled', required — Why a sandbox left its last open phase. ``UNKNOWN_RECONCILED`` is first-class and load-bearing. A hard preemption leaves nobody running to write a truthful cause, so the reconciler has to be able to say it does not know. Without this value the reconciler is forced to pick a plausible cause instead, and every other cause in the ledger stops being trustworthy.
  - `sandboxId` string, nullable, required
  - `sandboxAlias` string, required
  - `payload` object, required

## Other responses

- `422` — Validation Error

## Changes

- **2026-09-18** `abf76937a751` — 4 warning, 2 info
  - added the new `age_limit` enum value to the `items/causeOfDeath/anyOf[subschema #1: CauseOfDeath]/` response property for the response status `200`
  - added the new `lease_expired` enum value to the `items/causeOfDeath/anyOf[subschema #1: CauseOfDeath]/` response property for the response status `200`
  - added the new `lease_released` enum value to the `items/causeOfDeath/anyOf[subschema #1: CauseOfDeath]/` response property for the response status `200`
  - added the new `readiness_failed` enum value to the `items/causeOfDeath/anyOf[subschema #1: CauseOfDeath]/` response property for the response status `200`
  - …2 more
- **2026-09-10** `3a8d4a28ae93` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/quadrillion/apis/quadrillion-cloud-api/changes/api/sandboxes/admin/placement-refusals/get.md)

---

[API](https://skmtc.dev/quadrillion/apis/quadrillion-cloud-api.md) · [All operations](https://skmtc.dev/quadrillion/apis/quadrillion-cloud-api/llms.txt) · [OpenAPI document](https://skmtc.dev/quadrillion/apis/quadrillion-cloud-api/revisions/d61e2ec5a271?raw)
