Aere Cloud · API reference

One key. The whole network.

Base URL https://cloud.aere.network/v1. Authentication is an API key whose hash lives in an on-chain subscription: there is no signup form and no server-side account database to breach. Every endpoint returns JSON. Every claim in these docs can be re-checked against chain 2800.

Official SDK

Skip the raw HTTP: the official clients wrap every route below, with zero dependencies, in five languages. They are installed from the repository: they are not on the npm or PyPI registries yet, and a package there with a name like ours is not ours.

npm install git+https://git.aere.network/aere-network/aere-cloud-sdk.git                          # JavaScript, Node 18+ and browsers
pip install "git+https://git.aere.network/aere-network/aere-cloud-sdk.git#subdirectory=python"   # Python
go get git.aere.network/aere-network/aere-cloud-sdk/go@main                                        # Go

Java: build java/ in the same repository with the JDK alone (built against the Java 8 API since 1.6.1). .NET: build csharp/Aere.Cloud with the .NET SDK (8 or later). Go modules are also served by the Go module proxy (@v1.7.0). All five have the same routes and semantics, and none of them follows redirects, so your key is never sent to a host you did not name.

import { AereCloud } from '@aere/cloud';
const aere = new AereCloud({ apiKey: process.env.AERE_KEY });
const anchors = await aere.anchors(5);
const finality = await aere.finality(); // the block you may treat as final (SDKs 1.5.2)
const { verdict } = await aere.verify(envelope); // Trust API: VALID / INVALID / PARTIAL (SDKs 1.6.0)
const id = await aere.identityVerify({ presentation, audience, nonce, trustedIssuers }); // identity (SDKs 1.7.0)
const { valid } = await aere.pqVerify({ scheme: 'ml-dsa-44', publicKey: '0x…', signature: '0x…', message: '0x…' });
const receipt = await aere.notarize('0x' + sha256Hex);

Source and README: git.aere.network/aere-network/aere-cloud-sdk. It also ships verifyWebhook(rawBody, signatureHeader, secret) so you never hand-roll the HMAC check.

Overview

Aere Cloud exposes three families of endpoints behind one API key:

  • JSON-RPC: keyed access to chain 2800 with per-plan rate limits, full eth_*/net_*/web3_* namespaces plus read-only QBFT methods.
  • Post-quantum verification: NIST post-quantum signature verdicts computed by the chain’s native precompiles (live since block 9,189,161), not by application code.
  • Chain data: the validator set, chain head, and the post-quantum anchor certificates, proven and independently verifiable: every 128th block (every 32nd block until block 17,225,968, on 2026-09-05)’s Falcon-512 certificate digest and seal count, parsed for you.

Authentication

Send your key in the x-api-key header on every request except /v1/health.

x-api-key: ak2800.<your 0x address>.<secret>

The key format is load-bearing: the address tells the gateway whose subscription to check. On every request the gateway computes keccak256 of the whole key string and asks the subscription contract check(address, keyHash) on chain 2800. If the chain cannot be reached, the gateway answers 503 and refuses to guess: it fails closed, never open.

We never see or store your key. It is generated in your browser (or by you), and only its keccak-256 hash is registered on-chain. There is no key table on any server, so there is nothing to leak. If you lose the key, rotate to a new one: rotation is free, only gas.

Subscribing

The free trial is fully self-serve in the subscribe panel: connect a wallet, take the key, done. Paid plans, while AERE is pre-listing, are invoiced in USDC or EUR: email [email protected] (the panel prefills the order) and we activate your subscription on-chain via grantSubscription when payment clears; your account never needs gas. Everything the panel does is plain contract calls you can also make yourself:

# 1. generate a key and hash it (any keccak-256 tool works)
KEY="ak2800.0xYourAddress.$(openssl rand -base64 24 | tr '+/' '-_' | tr -d '=')"
HASH=$(cast keccak "$KEY")

# 2. read the plan's on-chain price (the dollar list price at the published reference rate)
cast call 0xfA2375F5c30d25e0b952F5Ac07Bc292aD3C20433 \
  "plans(uint64)(string,uint256,bool)" 0 --rpc-url https://rpc.aere.network

# 3. subscribe: planId, months (1-12), key hash; pay price x months exactly.
#    plan 5 is the free trial: a real key for the cost of gas alone
cast send 0xfA2375F5c30d25e0b952F5Ac07Bc292aD3C20433 \
  "subscribe(uint64,uint256,bytes32)" 5 1 "$HASH" \
  --value 0 --rpc-url https://rpc.aere.network --private-key $PK

# 4. use the key
curl -s https://cloud.aere.network/v1/account -H "x-api-key: $KEY"

Renewals extend from your current expiry, never from the payment date; pass 0x0 as the hash to keep your existing key. List prices are in US dollars; the contract stores each plan’s price as the AERE amount at the published reference rate ($0.05/AERE until market listing, then market, applied to new subscriptions only): always read the exact amount from plans(planId) before paying. Enterprise agreements skip the token and are invoiced in EUR or USDC.

Health

GET/v1/health  no key

$ curl -s https://cloud.aere.network/v1/health
{"ok":true,"chainId":2800,"block":15220078}

JSON-RPC

POST/v1/rpc

A JSON-RPC 2.0 endpoint on chain 2800; single requests and batches both work. Allowed methods: everything in eth_* (including eth_sendRawTransaction), net_*, web3_*, and the read-only QBFT set (qbft_getValidatorsByBlockNumber, qbft_getValidatorsByBlockHash, qbft_getSignerMetrics, qbft_getPendingVotes). Validator-vote methods are refused on every tier, paid included.

$ curl -s https://cloud.aere.network/v1/rpc \
  -H "content-type: application/json" -H "x-api-key: $KEY" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
{"jsonrpc":"2.0","id":1,"result":"0xe83aa9"}

A disallowed method answers inside the JSON-RPC envelope, so batch positions are preserved:

