Currently in Beta — use at your own risk. For support, please join the Discord 🐝

HiveSwap API

Stateless DEX and bridge API for Hive Engine. Returns unsigned custom_json ops and native Hive transfer ops; you sign with Hive Keychain (browser) or your own posting/active key (server). The API never sees private keys.

Quick facts

  • Base URL: https://api.hive-swap.com
  • Auth: none. Per-IP rate limit: 30 requests / minute.
  • Response envelope: { ok: true, data: ... } or { ok: false, error: { code, message } }.
  • CORS: Access-Control-Allow-Origin: * on every response.
  • Platform fee: 0.25% (25 bps) of input — collected by the first op the API returns. Don't strip it.
  • For LLM integrators: see /llms.txt and /llms-full.txt.

Endpoint index

Endpoints

GET/health

Liveness probe. Not rate limited.

Response
{ "ok": true, "data": { "status": "ok", "service": "hive-swap-api", "version": "v1", "time": "2026-05-11T..." } }

GET/tokens

All Hive Engine tokens with precision and icon.

Response
{ "ok": true, "data": { "tokens": [ { "symbol": "BEE", "name": "BEE Token", "precision": 8, "issuer": "aggroed", "icon": "https://..." } ] } }

GET/pools

All marketpools liquidity pools.

Response
{ "ok": true, "data": { "pools": [ { "tokenPair": "SWAP.HIVE:BEE", "baseQuantity": "...", "quoteQuantity": "...", "basePrice": "...", "quotePrice": "...", "totalShares": "..." } ] } }

GET/gateways

HIVE peg gateway info (uswap, honey-swap) — fees, minimums, and capacity.

Response
{ "ok": true, "data": { "platformFeeBps": 25, "heGateways": [ { "account": "uswap", "label": "USWAP", "feePct": 0.09, "pegInMin": 1, "pegInSoftCap": 10000 }, { "account": "honey-swap", "label": "HivePegged", "feePct": 0.75, "pegInMin": 1, "pegInSoftCap": null } ] } }

pegInSoftCapis the gateway's usable SWAP.HIVE capacity (null = unlimited); /bridge/in/build picks the cheapest gateway with enough capacity for the requested amount. External-chain bridges (EVM, BTC/LTC/DOGE/BCH, and HE-native ETH/BNB/POL/SOL) have been withdrawn and are no longer advertised here.

GET/gateways/latency

Observed gateway round-trip times + liveness, derived from chain history. A Cloudflare cron refreshes every 5 minutes by pairing each inbound transfer to a gateway with the matching outbound transfer (by user account, FIFO), reporting p50 / p90 / sample-count over a 24h lookback. The same history fetch also produces per-direction health (isHealthy + lastActivityHours) so clients don't need to poll a separate endpoint.

Response
{ "ok": true, "data": { "dswap": { "pegIn": { "samples": 47, "p50Ms": 480000, "p90Ms": 1320000, "observedAt": 1747140000000 }, "pegOut": { "samples": 38, "p50Ms": 720000, "p90Ms": 1800000, "observedAt": 1747140000000 }, "health": { "pegIn": { "isHealthy": true, "lastActivityHours": 0.12, "observedAt": 1747140000000 }, "pegOut": { "isHealthy": false, "lastActivityHours": 7.4, "observedAt": 1747140000000 } } }, "generatedAt": 1747140000000 } }

Latency stats are null when no pairs were observed in the lookback window (fall back to a documented estimate — DSwap quotes 5–30 min). Health is always present; lastActivityHours is null when nothing has been observed. Times are in milliseconds. The endpoint is edge-cached for 60 s and server-refreshed every 5 min — don't poll faster than that. Honey-swap / uswap directions aren't measured here yet.

POST/quote

Get a swap quote. GET with query params is also accepted. The router searches the full pool graph (up to 3 hops) through any intermediate token, considers AMM pools and the Hive Engine order book on every leg, and may split a single hop between them when that improves price. Pass username to get a quote that's BEED-aware and matches what /swap/build will produce.

