Skip to main content
Signing proves that a wallet authorized a request and binds the signature to its contents. Notional uses EIP-712: sign locally, then send the signature with the request. Signatures are required for trading, API-wallet approvals, withdrawals, protocol transfers, and Polymarket deposit reports. Public info requests, WebSocket subscriptions, and reportDeposit requests are unsigned.

Signing Formats

The signing format depends on the request:
  • Trading actions use NotionalExchange. Sign an Agent message containing the action hash, using chain ID 1337 and source: "a" for mainnet or "b" for testnet. The account owner or an approved API wallet can sign.
  • API-wallet approvals and withdrawals use NotionalSignTransaction. The account owner signs the approval or withdrawal typed message using the wallet chain ID.
  • Protocol transfers use NotionalExchange and require the account owner’s signature. Supply the wallet chain ID in signatureChainId; omitting it uses chain ID 1337. See the transfer example.
  • Polymarket deposit reports use NotionalPolymarketDeposit, with a domain bound to the deposit recipient and Notional deployment. Follow the deposit signing instructions.
  • Isolated operation status reads use NotionalSignTransaction with the wallet chain ID. Sign the user address, operation ID, and timestamp as shown in Get isolated operation status.
Vault addresses are unsupported. See the request schemas for action fields and Nonces and API wallets for replay protection and approvals.

Account routing

For orders, cancels, modifications, leverage and isolated-margin updates, TWAP actions, and Hyperliquid outcome merges, include optional expectedAccount: "0x..." alongside action, nonce, and signature to reject requests routed to a different account. Protocol transfers and version 2 Polymarket split/merge requests reject this field. API-wallet approvals, withdrawals, and Polymarket deposit reports do not enforce it.

Signature object

Requests that use an object for signature expect these fields:
object
Request signature.

Connect a Wallet

The examples below use public npm packages: viem for EIP-712 signing and signature parsing, and @msgpack/msgpack for trading and protocol-transfer action encoding.
For browser signing, pass your wallet integration’s EIP-1193 provider to connectWallet. For example, an injected wallet exposes this provider as window.ethereum.
Pass the returned walletClient to a signing function below. Those functions return a JSON-ready body without submitting it. Allocate a unique nonce for each exchange request using the nonce rules. The request functions also accept a Viem wallet client with a local account. They preserve walletClient.account so private-key signing happens locally. For the order example below, pass the API wallet’s private key directly to privateKeyToAccount from viem/accounts.

Sign an Order

Pass an approved API wallet’s private key, the market ID returned by metadata, and a unique Unix-millisecond nonce. This example uses normalized price and size strings and omits expiresAfter.

API Wallet Approvals

The account owner signs NotionalTransaction:ApproveAgent in the NotionalSignTransaction domain, version 1, using the wallet chain ID and zero address as verifyingContract. The signed notionalChain matches action.hyperliquidChain; the other signed fields are agentAddress, agentName, and nonce. Use the zero address and existing wallet name to revoke.

Withdrawals

The account owner signs NotionalTransaction:Withdraw in the NotionalSignTransaction domain, version 1, using the wallet chain ID and zero address as verifyingContract. Signed fields are notionalChain, destination, token, amount, source, and time. Keep the exact amount string, including its formatting, unchanged after signing.

Protocol Transfers

The account in quote.terms.userAddress signs the complete action using NotionalExchange. Retain every authenticated quote field and its order. Normalize numeric strings only in the action hash; submit the quote unchanged. Include the signed expiresAfter in the action hash and submit before that deadline.

Polymarket Deposit Reports

The source user or an approved API wallet signs PolymarketDepositIntent with one field: transactionHash: bytes32. The domain is NotionalPolymarketDeposit, version 1, chain ID 137, with the actual deposit recipient as verifyingContract. Its salt is the Keccak-256 hash of the UTF-8 string notional:mainnet or notional:testnet, matching the deployment. The endpoint accepts the full hex signature directly.

Submit a Signed Request

Use the API URL for the selected Notional deployment and submit the exact body returned by the signing example. Exchange writes use /exchange; signed status reads use /info.
Also inspect the response body: an HTTP 200 can contain a rejected action or a pending operation. Follow each endpoint’s response and retry rules.

Request Deadlines

For endpoints that accept it, expiresAfter must be a nonnegative safe integer in Unix milliseconds. Sign and submit the same value. The deadline is inclusive: a request is rejected when server time is greater than the deadline, including exact retries. Requests that expire while queued are rejected before state changes. Protocol transfers must arrive before their deadline. A request deadline does not set the lifetime of an already accepted resting order or TWAP. Version 2 outcome requests omit expiresAfter.

Common Signing Mistakes

An incorrect signature or a mismatch between the signed and submitted payload can cause the server to recover a different signer. An order may then be rejected with an error such as:
Here, account_value=0 can refer to the incorrectly recovered account, even if your signing account has collateral. When debugging, compare the signer recovered using the endpoint’s expected format with your signing wallet’s address. Different mismatched inputs can recover different addresses; the error itself does not identify the signing mistake. Common causes include:
  1. Using the wrong signing scheme, domain, chain ID, or network value.
  2. Changing MessagePack field order or value types; decimal amounts must remain strings.
  3. Mishandling trailing fractional zeroes; exchange action hashing normalizes decimal strings.
  4. Changing address casing; lowercase address strings before signing and submitting.
  5. Changing the action, nonce, or expiresAfter after signing.
  6. Assuming local signer recovery proves correctness. Signing and recovery can share the same incorrect payload construction; compare the domain, types, message, and encoded bytes.