API Reference
Node & Middleware

æternity Node & Middleware

The Superhero API is an index over the æternity chain, not the chain itself. For anything it does not carry (an arbitrary transaction, an AEX-9 balance, a name's pointers, a contract's event log, or submitting a transaction at all), talk to an æternity node or its middleware.

Node versus middleware

NodeMiddleware
Path prefix/v3/.../mdw/v3/...
AnswersCurrent stateHistorical and indexed state
Use it forContract calls, dry-runs, balances, submitting transactions, current heightTransactions by account or contract, AEX-9 transfers and balances, AENS names, contract event logs
Can it write?Yes, transactions are submitted hereNo, read-only

The æternity SDK's Node class wraps the node API. Everything that signs something (posting, creating a token, swapping, generating invites, voting) goes through a Node instance. The middleware is read with plain fetch.

Hosts

MainnetTestnet
Nodehttps://mainnet.aeternity.iohttps://testnet.aeternity.io
Middlewarehttps://mainnet.aeternity.io/mdwhttps://testnet.aeternity.io/mdw
Middleware WebSocketwss://mainnet.aeternity.io/mdw/v2/websocketwss://testnet.aeternity.io/mdw/v2/websocket
Explorerhttps://aescan.iohttps://testnet.aescan.io
Compilerhttps://v7.compiler.aepps.comhttps://v7.compiler.aepps.com

api.superhero.com indexes from these hosts. The web app reaches mainnet through a Superhero-operated node and middleware at https://mdw.wordcraft.fun and https://mdw.wordcraft.fun/mdw, which serve the same ae_mainnet chain; a transaction submitted to either host is visible from the other.

Node endpoints

Current height, read directly:

curl -s "https://mainnet.aeternity.io/v3/headers/top"

Everything else through the SDK. Contract initialisation, dry-run reads (has_community, calculate_buy_price, bonding_curve, supported_decimals), balance lookups and transaction submission all go through new Node(NODE_URL) and an AeSdk instance:

import { AeSdk, Node, MemoryAccount } from '@aeternity/aepp-sdk';
 
const node = new Node('https://mainnet.aeternity.io');
const aeSdk = new AeSdk({
  nodes: [{ name: 'mainnet', instance: node }],
  accounts: [new MemoryAccount(process.env.AE_PRIVATE_KEY)],
});

See Calling contracts for the contract side.

Middleware endpoints

EndpointPurpose
GET /mdw/v3/transactions?contract={ct}&account={ak}&limit={n}Read an account's posts from the social contract
GET /mdw/v3/transactions?contract={ct}&caller_id={ak}Find invite-creation transactions
GET /mdw/v3/transactions/{hash}Poll a transaction to confirmation
GET /mdw/v3/names?owned_by={ak}&state=active&limit=100List the .chain names an account owns
GET /mdw/v3/names/{name}Resolve a .chain name to an address
GET /mdw/v3/aex9/{address}AEX-9 token metadata
GET /mdw/v3/accounts/{ak}/aex9/balances?limit=100An account's AEX-9 balances
GET /mdw/v2/aex9/account-balances/{ak}?limit=100The v2 form of the same
GET /mdw/v3/statusMiddleware version and its distance from the chain tip

/v3/ is current; /v2/ paths still work against the same deployment.

Reading posts from the index

curl -s "https://mainnet.aeternity.io/mdw/v3/transactions?contract=ct_2Hyt9ZxzXra5NAzhePkRsDPDWppoatVD7CtHnUoHVbuehwR8Nb&account=ak_YOUR_ADDRESS&limit=20"

The response is { data: [...], next }. Each element carries hash, block_height, micro_time (milliseconds) and a tx object with function, arguments (an array of { type, value }) and return. Filter to tx.function === 'post_without_tip', then read the post body from arguments[0].value and the attached links from arguments[1].value.

next is a path, not a full URL. Concatenate it onto the middleware origin to page.

Name resolution

GET /mdw/v3/names/{name} returns a name record; the address is the pointer whose key is account_pubkey: pointers.find(p => p.key === 'account_pubkey').id. Check active and that the returned name matches what you asked for, and treat 404 as "no such name".

For chain names in bulk, prefer GET /api/accounts/chain-names?addresses=ak_a,ak_b, which resolves up to 25 at a time, and fall back to the middleware for names it does not know. See Accounts.