Request
{ "fromSymbol": "SWAP.HIVE", "toSymbol": "BEE", "amount": "10", "slippagePct": 1, "username": "alice", "autoSlippage": true }
Response
{ "ok": true, "data": { "quote": { "route": [{ "tokenIn": "SWAP.HIVE", "tokenOut": "BEE", "amountIn": "10", "amountOut": "...", "poolPair": "SWAP.HIVE:BEE", "poolPortion": { "amountIn": "6", "amountOut": "...", "poolPair": "SWAP.HIVE:BEE" }, "bookPortion": { "amountIn": "4", "amountOut": "...", "side": "buy", "worstPrice": "...", "limitPrice": "...", "levelsConsumed": 3, "fullyFilled": true } }], "amountIn": "10", "amountOut": "...", "priceImpact": "0.0123", "minAmountOut": "..." }, "recommendedSlippagePct": 1.5 } }

Each route step may carry poolPortion (AMM via marketpools), bookPortion (HE order book via market.buy/market.sell), or both (split route).

The top-level poolPair on a step is kept for backwards compatibility and mirrors poolPortion?.poolPair; new integrations should read the portions directly. bookPortion.limitPriceis the worst price you'll accept on the book leg — HE matches at the maker's price, not at limitPrice.

The router walks the pool graph up to 3 hops through any intermediate token and returns the route with the highest output after fees — that may be a longer path than the obvious direct one if an arbitrage route is more efficient, and pairs that previously failed because the target had no SWAP.HIVE pool (e.g. HSBIDAO) now route through whichever connector token has a path. Dead pools (zero reserves on either side) are filtered out. Order books still apply only to SWAP.HIVE-paired legs (HE protocol constraint), so multi-hop routes can layer in book depth on the hops that touch the hub.

Optional autoSlippage: true. When set, the response includes recommendedSlippagePct— the route's price impact plus a 0.5% buffer, rounded up to the nearest 0.5%, capped at 5%. Pass this value as slippagePct to /swap/build to get impact-aware slippage protection. The quote itself is still built with the slippagePct you supplied (or the default 1%).

Optional username.When supplied, the quote becomes BEED-aware: if the account holds < 0.002 BEED, book legs are stripped and a pool-only route is returned (the HE market.* contract burns 0.001 BEED per book action and the swap would otherwise revert at broadcast). Omit username to get the raw best-output route. Pass it when you want the quote to match what /swap/build will actually return for the same user.

Errors: NO_ROUTE (404) when no path within 3 hops connects the pair via pools and SWAP.HIVE-paired books. INVALID_INPUT when username is present but malformed.

POST/swap/build

Build the unsigned custom_json ops for a swap. Includes the 0.25% platform fee transfer as the first op. Ops can mix marketpools.swapTokens (pool portion) with market.buy / market.sell (book portion) when the router picks a split route.

Request
{ "username": "alice", "fromSymbol": "SWAP.HIVE", "toSymbol": "BEE", "amount": "10", "slippagePct": 1 }
Response
{ "ok": true, "data": { "quote": { ... }, "ops": [ { "contractName": "tokens", "contractAction": "transfer", "contractPayload": { "symbol": "SWAP.HIVE", "to": "hive-swap-fees", "quantity": "0.025", "memo": "HiveSwap swap: SWAP.HIVE→BEE | r:a8f2c1", "isSignedWithActiveKey": true } }, { "contractName": "marketpools", "contractAction": "swapTokens", "contractPayload": { "tokenPair": "SWAP.HIVE:BEE", "tokenSymbol": "SWAP.HIVE", "tokenAmount": "5.985", "tradeType": "exactInput", "minAmountOut": "...", "isSignedWithActiveKey": true } }, { "contractName": "market", "contractAction": "buy", "contractPayload": { "symbol": "BEE", "quantity": "...", "price": "..." } } ], "signing": { "method": "requestCustomJson", "hiveChainId": "ssc-mainnet-hive", "keyType": "Active", "displayName": "...", "note": "..." } } }

