Skip to Content
Hardware IntegrationCore API Guide

Hardware SDK Core API Guide

Single-page guide for integrators: happy path + params/events/safety/error handling in one place.

Quick flow

  • Call shape: HardwareSDK.method(connectId, deviceId?, params)Promise<{ success, payload }>; always guard on success before touching payload.
  • Identifiers: connectId from searchDevices (stable for the same device; reset does not change it); deviceId from getFeatures (required for BLE, recommended for WebUSB). Refresh deviceId after reset/recovery.
  • UI contract: subscribe UI_EVENT once; only call uiResponse on input-type UI_REQUEST (PIN/Passphrase/Bootloader select). Route per device when multiple devices are connected.
  • Param hygiene: validate HD Path per chain; reuse hidden wallet with initSession + passphraseState; serialize calls per device to avoid deadlocks.
const res = await HardwareSDK.evmGetAddress(connectId, deviceId, { path: "m/44'/60'/0'/0/0", }); if (!res.success) throw new Error(res.payload.error); console.log(res.payload.address);

Interaction flow (visual)

Hardware SDK request/response flow

Core identifiers & environments

Two identifiers do the routing in almost every SDK call — connectId (which connection) and deviceId (which seed).

IDPurposeObtain viaChanges when
connectIdRoutes calls to a specific device/connectionsearchDevices()A new connection opens (USB re-plug, BLE pairing, transport switch).
deviceIdIdentifies the currently-loaded seed / wallet stategetFeatures(connectId)Factory reset, wipe, seed recovery, or seed switch.

⚠️ USB and BLE connectId values for the same physical device are different — never pass a USB serial where a BLE handle is expected, and cache them separately per transport.

connectId format varies per transport (WebUSB = device serial, Android BLE = MAC, iOS BLE = CoreBluetooth UUID, Desktop BLE = hex UUID/MAC, …). See Identifiers → connectId for the full per-transport table and worked examples.

Caching & lifecycle

  • Cache connectId + deviceId as a pair. On DeviceCheckDeviceIdError, reset, or device switch, re-run getFeatures.
  • If you support both USB and BLE for the same device, store connectId separately per transport — the two values are not interchangeable.

Runtime requirements

  • webusb — HTTPS + user gesture.
  • react-native — BLE entitlement + (commonly) location permission.
  • lowlevel — 64-byte frame adapter on the host side.
  • Bridge — must be running and hold the port free if used.
  • Firmware — stay on latest stable; some APIs fail in Bootloader.

Which identifiers are required?

RequirementDescriptionExample APIs
🟢 No identifiersSDK init, config, event managementinit on/off searchDevices getLogs dispose uiResponse
🟡 connectId onlyDevice management, status, firmware opsgetFeatures getPassphraseState cancel deviceSettings deviceReset
🔵 connectId + deviceIdBlockchain signing, address, encryptionevmSignTransaction btcSignTransaction solanaSignMessage allNetworkGetAddress

Standard loop: init → search → getFeatures(connectId) → subscribe UI/DEVICE/FIRMWARE → call + uiResponse → cleanup

import HardwareSDK, { UI_EVENT, UI_REQUEST, UI_RESPONSE } from '@onekeyfe/hd-common-connect-sdk'; // 1) Idempotent init (do once at app entry) await HardwareSDK.init({ env: 'webusb', fetchConfig: true, debug: false }); // 2) Discover devices const devices = await HardwareSDK.searchDevices(); if (!devices.length) throw new Error('No device'); const [{ connectId }] = devices; // 3) Resolve deviceId (required for BLE; recommended for WebUSB) const features = await HardwareSDK.getFeatures(connectId); const deviceId = features?.payload?.device_id; // 4) Subscribe UI events; respond only on request HardwareSDK.on(UI_REQUEST.REQUEST_PIN, () => { // open UI, collect input, then call uiResponse }); HardwareSDK.on(UI_REQUEST.REQUEST_PASSPHRASE, () => {}); // 5) Make a chain call (EVM example) await HardwareSDK.evmSignTransaction(connectId, deviceId, { path: "m/44'/60'/0'/0/0", });

Concurrency/cleanup: serialize per device; refresh getFeatures when switching devices; remove listeners on unmount; call HardwareSDK.dispose() only when transport reset is needed.

Params & paths (essentials)

Common params

Every HardwareSDK.method(...) takes a params object. A handful of keys are accepted by every method — the “common params” documented here. Chain- and device-specific fields (e.g. path, coin, tx, message) are documented on each method page.

This table describes parameters you pass in. For the meaning of response ID fields (connectId, deviceId, uuid, session_id, passphraseState, …), see Identifiers.

