Fingerprint a tenant's footprint (relocation verify gate)
const url = 'https://api.aerandil.com/v1/tenant-verify-digest?tenant_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.aerandil.com/v1/tenant-verify-digest?tenant_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \ --header 'Authorization: Bearer <token>'Return an independent per-table count and content checksum for the tenant’s objects / links / events (cloud proposal 0007 §4 step 5). The cross-cell relocation cutover job reads this from the source and the target cell and refuses to switch traffic until the two fingerprints agree — a re-query of each cell’s actual persisted state, independent of the import’s self-reported tally. The checksum covers exactly the portable columns the import preserves verbatim (events fold on the portable tenant_seq, never the source-local seq / commit_xid). Reads stay live in every write-mode.
Operator-level scope: tenant_admin:write (same surface as tenant export / import / write-mode / erasure).
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The tenant whose footprint is fingerprinted.
Responses
Section titled “Responses”The tenant’s per-table count + content checksum.
An independent content fingerprint of a tenant’s footprint for the relocation cutover verify gate (0007 §4 step 5). Two cells whose digests compare equal hold identical portable content for the tenant.
object
One table’s fingerprint: a row count plus a 64-hex SHA-256-XOR checksum over the table’s portable columns (all-zero hex when the table is empty for the tenant). The XOR fold is order- and collation-independent, so two cells need not return rows in the same order to compare equal.
object
64-hex content checksum; all-zero when the table is empty.
Row count for the tenant in this table.
One table’s fingerprint: a row count plus a 64-hex SHA-256-XOR checksum over the table’s portable columns (all-zero hex when the table is empty for the tenant). The XOR fold is order- and collation-independent, so two cells need not return rows in the same order to compare equal.
object
64-hex content checksum; all-zero when the table is empty.
Row count for the tenant in this table.
One table’s fingerprint: a row count plus a 64-hex SHA-256-XOR checksum over the table’s portable columns (all-zero hex when the table is empty for the tenant). The XOR fold is order- and collation-independent, so two cells need not return rows in the same order to compare equal.
object
64-hex content checksum; all-zero when the table is empty.
Row count for the tenant in this table.
Examplegenerated
{ "events": { "checksum": "example", "count": 1 }, "links": { "checksum": "example", "count": 1 }, "objects": { "checksum": "example", "count": 1 }, "tenant_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0"}Missing the tenant_admin:write scope. Tenant-level tokens MUST NOT carry this scope.
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
object
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).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
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" }}