All ops sit in the same Hive custom_json, but Hive Engine's atomicity is per-op, not per-Hive-tx: each op reverts on its own, so the fee transfer executes even when every swap op after it reverts. That is why this endpoint refuses to build a swap it can already tell will revert (see INSUFFICIENT_BALANCE and BEED_REQUIREDbelow). Intermediate hops use minimal slippage protection on the pool leg; the final hop carries the user's minAmountOut. Book legs enforce slippage per-leg via price (= bookPortion.limitPrice).

BEED multi-tx fee — auto-routed around. Hive Engine's market contract burns 0.001 BEED per market.buy/market.sell action (via resourcemanager). Without BEED, those ops revert at the burn step while the fee transfer op in the same Hive tx still succeeds — silently draining the user's input token. To prevent this, /swap/build checks the supplied username and strips book-routed legs when the account holds < 0.002 BEED, returning a pool-only build that has no market.* ops. No client-side handling required for the common case.

Edge case: no pool path exists. If the only route to toSymbol goes through the order book (rare — obscure tokens with no AMM liquidity), there is nothing to strip, so the endpoint returns BEED_REQUIRED (400) rather than ops that would charge the fee and revert. /quote still returns the book route, so you can show the price and then have the user acquire any small amount of BEED through an HE wallet, or prepend a beedollar.convert op yourself (1 BEE → ~39 BEED, 1% fee, 1 BEE chain min) in the same Hive tx. The web UI offers an in-app bootstrap; third-party integrations can do the equivalent.

Balance check. The endpoint reads the account's fromSymbol balance (uncached) at build time and returns INSUFFICIENT_BALANCE (400) when it is below amount. Do not reuse a build across a balance change — the swap ops would revert while the fee transfer still lands. If the balance RPC is unreachable the check is skipped rather than failing the request.

POST/bridge/in/build

Build native Hive transfer ops to peg HIVE into SWAP.HIVE via uswap/honey-swap.

Request
{ "type": "he", "username": "alice", "amount": "5", "slippagePct": 1 }
Response
{ "ok": true, "data": { "gateway": "uswap", "ops": [ ["transfer", { "from": "alice", "to": "hive-swap-fees", "amount": "0.012 HIVE", "memo": "HiveSwap peg-in: HIVE→SWAP.HIVE | r:b7e3d2" }], ["transfer", { "from": "alice", "to": "uswap", "amount": "4.988 HIVE", "memo": "4.884" }] ], "split": { "netAmount": "4.988", "feeAmount": "0.012", "totalAmount": "5.000", "feePct": 0.25 }, "signing": { "method": "broadcastOps", "keyType": "Active", "displayName": "...", "note": "..." } } }
These are native Hive transfer operations, not custom_json. Sign as a normal Hive transaction (broadcastOps in the SDK, or window.hive_keychain.requestBroadcast in the browser). Errors: BELOW_MIN if the amount is below the gateway's pegInMin. The former type: 'evm' (HIVE → wHIVE on Base/BSC/Eth) has been withdrawn and now returns BRIDGE_DISABLED (410).

POST/bridge/out/build

Build custom_json ops for SWAP.HIVE → native HIVE peg-out via the hivepegged contract. SWAP.HIVE only — the contract is HIVE-only. The web UI also has a USWAP fast-path when that gateway has reserves; the API always returns the contract path.

Request
{ "username": "alice", "amount": "10" }
Response
{ "ok": true, "data": { "ops": [ { "contractName": "tokens", "contractAction": "transfer", "contractPayload": { "symbol": "SWAP.HIVE", "to": "hive-swap-fees", "quantity": "0.025", "memo": "HiveSwap peg-out: SWAP.HIVE→HIVE | r:c9a4b3" } }, { "contractName": "hivepegged", "contractAction": "withdraw", "contractPayload": { "quantity": "9.975", "isSignedWithActiveKey": true } } ], "split": { "netAmount": "9.975", "feeAmount": "0.025", "totalAmount": "10.000", "feePct": 0.25 }, "symbol": "SWAP.HIVE", "signing": { "method": "requestCustomJson", "hiveChainId": "ssc-mainnet-hive", "keyType": "Active", ... } } }

