mina-explorer-api
Drop-in, bug-compatible replacement for the Blockberry Mina REST API.
Base URL https://mina-explorer-api.minaprotocol.com
Path structure /mina-{network}/v1/... — the network is in the path; auth is the x-api-key header (unchanged from Blockberry).
Networks active: mina-mainnet, mina-devnet, mina-mesa · dormant (503): mina-pre-mesa
What this is
A drop-in, bug-compatible replacement for the Blockberry Mina REST API. Point your existing client at the base URL above, keep your x-api-key header, and the /mina-{network}/v1/... paths work unchanged. See the migration guide to switch over, and Get an API key to request credentials (key values are re-issued by us — Blockberry keys are not portable).
Where an endpoint diverges, it degrades honestly — documented null fields and window-bounded reads — rather than fabricate or 500. Every divergence is listed below.
Compatibility matrix
55 endpoints · Full 6 Partial 43 Stub 6
null fields or a coverage caveat.Stub — placeholder (empty / 404) with no backing source.| Endpoint | Status | Notes & null fields |
|---|---|---|
| Blocks | ||
/v1/blocksGET | Partial | null: accountName, accountImg, ledgerHash, parentHash, snarkJobsCount, snarkersCountEnvelope A; totalElements capped at 10 000, totalCount is the true count and a window-bounded lower bound in the fallback path (§A/§I.3). isCanonical is a real boolean here (contrast detail, §D). type=ORPHANED returns empty until the index. |
/v1/blocks/{stateHash}GET | Partial | null: coinbaseReceiver, snarkedLedgerHash, stagedLedgerHash, winnerAddressisCanonical is INTEGER 0/1 in the detail DTO (§D). Zero snarkersFee/transactionsFee re-emitted as int 0. Not found → empty-body 404, no content-type (§I.10 / §G probe 23). |
/v1/blocks/latest-block-state-hashGET | Full | Bare UNQUOTED string body served as application/json (§H/§I.2). Not found → empty-body 404. |
/v1/block-confirmation/{txHash}GET | Partial | null: txHashNext, txHashPreviousWindow-bounded. Pending-path also nulls blockHeight, failureReason, stateHash until confirmation. |
| Transactions | ||
/v1/transactionsPOST | Partial | null: fromAccountImg, fromAccountName, toAccountImg, toAccountNameblockHeight is a STRING here (bug-compatible, §C). age = block epoch-ms (§B). totalCount present but window-approximate until the index. |
/v1/transactions/pendingPOST | Partial | null: age, fromAccountImg, fromAccountName, toAccountImg, toAccountNameEnvelope A WITHOUT totalCount (§A). status constant 'pending'; receiverScam/sourceScam emitted as all-null objects (Blockberry parity). |
/v1/transactions/internalPOST | Partial | null: accountImg, accountName, receiverImg, receiverName, secondarySequenceNo, sequenceNo, txHashEnvelope A WITHOUT totalCount (§A). Coinbase + fee-transfer commands. |
/v1/transactions/{hash}GET | Partial | null: alert, balanceChanges, delegationAmount, delegationAmountUsd, receivedAmount, receivedAmountUsd, receivedDelegationAmount, receiverImg, receiverName, sequenceNumber, sourceImg, sourceNamePending path also nulls timestamp + failureReason. USD fields degrade to null on a CoinGecko outage (never 5xx). Not found → empty-body 404. |
| Latest | ||
/v1/latest-transactionsGET | Partial | null: fromAccountImg, fromAccountName, toAccountImg, toAccountNameBare JSON array of UserCommand items (§H). blockHeight is a STRING (§C), matching POST /v1/transactions. |
/v1/latest-zkapp-transactionsGET | Partial | null: proverImg, proverNameBare JSON array of ZkAppTransactionDto (§H); identical item to /v1/zkapps/txs. isAccountHijack / isZkappAccount constant false. |
| zkApps | ||
/v1/zkapps/txsGET | Partial | null: proverImg, proverNameEnvelope A WITH totalCount. isAccountHijack / isZkappAccount constant false; updatedAccounts[] off-chain fields (accountImg/accountName/verificationKey/verificationKeyHash/isZkappAccount) null. |
/v1/zkapps/accounts/{address}/txsGET | Partial | null: proverImg, proverNameEnvelope A WITHOUT totalCount (§A). |
/v1/zkapps/blocks/{stateHash}/txsGET | Partial | null: proverImg, proverNameEnvelope A WITHOUT totalCount (§A). |
/v1/zkapps/txs/{txHash}GET | Partial | null: feePayerImg, feePayerNameisAccountHijack / isZkappAccount constant false; updatedAccounts[] off-chain fields null. USD via CoinGecko (null on outage). Not found → empty-body 404. |
/v1/zkapps/txs/raw/{txHash}GET | Full | JSON string of the raw upstream zkApp command. Miss → empty-body 404. |
/v1/zkapps/txs/balance-change/{txHash}GET | Partial | null: accountImg, accountName, balanceBefore, balanceAfter, coingeckoCoinId, coinmarketCoinId, isBridged, isFeeIncluded, isVerified, isZkappAccount, tokenImage, tokenName, tokenScam, tokenSymbolaccountScam emitted as all-null object (Blockberry parity). |
/v1/zkapps/{address}GET | Partial | null: verificationKeyHashInvalid / nonexistent / non-zkApp address → HTTP 200 all-null object, NOT 404 (§I.9). accountScam emitted as all-null object (parity). Wire shape UNVERIFIED (no live key, plan §7.1). |
/v1/zkapps/{address}/last-verification-key-changeGET | Full | Bare int64 (slot of last vk change), or bare null on miss (§I.9 precedent). Wire shape UNVERIFIED (M3-T7). |
/v1/zkapps/{address}/verification-key-historyGET | Partial | null: verificationKeyHashBare ascending array of VerificationKeyHistoryDto; empty array on miss. Wire shape UNVERIFIED (M3-T7). |
| Accounts | ||
/v1/accounts/{address}GET | Partial | null: accountName, accountImg, description, discordNicknames, firstSeen, lastSeen, isNotActivated, isVerified, socialDiscord, socialEmail, socialGitHub, socialTelegram, socialTwitter, websiteInvalid / nonexistent address → HTTP 200 all-null AccountInfo, NOT an error (§I.9). accountScam emitted as all-null object (parity). balance reproduces Blockberry's double-division bug (nanomina ÷ 1e18) on THIS endpoint only; /balance uses the correct ÷1e9. |
/v1/accounts/{address}/balanceGET | Full | MINA + USD balance (correct ÷1e9). balanceUsd degrades to null on a CoinGecko outage (never 5xx). |
/v1/accounts/{address}/delegateeGET | Partial | null: epoch1, epoch2currentEpoch populated (delegate + delegate balance); currentEpoch.delegateeImg/delegateeName null (off-chain); currentEpoch.accountScam all-null object (parity). |
/v1/accounts/{address}/txsGET | Partial | null: accountName, accountImg, receiverName, receiverImg, senderName, senderImgEnvelope A WITHOUT totalCount (§A). blockHeight is an INTEGER here (§C, contrast the tx list's string). isAmountChangeable constant false; receiverScam/sourceScam all-null objects (parity). |
/v1/accounts/{address}/timing-infoGET | Partial | null: cliffTimeMillis, vestingTime, vestingTimeMillis, unlockStatus, liquidityRate, startTimeM1-T8. isHasLock semantic UNVERIFIED (no fixture). Absent address → all-null at 200; daemon outage → 503 (M2-T3, never a raw 500). |
/v1/accounts/{address}/is-validatorGET | Full | Bare JSON boolean (§I). Window-approximate until the M3 index; wire shape UNVERIFIED. |
/v1/accounts/{address}/is-snarkerGET | Full | Bare JSON boolean (§I). Window-approximate until the M3 index; wire shape UNVERIFIED. |
/v1/accounts/{address}/statisticsGET | Partial | null: minBalance, maxBalanceM3-T5, index-backed. Counts (incomingTxs/outgoingTxs/zkappTxs/totalTxs) real from the transactions projection. Wire shape UNVERIFIED. |
/v1/accounts/{address}/staking-balanceGET | Partial | Bare EpochDotDTO[] from staking_ledger; empty for mesa/pre-mesa (no GCS staking source). Wire shape UNVERIFIED (spec-only). |
/v1/accounts/{address}/tx-count-chartGET | Partial | Bare DataPointDto[] from the transactions projection (real). Wire shape UNVERIFIED (spec-only). |
/v1/accounts/{address}/zkapp-tx-count-chartGET | Partial | Bare ZkTxDataPointDto[] from the transactions projection (real). Wire shape UNVERIFIED (spec-only). |
| Rich list | ||
/v1/accountsGET | Partial | null: accountName, accountImg, accountScam, delegateName, delegateImg, delegateScam, receiptChainHash, isZkappAccountObserved-addresses-only rich list from the #19 seen_accounts projection (NOT a full-ledger snapshot; plan §7.2). Envelope A cut page WITH totalCount (true row count); totalElements capped at 10 000. sortBy BALANCE|NONCE, orderBy ASC|DESC; size>50 / bad sortBy → Spring 400. R8: index off → valid empty page, never 500. Wire shape UNVERIFIED (plan §7.1). |
| Info | ||
/v1/infoGET | Partial | null: nftsCount, collectionsCount, accountsCount, accountsCountDay, activeSnarkersCount, activeValidatorsCount, avgSnarkFee, blockHeightDay, paymentsCount, paymentsCountDay, snarkersCount, snarkersCountDay, tokensCount, txsCount, txsCountDay, validatorsCount, zkAppAccountsCount, zkappTxsCount, zkappTxsCountDay, zkappsCount, zkappsCountDayDashboardDto. Real (window-derived from archive/daemon): blockHeight, epoch, slot (post-fork), avgFee, avgFeeDay, maxTxFee, minTxFee. epoch/slot are POST-FORK values (M1-T9). |
| Validators | ||
/v1/validatorsGET | Partial | null: networkShare, stakePercent, validatorFeeEnvelope B (true content-keyed Spring Page; totalElements never capped). Real: validatorAddress, canonicalBlocksCount, allBlocksCount, stake, delegatorsCount, nextEpochStake, nextEpochDelegationsCount; scam is the all-null object (parity). Also null (data gap): diff* (e.g. diffStake), epoch2*, and all identity/social/verification fields. stake fields null on mesa/pre-mesa (no GCS staking source). R8: index off → empty/zero/null, never 500. |
/v1/validators/{address}GET | Partial | null: networkShare, stakePercent, validatorFeeSame null set + diff*/epoch2*/identity as the list. Absent/not-indexed → all-fields object with the address echoed + zero block counts, never 500. Wire shape UNVERIFIED (plan §7.1). |
/v1/top-validatorsGET | Partial | null: networkShare, stakePercent, validatorFeeServes the SAME ValidatorDTO as /v1/validators via the identical map_validator (8 of 31 fields populated), so diff* (diffStake/diffDelegatorsCount), epoch2* (epoch2Stake/epoch2DelegationsCount), isActive, isVerified, isStakingRewardsVerified, and all identity/social/terms fields are null too — the live devnet recording (tests/fixtures/blockberry/devnet/top-validators.json) shows Blockberry populates networkShare/stakePercent/isActive/isVerified, so these are real divergences. ROUTING is exact per network — config-driven asymmetry (§F, M3-T3 reprobe): devnet → bare ValidatorDTO[] (count 1–50); mainnet + mesa → byte-identical 405 {"error": "Handler is not instance of HandlerMethod"} (route absent upstream); pre-mesa → 503. |
| Snarks | ||
/v1/snarkersGET | Partial | null: accountName, accountImg, fee, isZkappAccount, snarkJobsCount, snarkWorksCount, totalJobsSoldEnvelope A data-keyed, NO totalCount, NO 10k cap (§I.4). Real: accountAddress, snarkAmountEarned, firstSeen, lastSeen. |
/v1/snarks/{stateHash}/jobsGET | Partial | null: accountName, accountImg, workIdsEnvelope B. Real: accountAddress, fee, isCanonical, timestamp. Wire shape UNVERIFIED. |
/v1/snarks/jobs/{address}GET | Partial | null: workIdsEnvelope B. Real: blockHeight, fee, isCanonical, stateHash, timestamp. Wire shape UNVERIFIED. |
/v1/snarks/jobs/{address}/snarker-by-addressGET | Partial | null: accountName, accountImg, avgAllTimeFee, avgMonthFee, currentFee, delegateeAddress, jobsProduction, snarkJobsCount, worksProducedReal: feesEarned, firstSeen, lastSeen. Unknown prover → 200 all-null. Wire shape UNVERIFIED. |
| Tokens | ||
/v1/tokensGET | Partial | null: lockedBalance, unlockPercent, isZkappAccount, ownerAddress, ownerName, ownerImg, ownerTokenId, ownerScam, tokenName, tokenImage, isVerified, isBridged, coingeckoCoinId, coinmarketCoinId, tokenScam, tokenSymbolEnvelope A WITHOUT totalCount. Wire shape UNVERIFIED (plan §7.1). |
/v1/tokens/symbolsGET | Partial | Flat {tokenId: SYMBOL} string map, NO envelope (§E/§I.6, PINNED). Returns an EMPTY map in production until #19 populates token symbols. |
/v1/tokens/{tokenId}GET | Partial | null: lockedSupply, unlockedSupply, unlockPercent, tokenHoldersCountDay, tokenAdminAddress, ownerAddress, tokenOwnerPk, ownerName, ownerImg, ownerScam, tokenName, tokenImage, isVerified, isBridged, coingeckoCoinId, coinmarketCoinId, tokenScamUnknown tokenId → empty-body 404 (§I.10, UNVERIFIED). Wire shape UNVERIFIED (plan §7.1). |
/v1/tokens/{tokenId}/holdersGET | Partial | null: lockedBalance, movableBalance, holderName, holderImg, accountScamHolder isZkappAccount IS real (seen_accounts join). Wire shape UNVERIFIED. |
/v1/tokens/{tokenId}/txsGET | Partial | null: fee, memo, nonce, proverAddress, proverImg, proverName, statusShares the ZkAppTransactionDto item mapper (map_token_tx → to_list_item), so it inherits that DTO's off-chain prover nulls on top of the token_activity gaps. proverScam/accountScam all-null objects (parity). Wire shape UNVERIFIED. |
/v1/tokens/accounts/{address}GET | Partial | null: nonce, tokenName, tokenImage, isVerified, isBridged, coingeckoCoinId, coinmarketCoinId, tokenScamPer-account token holdings (TokenByPkDto). Wire shape UNVERIFIED. |
| Time-locks | ||
/v1/time-locksPOST | Partial | null: name, img, totalSupply, isZkAppAccountVesting math is real, live-verified (M1-T8; app/vesting.py). Envelope A WITHOUT totalCount; totalElements capped 10 000. lockTypes body accepted + enum-validated (invalid → Spring 400) but NOT yet used to filter (LOCKED/UNLOCKED semantics UNVERIFIED). Date fields (cliffTimeMillis/vestingTimeMillis/lockDate/fullyUnlockedDate) computed via the original-genesis anchor; exact wire semantics UNVERIFIED. R8: index off → empty page, never 500. |
/v1/time-locks/dayGET | Partial | Per-day unlock aggregation (LocksEntity). Vesting/unlock totals are real + live-verified (M1-T8), property-tested for conservation; envelope + date-field wire semantics UNVERIFIED. R8: index off → empty page, never 500. |
/v1/time-locks/monthGET | Partial | Per-month unlock aggregation (LocksMonthEntity). Vesting/unlock totals real + live-verified (M1-T8); envelope + date-field wire semantics UNVERIFIED. |
/v1/time-locks/yearGET | Partial | Per-year unlock aggregation (LocksYearEntity). Vesting/unlock totals real + live-verified (M1-T8); envelope + date-field wire semantics UNVERIFIED. |
| Security | ||
/v1/security/scamsGET | Stub | No scam registry backs this deployment (§4) → bare empty [] (ScamDto[]) for every query. onChainIds kept REQUIRED (missing → Spring 400), matching the upstream contract (M1-T9). |
/v1/security/scams/tx-bodyPOST | Stub | No scam registry (§4) → bare empty [] (ScamDto[]). Body validated as WalletTransactionDto (malformed → Spring 400), upstream-parity (M1-T9). |
| MIPs | ||
/v1/mipsGET | Stub | Governance-metadata group not served (feasibility tier T4, plan §4). 404 {"error": "Not available on this network"} — a KNOWN-but-stubbed group, so a 404 stub, NOT the 405 unknown-path body (§F/§G/§I.8, M1-T9). |
/v1/mips/votesGET | Stub | 404 stub (T4). Registered BEFORE /mips/{id} so the literal is not captured by the int path param (M1-T9). |
/v1/mips/{id}GET | Stub | 404 stub (T4, M1-T9). |
/v1/mips/{id}/votesGET | Stub | 404 stub (T4, M1-T9). |