ParamTypePurposeNotes
passphraseStatestringBind the call to a specific hidden walletObtain once via getPassphraseState; pass on every subsequent call that must stay on the same hidden wallet. Cannot be combined with useEmptyPassphrase.
useEmptyPassphrasebooleanForce standard wallet (no passphrase)Prevents accidental hidden-wallet prompts. Cannot be combined with passphraseState.
initSessionbooleanForce session init before the callPair with passphraseState to build the session up-front and skip a subsequent prompt.
deriveCardanobooleanPre-derive the Cardano sub-tree on the deviceSet on the first Cardano call in a session.
retryCountnumberDevice-call retries on transport errorMainly useful for BLE on flaky links.
pollIntervalTimenumberPolling interval (ms) between retriesPaired with retryCount; BLE-oriented.
timeoutnumberPer-call timeout (ms)Raise for long-running ops (firmware update, big PSBT).
detectBootloaderDevicebooleanFail fast if device is in Bootloader modeUse on signing paths where Bootloader mode is never valid.
skipWebDevicePromptbooleanSkip the WebUSB chooser on re-entryWebUSB only. Reuses prior WebUSB authorization.
keepSessionbooleanDeprecated — use initSession + passphraseState insteadLegacy flows only.

Transport-specific notes

Most params are transport-agnostic. A few only matter on specific transports:

ParamWebUSBBridgenode-usbAndroid BLEiOS BLEDesktop BLE
skipWebDevicePrompt
retryCount / pollIntervalTime / timeoutno-op in practiceno-op in practiceno-op in practiceusefulusefuluseful
passphraseState / useEmptyPassphrase / initSession
deriveCardano / detectBootloaderDevice

Common combos

Standard wallet — avoid accidental hidden-wallet prompts

await HardwareSDK.evmGetAddress(connectId, deviceId, { path: "m/44'/60'/0'/0/0", useEmptyPassphrase: true, });

Hidden wallet — reuse a session across calls

// Once: acquire passphraseState (prompts for passphrase) const { payload: passphraseState } = await HardwareSDK.getPassphraseState( connectId, { initSession: true } ); // On every subsequent call that must stay on this hidden wallet const hiddenWallet = { initSession: true, passphraseState }; await HardwareSDK.evmGetAddress(connectId, deviceId, { path: "m/44'/60'/0'/0/0", ...hiddenWallet, }); await HardwareSDK.btcGetAddress(connectId, deviceId, { path: "m/84'/0'/0'/0/0", coin: 'btc', ...hiddenWallet, });

BLE with conservative retries

const bleDefaults = { retryCount: 3, pollIntervalTime: 1000, timeout: 30_000, }; await HardwareSDK.btcSignTransaction(connectId, deviceId, { ...tx, ...bleDefaults, });

HD path quick ref

  • Rule: path: string | number[] follows BIP44; ed25519 chains (e.g., Solana, NEAR) must be fully hardened.
  • Common paths:
