Skip to main content
Since SDK 2.12.0 every call that opens a review carries a request id. Your site can store it, follow the request, find it again after a reload, and wait for the chain without running its own RPC client. Nothing in the lifecycle ever signs or sends a second time. Wallets that speak wallet protocol 2 keep each request’s status for 24 hours. With an older wallet the SDK keeps its own record for the life of the page, and every call still works.

Detect before Connect

detectWallet() (or wallet.detect()) tells you what the page can offer before any click. It needs no initialize(), answers in about 300 ms and never shows a browser prompt.
  • unknown-until-connect means Chrome would ask for local network access before any page can reach 0xio Desktop. Asking would show that prompt to every visitor, so the SDK waits for a click. Show a Connect button.
  • blocked means the visitor denied local network access for your site. not-allowed covers desktop: false, a page that is not a secure context, another wallet’s adapter and phones.
  • isMobileBrowser() is the check detect() uses; iPads that report a Mac count as mobile.

Which wallet answered

After initialize(), wallet.walletInfo describes the wallet behind the transport:
kind is extension, desktop, app-expo, app-ios or app-android. The 0xio app’s browser speaks the extension channel, so wallet.transport still reads extension there; walletInfo.kind tells them apart. The SDK switches features on capabilities, never on version.

Opening your site in the 0xio app

On a phone without a wallet, offer a link into the 0xio app:
Only https pages without credentials in the URL get a link; anything else returns null. The SDK never navigates by itself: put the link on a button. The app shows your site’s origin and asks before it opens it, and your site still has to call connect().

Request ids

The SDK makes a request id for every call that opens a review or signs. Make your own with newRequestId() when you want to store it before the call:
  • A request id is 32 lowercase hex characters. Anything else is refused with INVALID_PARAMS.
  • Calling again with the same id never opens a second review. It joins the call in flight or returns the stored outcome.
  • The same id with another method, other params or another network is refused with REQUEST_ID_REUSED.
  • A failed, rejected or expired request never runs again under its id. A new id is a new review the user sees.
Every review call takes { requestId, timeoutMs, onStatus }. Writes also take wait.

Following a request

Statuses

  • A final status never changes.
  • A site that is not connected never learns the wallet is locked: its reads answer the same, its review requests get NOT_CONNECTED with no prompt, and its connect reads review_open with no update at unlock. It sees no address or network.
  • Connect from a connected site and a switch to the current network go pending to completed with no review.
  • A page that closes before the user answers closes its review. A request the user already approved finishes, and the reloaded page can read the outcome.

Waiting for the chain

wait: 'submitted' (the default) resolves when the node accepted the transaction, as before. wait: 'confirmed' resolves when the chain executed it:
  • Writes resolve with requestId and requestStatus on top of their usual result. The wallet’s own status field is left as it sent it.
  • Contract calls and deploys carry receipt: success, events and error. Octra’s receipt has no return value, so a contract that needs to report a result should emit it as an event.
  • receipt is null with receiptUnavailable: 'refused' when the wallet’s node refuses receipts (the public scanner does), or 'error' when the read failed.
  • A chain rejection or drop rejects with EXECUTION_FAILED, with details.hash and details.reason.
  • Protocol 2 wallets watch the chain for you. With an older wallet the SDK reads octra_transaction through the wallet’s read relay, every 4 seconds for a minute and then every 10 seconds, for at most 10 minutes. If the wallet refuses those reads, the call rejects with UNSUPPORTED_METHOD and the hash.

Timeouts

A timeout ends only the SDK’s wait. It never cancels the review and never sends anything again.
  • A review call whose wait runs out rejects with STATUS_UNKNOWN, with details.requestId and details.lastStatus. The user may still approve it. Ask requestStatus() or waitForRequest(); never treat it as a failure to retry.
  • With a protocol 2 wallet the wait restarts on every status change, so a user who reads the review for several minutes does not time your site out.
  • NETWORK_ERROR means the link to the wallet failed. On a review call it carries the request id and details.status: 'unknown', because the wallet may still finish the request.
  • timeoutMs on a call sets its wait. The default is 3 minutes, 10 minutes for private transfers and on 0xio Desktop.
STATUS_UNKNOWN never means “send again”. A second call with a new request id is a second transaction the user has to approve.

Errors

Every error of a review call carries error.requestId. RATE_LIMIT_EXCEEDED names its cause in details.reason:

Pre-signed transactions

submitTransaction(signedTx) broadcasts a transaction from signTransaction() without a second review: the signTransaction review already showed exactly what was signed. It goes pending to submitted. A transaction not signed by the connected wallet is refused with INVALID_PARAMS.

Registering a private receive key

registerPrivateViewKey({ address }) makes the connected wallet able to receive private transfers (its view key on chain) and claim them (a confirmed private key). There is no free registration. The node derives the view key from the public key a transaction carries, so a fresh account that never sent anything needs that one transaction.

Which wallets speak protocol 2

Older wallets keep working through the SDK’s fallbacks: walletInfo.protocol reads 1, requestStatus() answers from the SDK’s own record until a reload, and wait: 'confirmed' reads the chain through the wallet. Building a wallet? See Wallet protocol 2.