Get a report upload URL

Mints a presigned PUT URL for one report upload. Request { reportId }; response
{ uploadUrl, expiresAt, requiredContentType }. 400 on a malformed/unknown-field request; 403
when enrollment status ≠ Active; 429 when the per-device daily quota (REQ-072, quota_exceeded)
or the per-tenant aggregate rate (REQ-075, rate_limited) is reached; 503 when the ingest
pipeline is not provisioned here or signing fails.

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Body Params

Request body for POST /ingest: the scanner-generated reportId plus the optional check-in
fields the scanner piggybacks (checkin.md §2) — the three T61 bootstrap-outcome fields, the three
T124/D223 + D225 scheduler-slot fields, and the T258 Mine.Portal.Module.Aispm.Api.Portal.AispmIngestMintRequest.BootstrapVersion. The mint contract
stays strict — any field NOT named here is captured by Mine.Portal.Module.Aispm.Api.Portal.AispmIngestMintRequest.ExtraFields and rejected (400)
— but every check-in field is part of the accepted set, and any value one carries is tolerated (it
is normalized at the boundary, never a 400 — REQ-AISPM-064).


DEPLOY ORDERING IS A HARD GATE for every field added to this DTO — the scheduler-slot three

and Mine.Portal.Module.Aispm.Api.Portal.AispmIngestMintRequest.BootstrapVersion alike. Because an undeclared field is rejected 400 before the
check-in is recorded at all, an out-of-order rollout loses the report upload AND the liveness beat, after
which the device also reads as stopped-reporting. This DTO must merge and DEPLOY to a DC before any
scanner emitting those fields reaches devices pointed at that DC.

string | null

The report identifier, format YYYYMMDDTHHMMSSZ-<uuid> (≤53); the idempotency key and object-key segment.

string | null

Optional (T61-A) last bootstrap outcome from state.json.lastOutcome:
launched|ran-cached|no-scanner|verify-failed|scanner-failed. Boundary-mapped, never validated
as a strict enum — an unknown value maps to NoScanner (REQ-AISPM-064).

string | null

Optional (T61-A) cache integrity of that cycle: verified|reverify-failed|absent|null.
Combined with Mine.Portal.Module.Aispm.Api.Portal.AispmIngestMintRequest.LastBootstrapOutcome at the boundary to derive CacheTampered.

string | null

Optional (T61-A) device-clock run time of that cycle (ISO-8601 UTC). Best-effort context; an
unparseable value is dropped, never a 400.

string | null

Optional (T124/D223) the slot the device's OS scheduler is CONFIRMED to be running, from
state.json.schedulerSlot: a device-local 24h HH:MM token, no timezone (D197). Normalized
by M:Mine.Portal.Module.Aispm.Services.AispmSchedulerSlotMapper.NormalizeSlot(System.String) — a malformed value stores NULL, never a
400.

string | null

Optional (T124/D223) the slot still waiting to reach the running scheduler, from
state.json.schedulerSlotPending: HH:MM, or the literal unknown a damaged pending
marker legitimately emits. Any other non-empty value normalizes to unknown (something IS
outstanding), never a 400.

string | null

Optional (D225) how many scheduler fires the pending change has survived. A string, not a
number
— every field in this check-in family is a string parsed at the boundary (lastRunAt
is a timestamp carried the same way), and a typed numeric member would make the deserializer THROW on a
malformed value and 400 the whole mint, losing the report upload and the liveness beat. Normalized to
int? by M:Mine.Portal.Module.Aispm.Services.AispmSchedulerSlotMapper.ParsePendingCycles(System.String), which tolerates any string
content.

The string type is still a wire requirement, and it is enforced producer-side, not here.
An unquoted JSON number fails model binding under [ApiController] (JsonException → 400)
before the check-in is recorded — so "a malformed value never 400s" holds for malformed
content, not for a wrong JSON type. The scanner's own typeof === "string" gate is
what keeps that unreachable; no lenient converter is added here on purpose.

string | null

Optional (T258) the version of the bootstrap script actually executing on the device, taken
from the bootstrap's launch handoff — not from state.json, which records the version of
the run BEFORE this one and is therefore stale at exactly the moment an update lands. A three-component
dotted numeric token; normalized by
M:Mine.Portal.Module.Aispm.Services.AispmBootstrapOutcomeMapper.NormalizeBootstrapVersion(System.String), which stores an unrecognised shape
as NULL rather than a value nothing can compare — never a 400.

Headers
string
enum
Defaults to application/json-patch+json

Generated from available request content types

Allowed:
Response
200

Success

Language
Credentials
Header
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here!