ChainExample pathNotes
EVMm/44'/60'/0'/0/0Standard EVM account
BTC (Nested SegWit)m/49'/0'/0'/0/0Use 84’ for Native SegWit
Solanam/44'/501'/0'/0'Fully hardened
NEARm/44'/397'/0'/0'/1'Fully hardened
Cardanom/1852'/1815'/0'/0/0Stake at .../2/0
TRONm/44'/195'/0'/0/0EVM-style path
  • Number array example: [(44 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, 0x80000000, 0, 0]
  • Forbidden path errors: verify length/hardening per chain; see chain-specific pages in the sidebar.

Secure input (PIN & passphrase)

  • PIN: Pro/Touch require on-device input; others support blind PIN but prefer on-device input.
const BLIND_KEYBOARD_MAP = ['7', '8', '9', '4', '5', '6', '1', '2', '3']; HardwareSDK.uiResponse({ type: UI_RESPONSE.RECEIVE_PIN, payload: BLIND_KEYBOARD_MAP[label - 1], });
  • Passphrase: empty string = standard wallet; non-empty = hidden wallet (case-sensitive).
    • Safest: passphraseOnDevice: true
    • Software input: { value, passphraseOnDevice: false, save: true } is session-only; never persist plaintext.
    • Avoid accidental hidden wallet: add useEmptyPassphrase: true in method params.

Events & UI wiring

  • Channels: UI_EVENT (prompts), DEVICE_EVENT (connection/capability changes), FIRMWARE_EVENT (upgrade info). Subscribe once near app start; clean up on exit.
  • Only call uiResponse for input requests; use other notifications to drive UI hints; route per device when multiple devices are connected.

UI requests that require uiResponse

UI_REQUESTWhen it firesRespond with
REQUEST_PINProtected call on a locked deviceUI_RESPONSE.RECEIVE_PIN (payload is PIN value or blind PIN map)
REQUEST_PASSPHRASEHidden wallet selection via software inputUI_RESPONSE.RECEIVE_PASSPHRASE (value, passphraseOnDevice, attachPinOnDevice, save)
REQUEST_PASSPHRASE_ON_DEVICEHidden wallet selection on deviceUI_RESPONSE.RECEIVE_PASSPHRASE (passphraseOnDevice: true)
REQUEST_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICEWeb Bootloader device chooserUI_RESPONSE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE (deviceId)

UI notifications (no response needed)

UI_REQUESTPurpose
REQUEST_BUTTONAsk user to confirm on device
DEVICE_PROGRESSLong-running task progress
FIRMWARE_PROCESSING / FIRMWARE_PROGRESS / FIRMWARE_TIPFirmware upgrade/processing states
BLUETOOTH_PERMISSION / LOCATION_PERMISSIONSystem permission prompts for BLE
BOOTLOADER / REQUIRE_MODE / NOT_INITIALIZE / FIRMWARE_NOT_SUPPORTEDMode or support hints to display in UI

Device/Firmware events to observe

ChannelEventMeaningTypical handling
DEVICE_EVENTCONNECTDevice attached and availableRefresh device list, optionally auto-select
DEVICE_EVENTDISCONNECTDevice removed or BLE lostMark session invalid, prompt user to reconnect
DEVICE_EVENTACQUIRETransport session startedGate concurrent calls, mark device busy
DEVICE_EVENTRELEASETransport session endedAllow next queued request
DEVICE_EVENTCHANGEDFeatures changed (e.g., after unlock)Re-fetch getFeatures and refresh cached deviceId
DEVICE_EVENTUSED_ELSEWHERETransport conflict detectedAsk user to close other apps/bridges
DEVICE_EVENTUNREADABLEPermission or driver issuePrompt re-authorization or driver check
DEVICE_EVENTBUTTONDevice is waiting for confirmationShow “confirm on device” hint
DEVICE_EVENTPINDevice is waiting for PINKeep UI in PIN flow
DEVICE_EVENTPASSPHRASEDevice is waiting for software passphraseKeep UI in passphrase flow
DEVICE_EVENTPASSPHRASE_ON_DEVICEDevice is waiting for on-device passphraseShow device input hint
DEVICE_EVENTSELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICEBootloader selection in progressKeep chooser visible until resolved
DEVICE_EVENTFEATURESCapability snapshotCache capabilities for later checks
DEVICE_EVENTSUPPORT_FEATURESSupported capability snapshotCache support matrix
FIRMWARE_EVENTRELEASE_INFONew firmware infoOffer upgrade prompt when safe
FIRMWARE_EVENTBLE_RELEASE_INFONew BLE firmware infoOffer upgrade prompt when safe

Wiring template

import HardwareSDK, { UI_EVENT, UI_REQUEST, UI_RESPONSE } from '@onekeyfe/hd-common-connect-sdk'; const handleUiEvent = (msg: any) => { switch (msg.type) { case UI_REQUEST.REQUEST_PIN: openPinModal(({ value }) => HardwareSDK.uiResponse({ type: UI_RESPONSE.RECEIVE_PIN, payload: value }) ); return; case UI_REQUEST.REQUEST_PASSPHRASE: openPassphraseModal(({ value, onDevice, save }) => HardwareSDK.uiResponse({ type: UI_RESPONSE.RECEIVE_PASSPHRASE, payload: { value, passphraseOnDevice: onDevice, attachPinOnDevice: false, save }, }) ); return; case UI_REQUEST.REQUEST_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE: showDeviceList((deviceId: string) => HardwareSDK.uiResponse({ type: UI_RESPONSE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE, payload: { deviceId }, }) ); return; default: console.log('UI event', msg.type, msg.payload); } }; HardwareSDK.on(UI_EVENT, handleUiEvent);

Errors & checklist

GroupCommon causesRecommended actions
Device (101–118, 200)Wrong mode, busy, device_id mismatch, not initializedAsk user to confirm device mode, reconnect, re-run init + getFeatures
IFrame (300–305)Init missing, load/timeout/blockedEnsure init succeeded and CSP/iframe allow it
Method/Firmware (400–418)Bad params, firmware upgrade required, forbidden pathValidate params/HD path, prompt firmware upgrade
Transport (600–603)Transport not configured, concurrent call, protobuf errorCheck env/Bridge, serialize calls, align SDK version
Bluetooth (700–722)Scan/permission/connect/timeoutEnsure BLE/location permission, proximity/power, retry connect
Runtime/Bridge (800–821)PIN/action cancelled, Bridge permission/timeout, blind sign disabledRetry, ask to install/start Bridge, ensure signing mode
Web device (901–902)WebUSB/Bluetooth not authorized or chooser failureAsk user to re-authorize; ensure HTTPS + user gesture

More detail: see HardwareError.ts for exhaustive definitions and payload shapes.

Pattern: map error → user message + developer action; provide UI buttons for retry/check device/upgrade firmware.

Related links

  • Getting Started (install + first call): Introduction
  • Transports: WebUSB · React Native BLE · iOS/Android low-level adapters
  • Chain APIs: sidebar sign / getAddress method pages by chain
  • Legacy migration: bridge-to-common-connect/WebUSB migration guides
Last updated on