Transaction confirmation

GET /mdw/v3/transactions/{hash} returning 404 means pending, not failed. Poll every 5 seconds and compute confirmations as currentHeight - blockHeight + 1.

The middleware mirror on api.superhero.com

The Superhero API re-indexes a slice of middleware data under its own paths:

Method & pathReturns
GET /api/v2/mdw/txsTransactions, with type, contract_id, function, caller_id, sender_id, recipient_id filters
GET /api/v2/mdw/txs/{hash}One transaction
GET /api/v2/mdw/key-blocksKey blocks, filterable by hash, height, beneficiary, miner, version
GET /api/v2/mdw/key-blocks/{hash}One key block
GET /api/v2/mdw/micro-blocksMicro blocks
GET /api/v2/mdw/micro-blocks/{hash}One micro block
GET /api/v2/mdw/sync-stateIndexer sync state
GET /api/v2/mdw/plugin-sync-statePer-plugin sync state
GET /api/mdw/healthMiddleware health check

These take an includes parameter for nested relations: keyBlock, keyBlock.txs, microBlocks, txs.keyBlock and similar, comma-separated. An array relation is truncated to 50 items per parent. Response shapes are the mirror's own Tx, KeyBlock and MicroBlock records, not the upstream middleware's.

  • Rate-limited. 10 requests per minute per IP per route path, returning 429 with a retryAfter field in the body. See Conventions.
  • limit is capped at 100 with 400 Maximum limit is 100 items per request; an order_by outside the route's sortable set is a 400.
  • page goes up to 1,000,000. Deep paging still costs the database a scan of everything before your page, so prefer a height or block_height filter where you can.

Sortable fields on sync-state: id, last_synced_height, tip_height, is_bulk_mode, backward_synced_height, live_synced_height, created_at, updated_at. On txs: hash, block_height, micro_time, type, contract_id, function, caller_id, sender_id, recipient_id.

GET /api/mdw/health

How far behind Superhero's own index is. Not rate-limited; no parameters.

curl -s "https://api.superhero.com/api/mdw/health"
KeyContents
statushealthy, warning or critical
totalTxsRows in the mirrored transaction table
backwardSyncstatus, syncedHeight, tipHeight, remainingBlocks, progressPercent, mode (bulk or normal), isRunning
liveSyncstatus, syncedHeight, tipHeight, lag, progressPercent, gapFromBackwardSync, isActive
validationstatus, isValidating, lastValidationTime
comparisonsyncGap, backwardSyncProgress, liveSyncProgress
pluginsPer-plugin name, lastSyncedHeight, backwardSyncedHeight, liveSyncedHeight, startFromHeight
registeredPluginsThe plugin names that are loaded

liveSync.lag is tipHeight - liveSyncedHeight, in key blocks. The server grades it as:

Conditionstatus
Backfill complete and lag at most 100healthy
Backfill complete and lag above 100warning
lag above 1000, or more than 10,000 blocks of backfill leftwarning
lag above 5000, more than 50,000 blocks of backfill left, or the live indexer is not activecritical

Two syncs run independently: a live one following the tip, and a backward one walking from the tip towards genesis. remainingBlocks counts down to 0, so it stays large on a fresh deployment while live data is already current. Judge freshness from liveSync.

GET /api/stats gives a shorter summary of the same picture plus mdwConnected. See Factory & Contracts.

When to use which

You needGo to
Token prices, holders, trades, trending, portfolio valueSuperhero API: Tokens, Accounts
Posts, comments, topics, tipsSuperhero API: Posts
Claim status of invites you issuedSuperhero API: Invitations
A raw transaction by hash, or "is my transaction confirmed?"Middleware GET /v3/transactions/{hash}
Every call an account made to a specific contractMiddleware GET /v3/transactions?contract=&caller_id=
AEX-9 balances for an arbitrary tokenMiddleware GET /v3/accounts/{ak}/aex9/balances
AENS names owned by, or resolving to, an addressSuperhero API batch first, then middleware /v3/names
Contract event logsMiddleware
Reading contract state, or writing anything at allNode, through the SDK

The Superhero API knows about Superhero. The moment your question is about the chain rather than the product, it belongs to the middleware or the node. The middleware indexes after the fact and the Superhero API indexes after that, so for anything where staleness matters read the node, and check GET /api/mdw/health before expecting a recent event to be in the API.

Related