Reference
API reference
One client, one namespace per concern, one block stream. Every module is reachable from a HiveClient instance and every configuration context exposes the same surface.
HiveClient
import { HiveClient } from "hivexph-sdk";
const hive = new HiveClient({
endpoint: "https://api.hive.blog", // optional, Beacon picks a node otherwise
beaconUrl: "https://beacon.peakd.com/api/nodes",
applicationId: "my-application", // default custom_json id
accounts: {
treasury: { account: "my-account", keyEnv: "TREASURY_ACTIVE_KEY" },
},
tests: {
accounts: { minter: "test-minter" }, // your own structure
},
});
hive.endpoint; // resolved RPC endpoint
hive.accounts.treasury; // key-free account reference
hive.configs.tests.accounts.minter; // your configuration, typedNamespaces
| Parameter | Type | Required | Description |
|---|---|---|---|
| configs | HiveConfigs<TConfig> | No | The configuration object you passed, frozen and fully typed. |
| accounts | Record<string, AccountReference> | No | Key-free account references built from configs.accounts. |
| rpc | RpcClient | No | Raw JSON-RPC access, block reads and broadcasting. |
| beacon | BeaconClient | No | Node discovery and health scoring. |
| builder | CustomJsonBuilder | No | Build standardized custom_json operations. |
| parser | CustomJsonParser | No | Extract and validate custom_json payloads. |
| keychain | KeychainClient | No | Browser signing through the Hive Keychain extension. |
| blocks | BlockWatcher | No | The core block stream as a raw async iterator. |
| customJson | CustomJsonWatcher | No | parse() plus a filtered view of the core stream. |
| payments | PaymentClient | No | Native HIVE/HBD and Layer 2 payments, parse, validate, watch. |
| reader | ReaderClient | No | Single transaction reads and the unified multi-filter stream. |
| issuer | IssuerClient | No | Backend Hive Engine token and NFT operations. |
There is exactly one blockchain streaming engine. hive.blocks.watch(), hive.customJson.watch(), hive.payments.watch() and hive.reader.stream() are all consumers or dispatch layers over that same core block reader — never independent polling loops.
Full method map
The complete public surface, grouped by namespace.
// ── configuration ────────────────────────────────────────────────
hive.configs // your configuration object, frozen
hive.account(alias) | listAccounts() | resolveAccount(alias)
hive.endpoint
// ── blockchain access ────────────────────────────────────────────
hive.rpc.call(method, params, options?) -> Promise<T>
hive.rpc.getDynamicGlobalProperties(options?) | getHeadBlockNumber(options?)
hive.rpc.getBlock(blockNumber, options?) | resetEndpoint()
hive.beacon.getNodes(options?) | getHealthyNodes(options?) | getBestEndpoint(options?)
// ── frontend signing (Hive Keychain) ─────────────────────────────
hive.keychain.isAvailable() -> boolean
hive.keychain.requestSignIn({ username, message, authority? })
hive.keychain.customJson({ username, id, action, metadata?, authority?, message? })
hive.keychain.customJsonRaw({ username, id, json, authority?, message? })
hive.keychain.requestTransfer({ username, to, amount, currency, memo, enforce? })
// currency "HIVE" | "HBD" -> native transfer; any token symbol -> Hive Engine token transfer
hive.keychain.payments.hive.transfer({ username, account, amount, symbol, action, metadata?, message? })
hive.keychain.payments.engine.transfer({ username, account, symbol, quantity, action, metadata?, message? })
hive.keychainIssuer.token.issue | transfer | burn (+ buildIssue | buildTransfer | buildBurn)
hive.keychainIssuer.token.create({ username, symbol, name, precision, maxSupply, url?, skipChecks? })
// checks BEE balance vs the creation fee and that the symbol is free before signing
hive.keychainIssuer.token.checkCreate({ username, symbol }) -> TokenCreationCheck (read-only)
hive.keychainIssuer.token.buildCreate(input) -> offline payload preview
hive.keychainIssuer.nft.issue | issueMultiple | transfer | burn (+ build* variants)
hive.keychainIssuer.nft.create({ username, name, symbol, orgName?, productName?,
maxSupply?, website?, authorizedIssuingAccounts?,
authorizedIssuingContracts?, skipChecks? })
hive.keychainIssuer.nft.checkCreate({ username, symbol }) -> NftCreationCheck (read-only)
hive.keychainIssuer.nft.buildCreate(input) -> offline payload preview
// ── streaming: ONE engine, four views ────────────────────────────
hive.blocks.watch(options) -> AsyncGenerator<NormalizedBlock>
hive.customJson.parse(operation, options?) -> CustomJsonEvent | null
hive.customJson.watch(options) -> AsyncGenerator<CustomJsonEvent>
hive.payments.watch(options) -> AsyncGenerator<ParsedPayment>
hive.reader.stream(options) -> StreamEngine
engine.customJson(filter) | payment(filter) | onEvent(handler) -> StreamSubscription
engine.start() | stop() | pause() | resume() | clearFilters()
// ── reading ──────────────────────────────────────────────────────
hive.reader.transaction({ transactionId, id?, actions? }) -> TransactionResult
// ── payments ─────────────────────────────────────────────────────
hive.payments.parse({ transactionId }) -> ParsedPayment[]
hive.payments.validate({ transactionId, expected? }) -> ParsedPayment
hive.payments.hive.build(input) | transfer(input) // native HIVE / HBD
hive.payments.engine.build(input) | transfer(input) // Layer 2 tokens
hive.payments.engineRpc.getTransactionInfo(id) | findOne(params)
// ── issuing (backend, signed with a resolved key) ────────────────
hive.issuer.token.issue | transfer | burn (+ buildIssue | buildTransfer | buildBurn)
hive.issuer.token.create({ from, symbol, name, precision, maxSupply, url?, skipChecks? })
hive.issuer.token.checkCreate(input) | buildCreate(input) // input takes { from, symbol, … }
hive.issuer.nft.issue | issueMultiple | transfer | burn (+ build* variants) | countInstances
hive.issuer.nft.create({ from, name, symbol, orgName?, productName?, maxSupply?,
website?, authorizedIssuingAccounts?, authorizedIssuingContracts?,
skipChecks? })
hive.issuer.nft.checkCreate(input) | buildCreate(input) // input takes { from, symbol, … }
// burn is implemented as a transfer to "null"hive.configs
hive.configs; // exactly what you passed, frozen
hive.configs.tests.accounts.minter; // your own nested structure
hive.listAccounts(); // ["treasury"]
hive.account("treasury"); // AccountReference (no keys)
hive.resolveAccount("treasury"); // { alias, account }hive.rpc / hive.beacon
const head = await hive.rpc.getHeadBlockNumber();
const props = await hive.rpc.getDynamicGlobalProperties();
const block = await hive.rpc.getBlock(head);
// Any node method, typed by the caller.
const [account] = await hive.rpc.call<Account[]>(
"condenser_api.get_accounts",
[["alice"]],
);
// Node discovery. resetEndpoint() clears a sticky failed node.
const nodes = await hive.beacon.getHealthyNodes();
const best = await hive.beacon.getBestEndpoint();
hive.rpc.resetEndpoint();hive.keychain
if (!hive.keychain.isAvailable()) throw new Error("Install Hive Keychain");
const signIn = await hive.keychain.requestSignIn({
username: "alice",
message: "Sign in to my-application: nonce-123456",
authority: "posting",
});
// Standardized { action, metadata } payload.
await hive.keychain.customJson({
username: "alice",
id: "my-application",
action: "claim_reward",
metadata: { questId: 42 },
authority: "posting", // "posting" | "active"
message: "Claim your reward",
});
// Raw, already-serialized body — broadcast verbatim.
await hive.keychain.customJsonRaw({
username: "alice",
id: "my-application",
json: JSON.stringify({ action: "ping", metadata: null }),
});
// Native transfer with a standardized trigger in the memo.
await hive.keychain.requestTransfer({
username: "alice",
to: "treasury",
amount: "1.000",
currency: "HIVE", // "HIVE" | "HBD" -> Layer 1 transfer
memo: JSON.stringify({ action: "buy_pack", metadata: { packs: 1 } }),
enforce: true,
});
// Layer 2 token transfer — same call, just use the token symbol as currency.
await hive.keychain.requestTransfer({
username: "alice",
to: "treasury",
amount: "5",
currency: "SCRAP", // any Hive Engine symbol -> token transfer
memo: JSON.stringify({ action: "buy_pack", metadata: { packs: 1 } }),
});
// Layer 2 contract actions signed by the user's own keys (custom_json).
await hive.keychainIssuer.token.transfer({
username: "alice",
symbol: "SCRAP",
account: "bob",
quantity: "5",
});Keychain sign-in
Added in 1.2.0. requestSignIn() asks Hive Keychain to sign a challenge message with the account's key, so your backend can verify the signature and issue a session. Use a server-issued nonce in the message to prevent replays.
| Parameter | Type | Required | Description |
|---|---|---|---|
| username | string (required) | No | Hive account signing in. |
| message | string (required) | No | Challenge to sign. Include a server-issued nonce. |
| authority | "posting" | "active" | No | Key used for the signature. Defaults to "posting". |
| Parameter | Type | Required | Description |
|---|---|---|---|
| username | string | No | Account that signed. |
| message | string | No | Exact challenge that was signed. |
| authority | "posting" | "active" | No | Key authority used. |
| signature | string | No | Signature to verify server-side. |
| timestamp | number | No | Client timestamp of the signature. |
| raw | KeychainResponse | No | Untouched Keychain response. |
const { nonce } = await fetch("/api/auth/nonce").then((r) => r.json());
const signIn = await hive.keychain.requestSignIn({
username: "alice",
message: `Sign in to my-application: ${nonce}`,
authority: "posting",
});
await fetch("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username: signIn.username,
message: signIn.message,
signature: signIn.signature,
}),
});Token & NFT creation
Added in 1.2.0. Both a token and an NFT cost 100 BEE to create on Hive Engine and both symbols are unique on the sidechain, so every create() runs a preflight first: the signing account must hold the fee in BEE and the symbol must still be free. A failure throws INSUFFICIENT_BEE, TOKEN_ALREADY_EXISTS or NFT_ALREADY_EXISTS before Keychain opens or a key is resolved. Pass skipChecks: true to opt out — creation fees are non-refundable.
The same methods exist on both issuers: hive.keychainIssuer (browser, signed by the user) and hive.issuer (backend, signed with a resolved key).
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string (required) | No | Display name, up to 50 letters, digits and spaces. |
| symbol | string (required) | No | Uppercase letters only, up to 10 characters. |
| precision | number (required) | No | Decimal places, 0 to 8. |
| maxSupply | string (required) | No | Positive decimal string. Never a float. |
| url | string | No | Optional website. Editable later in the TribalDex Token Manager. |
| skipChecks | boolean | No | Skips the BEE / symbol preflight. Off by default. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string (required) | No | Display name, up to 50 letters, digits and spaces. |
| symbol | string (required) | No | Uppercase letters only, up to 10 characters. |
| orgName / productName | string | No | Optional organization and product names. |
| maxSupply | string | No | Optional positive decimal string. Unlimited when omitted. |
| website | string | No | Optional project website. |
| authorizedIssuingAccounts | string[] | No | Optional accounts allowed to issue instances. |
| authorizedIssuingContracts | string[] | No | Optional contracts allowed to issue instances. |
| skipChecks | boolean | No | Skips the BEE / symbol preflight. Off by default. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| fee / balance | string | No | BEE required by the sidechain and the account's liquid BEE balance. |
| hasEnoughBee | boolean | No | Balance covers the fee. |
| symbolExists | boolean | No | The symbol is already taken. |
| existingToken / existingNft | EngineTokenRow | EngineNftRow | null | No | The existing row when the symbol is taken. |
| ok | boolean | No | True only when the fee is affordable and the symbol is free. |
| issues | string[] | No | Human-readable reasons creation would fail. |
// ── Keychain (browser, user signs with their Active key) ─────────
const check = await hive.keychainIssuer.token.checkCreate({
username: "alice",
symbol: "SCRAP",
});
check.ok; check.fee; check.balance; check.issues;
await hive.keychainIssuer.token.create({
username: "alice",
name: "Scrap Token",
symbol: "SCRAP",
precision: 3,
maxSupply: "1000000",
url: "https://scrap.gg", // optional
});
await hive.keychainIssuer.nft.create({
username: "alice",
name: "Raider Cards",
symbol: "CARD",
orgName: "Idle Raiders", // optional
maxSupply: "10000", // optional
});
// ── Backend (signed with a resolved key) ─────────────────────────
const preview = hive.issuer.token.buildCreate({
symbol: "SCRAP",
name: "Scrap Token",
precision: 3,
maxSupply: "1000000",
}); // offline payload, no network
await hive.issuer.token.create({
from: hive.accounts.treasury,
name: "Scrap Token",
symbol: "SCRAP",
precision: 3,
maxSupply: "1000000",
});
await hive.issuer.nft.create({
from: hive.accounts.treasury,
name: "Raider Cards",
symbol: "CARD",
});hive.blocks.watch()
The raw core stream. Every other streaming API is built on it, so use this only when you need untouched blocks.
| Parameter | Type | Required | Description |
|---|---|---|---|
| fromBlock | number | No | First block to read. Defaults to the head block (live). |
| signal | AbortSignal | No | Stops the iterator cleanly. |
| pollIntervalMs | number | No | Poll interval while waiting for new blocks. Default 3000. |
| onError | (error, blockNumber) => void | No | Called on recoverable RPC errors instead of throwing. |
| maxRetriesPerBlock | number | No | Consecutive failures on one block before throwing. Default 5. |
const controller = new AbortController();
for await (const block of hive.blocks.watch({
fromBlock: 109_542_165,
pollIntervalMs: 3000,
signal: controller.signal,
onError: (error, blockNumber) => console.warn(blockNumber, error),
})) {
console.log(block.blockNumber, block.transactions.length);
}
controller.abort();hive.customJson
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string (required) | No | custom_json id to filter by. |
| actions | string[] | No | Action allow-list, OR-matched against the payload action. |
| onInvalidPayload | ({ reason, blockNumber, raw }) => void | No | Called when the id matches but the payload breaks the protocol. Never throws. |
// One-off parse of a single operation (needs the block position context).
const result = hive.customJson.parse(operation, position, { id: "my-application" });
if (result.status === "ok") console.log(result.event.action, result.event.metadata);
// Filtered async iteration over the core stream.
for await (const event of hive.customJson.watch({
id: "my-application",
actions: ["claim_reward", "buy_pack"], // OR filter
fromBlock: 109_542_165,
onInvalidPayload: ({ reason, blockNumber }) => console.warn(blockNumber, reason),
})) {
console.log(event.account, event.action, event.metadata);
}hive.payments
| Parameter | Type | Required | Description |
|---|---|---|---|
| filters.from | string | No | Sender account. |
| filters.account | string | No | Recipient account. |
| filters.symbol | string | No | HIVE, HBD or any Layer 2 token symbol. |
| filters.quantity | string | No | Exact amount, compared as a decimal string. |
| filters.actions | string[] | No | Trigger actions, OR-matched. Implies a valid trigger. |
| filters.requireTrigger | boolean | No | Only emit transfers carrying a valid standardized trigger. |
| onSuccess | (payment) => void | No | Verified payments (success === true). |
| onFailed | (payment) => void | No | Payments whose Layer 2 execution failed. |
// Build and send — native HIVE / HBD.
const preview = hive.payments.hive.build({
from: hive.accounts.treasury,
account: "bob", // recipient
amount: "1.000", // decimal string
symbol: "HIVE", // "HIVE" or "HBD"
action: "payout",
metadata: { invoice: "INV-1" },
});
preview.amount; // "1.000 HIVE"
preview.memo; // serialized trigger
await hive.payments.hive.transfer(preview);
// Build and send — Layer 2 token.
await hive.payments.engine.transfer({
from: hive.accounts.treasury,
account: "bob",
symbol: "SCRAP",
quantity: "1",
action: "payout",
metadata: { invoice: "INV-2" },
});
// Read a transaction's payments without execution checks.
const payments = await hive.payments.parse({ transactionId: "7b064a84…" });
// Verify one payment against expectations.
const result = await hive.payments.validate({
transactionId: "7b064a84…",
expected: { account: "rhiaji", symbol: "SCRAP", quantity: "1", action: "buy_pack" },
});
result.status; // "success" | "failed" | "pending" | "invalid" | "not_found"
// Preferred live iteration.
for await (const payment of hive.payments.watch({
filters: { account: "rhiaji", symbol: "SCRAP", actions: ["buy_pack"] },
onFailed: (failed) => console.warn("execution failed", failed.transactionId),
})) {
if (payment.trigger) fulfil(payment.trigger.action, payment.trigger.metadata);
}
// Raw sidechain access when you need it.
await hive.payments.engineRpc.getTransactionInfo("7b064a84…");hive.reader
| Parameter | Type | Required | Description |
|---|---|---|---|
| engineConfirmationAttempts | number | No | Re-reads of a pending Layer 2 execution before giving up. Default 6. |
| engineConfirmationDelayMs | number | No | Delay between Layer 2 execution reads, in ms. Default 2000. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | No | custom_json id, e.g. "my-game". |
| actions | string[] | No | OR-matched against the standardized payload action. |
| standardizedOnly | boolean | No | Only match payloads following the { action, metadata } protocol. |
| handler | (event) => void (required) | No | Receives every matching CustomJsonStreamEvent. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| from / account / symbol | string | No | Sender, recipient and currency or token symbol. |
| quantity | string | No | Decimal string, compared precision-safely. Never a number. |
| actions | string[] | No | Trigger actions, OR-matched. Implies a valid trigger. |
| requireTrigger | boolean | No | Only match transfers carrying a valid standardized trigger. |
| handler | (event) => void (required) | No | Verified successful payments only. |
| onFailed | (event) => void | No | Matching payments whose Layer 2 execution failed. |
// One transaction, decoded.
const read = await hive.reader.transaction({
transactionId: "7b064a84…",
id: "my-application", // optional custom_json id filter
});
read.blockNumber; read.operations; read.customJson; read.payments; read.nfts; read.invalid;
// One engine, one block reader, many filters.
const stream = hive.reader.stream({
fromBlock: 109_542_165,
engineConfirmationAttempts: 6,
engineConfirmationDelayMs: 2000,
});
const offJson = stream.customJson({
id: "my-application",
actions: ["claim_reward"],
standardizedOnly: true,
handler: (event) => console.log(event.account, event.action, event.metadata),
});
const offPay = stream.payment({
account: "rhiaji",
symbol: "SCRAP",
actions: ["buy_pack"],
handler: (event) => fulfil(event.trigger?.action, event.trigger?.metadata),
onFailed: (event) => console.warn("failed", event.transactionId, event.error),
});
// Firehose of every normalized event produced by the registered filters.
stream.onEvent((event) => {
if (event.type === "custom_json") console.log(event.id, event.action);
else console.log(event.transfer.symbol, event.status);
});
await stream.start();
stream.pause();
stream.resume();
offJson.unsubscribe();
offPay(); // subscriptions are callable too
stream.clearFilters();
stream.stop();hive.issuer
// Offline preview: no key resolution, no network.
const preview = hive.issuer.token.buildTransfer({
from: hive.accounts.treasury,
symbol: "SCRAP",
account: "bob",
quantity: "5",
});
preview.alias; preview.account; preview.id; preview.json; preview.operation;
// Broadcast variants.
await hive.issuer.token.issue({ from: hive.accounts.treasury, symbol: "SCRAP", account: "bob", quantity: "10" });
await hive.issuer.token.transfer({ from: hive.accounts.treasury, symbol: "SCRAP", account: "bob", quantity: "5" });
await hive.issuer.token.burn({ from: hive.accounts.treasury, symbol: "SCRAP", quantity: "5" }); // transfer to "null"
// NFTs.
await hive.issuer.nft.issue({
from: hive.accounts.treasury,
symbol: "CARD",
account: "bob",
feeSymbol: "BEE",
properties: { rarity: "rare" },
});
await hive.issuer.nft.issueMultiple({
from: hive.accounts.treasury,
instances: [
{ symbol: "CARD", account: "bob", feeSymbol: "BEE" },
{ symbol: "CARD", account: "carol", feeSymbol: "BEE" },
],
});
await hive.issuer.nft.transfer({
from: hive.accounts.treasury,
account: "bob",
nfts: [{ symbol: "CARD", ids: ["1", "2"] }],
});
await hive.issuer.nft.burn({
from: hive.accounts.treasury,
symbol: "CARD",
id: "3", // string | string[]
});
hive.issuer.nft.countInstances({ nfts: [{ symbol: "CARD", ids: ["1", "2"] }] }); // 2Every result branch
Payments are normalized to one shape for both networks, so branching is the same code path whether the transfer was native HIVE/HBD or a Layer 2 token.
| Parameter | Type | Required | Description |
|---|---|---|---|
| success | success === true | No | The transfer and, for Layer 2, its execution succeeded. |
| failed | success === false | No | The transaction exists but execution failed. |
| pending | success === null | No | Not yet indexed enough to verify — retried automatically while streaming. |
| invalid | success === false | No | The transaction exists but does not match expectations. |
| not_found | success === false | No | The transaction cannot be found. |
switch (payment.status) {
case "success": return fulfil(payment);
case "failed": return refund(payment);
case "pending": return retryLater(payment);
case "invalid": return flagMismatch(payment);
case "not_found": return ignore(payment);
}
// Trigger branches — a bad memo never breaks the stream.
if (payment.trigger) {
handle(payment.trigger.action, payment.trigger.metadata);
} else {
// empty, plain-text or malformed memo: surfaced, but not processed
log("no trigger", payment.transactionId);
}
// Custom JSON branches.
if (event.standardized && event.customJson) {
handle(event.action, event.metadata);
} else {
inspectRaw(event.json); // raw protocol payload, still emitted
}
// Idempotency key for both event kinds.
const key = `${payment.transactionId}:${payment.operationIndex ?? 0}`;