HBD ↔ SWAP.HBD — web UI only

HBD bridging is a direct 1:1 peg through the graphene-swap gateway account, minus a 0.75% gateway fee. It is currently available only in the web UI, via the swap widget at /swap.

The gateway memo grammar is <TOKEN> <destination-account> — it mints TOKEN and credits it to destination-account. Peg-in is a Hive L1 transfer to graphene-swap with memo SWAP.HBD <username>; peg-out is a Hive Engine tokens.transfer with memo HBD <username>. Completion is observed by polling the recipient's balance.

Do not place a routing hint or request id in the second field — the gateway reads it as the destination account and delivers the pegged funds there instead of to the user. There is no /bridge/hbd/* endpoint yet; integrators must build against graphene-swap directly as described above.

GET/status/{ref}

Bridge transaction status by reference. This backed the webhook-driven external-chain flows, which have been withdrawn — it now serves historical records only, and no active flow produces new refs.

Response
{ "ok": true, "data": { "reference": "...", "status": "pending|completed|failed", "direction": "...", "hops": [...], "createdAt": ..., "updatedAt": ... } }

Points, profiles, and leaderboard

Every successful swap and bridge earns the user Points. Swaps award 10 pts per $1 of input volume, bridges 15 pts per $1. Points are fractional — a $0.05 swap earns 0.5 pts, a $0.005 bridge earns 0.075 pts. Trades below $0.005 USDearn 0. Points are derived from on-chain fee events by replaying transaction logs — failed routes earn nothing (fee was paid, action didn't execute). New activity typically reflects on profiles within ~5 minutes.

Levels 1-30 are grouped into 6 tiers: Shrimp → Crab → Octopus → Dolphin → Shark → Whale. Threshold curve: floor(30 × (L-1)^3.8). Reaching L30 (Whale max) takes ~$1.08M lifetime volume.

Badges are computed at read time — adding a new badge applies retroactively and never requires a migration.

GET/profile/{username}

Points profile for a Hive user. Always succeeds — users with no activity return level 1 / 0 points / all badges locked.

Response
{ "ok": true, "data": { "username": "alice", "level": 12, "maxLevel": 30, "tier": { "id": "octopus", "name": "Octopus", "color": "#b85450" }, "totalPoints": 312450, "pointsIntoLevel": 45753, "pointsToNext": 57250, "currentThreshold": 266697, "nextThreshold": 369902, "lifetimeVolumeUsd": 31245.7, "swapCount": 142, "bridgeCount": 8, "firstSeenTs": 1722470000, "lastActivityTs": 1747000000, "badges": [ { "id": "tier_shrimp", "label": "Shrimp", "description": "Reach level 5", "earned": true }, { "id": "tier_whale", "label": "Whale", "description": "Reach level 30", "earned": false }, { "id": "first_swap", "label": "First Swap","description": "Complete your first swap", "earned": true }, { "id": "centurion", "label": "Centurion", "description": "Complete 100 swaps", "earned": true } ], "leaderboardRank": 17 } }

Tier ceiling volumes (approx): Shrimp ~$582 · Crab ~$12.7k · Octopus ~$68k · Dolphin ~$218k · Shark ~$528k · Whale ~$1.08M. Badge IDs: tier_*, first_swap, centurion, first_bridge, cross_chain, megalodon ($10k+ event), kraken ($100k+ event), og.

GET/profile/{username}/activity

Paginated points-earning events for a user. Newest first. Pass ?before=<ts> for the next page.

Request
GET /profile/alice/activity?limit=25&before=1747000000
Response
{ "ok": true, "data": { "events": [{ "opId": "67d8a3c1e9b8d4a000000123", "ts": 1747000000, "kind": "swap", "volumeUsd": 0.05, "pointsEarned": 0.5, "symbol": "SWAP.HIVE", "amount": "0.305", "txId": "abc123...", "source": "he", "memo": null, "routeSteps": [{ "symbol": "SWAP.HIVE", "amount": "122.0" }, { "symbol": "BEE", "amount": "..." }] }], "nextBefore": 1747000000 } }

Failed swaps appear with volumeUsd: 0, pointsEarned: 0so they show up in history but don't earn points. routeSteps is best-effort — nullif the route couldn't be resolved.

GET/leaderboard

Top users by total points (all-time). Time-windowed variants (24h / 7d / 30d) are not yet supported.

Request
GET /leaderboard?limit=100
Response
{ "ok": true, "data": { "rows": [{ "rank": 1, "username": "alice", "level": 27, "tier": { "id": "whale", "name": "Whale", "color": "#1e3a5f" }, "totalPoints": 8104225, "lifetimeVolumeUsd": 810422.5, "swapCount": 412, "bridgeCount": 28, "lastActivityTs": 1747000000 }], "total": 1247 } }

Signing the returned ops

Browser — Hive Keychain (custom_json)

for (const op of data.ops) { await new Promise((resolve, reject) => { window.hive_keychain.requestCustomJson( 'alice', // username 'ssc-mainnet-hive', // chain id (always this for HE) 'Active', // key type JSON.stringify(op), 'HiveSwap', // display label (r) => r.success ? resolve(r) : reject(new Error(r.message)) ); }); }

Each op produces one Keychain prompt. The SDK's broadcastOps wraps this loop.

Server — dhive (bundle into one tx)

import { Client, PrivateKey } from '@hiveio/dhive'; const client = new Client(['https://api.hive.blog']); // Hive Engine ops (from /swap/build, /bridge/out/build): const ops = data.ops.map(op => ['custom_json', { required_auths: ['alice'], required_posting_auths: [], id: 'ssc-mainnet-hive', json: JSON.stringify(op), }]); // Native bridge transfers (from /bridge/in/build) are already in [opName, payload] shape: // const ops = data.ops; await client.broadcast.sendOperations(ops, PrivateKey.fromString(process.env.HIVE_ACTIVE_KEY));

Error codes

CodeHTTPMeaning
INVALID_INPUT400Missing or malformed parameter.
NO_ROUTE404No swap path within 3 hops.
BELOW_MIN400Bridge amount below the gateway minimum.
INSUFFICIENT_BALANCE400/swap/build: account holds less than amount of fromSymbol.
BEED_REQUIRED400/swap/build: only route is order-book and the account holds < 0.002 BEED.
NOT_FOUND404Reference not found.
RATE_LIMITED429Per-IP limit exceeded. Includes Retry-After.
UPSTREAM502Hive / Hive Engine RPC unreachable.
INTERNAL500Unhandled error.

Tips for integrators

  • Always re-quote close to broadcast time. Pool reserves shift and book depth turns over fast; an old minAmountOut or bookPortion.limitPrice can be too tight and revert.
  • Book routes need BEED — but /swap/build handles it. When you call /swap/build with username (already required) the API strips book legs for accounts holding < 0.002 BEED and returns a pool-only build. Pass username to /quote too so the displayed quote matches. For the rare pair with no pool path at all it returns BEED_REQUIRED instead of a build that would only charge the fee.
  • Builds are balance-checked. /swap/buildreads the account's input-token balance and returns INSUFFICIENT_BALANCE rather than ops. Because HE atomicity is per-op, a stale build reverts every swap op while the fee transfer still lands — build fresh.
  • The platform fee is in the ops, not deducted by the API. The first op in every build response is the fee transfer to hive-swap-fees. Do not strip it — your effective output assumes it ran.
  • Bridge minimums are HARD. Sending below minTotalHive to a gateway can result in funds being permanently stuck (the gateway oracle ignores the transfer). The API enforces BELOW_MIN to prevent this — do not bypass it client-side.
  • Native vs custom_json ops are different shapes. /swap/build and /bridge/out/build return [{ contractName, contractAction, contractPayload }, ...] (Hive Engine custom_json). /bridge/in/build returns [[opName, payload], ...] (native Hive ops). Sign accordingly.
  • Chain id for HE ops is ssc-mainnet-hive. Always.

Changelog

  • v1.0 — Initial public API: tokens, pools, gateways, quote, swap/build, bridge in/out, status.
  • 2026-08-19 — Removed the dedicated /bridge page; it now redirects to /swap, which handles both Hive-internal pegs through the same gateways. Bridge history moved into the swap history drawer as a sub-tab.
  • 2026-08-19 — Withdrew external-chain bridges. /bridge/converter/quote and /bridge/converter/coins are removed; /gateways no longer returns evmBridges, converterBridges or nativeBridges; /bridge/in/build accepts only type: 'he'. Only the Hive-internal pegs remain (HIVE ↔ SWAP.HIVE, HBD ↔ SWAP.HBD). /status/{ref} serves historical records only.
  • 2026-08-18 — Fixed HBD ↔ SWAP.HBD peg memos. The gateway memo now names the receiving user (SWAP.HBD <username> / HBD <username>) instead of a DSwap routing hint, which the gateway read as the destination account and misdelivered to dswap. HBD pegs no longer involve the DSwap API; the quoted receive is now the true 1:1-minus-0.75% peg rate.
  • 2026-05-11 — Clarified /bridge/out/build is SWAP.HIVE-only (the hivepegged contract is HIVE-only). HBD ↔ SWAP.HBD bridging (added to the web UI via DSwap / graphene-swap) is web-only — no API endpoint yet.
  • 2026-05-12 — Added Points system: /profile/{username}, /profile/{username}/activity, and /leaderboard. 30 levels grouped into 6 tiers (Shrimp → Whale). Points derived from successful swap and bridge events.
  • 2026-05-12 — Documented /bridge/converter/quote and /bridge/converter/coins (BTC/LTC/DOGE/BCH ↔ SWAP.X). Expanded /gateways response to include converterBridges and nativeBridges (ETH/BSC/Polygon/Solana) — these already shipped in the response but were missing from the docs.
  • 2026-05-14 — Points are now fractional. Previously pointsForActivity floored to integer, so any swap below $0.10 (or bridge below $0.067) earned 0 pts. Now pointsEarned can be a float (e.g. 0.5 for a $0.05 swap), with a hard floor of $0.005 USD below which 0 is still awarded. Level curve and pts-per-$ rates unchanged; existing integer totals continue to render as integers.
  • 2026-05-13/quote now accepts optional username for BEED-aware route selection. /swap/build automatically strips book-routed legs for accounts holding < 0.002 BEED on its already-required username, returning a pool-only build that doesn't revert at HE's market.* multi-tx fee. Prior behavior (build returning market.buy/market.sell ops that silently lose the platform fee on every retry for BEED-less users) is fixed.
  • 2026-05-26/quote now accepts optional autoSlippage: true. When set, the response includes recommendedSlippagePct — price impact + 0.5% buffer, rounded up to the nearest 0.5%, capped at 5%. Pass this as slippagePct to /swap/build for impact-aware slippage protection instead of a fixed value.
  • 2026-05-13 — Platform-fee transfer ops now carry typed memos so they're self-describing in Hive wallet history. Format: HiveSwap swap: A→B | r:XXXXXX for swap fees, HiveSwap peg-in: HIVE→Base | r:XXXXXX / HiveSwap peg-out: SWAP.X→Y | r:XXXXXX for bridge fees. The 6-hex r: ref is per-build random — useful for cross-referencing a wallet entry to a build response, not used by analytics. Integrators rendering the ops list can show the memo verbatim; integrators classifying transfers can match the HiveSwap swap / HiveSwap peg prefixes. Prior memo (HiveSwap platform fee on bridge ops, empty on swap ops) still classifies correctly for historical events.