@ixo/signx-sdk orchestrates mobile-to-web authentication and transaction signing through QR code scanning by the Impacts X mobile wallet. A web app generates a QR code, the user scans it with their Impacts X app, and the SDK long-polls a relayer server until the wallet returns either a login payload or a signed-and-broadcast transaction. Once a transaction session is open, additional transactions are added to the same session without re-scanning the QR — the wallet activates the next transaction in sequence on each broadcast.
This is the publicly documented signing path. There is no in-browser private key — every signature comes from the user’s mobile wallet.
Before you start
You need:- A web app (React or other) running over HTTPS.
- A reachable
ixo-message-relayerendpoint, or an IXO-operated equivalent for your network — see Networks and endpoints. - The Impacts X mobile app installed by your user (App Store / Play Store).
@ixo/signx-sdkand@ixo/impactxclient-sdkinstalled:
Initialize the SignX client
network is one of mainnet | testnet | devnet. The sitename is shown to the user inside the Impacts X app on every confirmation.
Log the user in
login() returns the QR payload to render and starts long-polling for the wallet’s response. Subscribe to SIGN_X_LOGIN_SUCCESS and SIGN_X_LOGIN_ERROR to receive the result.
{ useDeeplink: true } on mobile devices so the SDK opens the Impacts X app via deeplink before polling — this prevents some mobile browsers from cancelling the long-polling request when the user navigates away.
Sign and broadcast a transaction
Build the transaction body using the@ixo/impactxclient-sdk registry, then pass the hex-encoded txBody to signXClient.transact(). The wallet signs the transaction and broadcasts it on the user’s behalf.
transactRequest.sessionHash is present a new session was opened — render a QR with transactRequest. If it is absent the transaction was added to the existing session — call signXClient.pollNextTransaction() and update the UI to indicate the next signature is pending in the wallet.
The wallet returns the chain’s broadcast result (code, transactionHash, …) directly through SIGN_X_TRANSACT_SUCCESS.
Manage the session
Every transaction extends the session’svalidUntil timestamp. Inspect signXClient.transactSessionHash to know whether a session is active and signXClient.transactSequence for the current sequence the wallet is being asked to sign.
transactSessionHash lives in memory only. After a refresh, the next transact() call starts a new session and renders a fresh QR.
Transaction-type restrictions
Restricting which message types a session can sign is enforced on the wallet — the Impacts X app inspects each transaction body against the user’s saved policy before signing. The web SDK does not impose its own filter. To restrict the messages a session can sign in your dApp, build the txBody only for the message types your flow needs and refuse to calltransact() for anything else; pair this with smart-account authenticators (see Manage smart accounts) for an on-chain enforcement layer.
When you build a MsgGrant (cosmos.authz.v1beta1.MsgGrant) with a GenericAuthorization, the msg field is the fully qualified message URL, e.g. /ixo.entity.v1beta1.MsgCreateEntity. The same convention applies everywhere transaction filtering is configured.
Verify the result
SIGN_X_TRANSACT_SUCCESS returns the transaction hash directly. To independently verify, query cosmos.tx.v1beta1.GetTx on the gRPC gateway API with that hash, or fetch the transaction from the Blocksync GraphQL API.
Troubleshooting
QR code never resolves
QR code never resolves
Confirm
endpoint points to a reachable Message Relayer for the same network as the user’s wallet, and that network matches the chain the user logged in on. Check the relayer is healthy.Long-polling cancelled on mobile
Long-polling cancelled on mobile
Mobile browsers may cancel ongoing requests when navigating to deeplinks. Pass
useDeeplink: true to login, matrixLogin, dataPass, and as the third argument to transact so the SDK opens the deeplink first and waits 300 ms before polling.Wallet rejected the transaction
Wallet rejected the transaction
The wallet may reject if the message type is outside the user’s signing policy, the chain ID does not match, or the user manually denies.
SIGN_X_TRANSACT_ERROR carries the reason. Re-issue the transaction after the user adjusts their policy.Session expired mid-flow
Session expired mid-flow
transactSessionHash is cleared when the relayer reports the session expired. The next transact() call starts a new session — surface this to the user (a fresh QR is needed). Call stopPolling(message, event, false) to stop polling without clearing the session if you want to retain it.Next steps
SignX SDK reference
Methods, events, and types.
SignX SDK README
Source of truth for the SDK.
Smart accounts
Add on-chain enforcement of which message types may be signed.
Manage authorization
Combine SignX with Cosmos
x/authz and x/feegrant.