Internal API

This is the machine-facing API that connects the edge Workers to AVERASE: the engine Worker verifies a device token at the edge, then forwards each call here with an HMAC signature. Customers never call these endpoints directly — the erasure engine and hotswap station drive them through the Worker — but the contract is documented in full because it defines everything a wipe session produces, and because the sandbox mirrors it endpoint-for-endpoint so you can exercise the whole flow locally.

Authentication

Every request to /internal/* must carry two headers:

  • Name
    X-Averase-Timestamp
    Type
    string
    Description

    Unix time in seconds (digits only, up to 12). Requests are rejected when the timestamp is more than ±300 seconds from server time.

  • Name
    X-Averase-Signature
    Type
    string
    Description

    sha256= followed by the lowercase hex HMAC-SHA256 of the string "{timestamp}.{raw body}", keyed with the shared internal API secret. The signature covers the exact raw request bytes — sign the body you send, not a re-serialization of it.

A missing header, a stale timestamp, or a signature mismatch returns 401:

{ "error": "unauthorized" }

If the server has no internal API secret configured, the entire /internal/* namespace answers 503 — the API fails closed rather than accepting unsigned traffic.

Signing a request

TS=$(date +%s)
BODY='{"jti":"0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b","account_id":"acct_demo"}'
SIG=$(printf '%s.%s' "$TS" "$BODY" \
  | openssl dgst -sha256 -hmac "$INTERNAL_API_SECRET" -hex | awk '{print $NF}')

curl -X POST https://averase.com/internal/tokens/verify \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d "$BODY"

Deny reasons

The two /internal/tokens/* endpoints run the full license-token decision ladder, evaluated strictly in this order — the first match wins:

ReasonMeaning
disabledMAESON staff kill switch. Outranks every other status; account admins cannot lift it.
revokedThe account admin revoked the token. Permanent unless the admin reinstates it.
suspendedThe account admin suspended the token. Reversible from the ISO control column.
account_inactiveThe account's subscription has lapsed.
quota_exceededThe token's use_count has reached its quota_limit.

A deny returns 403; an unknown jti — or a supplied account_id that doesn't match the token's account — returns 404. The other endpoints (assets, wipe_results, chassis_maps) do not run the full ladder: they check only that the token's status is active, answering 403 with {"error": "token revoked"} (or suspended/disabled) otherwise.


POST/internal/tokens/verify

Verify a token

The boot-unlock check. The kiosk boots into a hard lock and calls this once it is online; only an affirmative allow unlocks the UI, for that boot. It applies the same decision ladder as check-in but is unmetered — booting isn't wiping, so it never touches quota. On allow it only updates the token's last_seen_at (a heartbeat).

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID (the jti claim from the device token).

  • Name
    account_id
    Type
    string
    Description

    Optional cross-tenant defense. When present, a mismatch with the token's account returns 404 — never a silently widened lookup.

Responses

  • 200 — allowed. account is the account's display name; quota_remaining is null when the token is unlimited.
  • 403 — denied, with a reason from the table above. Fires the wipe_session_blocked webhook with phase "verify".
  • 404 — unknown token or mismatched account_id.

Note the asymmetry with check-in: verify returns account, validate returns job_id — never both.

Request

POST
/internal/tokens/verify
curl -X POST https://averase.com/internal/tokens/verify \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{"jti":"0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b","account_id":"acct_demo"}'

200 — allowed

{
  "allow": true,
  "status": "active",
  "account": "Acme ITAD, LLC",
  "quota_remaining": null
}

403 — denied

{
  "allow": false,
  "status": "revoked",
  "reason": "revoked",
  "quota_remaining": 0
}

404 — unknown

{
  "allow": false,
  "status": "unknown",
  "reason": "not_found"
}

POST/internal/tokens/validate

Check in before a wipe

The metered pre-wipe check-in. Same request body and same decision ladder as verify, with two differences: an allow atomically increments the token's use_count (a single-writer SQL increment, so concurrent check-ins can't double-spend quota), and the response carries a fresh job_id — the UUID that ties the eventual wipe result back to this check-in and makes wipe-result submission idempotent.

quota_remaining is computed after the increment; null means unlimited.

This is the fail-closed gate: a deny, an unprovisioned stick, or any network failure blocks the wipe. On allow it fires the wipe_session_ready webhook; on deny, wipe_session_blocked with phase "checkin".

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID.

  • Name
    account_id
    Type
    string
    Description

    Optional cross-check, as on verify.

Responses

  • 200 — allowed, quota consumed, job_id issued.
  • 403 / 404 — same shapes and reasons as verify (phase "checkin" on the blocked webhook).

Request

POST
/internal/tokens/validate
curl -X POST https://averase.com/internal/tokens/validate \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{"jti":"0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b","account_id":"acct_demo"}'

200 — allowed

{
  "allow": true,
  "status": "active",
  "quota_remaining": 1,
  "job_id": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b"
}

403 — denied

{
  "allow": false,
  "status": "revoked",
  "reason": "revoked",
  "quota_remaining": 0
}

POST/internal/assets

Report an asset

The once-per-boot hardware report: the complete serialized fingerprint plus internal storage for the machine the kiosk booted on. This is what populates /webapp/inventory.

Upsert semantics

Assets are upserted one row per physical machine per account, keyed by hardware_uid = [system.uuid, system.serial].join("/") (falling back to record_id when DMI identity is missing). The first sighting records who reported it (user, license token, ISO download) and first_seen_at; every subsequent boot updates record_id, engine_version, the full fingerprint document, and last_booted_at.

Alongside the raw document, a set of promoted columns is refreshed on every boot for grids and the public API: manufacturer, model, serial_number, board_model/board_serial, asset_tag, bios_version, tpm_version, firmware_mode, secure_boot, cpu_model/cpu_cores/cpu_threads, memory_total_bytes, gpu, storage_summary, storage_serials, and battery_health_pct (the minimum across batteries).

Fires the asset_reported webhook on the machine's first boot only — repeat boots update the stored asset silently.

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID. Required.

  • Name
    record_id
    Type
    string
    Description

    The boot record id, e.g. CW-20260726-210639. Required.

  • Name
    engine_version
    Type
    string
    Description

    The engine build reporting the machine.

  • Name
    fingerprint
    Type
    object
    Description

    The complete hardware document: system (manufacturer, product, serial, uuid), cpu, storage, memory, batteries, and the rest of the collected sections. Required.

Responses

  • 201 — upserted (created or refreshed).
  • 403{"error": "token revoked"} (or suspended/disabled).
  • 404{"error": "unknown token"}.
  • 422{"error": "missing record_id or fingerprint"}.

Request

POST
/internal/assets
curl -X POST https://averase.com/internal/assets \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{
    "jti": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "record_id": "CW-20260812-000117",
    "engine_version": "1.0.0",
    "fingerprint": {
      "system": {
        "manufacturer": "Dell Inc.",
        "product": "Latitude 5540",
        "serial": "74HRKY3",
        "uuid": "4c4c4544-0034-5a10-8052-b9c04f4b5933"
      },
      "cpu": { "model": "13th Gen Intel(R) Core(TM) i5-1335U" },
      "memory": { "total_bytes": 17179869184 },
      "storage": [
        {
          "model": "PM9B1 NVMe Samsung 512GB",
          "serial": "S6MZNF1WA04527"
        }
      ]
    }
  }'

201 — upserted

{
  "ok": true,
  "asset_id": "asset_Mlrnd05DOeK6qILJp1gE9bN3"
}

422

{ "error": "missing record_id or fingerprint" }

POST/internal/assets/notes

Attach operator notes

Attaches the kiosk operator's free-text notes to an already-reported asset, addressed by the boot's record_id. Fires no webhook.

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID.

  • Name
    record_id
    Type
    string
    Description

    The boot record id of the asset the notes belong to.

  • Name
    notes
    Type
    string
    Description

    The operator's notes.

Responses

  • 200 — saved.
  • 403 — token not active.
  • 404{"error": "unknown token"} or {"error": "unknown asset"} (the boot's asset report must land first).

Request

POST
/internal/assets/notes
curl -X POST https://averase.com/internal/assets/notes \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{
    "jti": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "record_id": "CW-20260812-000117",
    "notes": "Chassis dent on left corner; otherwise clean."
  }'

200

{
  "ok": true,
  "asset_id": "asset_Mlrnd05DOeK6qILJp1gE9bN3"
}

POST/internal/assets/tests

Submit hardware test results

Records the kiosk's hardware test results against the asset. Each submission replaces the whole snapshot — send the complete set every time, not a delta. Fires the hardware_tests_completed webhook.

Wire ids and statuses

tests is an object keyed by wire id, each value { "status": ..., "detail": ... }:

Wire idStatuses
keyboard, display, usb_ports, battery, wifi_adapter, bluetooth, webcam, audio, touchscreenpassed, failed, not_started, not_applicable (plus detected for detection-only checks)

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID.

  • Name
    record_id
    Type
    string
    Description

    The boot record id of the tested asset.

  • Name
    tests
    Type
    object
    Description

    Map of wire id → {status, detail}. detail is optional free text (e.g. a failure note).

Responses

  • 200 — snapshot replaced.
  • 403 / 404 — as on notes.
  • 422{"error": "invalid tests"}.

Request

POST
/internal/assets/tests
curl -X POST https://averase.com/internal/assets/tests \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{
    "jti": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "record_id": "CW-20260812-000117",
    "tests": {
      "keyboard": { "status": "passed" },
      "webcam": { "status": "failed", "detail": "no image" },
      "touchscreen": { "status": "not_applicable" }
    }
  }'

200

{
  "ok": true,
  "asset_id": "asset_Mlrnd05DOeK6qILJp1gE9bN3"
}

POST/internal/wipe_results

Submit a wipe result

One POST per erased drive, carrying the full evidence of the wipe. The endpoint is idempotent on job_id: the first receipt creates the record and returns 201; a re-POST with the same job_id returns 200 with the existing record and fires nothing again. That makes retries safe — the engine can resend after a network blip without duplicating results, quota, or certificates.

On first receipt only, when the result is certifiable — wipe_status absent or completed, and validation absent or approved — AVERASE enqueues certificate generation (a signed PDF uploaded to private storage) and fires the wipe_session_completed webhook. Non-certifiable results are persisted and listed on /webapp/wipes but never certify.

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID. Required.

  • Name
    job_id
    Type
    string
    Description

    The UUID issued by /internal/tokens/validate. Required — the idempotency key.

  • Name
    drive_serial
    Type
    string
    Description

    Serial number of the erased drive.

  • Name
    drive_model
    Type
    string
    Description

    Drive model string.

  • Name
    drive_capacity_gb
    Type
    integer
    Description

    Capacity in gigabytes (decimal).

  • Name
    wipe_method
    Type
    string
    Description

    The sanitization method, e.g. NIST 800-88 R2 Purge.

  • Name
    passes_completed
    Type
    integer
    Description

    Overwrite passes completed; null for cryptographic and block erase.

  • Name
    started_at
    Type
    timestamp
    Description

    Wipe start time (ISO-8601).

  • Name
    completed_at
    Type
    timestamp
    Description

    Wipe finish time (ISO-8601).

  • Name
    verification_hash
    Type
    string
    Description

    SHA-256 over the re-read verification bytes.

  • Name
    wipe_status
    Type
    string
    Description

    completed, failed, or cancelled. Absent reads as legacy completed.

  • Name
    technique
    Type
    string
    Description

    The concrete technique used, e.g. NVMe Sanitize — crypto erase.

  • Name
    validation
    Type
    string
    Description

    approved or rejected; absent reads as approved.

  • Name
    disposition
    Type
    string
    Description

    sanitized, review, or destroy.

  • Name
    markings_removed
    Type
    boolean
    Description

    Whether media markings were removed.

  • Name
    tool_components
    Type
    string
    Description

    Tooling used, e.g. nvme-cli 2.4.

  • Name
    verification_result
    Type
    string
    Description

    Human-readable verification outcome, e.g. Pass — 32/32 fingerprint sectors overwritten.

Responses

  • 201 — first receipt; certificate generation enqueued when certifiable.
  • 200 — duplicate job_id; the existing record, no side effects.
  • 403 — token not active.
  • 404{"error": "unknown token"}.
  • 422{"error": "missing job_id"}.

certificate_status in the response is the current state of the certificate pipeline (pending, generating, complete, failed) — don't poll it; the certificate_generated webhook announces completion.

Request

POST
/internal/wipe_results
curl -X POST https://averase.com/internal/wipe_results \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{
    "jti": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "job_id": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "drive_serial": "S64FNE2R504071",
    "drive_model": "SAMSUNG MZVL2512HDJD-00BL2",
    "drive_capacity_gb": 512,
    "wipe_method": "NIST 800-88 R2 Purge",
    "passes_completed": null,
    "started_at": "2026-08-12T17:03:01Z",
    "completed_at": "2026-08-12T17:40:58Z",
    "verification_hash": "1f7c9d0a4b2e8f6c3a5d7e9b1c4f8a2d6e0b3c7f9a1d5e8b2c6f0a4d7e9b1c4f",
    "wipe_status": "completed",
    "technique": "NVMe Sanitize — crypto erase",
    "validation": "approved",
    "disposition": "sanitized",
    "markings_removed": true,
    "tool_components": "nvme-cli 2.4",
    "verification_result": "Pass — 32/32 fingerprint sectors overwritten"
  }'

201 — first receipt

{
  "ok": true,
  "wipe_result_id": "wr_01J4R2M8K3P7QS5TV9WX6YZABC",
  "certificate_status": "pending"
}

422

{ "error": "missing job_id" }

POST/internal/chassis_maps

Save a chassis map

Saves the hotswap station's bay map — the mapping-wizard output that ties physical bay labels to controller lanes — keyed to the chassis by its DMI identity (system.uuid + system.serial). The endpoint first records the chassis itself as an asset (so the chassis appears in /webapp/inventory), then stores the map.

Bay normalization

Each entry in map.bays must have a non-blank lane and label; entries missing either are dropped. An optional connector is kept only when it is an object. If normalization leaves no usable bays, the request fails with 422.

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID. Required.

  • Name
    record_id
    Type
    string
    Description

    The boot record id. Required.

  • Name
    engine_version
    Type
    string
    Description

    The station build saving the map.

  • Name
    fingerprint
    Type
    object
    Description

    The chassis hardware document — its system DMI section supplies the identity key. Required.

  • Name
    map
    Type
    object
    Description

    { "name": ..., "bays": [{ "lane", "label", "connector"? }] }.

Responses

  • 201 — map saved (and chassis asset upserted).
  • 403 / 404 — as elsewhere.
  • 422{"error": "missing record_id or fingerprint"} or {"error": "map has no usable bays"}.

Request

POST
/internal/chassis_maps
curl -X POST https://averase.com/internal/chassis_maps \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{
    "jti": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "record_id": "CW-20260812-000117",
    "engine_version": "1.0.0",
    "fingerprint": {
      "system": {
        "manufacturer": "Supermicro",
        "product": "SSG-6029P",
        "serial": "S424521X9B00432",
        "uuid": "9c7e2f10-44aa-4b7d-9d3e-1f2a3b4c5d6e"
      }
    },
    "map": {
      "name": "Rack 2 shelf A",
      "bays": [
        { "lane": "05:00.0/phy14", "label": "Bay 1" },
        { "lane": "05:00.0/phy15", "label": "Bay 2" }
      ]
    }
  }'

201 — saved

{
  "ok": true,
  "chassis_map_id": "cmap_01J4R5P0M6S9UV8WX2YZ3ABCDE",
  "asset_id": "asset_01J4R5NZ7Q4T6VW9XA1BC2DEFG"
}

422

{ "error": "map has no usable bays" }

POST/internal/chassis_maps/lookup

Look up a chassis map

Fetches a previously saved bay map by chassis DMI identity — the hotswap station calls this at every boot so bay labels survive re-imaging. It is a read modelled as a POST because the HMAC scheme signs the request body.

Request body

  • Name
    jti
    Type
    string
    Description

    The license token's UUID.

  • Name
    system
    Type
    object
    Description

    The chassis DMI identity: { "uuid", "serial" }.

Responses

Always 200: {"found": true, "map": {...}} when a map exists for this account and chassis, {"found": false} otherwise — a station booting an unmapped chassis simply runs the mapping wizard.

Request

POST
/internal/chassis_maps/lookup
curl -X POST https://averase.com/internal/chassis_maps/lookup \
  -H "Content-Type: application/json" \
  -H "X-Averase-Timestamp: $TS" \
  -H "X-Averase-Signature: sha256=$SIG" \
  -d '{
    "jti": "0e6f4a8c-2d1b-4e5f-9a7c-8b6d5e4f3a2b",
    "system": {
      "uuid": "9c7e2f10-44aa-4b7d-9d3e-1f2a3b4c5d6e",
      "serial": "S424521X9B00432"
    }
  }'

200 — found

{
  "found": true,
  "map": {
    "name": "Rack 2 shelf A",
    "bays": [
      { "lane": "05:00.0/phy14", "label": "Bay 1" },
      { "lane": "05:00.0/phy15", "label": "Bay 2" }
    ]
  }
}

200 — not found

{ "found": false }

  • Sandbox — run this whole API locally, mint test tokens, and watch webhooks fire.
  • License tokens — the entitlement model behind verify and validate.
  • Certificates — what happens after a wipe result lands.

Was this page helpful?