{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not allowed on this endpoint"}}
Mind the 512-block state window: public endpoints keep world state for 512 blocks and eth_getTransactionCount answers 0x0 beyond it instead of erroring. Details in the chain RPC docs.

WebSocket subscriptions

WSS/v1/ws

Live JSON-RPC over WebSocket, including eth_subscribe for newHeads and logs: a new head arrives roughly every half second. The WS route exposes the eth/net/web3 namespaces only, so validator-vote methods do not exist on this path at all. Authenticate one of two ways:

  • Header (servers, preferred): x-api-key: ak2800.… on the upgrade request.
  • Query (browsers, which cannot set WS headers): wss://cloud.aere.network/v1/ws?key=ak2800.…: access logging is disabled on this route so the key is not written to server logs; still prefer the header wherever you control the client.
// node, with the ws package
const ws = new WebSocket('wss://cloud.aere.network/v1/ws', { headers: { 'x-api-key': KEY } });
ws.on('open', () => ws.send(JSON.stringify(
  { jsonrpc: '2.0', id: 1, method: 'eth_subscribe', params: ['newHeads'] })));
ws.on('message', (d) => console.log(JSON.parse(d).params?.result?.number));
// → a new block number roughly every 0.5s

A bad or missing key is refused at the door with 403/401 before any socket to the node is opened.

Post-quantum verification

POST/v1/pq/verify

The verdict is computed by the chain’s native precompiles via eth_call: the response tells you which precompile answered and at what block height. Send hex fields with 0x prefixes.

schemeprecompilerequest fieldsnotes
ml-dsa-440x…0ae3publicKey (1312 B), signature (2420 B), messageNIST ML-DSA-44 (Dilithium2)
slh-dsa-128s0x…0ae4publicKey (32 B), signature (7856 B), messageNIST SLH-DSA-SHA2-128s; ~11.8 KB requests are fine here
falcon-5120x…0ae1publicKey (897 B), signedMessageFalcon reference signed-message blob
falcon-10240x…0ae2publicKey (1793 B), signedMessagesame shape as falcon-512

Internal or external interface (2026-09-17). The ML-DSA and SLH-DSA precompiles verify the FIPS internal interface: the message is checked exactly as given (that is what the NIST ACVP sigVer internal vectors exercise). A standard external signature, the kind every library, HSM and the AIP-20 tooling produces, is made over M' = 0x00 || len(ctx) || ctx || M. Pass "interface": "external" (and optionally "context", 0x-hex, at most 255 bytes) and the gateway builds M' for you; the response echoes interface. Measured on chain for ML-DSA-44 with an AIP-20 vector: raw message false, external interface true, corrupted signature false, another context false. For SLH-DSA-128s the same encoding follows FIPS 205 and has not yet been measured against an external vector; say so in your own tests.

# a real exchange, produced by this endpoint from a NIST ACVP vector
$ curl -s https://cloud.aere.network/v1/pq/verify \
  -H "content-type: application/json" -H "x-api-key: $KEY" \
  -d '{"scheme":"ml-dsa-44","publicKey":"0x…","signature":"0x…","message":"0x…"}'
{"valid":true,"scheme":"ml-dsa-44",
 "precompile":"0x0000000000000000000000000000000000000ae3",
 "block":15220111,"chainId":2800}

# flip one bit of the signature and the chain flips the answer
{"valid":false,"scheme":"ml-dsa-44", …}

Quantum readiness scan

POST/v1/pq/readiness  ·  GET/v1/pq/readiness/{domain}

Is a domain quantum-safe on the wire? The Aere Cloud host opens five real TLS connections to port 443 of the hostname (a classical TLS 1.3 baseline; a handshake offering only the hybrid post-quantum group X25519MLKEM768; one offering it first, to see preference; a TLS 1.2-only handshake; an HTTPS HEAD for HSTS), reads the served certificate chain, and returns a score, a verdict, the measured facts and concrete recommendations. Free, no key; results are cached for six hours per domain, scans are limited per client. Certificates are reported, not penalised: no public CA issues post-quantum certificates yet. Browser version: /quantum-readiness.html.

$ curl -s https://cloud.aere.network/v1/pq/readiness -H "content-type: application/json" -d '{"domain":"aere.network"}'
{"domain":"aere.network","measuredAt":"2026-09-17T20:48:44.940Z","from":"AERE Cloud, EU (Helsinki)",
 "score":75,"verdict":"partially prepared",
 "summary":{"tls13":true,"pqKeyExchange":"X25519MLKEM768","prefersPqWhenOffered":false,
  "tls12Accepted":true,"hsts":false,"harvestNowDecryptLater":"protected for TLS 1.3 clients that offer the hybrid group",
  "certificate":{"keyType":"EC/prime256v1","bits":256,"issuer":"Let's Encrypt","daysLeft":69}},
 "findings":[{"id":"pq-not-preferred","severity":"medium",…},{"id":"tls12-accepted","severity":"medium",…},{"id":"hsts-missing","severity":"low",…},{"id":"auth-classical","severity":"info",…}],
 "handshakes":{…}, "method":"…"}

Attested reports (keyed). Add "attest": true with your API key and the SHA-256 digest of the measured report is notarized on chain 2800, so the report carries a first-seen time that cannot be backdated and is covered by the validators’ post-quantum certificate at the next anchor. The response adds attestation: reportJson (the exact UTF-8 text that was hashed; recompute sha256(reportJson) in any language and it equals reportHash), txHash, block, firstSeenAt, and proof, the path of the Proof API record for it. Attesting without a key answers 401; the scan itself never needs one. Counted as one data request.

$ curl -s https://cloud.aere.network/v1/pq/readiness -H "x-api-key: $KEY" -H "content-type: application/json" -d '{"domain":"aere.network","attest":true}'
{ …the report…,
 "attestation":{"reportHash":"0x367a…021d","digest":"sha256 over reportJson, the exact UTF-8 text below","reportJson":"{…}",
  "txHash":"0x0c99…0ef1","block":19018082,"firstSeenAt":1789679286,"firstTime":true,
  "contract":"0x4aB392c4Aca7D9D4C16c0b60a9514c5025bd58c7","chainId":2800,"proof":"/v1/proof/0x367a…021d"}}

The whole perimeter of a domain

POST/v1/pq/readiness/perimeter (keyed)

One hostname says little about a company: the front page is usually behind a modern edge, while the API, the mail gateway and the login host are where classical-only TLS survives. This route measures every public host of a domain in one report: the hosts you name in hosts (labels such as "api", or full names, which must be the domain or under it) plus common prefixes (www, api, app, mail, login, auth, portal, vpn, cdn, admin, secure, shop, status, docs) tried through DNS unless "discover":false. Each host found goes through the same five handshakes as the single scan, at most 16 hosts per report.

$ curl -s https://cloud.aere.network/v1/pq/readiness/perimeter -H "x-api-key: $KEY" -H "content-type: application/json" \
    -d '{"domain":"example.com","hosts":["api","mail"]}'
{"domain":"example.com","generatedAt":"2026-09-18T09:50:00.000Z",
 "summary":{"hostsFound":5,"measured":4,"pending":0,"withoutTls":["mail.example.com"],"failedTransient":0,"notScannedOverLimit":0,
   "withPqKeyExchange":3,"withoutPqKeyExchange":["legacy.example.com"],"tls12Accepted":["legacy.example.com"],
   "worstScore":45,"averageScore":79,"soonestCertificateExpiry":{"host":"api.example.com","daysLeft":9,"validTo":"…"},
   "verdict":"partially prepared: some hosts are exposed to harvest-now-decrypt-later","complete":true},
 "hosts":[{"host":"api.example.com","measured":true,"score":90,"pqKeyExchange":"X25519MLKEM768","tls12Accepted":false,
           "certificate":{"keyType":"EC/prime256v1","issuer":"…","validTo":"…","daysLeft":9},"findings":[],"report":"/v1/pq/readiness/api.example.com"}, …],
 "pending":[],"notFound":[],"refused":[],"discovery":{"tried":13,"wildcardDns":false,"wildcardEchoesDropped":0,"note":"…"}}

It does not invent. The verdict covers measured hosts only and names the exposed ones. A host you named that does not resolve is listed in notFound; a guessed prefix that does not resolve is simply omitted. A host without TLS on port 443 (a mail server, say) is a definitive answer and is listed in withoutTls. In a zone with wildcard DNS every name resolves, so a guessed prefix that resolves to the same addresses as a random name is not evidence of a host: it is dropped and counted in wildcardEchoesDropped; name your real hosts. A host that resolves to an address that is not public is never connected to and appears in refused.

The request has a deadline. A host that swallows connections can hold a scan for most of a minute, so hosts still being measured when the deadline passes are returned in pending with summary.complete:false. Call again: finished scans are cached for six hours and return at once. With "attest":true the digest of a complete report is notarized on chain 2800 exactly like a single scan (an incomplete one answers 409 perimeter_incomplete: an attestation says “this is the measured perimeter”, not “part of it”), and the proof appears in the console beside your other proofs. SDKs 1.3.0: readinessPerimeter(domain, { hosts, discover, attest }), readiness_perimeter(domain, hosts=…, discover=…, attest=…).

Post-quantum adoption by sector

A weekly public series (readable page): what share of the most visited websites, government sites, universities and banks (.bank) negotiate hybrid post-quantum key exchange on their public TLS edge, measured with the same handshakes as the scanner above. Free, no key. GET /v1/pq/adoption returns the latest edition; GET /v1/pq/adoption/YYYY-MM-DD a dated one (404 no_edition if none). Each sector carries its sample rule, the counts selected, measured and not measured (by reason), and every share with numerator, denominator and a Wilson 95% interval; a sector with fewer than 30 measured hosts gets no share. Samples come from the Tranco list named in the edition, so the list can be rebuilt. No host is ever named: the per-host results are kept, and commitment.sha256 commits to them so they cannot be rewritten after publication.

Post-quantum finality of a block (AIP-21)

GET/v1/pq/finality/{block}?network=testnet  ·  GET/v1/pq/finality

Every block is committed with a Falcon-512 seal on each validator’s Commit message; those seals never reach the header (only every 128th block carries a certificate), so until 2026-09-18 the immediate post-quantum finality of a block was true and not observable. This route returns, for one block, the seals a validator heard, re-verified now against the anchored registry over the exact message the validators signed, and the verdict: post-quantum when at least the commit quorum of distinct validators verifies, partial below it, none when nothing verifies, unavailable when nothing was heard (outside the node’s retention window), unverifiable-form when the signed message cannot be rebuilt from the header. Free, no key. Testnet 28001 first: the answer comes from a testnet validator through a read-only door that accepts only this method; chain 2800 follows when the method reaches its validators. Verify each seal yourself: signedMessage is what was signed, the public key is the validator’s Falcon-512 key in the published registry epoch for that index.

$ curl -s "https://cloud.aere.network/v1/pq/finality/latest?network=testnet"
{"network":"testnet","chainId":28001,"blockNumber":2245120,"blockHash":"0x…",
 "validators":5,"quorum":4,"sealForm":"anchor","signedMessage":"0x…",
 "falconSealsHeard":4,"falconSealsVerified":4,"verifiedIndexes":[0,1,2,3],
 "falconSeals":[{"scheme":"falcon-512","index":0,"verified":true,"signature":"0x…"}, …],
 "hybridSeals":[], "finality":"post-quantum", "retentionBlocks":256,
 "answeredBy":"validator@8601", "source":"a testnet validator, through the read-only finality door; …", "aip":"AIP-21"}

Two independent implementations, one verdict (2026-09-18)

Testnet 28001 is validated by two client implementations (Besu-derived and Nethermind-derived), and both implement AIP-21. client=besu (default) asks a Besu validator, client=nethermind asks the Nethermind validator, and client=both asks each for the same block and reports agreement (the two records carry the same block hash, the same verdict and the same quorum) and postQuantumConfirmedByBoth (both say post-quantum on that hash: the flag to act on). Two clients that both answer unavailable for an old block agree, and the route says unavailable, never a guessed finality. A post-quantum finality claim that two independently written code bases confirm is a stronger fact than one implementation reporting on itself, and it is the form we recommend for anything you notarize or settle on.

$ curl -s "https://cloud.aere.network/v1/pq/finality/latest?network=testnet&client=both"
{"network":"testnet","chainId":28001,"client":"both","blockNumber":2251090,"blockHash":"0x…",
 "finality":"post-quantum","agreement":true,"postQuantumConfirmedByBoth":true,
 "agreementDetail":{"blockHash":true,"finality":true,"quorum":true,"verifiedIndexes":true},
 "besu":{"blockNumber":2251090,"finality":"post-quantum","falconSealsVerified":5,"answeredBy":"validator@8601", …},
 "nethermind":{"blockNumber":2251090,"finality":"post-quantum","falconSealsVerified":5,"answeredBy":"nethermind@8651", …},
 "source":"two independent client implementations …", "aip":"AIP-21"}

Each client keeps only a window of recent blocks (retentionBlocks); a block outside one client’s window returns agreement:false with that client’s record saying unavailable, never a guess. Older blocks are covered by the anchor certificate in the header, which is what /v1/proof reads.

Account

GET/v1/account

Your subscription as the gateway sees it, plus usage across the last 31 days. Usage counts requests by family (rpc, pq, data).

$ curl -s https://cloud.aere.network/v1/account -H "x-api-key: $KEY"
{"address":"0xbeb3…6465","planId":0,
 "plan":{"name":"rpc-build","monthlyPriceWei":"39000000000000000000","active":true},
 "expiresAt":1790065218,"expiresAtIso":"2026-09-22T08:20:18.000Z",
 "usageLast31Days":{"rpc":1204,"pq":37,"data":12},
 "contract":"0xbe65a4f3a1fc300c262adc0fbb9c6968fcc81fa0","chainId":2800}

Audit log (2026-09-17)

GET/v1/account/audit?day=YYYY-MM-DD&offset=0&limit=1000

Every keyed request made with your account, with time, method, path and the response status, kept in one append-only file per day (UTC) and served in pages of up to 5,000 entries. The response carries digest, the SHA-256 of the whole day file as served across pages: export it, and if you want the log to be tamper-evident with post-quantum finality, notarize the digest and keep the proof. A day is capped at 200,000 entries per account; past the cap a single {"truncated":true} line is written and the rest of the day is not journaled. The free health route and the keyless readiness scan are not in the log (they carry no key).

$ curl -s "https://cloud.aere.network/v1/account/audit?day=2026-09-17&limit=3" -H "x-api-key: $KEY"
{"account":"0xbeb3…6465","day":"2026-09-17","total":412,"offset":0,"limit":3,
 "entries":[{"t":"2026-09-17T22:10:03.114Z","m":"GET","p":"/v1/account","s":200},
            {"t":"2026-09-17T22:10:03.401Z","m":"POST","p":"/v1/pq/verify","s":200},
            {"t":"2026-09-17T22:10:04.020Z","m":"GET","p":"/v1/proof/0x367a…021d","s":200}],
 "digest":"0x…","digestOf":"sha256 of the whole day file (one JSON object per line, as served across pages)",
 "maxPerDay":200000, "note":"…"}

The day as a file: format=jsonl and format=cef (2026-09-18)

With format=jsonl the response is the exact bytes of the day file (one JSON object per line). The header x-aere-digest is the SHA-256 of the bytes you received, which is the digest you notarize: checking the log against its proof is one sha256sum, with nothing of ours in between.

$ curl -s "https://cloud.aere.network/v1/account/audit?day=2026-09-17&format=jsonl" -H "x-api-key: $KEY" -D headers.txt -o audit-2026-09-17.jsonl
$ grep -i x-aere-digest headers.txt        # x-aere-digest: 0x5f0c…
$ sha256sum audit-2026-09-17.jsonl          # 5f0c…  the same digest: notarize it, keep the proof

With format=cef the same entries come as ArcSight CEF lines for a SIEM (Splunk, QRadar, Sentinel): CEF:0|Aere Network|Aere Cloud|1|api-ok|GET /v1/account|1|rt=… suser=0x… requestMethod=GET request=/v1/account outcome=200. Severity follows the status class: 1 for 2xx, 5 for 4xx, 6 for 401, 403 and 429, 8 for 5xx. The header still carries x-aere-digest, the digest of the source day file, so an exported day can be tied to its notarized proof. Headers on both: x-aere-day, x-aere-entries; on CEF also x-aere-cef-lines. A day without keyed requests is an empty file, not an error. While a day is still open its file grows, so two downloads can carry two digests, each true of the bytes it came with; notarize closed days. SDKs 1.4.0: auditExport({ day, format }) returns verified (the bytes received hash to the stated digest); Python audit_export(day, fmt) returns the bytes and their SHA-256 computed locally.

Retention of the audit log (2026-09-18)

GET/v1/account/audit/retention with your key, read-only. By default nothing is deleted. You decide how long your audit days are kept, and you set it only with a wallet signature in the console (auditAction: "setRetention" on POST /v1/console/account), never with the API key: a stolen key must not be able to shorten the trail of its own use. POST to the retention route with a key answers 405 read_only_with_api_key.

  • retentionDays: 30 to 3650, or null to keep every day. hold: true stops all deletion (a legal hold).
  • A change that deletes more (fewer days, releasing a hold) takes effect after a 7-day cooling-off, visible as pending with its effectiveAt, and is cancelled by asking again for the value in force. A change that keeps more is immediate.
  • Before a day is deleted, its digest, entry count and size are written to a retention ledger that is never deleted (ledger.entries, with the ledger’s own digest). A deleted day answers 410 audit_day_expired carrying that tombstone, never an empty day: a digest you notarized still verifies the export you kept.

SDKs 1.5: auditRetention(), and auditVerifyKept(day, bytes), which hashes the export you kept locally and compares it with the day we hold or with the tombstone of a deleted day; an error is raised, never returned as “does not match”.

Console sign-in

POST/v1/console/account

Powers the account console: the same account view as /v1/account, plus the full on-chain receipt history, authenticated by a wallet signature instead of the API key: so a company admin can see the account without handling the production key. Sign this exact message with the account’s wallet (personal_sign):

Aere Cloud console login
address: <your 0x address, lowercase>
timestamp: <unix seconds, within 10 minutes>
$ curl -s https://cloud.aere.network/v1/console/account   -H "content-type: application/json"   -d '{"address":"0x…","timestamp":1787490000,"signature":"0x…"}'
{"address":"0x…","subscription":{"planId":5,"plan":{"name":"trial",…},"active":true,…},
 "usageLast31Days":{"rpc":3,"pq":4,"data":8},
 "history":[{"type":"Subscribed","planId":5,"paidWei":"0","block":15236801,"tx":"0x…"}],
 "historyComplete":true,"contract":"0x…","chainId":2800}

The gateway rebuilds the message, hashes it under the EIP-191 prefix, and recovers the signer through the chain’s own ecrecover precompile: no signature code of ours to trust. A stale timestamp or a signature by any other key answers 401. The route is read-only: rotation and renewal are transactions only your wallet can sign.

Security command center

The same signed body with "securityAction":"overview" returns the security view the console renders. Read-only, and every number is measured: from the chain, from the readiness scanner, or from your own audit log.

$ curl -s https://cloud.aere.network/v1/console/account   -H "content-type: application/json"   -d '{"address":"0x…","timestamp":1787490000,"signature":"0x…","securityAction":"overview"}'
{"address":"0x…","generatedAt":"2026-09-18T09:05:11.000Z","head":19090832,"passed":3,"failed":3,"unknown":0,
 "checks":[{"id":"api-key-rotated","pass":true,"title":"API key set or rotated in the last 90 days","detail":"25 days (first subscription …)","fix":"…"},
           {"id":"pq-key-exchange","pass":false,"title":"Every monitored hostname negotiates a post-quantum key exchange","detail":"api.example.com","fix":"…"}, …],
 "apiKey":{"known":true,"rotations":0,"lastKeyEvent":"Subscribed","block":15300000,"since":"…","ageDays":25,"basis":"…"},
 "hosts":[{"domain":"www.example.com","score":92,"pqKeyExchange":"X25519MLKEM768","certificate":{"keyType":"EC P-256","issuer":"…","validTo":"…","daysLeft":60},"lastScanAt":1789722300,…}],
 "proofs":{"total":2,"distinct":2,"latest":[{"hash":"0x…","kind":"readiness-attestation","domain":"www.example.com","block":19018082,"txHash":"0x…","finality":"post-quantum","pqAnchor":{"height":19018096,"falconSeals":9,"slhDsaSeals":9},"proof":"/v1/proof/0x…"}]},
 "audit":{"days":[{"day":"2026-09-17","counted":true,"total":7,"ok":4,"clientErrors":2,"serverErrors":1,"digest":"0x…","digestNotarized":true}],"maxPerDay":200000},
 "webhooks":{"total":4,"disabled":1,"max":5}}

Six checks: the API key was set or rotated in the last 90 days; at least one hostname is under continuous quantum-readiness monitoring; every monitored hostname negotiates a post-quantum key exchange; no monitored certificate expires within 14 days; an audit-log day digest of the last 7 days is notarized; no webhook is disarmed. A check is true, false or null: null means it cannot be told from what we hold (no report measured yet, no closed day), and it is counted neither as passed nor as failed. Nothing is scored beyond that.

Proofs. The chain records which digest was notarized and when, not by which customer, so the gateway keeps an address book of what each account notarized through it (POST /v1/notarize, attest:true scans). The address book is a convenience; the finality shown beside each entry is read from the header of the anchor that covers the block, and the proof itself stays on chain 2800, verifiable without us (Proof API). Notarize the digest of a closed audit-log day and that day of your log becomes tamper-evident, against us included: the console shows which days you have closed that way.

Webhooks can be managed with the same signature ("webhookAction":"list" | "create" | "delete", the fields of /v1/webhooks), so an admin adds a hostname to monitor without the production key touching a browser.

The same signed body also manages webhooks without exposing your API key: add "webhookAction":"list", or "create" (with type, url, and watch for address-activity), or "delete" (with id). Creation returns the HMAC secret once, exactly like the keyed route; private targets are refused on this path too.

Chain head

GET/v1/data/head

{"chainId":2800,"block":15225986,"hash":"0x6539…a3b0",
 "timestamp":1787477821,"baseFeeWei":"1000000000"}

Validator set

GET/v1/data/validators

The live QBFT validator set, read from consensus, not from a config file.

{"chainId":2800,"count":9,"validators":["0x1bd5…1c9d","0x4bf6…0044", …]}

Post-quantum finality point

GET/v1/data/finality

The block a bridge, an exchange or a rollup may treat as final on chain 2800, by the chain’s own definition (AIP-15 / AIP-22): the parent of the most recent anchor whose post-quantum certificate is present and reaches the threshold in force. Nothing between anchors is final. Returned as finalized / safe (the same block, the same hash), with the anchor that covers it, the certificate’s seal counts per scheme, the threshold and lagBlocks behind the head (at most one anchor interval plus one, normally). The certificate is read from the header bytes and counted against the threshold here; its seals are verified cryptographically by the published verifier, which anyone can run. Measured 2026-09-26: on every public node of this chain eth_getBlockByNumber("finalized") and ("safe") answer Unknown block, because QBFT does not set those tags; until the nodes expose them (planned, same definition), this route is the reference.

$ curl -s "https://cloud.aere.network/v1/data/finality" -H "x-api-key: $KEY"
{"chainId":2800,"head":20266956,"finalized":20266863,"finalizedHash":"0x…","safe":20266863,
 "anchor":20266864,"threshold":6,"lagBlocks":93,
 "certificate":{"version":2,"falconSeals":9,"slhDsaSeals":9,"signers":9,"digest":"0x…"},
 "verified":"presence-and-threshold","note":"finalized = the parent of the most recent anchor …"}

Errors: 503 no_certified_anchor when none of the recent anchor heights carries a certificate reaching the threshold (never happened on the live chain; stated so a partial answer never looks complete).

Post-quantum anchors

GET/v1/data/anchors?limit=10  ·  GET/v1/data/anchors/{height}

Anchor blocks of chain 2800 carry the validators’ post-quantum certificate: its 32-byte digest sits in the first bytes of extraData, under the block hash, and the seals themselves ride alongside (since 2026-09-04 a hybrid v2 certificate: Falcon-512 and SLH-DSA-128s seals from each signer). The grid is a consensus parameter with dated steps, returned as anchorSchedule: heights 13,014,000 + k·32 until block 17,225,968, then 17,225,968 + k·128 (since 2026-09-05). anchored is measured from the header bytes, never assumed from the height. This endpoint parses that structure for you: the data no other public chain can serve.

$ curl -s "https://cloud.aere.network/v1/data/anchors?limit=2" -H "x-api-key: $KEY"
{"chainId":2800,"head":19018276,"anchorIntervalBlocks":128,"firstAnchorBlock":13014000,
 "anchorSchedule":[{"fromBlock":13014000,"intervalBlocks":32,"since":"2026-08-05"},
                   {"fromBlock":17225968,"intervalBlocks":128,"since":"2026-09-05"}],
 "note":"anchor heights: 13,014,000 + k*32 until 17,225,968, then 17,225,968 + k*128. …",
 "anchors":[
  {"height":19018224,"hash":"0x2b45…f297","timestamp":1789679371,"anchored":true,
   "certificateVersion":2,"falconSeals":9,"slhDsaSeals":9,"signers":9,"seals":18,
   "certificateDigest":"0x45f3…b0ff"},
  {"height":19018096,"hash":"0xf776…b3f1","timestamp":1789679295,"anchored":true,
   "certificateVersion":2,"falconSeals":9,"slhDsaSeals":9,"signers":9,"seals":18,
   "certificateDigest":"0x19c4…f870"}]}

limit is 1–50 (default 10). A height that is not an anchor answers 400 not_an_anchor_height with the rule in the hint. Since block 14,961,456 an anchor does not finalize with fewer than six valid seals (six of the nine validators of that time; ten validators since 2026-09-11, so six is now below the quorum of seven); the counts you see here are the chain’s own, typically 9.

Webhooks

POST/v1/webhooks  ·  GET/v1/webhooks  ·  DELETE /v1/webhooks/{id}

The chain pushes to you. Up to 5 webhooks per account, three event types:

typefirespayload data
pq-anchorsevery new post-quantum anchor (every 128 blocks, roughly once a minute)height, hash, timestamp, anchored, certificateVersion, falconSeals, slhDsaSeals, signers, certificateDigest
address-activityany transaction touching your watched addresshash, from, to, valueWei, block, timestamp
subscription-eventsyour account’s billing eventsthe on-chain receipt (type, planId, paidWei, tx)
quantum-readinesscontinuous monitoring of one hostname (2026-09-17): the readiness scan is repeated every six hours; the first report is delivered as a baseline, then only changes (post-quantum key exchange appearing or disappearing, preference, TLS 1.2, HSTS, findings, certificate expiry crossing 30 / 14 / 7 / 1 days) or a measurement errordomain, changed[], report (score, verdict, summary, certificate expiry step, finding ids), previous, measuredAt, reportUrl
quantum-perimetercontinuous monitoring of every public host of a domain (2026-09-18): the perimeter scan is repeated every 6 hours with the same domain, hosts and discover you give at creation. The first delivery is the baseline; after that you are called only when something changes: a host appeared or disappeared, a host gained or lost post-quantum key exchange, TLS 1.2 acceptance changed, or a certificate crossed an expiry step (30, 14, 7, 1 days). Each change names the host, with from and to. An incomplete measurement is never judged or delivered; it is retried five minutes later.

Create with {"type":"quantum-readiness","url":"…","domain":"example.com"}; the listing shows lastScanAt, lastScore, lastChangeAt per watched domain.

$ curl -s https://cloud.aere.network/v1/webhooks -H "x-api-key: $KEY"   -H "content-type: application/json"   -d '{"type":"pq-anchors","url":"https://your-server.example/hooks/aere"}'
{"id":"wh_7e584f1d0ad0d403","secret":"<shown once, store it>", …}

Every delivery is a POST with headers x-aere-event and x-aere-signature: hex HMAC-SHA256 of the raw body, keyed with your webhook secret. Verify it before trusting the payload:

const valid = crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex')
            === req.headers['x-aere-signature'];

Delivery policy, stated plainly: 10s timeout, 3 attempts with backoff; 20 consecutive failures disable the webhook (visible in the list) until you recreate it. Targets must be public http(s): private and loopback addresses are refused at creation and re-checked at every delivery. On gateway restart, catch-up is capped at 300 blocks: webhooks are near-real-time signal; complete history lives in the data API.

Notarization

POST/v1/notarize  ·  GET/v1/notarize/{hash}

Prove a document existed no later than a moment in time: on a chain whose every 128th block (every 32nd block until block 17,225,968, on 2026-09-05) carries a post-quantum validator certificate, so the proof is built to outlive the cryptography era it was made in. Your file never leaves your hands: hash it locally, send only the 32-byte digest, we pay the gas and carry the transaction.

$ HASH="0x$(sha256sum contract.pdf | cut -d' ' -f1)"
$ curl -s https://cloud.aere.network/v1/notarize -H "x-api-key: $KEY"   -H "content-type: application/json" -d "{\"hash\":\"$HASH\"}"
{"hash":"0x2cdc…af96","txHash":"0x4949…0f51","block":15244146,
 "firstSeenAt":1787488094,"firstTime":true,
 "contract":"0x4aB392c4Aca7D9D4C16c0b60a9514c5025bd58c7","chainId":2800}

$ curl -s https://cloud.aere.network/v1/notarize/$HASH -H "x-api-key: $KEY"
{"notarized":true,"firstSeenAt":1787488094,"firstSeenIso":"2026-08-23T12:28:14.000Z",…}

The property that makes it a proof: first-seen can never be overwritten, re-notarizing answers firstTime:false with the original timestamp, enforced by the contract, covered by tests with negative controls. The contract (AereNotary) has no owner, no funds and no admin path; it is also fully permissionless, you can skip our API entirely and call notarize(bytes32) yourself, paying your own gas. The API is the convenience, not the gatekeeper.

Proof API: post-quantum finality of a digest

GET/v1/proof/{hash}

A timestamp is only as strong as the chain under it. For any notarized digest this endpoint returns the block and transaction of its first appearance (read from the contract’s own event log, not from our memory), the post-quantum anchor that covers it (the first anchor block at or after that height, read from its header: certificate version, Falcon-512 and SLH-DSA-128s seal counts, distinct signers, certificate digest), a finality verdict, and verify: how to check every claim on any chain-2800 node and with the public anchor verifier, without us. finality is post-quantum once the covering anchor exists and carries a certificate, pending until then (with pqAnchorExpectedAt), and first-seen-only if the first appearance could not be located in the log. Unknown digests answer 404 with notarized:false. Counted as one data request.

$ curl -s https://cloud.aere.network/v1/proof/0x367a1967df839dab40e2a62e053a38950e759f90b26aa87a259d38cb784e021d -H "x-api-key: $KEY"
{"hash":"0x367a…021d","notarized":true,
 "firstSeenAt":1789679286,"firstSeenIso":"2026-09-17T21:08:06.000Z",
 "block":19018082,"blockHash":"0xc5fb…cba9","txHash":"0x0c99…0ef1",
 "confirmations":194,"head":19018276,
 "finality":"post-quantum",
 "pqAnchor":{"height":19018096,"hash":"0xf776…b3f1","timestamp":1789679295,"anchored":true,
   "certificateVersion":2,"falconSeals":9,"slhDsaSeals":9,"signers":9,"seals":18,
   "certificateDigest":"0x19c4…f870"},
 "pqAnchorsSince":2,
 "contract":"0x4aB392c4Aca7D9D4C16c0b60a9514c5025bd58c7","chainId":2800,
 "verify":{"firstSeenAt":"eth_call to the contract with proofOf(bytes32) on any chain-2800 node …",
   "firstAppearance":"eth_getLogs address …, topics [Notarized, hash] at block 19018082",
   "pqAnchor":"the header of block 19018096 carries the validators' post-quantum certificate under its hash; verify it without us: https://aere.network/tools/verify-anchor.mjs",
   "meaning":"after the anchor, rewriting the block that holds this proof would require forging a post-quantum validator certificate, not only classical ECDSA keys"}}

What it means, plainly: a classical timestamping service proves order with ECDSA-signed blocks, and a future quantum adversary who recovers those keys could rewrite the history under the proof. Here, once the covering anchor exists, rewriting that history would also require forging a certificate signed with two NIST post-quantum schemes by the validator set. GET /v1/notarize/{hash} now returns proof, the path to this record.

Verify any AERE proof: Trust API

POST/v1/verify  ·  optional ?chain=2800|28001

Send one envelope of the AERE Proof Protocol (AIP-23), of any kind (data, execution, identity, compliance, runtime, location, device, payment, ownership, time, block, authorization, settlement, provenance, AI, software), and get one verdict back: VALID, INVALID or PARTIAL, with every level that was checked. The judgment is not a second implementation: the gateway runs the published reference verifier, verify-proof.mjs, unmodified, on your envelope, and the answer carries that file’s SHA-256 and the command that reproduces the verdict on your own machine, without us.

$ curl -s https://cloud.aere.network/v1/verify -H "x-api-key: $KEY" -H "content-type: application/json" -d @payment.json
{"verdict":"VALID",
 "statementHash":"0x0e937d67740e2314dfa003848dc46600bf6086d3449097f5eb222665c75a4e32",
 "levels":[
  {"level":"form","state":"PASSED","detail":"kind=aere-proof-of-payment-attestation"},
  {"level":"integrity","state":"PASSED","detail":"sha256(statement) == statementHash (0x0e937d67740e2314..)"},
  {"level":"signature","state":"ABSENT","detail":"the envelope carries no signature"},
  {"level":"finality","state":"ABSENT","detail":"no notarization claimed and no --rpc given"}],
 "verifier":{"file":"verify-proof.mjs","sha256":"…",
   "url":"https://aere.network/tools/verify-proof.mjs"},
 "reproduce":"node verify-proof.mjs envelope.json --json"}

The levels, in order: form (a statement and a statementHash); integrity (SHA-256 of the canonical statement equals statementHash: change one field and it is FAILED); signature (an ML-DSA signature over the statement, when the envelope carries one); finality (when the envelope claims a notarization: the chain’s most recent post-quantum anchor is verified seal by seal against the published key manifests, and a Merkle proof under that certified block shows the notary contract holds the digest and when it was first seen). A level the envelope does not carry is ABSENT, never counted as passed. The verdict: INVALID if a level present failed, PARTIAL if a level present could not be measured, VALID if every level present passed. So a bare, unsigned envelope is VALID as to its integrity only: read the levels, not just the verdict.

What it does not decide: whether a statement is true in the world. An envelope says what is claimed and who signed it; the truth of a “location” or a “device” depends on who attests it. Limits: one envelope per request, at most 64 KB; chain selects the network whose notary and anchors are read (by default, the one the envelope’s notarization declares, else 2800). A verification with finality reads the chain and takes seconds, not milliseconds. Errors: 400 bad_envelope or unknown_chain, 413 envelope_too_large, 429 busy or busy_account with Retry-After (verifications in flight are capped overall and per account), 502 verifier_inconsistent when the verifier’s verdict and exit code disagree (never passed on as a verdict), 504 verifier_timeout (not INVALID). Counted as one verify request in your account usage.

Verify an identity presentation

POST/v1/identity/verify

Checks a presentation of an AERE Identity credential: a credential its issuer signed with a hybrid signature (Ed25519 and ML-DSA-65, both required), bound to its holder’s keys, of which the holder showed only the claims they chose (selective disclosure), made for your verifier (your audience and your nonce), optionally presented through a chain of delegations that can only narrow, and revocable through the issuer’s status list. As with the Trust API, the judgment is not a second implementation: the gateway runs the published command line, identity-cli.mjs verify, on your request, and the answer carries the SHA-256 of the files that judged and the command that reproduces the verdict without us.

$ curl -s https://cloud.aere.network/v1/identity/verify -H "x-api-key: $KEY" -H "content-type: application/json" -d '{"presentation":{…},"audience":"https://your.app/verifier","nonce":"c-7f3a","trustedIssuers":["aere-id:…"],"statusLists":[{…}]}'
{"verdict":"VALID","notJudged":0,
 "subject":{"type":"KycCredential","credential":"urn:uuid:…","issuer":"aere-id:…",
   "holder":"aere-id:…","presenter":"aere-id:…","delegations":0},
 "claims":{"age_over_18":true,"jurisdiction":"RO","kyc_level":2},
 "rows":[{"name":"credential: signed by aere-id:… (Ed25519 and ML-DSA-65, both)","pass":true,"detail":""},…],
 "judgedAt":"2026-09-30T…Z",
 "verifier":{"tool":"identity-cli.mjs verify","sha256":{"identity.mjs":"…",…},"source":"https://git.aere.network/aere-network/aere-quantum/src/branch/main/identity"},
 "reproduce":"node identity/identity-cli.mjs verify --presentation presentation.json --audience <audience> --nonce <nonce> … --at 2026-09-30T…Z --json"}

Required: presentation (the file identity-cli.mjs present writes), audience and nonce, your verifier’s identifier and the challenge you gave the holder: without them a presentation made for someone else would pass, so the route does not run without them (URI characters, up to 256). Optional: trustedIssuers (issuer ids or public keys, up to 32), statusLists (the issuers’ current lists, up to 8), revocations (revocations of delegations, up to 32), maxAgeSeconds (1 to 3600, default 300: how far the presentation’s time may be from ours). Clocks differ: a credential or status list that starts up to 60 seconds in our future is accepted, and a revocation dated up to 60 seconds ahead already counts; an end date gets no allowance. The verdict: INVALID if a row failed; PARTIAL if every row that could be judged held but some could not be judged (no trusted issuers given, the issuer’s status list not handed over, a delegation without its revocations), and those rows say so with pass: null; VALID only if everything was judged and held: read verdict, since a PARTIAL presentation may carry claims that anyone could have signed with their own keys. claims and subject are returned only when no row failed. The reproduce command carries the moment of the judgment (--at), so run later on the same files it gives the same verdict, and for a compliance check the same record, byte for byte.

Verify a standard SD-JWT

POST/v1/identity/sd-jwt/verify

The same verification for credentials in the IETF standard format, Selective Disclosure for JSON Web Tokens (RFC 9901): an SD-JWT with a Key Binding JWT, in compact serialization. You give the issuer’s public key (a JWK, or the public keys of an AERE identity), and the answer follows the verification steps of RFC 9901 sections 7.1 and 7.3: the issuer signature with that key and no other, every disclosure bound to a digest, no digest twice, the key binding signed by the holder key named in the token, for your audience and your nonce, recent, and over exactly what was presented. Algorithms: ES256, EdDSA (Ed25519) and ML-DSA-65, whose JOSE name comes from an IETF draft, not yet a published standard. Judged by identity-cli.mjs verify-sdjwt from the same repository, checked there against the RFC’s own example vectors (not against another SD-JWT library).

$ curl -s https://cloud.aere.network/v1/identity/sd-jwt/verify -H "x-api-key: $KEY" -H "content-type: application/json" -d '{"sdJwt":"eyJ…~WyJ…~eyJ…","issuerKey":{"kty":"OKP","crv":"Ed25519","x":"…"},"issuerAlg":"EdDSA","audience":"https://your.app/verifier","nonce":"c-7f3a","expectedIssuer":"https://issuer.example"}'
{"verdict":"VALID","reason":"","payload":{"iss":"https://issuer.example","exp":…,"age_over_18":true,…},
 "disclosed":["age_over_18"],"issuer":"https://issuer.example","issuerChecked":true,
 "keyBinding":{"aud":"https://your.app/verifier","nonce":"c-7f3a","iat":…,"alg":"EdDSA"},"alg":"EdDSA",…}

Required: sdJwt, issuerKey, audience and nonce. Optional: issuerAlg (default EdDSA), expectedIssuer (the iss you expect; without it issuerChecked is false), maxAgeSeconds for the key binding (1 to 3600, default 300). The token must carry exp and be explicitly typed (…+sd-jwt). INVALID comes with its reason; payload is the processed payload of RFC 9901 (the claims in the clear plus those disclosed) and only for a valid token. Counted as an identity request; the same errors as the identity route.

Check a compliance policy

POST/v1/compliance/check

Your compliance policy (which issuers you trust, which claims you require: over 18, a jurisdiction outside a list, a verification level of at least 2) judged on a presentation, with the same checks as above; the trusted issuers are those of the policy, under its hash. The answer is COMPLIANT or NOT_COMPLIANT with the reasons, the policy’s hash and the presentation’s digest, and none of the claims. With "record": true it also returns the record of the decision as an AIP-23 compliance envelope that carries no personal data: a pseudonym of the holder bound to your audience, the policy hash, the result and the digest of the presentation’s signed binding (it names the credential, the disclosures, the delegations, your audience, your nonce and the time). Keep it, or notarize it with /v1/notarize so that the chain fixes the moment; the Trust API verifies it. The pseudonym is a hash of the holder id and your audience, which anyone who knows both can recompute; the command line can key it with a secret of yours, which this route does not take.

$ curl -s https://cloud.aere.network/v1/compliance/check -H "x-api-key: $KEY" -H "content-type: application/json" -d '{"presentation":{…},"audience":"https://your.app/verifier","nonce":"c-7f3a","statusLists":[{…}],"record":true,"policy":{"id":"onboarding-v1","trustedIssuers":["aere-id:…"],"require":[{"claim":"age_over_18","equals":true},{"claim":"jurisdiction","notIn":["KP","IR"]},{"claim":"kyc_level","atLeast":2}]}}'
{"verdict":"COMPLIANT","compliant":true,"reasons":[],"policyId":"onboarding-v1","policyHash":"0x…",
 "presentationHash":"0x…","notJudged":0,
 "record":{"v":1,"kind":"aere-proof-of-compliance-attestation","statement":{…},"statementHash":"0x…"},…}

Rules: equals, in, notIn, atLeast, present; unknown fields are refused, in the policy and in the request. A policy requires the credential’s status to be judged unless it says "requireStatus": false: a status list not handed over is “not judged”, never “not revoked”. What neither route is: a zero-knowledge proof (a disclosed claim is shown whole; “over 18” is a claim the issuer made, not a computation over a birth date nobody saw), an AML or sanctions screening (no list is consulted), or a statement that anyone complies with a law: it says that one presentation met one policy at one moment, judged by you. Errors (both routes): 400 bad_request, unknown_field or rejected_input (the tool’s own reason, for a broken policy or issuer key), 413 body_too_large (256 KB), 429 busy or busy_account (verifications in flight are capped overall and per account; the caps are shared with /v1/verify), 400 too_deep (JSON nested beyond 64 levels), 502 verifier_inconsistent or verifier_no_verdict, 504 verifier_timeout. Counted as identity and compliance requests in your account usage. The claims a holder disclosed reach us in the request: see data handling.

Transfer history

GET/v1/data/transfers?address=0x…&limit=50

Transfers touching an address, split honestly along what the chain itself allows: token transfers (ERC-20/721 Transfer events) are indexed from genesis; native AERE transfers emit no events, so they are indexed from the feature’s launch block onward: the response carries both boundaries (tokenHistoryComplete, nativeSince) so you never mistake a partial answer for a full one.

$ curl -s "https://cloud.aere.network/v1/data/transfers?address=0xYourAddr&limit=5"   -H "x-api-key: $KEY"
{"chainId":2800,"address":"0x…",
 "tokenTransfers":[{"token":"0x7e84…f5e8","from":"0x…","to":"0x…",
   "valueWei":"5000000000000000","tx":"0x…","block":15245202}],
 "nativeTransfers":[{"from":"0x…","to":"0x…","valueWei":"1000000000000000",
   "tx":"0x…","block":15245105,"timestamp":1787488549}],
 "tokenHistoryComplete":true,"nativeSince":15245018,…}

POST/v1/sponsor/createAccount  ·  POST/v1/sponsor/execute  ·  GET/v1/sponsor/health

Onboard users who hold zero AERE: your backend calls with your API key, the Foundation relayer deploys the user’s passkey smart account and submits their transactions, paying the gas. The smart account validates every signature itself: the relayer never sees a user key, so even a fully hostile relayer could only waste its own gas; user funds stay out of its reach by construction. Usage is metered per account (the sponsor counter in /v1/account).

$ curl -s https://cloud.aere.network/v1/sponsor/createAccount   -H "x-api-key: $KEY" -H "content-type: application/json"   -d '{"initialOwners":[…],"salt":"0x…"}'
# the relayer deploys the account and pays the gas; see the wallet
# infrastructure engagement for the full passkey flow

Honest phase-1 limits, same as the public relayer’s: a single relayer EOA, no high availability; if it is down, users holding AERE can still transact directly. The keyed route adds authentication and metering on top of the same engine.

Data handling

Written for procurement, and true as of 2026-09-17, amended 2026-09-30 for the identity routes. What we receive: 32-byte digests (notarization, Proof API), public keys, signatures and messages you choose to verify (post-quantum verification), hostnames (readiness scans, monitors), addresses you choose to watch, webhook URLs, and the JSON-RPC calls you route through your key. What we never receive: your documents, your private keys, your users’ keys (accounts created through gas sponsorship are smart accounts owned by your users), or the reports of readiness scans you did not ask us to attest. Hybrid signing (@aere/pq-sign) and Proof of Software run entirely on your side; only digests reach us, and only if you send them. One exception, since 2026-09-30: the identity and compliance routes receive the presentation you send, with the claims its holder chose to disclose. The gateway uses them to answer and keeps none of them: they are written only to a temporary directory deleted when the answer is sent, and neither the audit log (time, method, route and status of each request) nor the usage counters hold them. If disclosed claims must not leave your systems, run the same command line yourself: the verdict is the same. What we keep: per-account usage counters (31 days, for billing and /v1/account), the per-account audit log (append-only day files; export it with /v1/account/audit), webhook definitions and delivery state, cached readiness reports (six hours), the last readiness fingerprint per monitored hostname. Everything written to chain 2800 (notarized digests, attested report digests, subscriptions) is public and permanent by design. Where: all processing and storage is in the European Union. Encryption we cannot undo: there is nothing to decrypt, because nothing sensitive is sent (the identity routes aside, whose claims are not stored); that is the design, not a policy. Formal certifications (SOC 2, ISO 27001) are on the roadmap; until then every claim on this page is measurable from the public endpoints that make it.

Rate limits

Limits are per key, per second, by plan; the gateway also meters usage for your /v1/account view. Above the limit you get 429 with Retry-After: 1.

planlist pricerequests / second
trial (5)free25
rpc-build (0)$49/mo150
data-api (2)$199/mo100
rpc-scale (1)$249/mo500
pq-verify-api (3)$299/mo50
managed-node (4)$999/mo150

Request bodies are capped at 256 KB at the gateway (1 MB at the edge). The API plans above are the developer tier; enterprise programs (post-quantum migration, dedicated chains, compliance infrastructure, managed fleets) are scoped from six figures a year and invoiced in EUR or USDC: [email protected].

Errors

statusbody errormeaning
401missing_api_keyno x-api-key header; the body repeats the key format and contract
403invalid_or_expired_keybad format, unregistered hash, or an expired subscription
429rate_limitover your plan’s per-second limit; retry after 1s
400bad_json, unknown_scheme, bad_publicKey, not_an_anchor_height, …malformed input; the hint says what to fix
413body_too_largerequest body over 256 KB
503subscription_check_unavailablethe gateway could not verify your key on-chain and refuses to guess; temporary
502upstreamthe node behind the gateway failed to answer

The subscription contract

AereCloudSubscriptionsV2 at 0xfA2375F5c30d25e0b952F5Ac07Bc292aD3C20433 on chain 2800 (explorer). Properties, each enforced by code and covered by tests with negative controls:

  • No custody. Every payment is forwarded to the Foundation treasury inside the same transaction; the contract’s balance is always zero. There is no receive(): a bare transfer to the contract reverts, so funds cannot get stuck in it.
  • Only the key hash on-chain. subscribe(planId, periods, keccak256(key)); pass 0x0 to keep the current key.
  • Extension from expiry. Renewing early never costs you time: the new expiry is max(now, current expiry) + 30 days × periods. Prepay is capped at 12 periods.
  • Never retroactive. Price changes apply to new subscriptions only; a retired plan stops selling but every paid subscription stays valid to its expiry.
  • No upgradability, no pause, no backdoor. The owner can configure plans and move the treasury target, nothing else.

Interface

function subscribe(uint64 planId, uint256 periods, bytes32 apiKeyHash) payable
function rotateApiKey(bytes32 newApiKeyHash)            // free, needs a live subscription
function grantSubscription(address account, uint64 planId,
                           uint256 periods, bytes32 apiKeyHash)  // owner only: invoice-paid customers
function check(address account, bytes32 apiKeyHash)
    view returns (bool valid, uint64 planId, uint64 expiresAt)
function plans(uint64 planId)
    view returns (string name, uint256 monthlyPriceWei, bool active)
function subs(address account)
    view returns (uint64 expiresAt, uint64 planId, bytes32 apiKeyHash)

event Subscribed(address indexed account, uint64 indexed planId,
                 bytes32 apiKeyHash, uint64 expiresAt, uint256 paidWei)
event Granted(address indexed account, uint64 indexed planId,
              bytes32 apiKeyHash, uint64 expiresAt)   // invoice-paid, distinguishable on-chain
event ApiKeyRotated(address indexed account, bytes32 newApiKeyHash)

Changelog & status

  • 2026-09-30: identity and compliance verification (POST /v1/identity/verify, POST /v1/compliance/check): AERE Identity presentations judged by the published command line, VALID / PARTIAL / INVALID and COMPLIANT / NOT_COMPLIANT, and standard SD-JWT (RFC 9901) with key binding (POST /v1/identity/sd-jwt/verify), with the record of a compliance decision as an AIP-23 envelope without personal data. Account usage now reports the identity and compliance families. OpenAPI 1.7.0. The official clients 1.7.0 carry them in all five languages (identityVerify / complianceCheck; in Go the presentation travels as its bytes, so large numbers stay exact).
  • 2026-09-29: Trust API (POST /v1/verify): one AIP-23 proof envelope of any kind in, VALID / INVALID / PARTIAL out, with each level checked, judged by the published reference verifier and reproducible without us. Account usage now reports the verify family. OpenAPI 1.6.0. The official clients 1.6.0 carry it in JavaScript, Python, Go and Java, plus a new .NET client; in Go the envelope is passed as its bytes, since a map would reorder the statement's keys and change its hash.
  • 2026-09-26: the post-quantum finality point of the chain (GET /v1/data/finality): finalized and safe as the parent of the most recent anchor whose certificate is present and reaches the threshold in force, with the anchor, the certificate’s seal counts and the lag behind the head. Measured the same day: eth_getBlockByNumber("finalized") answers Unknown block on every public node of chain 2800, because the consensus does not set the tag; this route is the reference until the nodes expose it themselves. SDKs 1.5.2 (finality() in JavaScript, Python, Go, Java), OpenAPI 1.5.2.
  • 2026-09-22: post-quantum adoption by sector, a weekly public series (GET /v1/pq/adoption, no key): sector aggregates only, each share with its 95% interval, per-host results committed by SHA-256 and never published. The console's security view now saves as a PDF report, including the hosts of a monitored perimeter. OpenAPI 1.5.0.
  • 2026-09-25: the official clients in four languages (JavaScript, Python, Go, Java), installed from the repository because they are not on npm or PyPI yet (the page said npm install of a name that did not exist there); none of them follows redirects. The retention of the audit log, live since 2026-09-18, is now documented.
  • 2026-09-18: the audit log of a day as a file: format=jsonl returns the exact bytes whose SHA-256 is the digest you notarize (one sha256sum verifies it), format=cef returns CEF lines for a SIEM; SDKs 1.4.0.
  • 2026-09-18: webhook type quantum-perimeter: the whole perimeter of a domain under continuous monitoring, changes only, each naming the host; its hosts appear in the console’s security view.
  • 2026-09-18: The whole perimeter of a domain in one keyed report (POST /v1/pq/readiness/perimeter): named hosts plus common prefixes found through DNS, a summary derived from measured hosts only, wildcard-DNS echoes dropped, a request deadline with pending, and attest for complete reports; SDKs 1.3.0. The readiness scanner and webhook delivery now refuse any hostname that resolves to an address that is not public, and connect to the verified address.
  • 2026-09-18: Security command center in the console, behind the wallet signature: six measured checks (API key age, monitored hostnames, post-quantum key exchange, certificate expiry, notarized audit-log days, disarmed webhooks), the proofs your account notarized with their finality read from the chain, and the audit log of the last 7 days with each day’s digest. Webhooks of type quantum-readiness can now be created from the console too.
  • 2026-09-18: Post-quantum finality of a block (AIP-21) served by two independent client implementations: client=besu|nethermind|both, with agreement and postQuantumConfirmedByBoth computed by the gateway on the same block; SDKs 1.2.1 (pqFinality(block, network, client)).
  • 2026-09-17: Quantum readiness scan (free, keyless; keyed attest notarizes the report digest on chain), Proof API (GET /v1/proof/{hash}: first appearance from the contract log, the covering post-quantum anchor, a finality verdict and independent verification steps), and a correction to the anchor endpoints: since the anchor interval moved to 128 blocks on 2026-09-05, /v1/data/anchors and the pq-anchors webhook had kept the old 32-block grid, so three of every four heights they reported were not anchors; both now follow the dated anchorSchedule, report anchored from the header bytes, and count the hybrid v2 certificate’s seals per scheme (falconSeals, slhDsaSeals, signers) instead of the previous wrong count. OpenAPI 1.1.0.
  • 2026-08-23: v1 launch: keyed JSON-RPC, keyed WebSocket subscriptions, webhooks (PQ anchors, address activity, billing events), the notarization API, keyed gas sponsorship, post-quantum verification API, account & usage, chain data endpoints (head, validators, PQ anchors, transfer history), wallet-based subscribe panel, dollar list pricing settled on-chain at the published reference rate, and a free keyed trial plan. Machine-readable spec at /cloud-openapi.json.
  • Planned next, in the open: USDC settlement for enterprise invoices, native-transfer history backfill.

Live status: /cloud-status.html runs every check in your own browser; GET /v1/health answers without a key. Support: [email protected].

Aere Cloud: overview · API docs · console · status