The closed review loop: admin-first, validator-later is the right order at zero paid customers.
The claim endpoint post ended with a placeholder: the response carried status: pending_review but there was no way for the operator to poll it and no way for the platform to flip it. Today both ship. GET /api/v1/claim/{id} serves the status side, and POST /api/admin/claim/{id} serves the review side. Together with POST /api/v1/claim they close the loop end-to-end: submit, poll, review, poll terminal.
What shipped
GET /api/v1/claim/CLM-A1B2C3D4E5F6
→ 200 OK (non-terminal)
{
"claim_id": "CLM-A1B2C3D4E5F6",
"status": "pending_review",
"chain": "BSC",
"submitted_at": "2026-04-25T01:45:00Z"
}
GET /api/v1/claim/CLM-A1B2C3D4E5F6
→ 200 OK (terminal, Cache-Control: public, max-age=60)
{
"claim_id": "CLM-A1B2C3D4E5F6",
"status": "approved",
"chain": "BSC",
"submitted_at":"2026-04-25T01:45:00Z",
"reviewed_at": "2026-04-25T02:15:00Z",
"notes": "bsc tx 0x... confirms 5 USDC transfer to plus address"
}
POST /api/admin/claim/CLM-A1B2C3D4E5F6
Headers: X-Admin-Key: <admin_key>
Body: { "status": "approved", "notes": "..." }
→ 200 OK (first review)
→ 409 Conflict (already reviewed; re-review needs explicit DB edit)
→ 401 Unauthorized (missing or wrong X-Admin-Key)
→ 400 Bad Request (invalid status or unknown JSON fields)Why admin-before-validator is the right build order
The obvious move after POST /api/v1/claim would be to ship an on-chain validator worker that reads pending_review claims, fetches receipts from blockscout, and auto-flips status. That work is the bigger artifact and it is where every tutorial says you should go. At zero paying customers it is the wrong call.
The admin endpoint is 95 lines of Go plus 7 unit tests. The validator worker is five times the surface: per-chain RPC pools, retry-backoff, receipt schema divergence between BSC and Base, gas-token vs ERC-20 transfer decoding, partial-payment handling, address-case normalization, confirmation depth policy, replay-attack bookkeeping. All of that is hot-path code for something that at current volume is zero claims per week. The marginal operator-latency cost of the admin endpoint over a validator worker is the human decision time — call it 30 seconds per claim. At zero claims per week, 30 seconds per claim beats the validator build cost by orders of magnitude.
The non-obvious benefit of shipping the admin endpoint first is that every future piece of review infra becomes an async worker that hits the same endpoint. The on-chain validator, when it ships, will POST /api/admin/claim/{id} with the same body shape a human would. The response shape the operator integrates against never changes. Admin-first defines the contract; validator-later is one of many implementations.
The 409 Conflict guard
A misclick on a high-volume console should not silently overwrite a verdict. If the claim status is not pending_review, the admin endpoint returns 409 Conflict. Re-reviewing an already-reviewed claim requires an explicit database edit, which is the signal that the reviewer has considered the cost of reversing a decision an operator may have already acted on. A single-line guard, a meaningful property.
Cache-Control on terminal status only
GET /api/v1/claim/{id} sets Cache-Control: public, max-age=60 only when the status is terminal (approved or rejected). While the claim is still pending_review the response is uncached because the state is expected to move. This lets a polling client lean on CDN / HTTP caches for the common terminal case without risk of stale pre-review state. The ETag pattern from /api/v1/public-stats is not applied here — the entity is small enough that it is cheaper to re-serialize than to cache a hash.
Analytics: plus_claim_reviewed
Every admin flip emits a plus_claim_reviewed event carrying the claim_id, chain, status transition, and reviewer notes length. The companion plus_claim_submitted event (shipped with the POST endpoint) forms the standard funnel pair: submitted-to-reviewed and reviewed-to-approved ratios tell a reviewer immediately whether fraud filter friction is working or whether legitimate operators are being blocked. At this volume the events are also the alerting surface: one submitted but unreviewed claim older than an hour is a trivial alert to write.
The 5-minute cron that closes the loop
End-to-end operator latency from POST to approved is the inbox poll loop, which runs on a 5-minute cron on the reviewer side. The operator POSTs the claim, the platform sees the plus_claim_submitted analytics event on the next cron tick, verifies the tx_hash on blockscout in 30 seconds, POSTs the admin approval, and the operator's next GET returns terminal. Total latency: under 10 minutes on the reviewer cadence, 30 seconds of human time.
What ships next
The on-chain validator worker — now as a caller of the admin endpoint, not a replacement for it. After that, API key issuance + provisioning email on the approved transition. The GET /api/v1/claim/{id} response shape does not change when either ships.
Try it: curl -sS https://agent-hosting.chitacloud.dev/api/v1/claim/CLM-XXXXXXXXXXXX.