peaq-os-sdk on PyPI is the Python equivalent of @peaqos/peaq-os-sdk. Every method and type mirrors the JS SDK; the key differences are listed below.
Pass tokenomics20=Tokenomics20Config(deployment_id=...) to the constructor to enter Tokenomics mode: one-transaction activation, machine management, and the 2.0 monetization client. In that mode the legacy registration, mint, bridge, and DID-helper methods raise typed errors instead of running (full list). Without tokenomics20 the client behaves as before. Full-width machine IDs are Python int; serialize them as decimal strings. Tokenomics20Config(deployment_id="peaq-mainnet", creation_home="solana", solana_rpc_url=...) and the [solana] extra cover machines homed on Solana: see Solana.
Differences from the JavaScript SDK
Install
- Python: ≥ 3.10
- Dependencies: installed automatically; the main ones are
web3>=6.0,eth-accountandrequests>=2.33.1,<2.34, and some (for examplecryptography==50.0.0) are pinned exactly - Optional wallet dependency:
open-wallet-standardthrough the[ows]extra - Optional Solana dependency: the
[solana]extra, needed for Solana reads and writes (account decoding and transaction encoding); a plainimport peaq_os_sdkloads no Solana package, and keyless MCR HTTP reads need nothing (see Solana) - Virtualenv recommended.
python-dotenv is optional but recommended: PeaqosClient.from_env() reads os.environ and does not load .env itself, so call load_dotenv() at the top of your entry file first.
Environment variables
Same set as the JS SDK: 8 required core vars (RPC URL, private key, and the 6 contract addresses), plusPEAQOS_MCR_API_URL (defaults to http://127.0.0.1:8000), plus 2 optional vars for smart-account deploy (MACHINE_ACCOUNT_FACTORY_ADDRESS) and cross-chain Machine NFT bridging (MACHINE_NFT_ADAPTER_ADDRESS). See JS environment variables and peaq mainnet contracts. For agung testnet addresses see Install → Agung testnet contracts. Bridging is mainnet-only since LayerZero has no DVN routes to agung.
For OWS wallet lifecycle helpers, pass a passphrase argument or set OWS_PASSPHRASE.
PEAQOS_SVM_RPC_URL and PEAQOS_SVM_NETWORK are CLI variables; from_env() keeps its EVM configuration and does not read them. Pass the Solana endpoint as Tokenomics20Config(deployment_id="peaq-mainnet", solana_rpc_url=...) (see Solana).
For Scale, set PEAQOS_ORCHESTRATION_URL (and optionally PEAQOS_API_KEY) before PeaqosClient.from_env() to enable client.orchestration. Full method reference: Orchestration (Python).
Client
PeaqosClient
Tokenomics20Config | None
Tokenomics20Config(deployment_id="peaq-mainnet") or "agung-2026-08-28". Selects the Economics 2.0 deployment and puts the client in Tokenomics mode. The seven contract addresses come from the SDK’s snapshot, resolved once in the constructor with no network call; an unknown ID raises TokenomicsConfigError DEPLOYMENT_UNKNOWN. Addresses are never accepted here. from_env() reads TOKENOMICS_DEPLOYMENT_ID (see from_env). creation_home="solana" and solana_rpc_url= select Solana as the home for new machines and enable Solana reads: see Solana.str
required
RPC endpoint.
str | None
0x + 64 hex. Required, except on a tokenomics20 client with creation_home="solana": its Solana writes take their signer as an argument (the onboarding script runs keyless), and only register_solana_operator and the other peaq-side writes need it.str
required
Identity Registry contract address.
str
required
Identity Staking contract address.
str
required
Event Registry contract address.
str
required
Machine NFT contract address (ONFT).
str
required
DID Registry precompile address.
str
required
Batch precompile address.
str | None
MachineAccountFactory contract address. Required only for deploy_smart_account and get_smart_account_address.str | None
MachineNFTAdapter (LayerZero ONFT adapter) contract address on peaq. Required only for bridge_nft when source="peaq".str
Defaults to
DEFAULT_API_URL. A tokenomics20 client does not read it: the MCR server comes from the deployment record.OperationalLimits | None
Per-tx and rate-limit caps.
PeaqosClient instance. __repr__ redacts the private key.
Other RPC endpoints are available. See Public RPC endpoints.
Errors: ValidationError for a missing rpc_url or a missing or malformed private_key; a malformed contract address raises web3’s ValueError; an unknown tokenomics20 deployment raises TokenomicsConfigError.
from_env
from_env() reads TOKENOMICS_DEPLOYMENT_ID (same spelling as the JavaScript SDK): a non-empty value puts the client in Tokenomics mode, absent or empty stays legacy, an unknown or unreleased ID raises TokenomicsConfigError.
ValidationError: any required env var missing or empty.
from_wallet
PeaqosClient.fromWallet. The remaining keyword arguments (rpc_url, contract addresses, etc.) match the regular PeaqosClient constructor.
In OWS-native mode the SDK never holds the private key: OWS decrypts it inside the Rust FFI for each
sign_hash call and wipes it immediately. A missing passphrase raises PeaqosError at construction; a wrong one is not detected until the first sign_hash call, because OWS has no verify-only endpoint (with ows_signing=False the key is decrypted at construction, so a wrong passphrase fails there). Each transaction’s chainId (from the tx dict) drives both the CAIP-2 OWS arg and the EIP-155 v value, so the same client transparently signs both peaq (eip155:3338) and Base (eip155:8453) bridge transactions.
Errors: PeaqosError when the wallet is missing, the passphrase is wrong (eager-mode) or missing, or OWS itself rejects the request. See OWS signing error codes for the canonical 5 codes mapped from OWSAccount.sign_transaction.
Wallets (OWS)
Wallet lifecycle helpers (create_wallet, import_wallet, import_wallet_mnemonic, list_wallets, get_wallet, export_wallet, delete_wallet) back the Open Wallet Standard integration: mnemonic-backed encrypted vault, multi-chain accounts (peaq, Base, Ethereum, Solana, Bitcoin, etc.). Available under peaq_os_sdk.wallet and as @staticmethods on PeaqosClient. Install with the optional [ows] extra (pip install 'peaq-os-sdk[ows]'). The raw-key constructor and from_env flow keep working unchanged. Full reference on the Wallets page.
Wallet returns are typed as WalletInfo (frozen dataclass) with an accounts: list[AccountInfo] field; account_id is CAIP-10 and chain_id is CAIP-2. Both classes are re-exported from the package root.
generate_keypair
(address, private_key). Both are 0x-prefixed hex strings; Address is a NewType over str (checksummed).
OWS wallet lifecycle
OWS wallet helpers are available as staticPeaqosClient methods. They derive multi-chain accounts, keep wallet material in an encrypted OWS vault, and return public WalletInfo metadata.
create_wallet, import_wallet, import_wallet_mnemonic, and export_wallet require a passphrase argument or OWS_PASSPHRASE. vault_path can point at a custom OWS vault directory.
dataclass
Frozen dataclass with
id, name, created_at, key_type, peaq_address, and accounts. Each account has account_id, address, chain_id, network, and derivation_path. Supported EVM accounts include peaq, Ethereum, Base, Polygon, Arbitrum, and Optimism; missing EVM chain entries are synthesized from the first available EVM address.Accessors (Python-only)
Tokenomics 2.0
Available on a client constructed withtokenomics20. Every machine operation below is a PeaqosClient method and a package-root function taking the client as its first argument; the deployment and machine-ID helpers are standalone package-root functions. Concepts: Economics 2.0.
Deployments
resolve_tokenomics20_deployment(deployment_id, overrides=None) cross-checks an optional role -> address mapping against the snapshot and raises ADDRESS_OVERRIDE_MISMATCH on any difference. Overrides never introduce addresses. The PEAQ token is resolved at call time from InfoDesk.peaqToken().
activate_machine
MachineStateAndSync.activateMachine: mints the ERC-721 in MachineRegistry (token ID equals machine ID), stores the DID document, bonds the tier in MachineSubscription, and records the home chain. The signer becomes owner and bond payer.
ActivateMachineResult with machine_id, owner, controller, tier, bond_amount, voucher_credit_applied, net_peaq_amount, transaction_hash, is_homed_locally, the receipt, and the correlated events. Amounts come from the receipt, not the preflight quote. Success requires MachineOnboarded, MachineMinted, and Activated from the right contracts plus a matching post-state read.
Sequence: local validation, chain and bytecode checks, InfoDesk.peer(role) match, isEconomicAuthority() (False raises NOT_ECONOMIC_AUTHORITY), compute ID, both MachineStateAndSync technical pause flags (TECHNICALLY_PAUSED before any approval), quote, resolve PEAQ, balance and allowance, approve exactly the net if short (spender MachineSubscription), re-read everything, simulate, submit once, correlate, reconcile. The write is never retried. cancel is honoured up to submission.
Errors: ValidationError, TokenomicsConfigError, TokenomicsActivationError (codes below), TokenomicsPendingTransactionError (PENDING_TRANSACTION, carries .submitted).
activate_machine_with_usdt
SubscriptionTokenProvisionPool (the allowance spender). Not usable on peaq mainnet: the pool has no USDT token configured, so the USDT quote and the write both revert. Requires max_usdt_amount, taken from preview_machine_activation_with_usdt(...).max_usdt_amount after applying your slippage_bps. The bond, credit, and net stay in PEAQ; a fully credited bond converts nothing.
preview_machine_activation, preview_machine_activation_with_usdt
machine_id, bond_amount, voucher_credit, net_peaq_amount, balance, approval_required. Raises MACHINE_ID_MISMATCH when expected_machine_id disagrees and MAX_NET_PEAQ_EXCEEDED when the bound is already exceeded; a low balance is returned, not raised.
compute_machine_id
uint256(keccak256(abi.encode(machine_type, credential_subject))), read from MachineRegistry.computeTokenId.
Reads
MACHINE_HOMED_ELSEWHERE naming the chain, not MACHINE_NOT_FOUND: see Solana.
Lifecycle and subscription
RenewMachineParams, RenewMachineWithUsdtParams and PreviewMachineRenewalParams take an optional tier (0 entry, 1 basic, 2 pro), but neither peaq-mainnet nor agung-2026-08-28 enables tier selection on renewal: passing any tier, even the stored one, raises RENEWAL_TIER_UNSUPPORTED before an RPC call. Omit tier to renew at the stored tier. On a deployment that enables it, the preview reports stored_tier, requested_tier and tier_change_allowed (true from Grace or Runoff), a change while Active raises TIER_CHANGE_WHILE_ACTIVE, and a tier change is priced at the full bond of the new tier.
PEAQ writes require max_net_peaq_amount, USDT writes max_usdt_amount; take both from the matching preview. USDT writes are not usable on peaq mainnet (no USDT token configured in the pool). The SDK re-quotes before simulation and never raises an accepted bound. Owner or controller may sign; credits accrue to the owner.
Ownership (ERC-721)
DID updates
AUTHENTICATION_REWRITE_REQUIRED before submission.
Previews and reconciliation
pending | confirmed | failed | conflicting. A hash with no receipt is always pending; the SDK never infers a dropped transaction from age, mempool absence, or nonce.
Machine-ID helpers
bool is rejected wherever an int machine ID is expected.
Disabled in Tokenomics mode
Enabled in Tokenomics mode:
submit_event, batch_submit_events (Events) and query_mcr, query_machine, query_operator_machines (Queries). Still available in Tokenomics mode: stream, provisioning, wallets, heartbeat, orders, other orchestration calls. wait_for_bridge_arrival is not gated (it takes no client) and only emits a DeprecationWarning. peaq_os_sdk.bridge.quote_send takes a bare contract, is not gated and emits no warning.
Solana
Machines can be homed on Solana. There is no separate Solana client and no machine-keyed method gained a chain argument: the existing Tokenomics 2.0 methods resolve the machine’s home from its ID, and asolana= options object selects the native path where a write needs a Solana signer. Requires pip install "peaq-os-sdk[solana]" for anything that encodes a Solana transaction; a plain import peaq_os_sdk loads no Solana package. Walkthrough: Onboard a machine on Solana.
Configuration
A Solana-capable client is the ordinary client withcreation_home="solana" and the Solana endpoint in Tokenomics20Config. This is how the runner builds it, keyless, from the machine directory’s .env (need reads one variable or stops):
peaq-mainnet has a Solana half (agung-2026-08-28 has none, DEPLOYMENT_UNAVAILABLE); resolve_tokenomics20_solana_deployment("peaq-mainnet", solana_rpc_url) from peaq_os_sdk.tokenomics.deployments returns it (protocol_chain_id == 5, layerzero_eid == 30168). The RPC endpoint is never defaulted, and the SDK compares its getGenesisHash with the record before the first account read, because the same program IDs exist on more than one cluster. private_key may be omitted for a client that only previews or reads. Anchor IDLs for the programs ship as package data with a MANIFEST.json (source commit, sha256 per file); layout skew is detected at decode time (discriminator plus exact byte consumption), never zero-filled. Machine IDs stay full-width int, cross to Solana as 32-byte big-endian words, and the DID is did:peaq:<decimal machine id>.
Reads
A machine-keyed read that finds no peaq record asks peaq where the machine lives and raisesTokenomicsActivationError with code="MACHINE_HOMED_ELSEWHERE" naming the chain, instead of MACHINE_NOT_FOUND. A machine that exists nowhere still raises MACHINE_NOT_FOUND with its decoded revert; an unreachable node still raises READ_FAILED. Solana reads wait out a rate limit (HTTP 429) and a server behind the slot a read needs (JSON-RPC -32016) and retry, up to five attempts, never for a send; a server that stays behind is named in the final READ_FAILED. get_machine_owner keeps its EVM return type: a 32-byte Solana key is never cast into a 20-byte address. Native identity comes from peaq_os_sdk.tokenomics.svm_results: MachineHomeChain (chain, protocol_chain_id, state, provenance), MachineNativeIdentity (owner, did, controller, evm_operator, manufacturer, machine_type, is_relocating), MachineMirrorEvidence. Resolution states: resolved, reserved, in_flight, unknown, conflict, unavailable (with reason: missing_configuration, missing_dependency, missing_capability, conflicting_evidence). Absent is not withdrawn, not zero, not disabled; unavailable is not unknown.
Onboarding
Terminal-first (SDK 0.11.2 and newer): the Solana owner pays the bond on Solana, in PEAQ or USDC, throughmachine_subscription_terminal, and peaq books it. The link push back to peaq is delivered by peaq’s Trust Validator node (the node), with no messaging fee. Both rails run on production. The phases, in order:
The example is the script that onboarded the proven Python machines, given in full on the guide’s Python tab (the collapsed block under its run command, to copy): one loop over
get_machine_activation_state that does whatever next_step names until complete, journaling every write. Its two write calls:
COMPUTE_UNIT_LIMIT is the mint’s compute unit limit. Since 0.11.2 the value to pass is the plan’s suggestion, plan.native.suggested_compute_unit_limit; before, scripts passed 600,000 (see The mint below).
- Registration.
register_solana_operatorspends peaq gas only (about 0.01 PEAQ; 98,688 and 105,432 gas measured) and waits for the node to mirror the binding (1 to 2 minutes measured). A wallet already bound to the signer isreconciled, and nothing is sent. A wallet bound to another peaq address is refusedOPERATOR_BOUND_ELSEWHERE.get_solana_operator_registration(wallet, peaq_operator=None)reads the state keyless:unbound,bound,bound_elsewhereormirroring. Confirmation is theOperatorAddressBoundevent in a final block, never receipt status. - The quote.
quote_solana_activation(identity, *, tier, pay_in, wallet, slippage_bps=100, peaq_operator=None)is keyless and refuses in the program’s order (OPERATOR_NOT_REGISTERED,REQUEST_ALREADY_OPEN,MACHINE_ALREADY_ACTIVE,ROUTE_NOT_WHITELISTED,INSUFFICIENT_BALANCE…). It returns the bond,max_in(the suggested escrow: the bond plusslippage_bps; on USDC the pool’s spot estimate with its fee plus the cushion), the wallet’s balance, the rents and peaq’s preflight. Passingpeaq_operatorquotes a wallet not registered yet, for that operator (quote.registration == "assumed"). - The priority price.
ActivateSolanaTerminalParams,quote_solana_link_pushandpreview_solana_settlementdefaultcompute_unit_price_micro_lamportsto0, andPreviewSolanaMachineActivationParamsrequires it. Pass10_000, as the script does: a write without priority can be dropped by Solana’s public endpoint under load. Since 0.11.2 the SDK re-sends a write that was lost on its way. While the write’s receipt wait sees the signature unknown and the blockhash still valid, the SDK sends the same signed bytes again every 2 s, at most 40 times. The same bytes carry the same signature, so the cluster processes the write at most once and nothing can be spent twice. The bytes stay in this process’s memory: a rerun in a new process re-sends nothing and reconciles the journal row. A re-send’s errors are ignored; the receipt decides. A mint that never lands at all is still proven dead by the recovery (SDK 0.11.1,NativeOnboardingReconciliation.may_resubmit) and minted again. At 10,000, with the mint’s limit sized from its simulation, the whole onboarding pays about 4,900 lamports of priority fees on PEAQ and about 7,900 on USDC. request. Escrowsmax_in_amount(the quote’s suggestion when omitted) in the pay-in token and freezes the bond. On PEAQ the escrow must cover the bond (ESCROW_BELOW_BOND). Rent: the request (2,169,160 lamports), its escrow account (1,488,440) and, on the machine’s first request, itsSubscriptionTerminal(1,071,880), againstmax_native_rent_lamports. One request per machine: a rerun with one open reconciles it. A request the node does not credit within its hour endsexitedwithREQUEST_EXPIRED. The node cancels that request once it can, returning the escrow and the request’s rents, or the owner cancels it withcancel_request. A rerun after the request was cancelled (by the owner, or by the node once it expired) or refunded opens a new request at the next nonce (0.11.2): the request phase reads the machine’s terminal record first, and a request that is gone, with its nonce no longer open and no live subscription, is spent, not taken for a live one. A request closed after the mint stays done.finalise. The request decides the path:finalise_in_peaq(the bond to the terminal’s vault, the rest back in PEAQ),finalise_without_swap(a credit covers the bond), or on USDCfinalise_activation, a v0 transaction against the record’s finalise lookup table that buys exactly the bond through the provision pool’s Raydium route. The swap is quoted by simulating the exact instruction; the cap sent is that cost plusslippage_bps, never above the escrow, and the USDC remainder comes back in USDC.result.settlement(SwapSettlementQuote:simulated_in_amount,max_in_amount,escrow_amount,slippage_bps,lookup_table,lock_in_table) says how a USDC settlement was priced; on production the swap paid exactly its simulation (200,807 USDC base units).preview_solana_settlement(identity, wallet=...)runs the same preparation keyless;verify_solana_finalise_table()checks the table alone (FinaliseTableCheck:address,entries,lock_in_table). Refused before signing:REQUEST_CLOSED(the request was cancelled or refunded; 0.11.2),REQUEST_NOT_COMMITTED,COMMIT_EXPIRED,NOT_ACTIVATION_PAYER,FINALISE_TABLE_MISSING/FINALISE_TABLE_STALE,TICK_ACCOUNTS_INVALID,SLIPPAGE_EXCEEDED. After a finalise there is no cancel: if peaq refuses the bond, the refund comes back in PEAQ on both rails (exit == "ACTIVATION_REFUNDED", withresult.refund).- Results. Each terminal call returns
SolanaTerminalActivationResult:statusiscomplete,pending(unresolved,advice) orexited(a namedexitsuch asREQUEST_EXPIRED, with the way out inadvice).confirmation.spendis what the write moved for its payer (lamports with the fee, token deltas per mint).confirmation.send_count(SendCount(sends, resend_errors), 0.11.2) counts the sends this process made for the write; it isNonefor a row this process did not send.cancel_requestreturns the escrow and the request’s rents from aPendingorCommittedrequest. On a request already cancelled or refunded,cancel_requestrun alone is refused withREQUEST_CLOSED; a cancel this journal recorded still reconcilescomplete. REQUEST_CLOSED(0.11.2). A phase run alone on a request that was cancelled or refunded is refused with this code before anything is signed: thecreditandbondwaits,finaliseandpreview_solana_settlement, andcancel_request. It replacesREQUEST_NOT_COMMITTED,STATE_MISMATCHorREQUEST_NOT_CANCELLABLEin that situation. Nothing is left to wait for, settle or cancel; the request phase opens a new request at the next nonce. A refund still ends thebondwait asACTIVATION_REFUNDED.- Inputs and plan.
SolanaOnboardingInputsis the machine as the mint and the link push need it: owner, controller, manufacturer, DID lists, identity, the two native ceilings, and optionalexpected_machine_idandevm_operatorassertions. No operator, tier or funding: the registration and the request carry them.inputs.identityis theSolanaMachineIdentitythe terminal phases take.preview_machine_activation(PreviewSolanaMachineActivationParams(...))returnsSolanaOnboardingPlan, read at one pinned finalized peaq block, with sevenstages(registration…linkage), each withaction(estimate,reconcile,observe,blocked,unavailable),signer,unresolvedandexpected_wait_seconds. - The mint.
native_onboardingmints against theBondedrequest at the terminal’slast_nonce; the record’sevm_operatoris the request’s peaq operator. Refused before signing:SUBSCRIPTION_NOT_ELIGIBLE,ACTIVATION_NOT_BONDED,NOT_ACTIVATION_PAYER,EVM_OPERATOR_MISMATCH,TECHNICALLY_PAUSED. Get signers withget_solana_onboarding_signer_requirements(inputs, plan, phase)andsolana_signer_from_wallet(name, passphrase, chain_id=required.chain_id).plan.native.suggested_compute_unit_limit(0.11.2) is the value to pass as the mint’scompute_unit_limit: the plan’s simulated units × 1.3, rounded up to the next 1,000, at least 50,000 and at most the cluster maximum. Before, scripts passed 600,000; on production the mint used 99,009 of them on 2026-10-08. A mint whose receipt failed withComputationalBudgetExceeded(reasoncompute_budget_exceeded), with theMachineandMachineStateaccounts absent, is minted again by the rerun, like a mint that never landed: the reconciliation marks itfailed_without_effect, andno_effectcovers both cases. Every other failed mint staysfailed. - The link push. The SDK reads the route from the chain before every push.
quote_solana_link_push(machine_id, payer=...)quotes it keyless:transportistrust_validator(production:native_fee_lamports0,compute_unit_limit120,000, the push account’s one-time rent of 1,005,840 lamports) orlayerzero;statusalready_pushed(codeLINK_ALREADY_PUSHED) means nothing is left to send. On the node’s routemax_link_push_fee_lamportsis not needed; on a LayerZero route it is, and a push without it raisesValidationErroron that field before signing. Refused before signing:TV_OUTBOX_MISSING(no outbox for peaq on the adapter),TV_INBOUND_REFUSED(peaq refuses the node’s deliveries),FEE_LIMIT_EXCEEDED,RENT_LIMIT_EXCEEDED,INSUFFICIENT_NATIVE_BALANCE(the owner cannot pay the push and keep its own rent-exempt minimum, 650,240 lamports for a plain wallet), and on a LayerZero routeBRIDGING_DISABLEDorLINK_CONFIG_UNAVAILABLE. The confirmed push carries the node’s queue entry:transport,tv_nonce,sequence. - Complete. When peaq’s
MachineBridgeAdapter.lastAppliedMirrorPushSeqfor the machine reaches the onboarding push’s sequence: a status read’snext_step.phase == "complete".reasonislink_applied, orlater_push_pendingwhile a later Solana push is in flight; both are complete.state.tv_relayslists the pushes that went over the node (TvRelayEvidence:signature,dst_eid,nonce,applied);state.messageslists LayerZero messages and is empty on the node’s route. The Solana receipt of the push proves the send, not the delivery. - Status read and recovery. Two option classes for
get_machine_activation_state:SolanaMachineActivationStatusParams(inputs, records=...)names the next step from the chain (the loop’s status read), andSolanaOnboardingRecoveryParams(inputs, records)reconciles the journal’s rows intorecovery.history.records, which the native phases take. Both take every journal row; neither signs. - Journal and recovery. One journal,
peaq-native-onboarding-attempt/v2:PeaqRegistrationTransaction,TerminalActivationAttempt,NativeOnboardingTransaction,LinkPushTransaction. The three Solana rows are handed toon_transaction_submittedbefore broadcast, the registration row right after its broadcast, before its receipt is read; an uncertain broadcast raisesTokenomicsPendingTransactionErrorwith the row on.submitted.serialize_solana_onboarding_attempt/decode_solana_onboarding_attempt/restore_solana_onboarding_historyinpeaq_os_sdk.tokenomics.solana_onboarding_attempts; every integer a decimal string, no keys or payloads. Pass every row asrecordsto status reads and the native phases. A sent transaction is waited for and reconciled. The process that signed it may re-send the same signed bytes while the write can still land (0.11.2); a rerun in a new process re-sends nothing.get_machine_activation_state(machine_id, solana=SolanaMachineActivationStatusParams(inputs, records=...))names the next step from the chain (registration,request,credit,finalise,bond,cancel_request,native_onboarding,linkage,complete) and its actor. After an earlier request was cancelled, refunded or closed (the status read’sobservations.terminal.request_state), the request phase reads the machine’s terminal record first and opens a new request at the next nonce (0.11.2); before 0.11.2 it took the old row for a live request. The script’sfor_requestalso leaves that request’s rows (nonce at or belowobservations.terminal.terminal.last_nonce) out of the new call’srecords. - What ran.
get_solana_onboarding_history(machine_id, *, timeout_seconds=...)rebuilds the onboarding from the chains alone, keyless:SolanaOnboardingHistorywithrows(OnboardingHistoryRow:step,actorowner/operator/node/layerzero/other, slot or block, cost to its payer, the owner’s own change whoever paid inowner_lamports_deltaandowner_token_deltas, explorerlinks) andtotalsper payer (OnboardingPayerTotal:payer,chain,lamports_delta,token_deltas,gas_wei,transactions; the owner’s is its net change, refunds from others’ transactions included). The CLI’smachine history --jsonadds aroleper payer; the Python object has none. A cancel the node sends reads actornode. A later machine of the same owner lists the registration and binding withreused=True, outside its totals. Sources it could not read are named inunread; a rerun reads them. Right after a run the public endpoints are busy: the script allows 600 s.confirm_solana_onboarding_receipts(records)reads back the registration’s and the terminal writes’ receipts from a journal (SolanaOnboardingReceipt, withgas_weior the terminalspend), for a cost report after a resume. - Migrating from 0.10.x.
reservation,subscription,from_block,PeaqOnboardingFunding,UsdtOnboardingFunding,SolanaReservationStatusParamsand the operator, tier and funding fields ofSolanaOnboardingInputsare gone.v1journal rows restore as read-only history and are never resumed.
Management
The module-level functions exported frompeaq_os_sdk take the native path: transfer_machine, suspend_machine, resume_machine, set_machine_controller, set_machine_verification_methods, set_machine_authentication, set_machine_service_endpoints and set_machine_evm_operator accept solana=SolanaMachineWriteParams(signer=..., max_fee_lamports=...) with the client as first argument, for example transfer_machine(client, from_pubkey, to_pubkey, machine_id, solana=SolanaMachineWriteParams(...)). The PeaqosClient methods of the same names are the peaq path and take no solana argument; set_machine_evm_operator exists only as the module-level function and requires solana=. The signer is an argument, not client configuration, because Solana’s key space and the EVM account are unrelated.
approve_machine and safe_transfer_machine run the EVM write preflight first (signer, chain, bytecode, peers) and raise TokenomicsUnsupportedError SOLANA_OPERATION_UNSUPPORTED once the machine resolves to Solana; no write happens, but a signer, deployment or RPC problem surfaces before that code. set_machine_approval_for_all is owner-wide, has no machine to resolve and keeps its EVM behaviour: with an EVM signer it submits setApprovalForAll on peaq. Results report instead of raising once a transaction landed: status is confirmed, conflicting (with conflicts), failed or pending; pending means not yet known. set_machine_evm_operator returns local and synchronization (synchronized, pending, unavailable) separately; only peaq’s lastAppliedMirrorPushSeq for source chain 5 proves application. Clearing a controller needs the default key plus confirm_clear_controller=True; the operator link has no clear. DID setters replace whole lists (8 / 8 / 8, 128 UTF-8 bytes per string) and resize the account, so rent moves to or from whoever signed (preview.rent). Journal the NativeManagementTransaction from on_transaction_submitted before broadcast (serialize_native_management_transaction); reconcile with SolanaManagementReconciliationContext, where expired is the only status with may_resubmit=True, and hand a known unreconciled attempt back as SolanaMachineWriteParams(previous=attempt) so the next write refuses instead of doubling.
Events
submit_event and batch_submit_events resolve each machine and route the batch to its home chain; a Solana-homed machine is written to the Solana EventRegistry program with the owner’s or controller’s OWS Solana signer (assign it first: client.solana_signer = PeaqosClient.solana_signer_from_wallet(name, passphrase), otherwise SIGNER_UNAVAILABLE), needs the [solana] extra, and a batch mixing peaq-homed and Solana-homed machines is refused before either chain is written. The native pipeline reads the gate accounts in one batch, prices the rent shortfall (the first event for a machine funds its event-log account once), simulates, signs, broadcasts and reports completion only when the emitted EventSubmitted events correlate with the instructions. Program errors decode by name from the packaged IDL (NotOwnerOrController, SubscriptionNotEligible, Paused, MachineRelocating). submit_event keeps the EVM return shape, a (signature, data_hash) tuple with the base58 signature in place of the transaction hash; batch_submit_events returns the base58 signatures as strings. The typed SolanaEventSubmissionResult (slot, confirmation level, finalized only for finalized evidence, event index, event log, submission ID) is not returned by either entry point: submit_native_event(client, params, on_broadcast=..., cancel=...) from peaq_os_sdk.events returns it for one event, preview_event_submission(client, params, submitter=...) prices and checks an event without unlocking a wallet, and resolve_event_submission(client, attempt) reconciles an attempt journaled from on_broadcast, read-only (confirmed, expired_unlanded, unresolved). Walkthrough: Submit events: machines homed on Solana. An unavailable confirmation is unresolved with its signature preserved, never a failure. Rate-limit usage is held as per-attempt reservations shared by both chains.
MCR API compatibility
Three breaking changes, required by the 2.0 server’s contract and not optional in Tokenomics mode:revenue_trend and average_revenue_per_event may be None (keys always present; None means not computable, never substitute "stable" or 0; total_revenue stays non-null), a None or non-integer mcr_score raises ApiError BAD_RESPONSE, and MonetizationState.signer accepts a base58 key. Additive Tokenomics-only fields, absent when the server omits them: home_chain (protocol ordinal, Solana is 5, SOLANA_PROTOCOL_CHAIN_ID; not 3338, not 30168, not the InfoDesk ChainKind 3), rating_unavailable, and on the profile owner (base58 for a Solana machine, never pass it to an EVM validator), controller, machine_type, relocating. operator stays a did:peaq:0x… DID or None on every home. ApiError gains http_status, server_code, server_message, operation, home_protocol_chain_id, retryable; 400, 401/403, 404, 409 and 503 map to INVALID_REQUEST, UNAUTHORIZED, NOT_FOUND, MACHINE_HOMED_ELSEWHERE or CONFLICT, SERVICE_UNAVAILABLE (MCR_HTTP_ERROR_CODE). Solana monetization signing (MonetizationConfig(solana_signer=...), five-line message with home_chain: 5, raw Ed25519 sign_message) is implemented. When solana_signer is set, the SDK reads the machine’s home chain first (a compatibility GET and a profile GET) and refuses a Solana-homed write with ValidationError SOLANA_MONETIZATION_UNVERIFIED (MONETIZATION_REFUSAL_CODE) before signing. Without a Solana signer or a SetMonetizationOptions.accepted_context (from peaq_os_sdk.client import SetMonetizationOptions), the SDK does not check the home chain and sends the EIP-191 write; with accepted_context it reads the profile and checks home and owner before every attempt, EVM writes included.
Registration
This is the Tokenomics 1.0 path.register_machine and register_for address IdentityRegistry (1 PEAQ native bond, separate Machine NFT). They emit DeprecationWarning and raise TokenomicsUnsupportedError on a client constructed with tokenomics20. New machines use activate_machine.
register_machine
machine_id. The SDK decodes it from the Registered event in the transaction receipt. 1 PEAQ is sent as msg.value: the payable register() function auto-bonds the machine.
Errors: RpcError: chain revert (AlreadyRegistered), insufficient balance for gas + 1 PEAQ bond, or any other on-chain failure. See errors.
register_for
str
required
Machine EOA to register. The caller acts as proxy operator.
machine_id for the proxied machine. 1 PEAQ is sent as msg.value.
Errors: ValidationError on invalid machine_address. RpcError on chain revert (AlreadyRegistered, InvalidMachineAddress).
Gas Station
setup_faucet_2fa
str
required
Owner to enroll.
str
required
Gas Station base URL.
'svg' | 'png'
QR format. Defaults to
"svg".TypedDict
Keys:
owner_address: str, otpauth_uri: str (OTP auth URI for authenticator apps), qr_image_url: str (expires after ~2 minutes).ValidationError if owner_address or faucet_base_url is empty. ApiError for INVALID_OWNER_ADDRESS, QR_GENERATION_FAILED, NETWORK_ERROR, or an unexpected response envelope. See errors.
confirm_faucet_2fa
ValidationError, ApiError (INVALID_2FA, 2FA_NOT_CONFIGURED, 2FA_LOCKED).
fund_from_gas_station
str
required
2FA-enrolled owner address.
str
required
Machine EOA to fund.
str
required
Chain identifier configured on the faucet, e.g.
"peaq".str
required
Current TOTP.
str
required
Gas Station base URL.
str | None
UUID idempotency key. Auto-generated if omitted.
union
Discriminated union on
status. Either a FundedResponse ({status: "success", tx_hash: str, funded_amount: str}, funded_amount is decimal wei) or a SkippedResponse ({status: "skipped", current_balance: str, min_gas_balance: str}). request_id is a request-side idempotency key passed by the caller; the response does not echo it back.requestId back, in both success and skipped responses. Do not read it from the response in code that has to work with both SDKs.
Errors: ValidationError, ApiError (the /faucet/fund codes from the faucet table, plus NETWORK_ERROR and UNEXPECTED_RESPONSE). See errors.
NFT & DID
This is the Tokenomics 1.0 path. In Tokenomics modemint_nft and token_id_of raise TokenomicsUnsupportedError (minting happens inside activate_machine; the machine ID is the token ID) and the DID writers raise TokenomicsIntegrationUnavailableError. Use the DID setters instead.
Machine NFT minting, token-ID lookup, and the two canonical DID attribute writers. The DID writes are submitted as a single atomic batchAll transaction via the peaq Batch precompile.
mint_nft
Mints a Machine NFT on the MachineNFT contract for a registered, bonded machine.
int
required
Registered machine ID. Must be a positive integer.
str
required
0x-prefixed 20-byte hex address that will receive the NFT.str
Transaction hash as a hex string. With web3 7 or later (what
pip install resolves today) it has no 0x prefix; add it before passing the hash to an RPC call or explorer.ValidationError on non-positive machine_id or invalid recipient. RpcError on chain revert (MachineNotBonded, AlreadyMinted, NotMachineOwner) or transaction failure.
token_id_of
Reads the NFT token ID assigned to a registered machine via a view call.
int
required
Registered machine ID. Must be a positive integer.
int
The NFT token ID, or
0 when no NFT has been minted for this machine.ValidationError if machine_id is not positive.
Like the JS SDK, Python returns 0 when the machine has no NFT; check for 0 in both.
write_machine_did_attributes
Atomically writes the six canonical Machine DID attributes to the caller’s DID via a single batchAll transaction.
int
required
Registered machine ID.
int
required
NFT token ID assigned to the machine.
str
required
Operator DID reference. May be an empty string. ASCII, ≤ 2560 bytes.
str
required
Non-empty ASCII URL, ≤ 2560 bytes.
str
required
Non-empty ASCII URL for the machine’s data API, ≤ 2560 bytes.
'public' | 'private' | 'onchain'
required
Visibility setting.
write_proxy_did_attributes
Atomically writes the two canonical Proxy DID attributes (machineId, machines) to the caller’s DID.
int
required
The proxy operator’s registered machine ID.
list[int]
required
Non-empty list of positive machine IDs. The JSON-encoded array must be ≤ 2560 bytes.
read_attribute
Reads a single DID attribute directly from the peaq DID precompile. Not exported from the package root: import from peaq_os_sdk.did.did_precompile.
str
required
The machine address whose DID is being read.
str
required
Attribute key, e.g.
"machineId", "data_visibility", "machines".TypedDict
Keys:
name: str, value: str, validity: int (the absolute block number the attribute is valid until, not the valid_for duration), created: int (block timestamp). A missing attribute raises the underlying web3 exception (for example web3.exceptions.Web3RPCError with revert Cannot find the item), not RpcError.Smart accounts
ERC-4337 smart accounts deployed via theMachineAccountFactory. Requires the client to be constructed with machine_account_factory (or MACHINE_ACCOUNT_FACTORY_ADDRESS when using from_env).
deploy_smart_account
Deploys a smart account via MachineAccountFactory.createAccount and returns the deployed address.
str
required
EOA that will own the smart account.
str
required
Machine EOA the account is scoped to.
int
required
Non-negative CREATE2 salt.
ValidationError on invalid param or client constructed without machine_account_factory. RpcError on revert or missing AccountCreated event.
get_smart_account_address
Read-only equivalent: computes the CREATE2 address without deploying. Identical result to deploy_smart_account for the same inputs.
deploy_smart_account. No transaction, no gas.
Bridge
LayerZero v2 Machine NFT bridging between peaq and Base. Requiresmachine_nft_adapter (or MACHINE_NFT_ADAPTER_ADDRESS) when sending from peaq.
In Tokenomics mode bridge_nft raises MACHINE_RELOCATION_UNAVAILABLE: Economics 2.0 relocates whole machine records and that is disabled on chain. A 2.0 machine that should live on Solana is created there, not bridged: see Solana. Portability of the 1.0 NFT: Machine NFT cross-chain portability.
bridge_nft
Bridges a Machine NFT from source to destination.
On the peaq→Base path the SDK runs an ERC-721 approval pre-flight: it reads MachineNFT.getApproved(token_id) and submits a one-shot approve(adapter, token_id) if the token isn’t already cleared for the adapter. The Base→peaq path uses burn-and-unlock and needs no approval. Callers don’t handle approvals themselves.
int
required
Positive NFT id to bridge.
'peaq' | 'base'
required
Origin chain.
'peaq' | 'base'
required
Target chain. Must differ from
source.str
required
Destination-chain recipient address.
str | None
Base RPC URL. Required only when
source == "base".str | None
MachineNFTBase address on Base. Required only when source == "base".bytes
Raw LayerZero v2
extraOptions bytes.wait_for_bridge_arrival
Static method that polls the destination chain’s MachineNFT.ownerOf(token_id) every 10 seconds until a non-zero owner returns or the timeout elapses. Does not require a client instance.
str
required
Destination-chain RPC endpoint.
str
required
MachineNFT contract address on the destination.int
required
The NFT id expected to arrive.
int
Wait budget in seconds. Defaults to 300 (5 min).
Events (Qualify)
Both calls write to theevent_registry address the client was constructed with (EVENT_REGISTRY_ADDRESS); the SDK adds no 2.0-specific address. They resolve each machine’s home and write a Solana-homed machine’s events to the Solana EventRegistry program, which needs the [solana] extra: see Solana.
submit_event
Submits a single event to EventRegistry. Returns (tx_hash, data_hash).
validate_submit_event_params below.
value is an ISO 4217 minor-unit integer: cents for USD/HKD, whole units for JPY/KRW/VND. The MCR pipeline FX-normalizes to USD cents using the rate at timestamp and counts revenue only in its 25 supported currencies, listed on Submit events. currency is a 3-10 char uppercase alphanumeric code on revenue events and "" on activity events; omitting the kwarg applies the smart default for a peaq-homed machine. For a Solana-homed machine pass currency explicitly: the omitted default raises ValidationError (field="currency") on that path. batch_submit_events is strict: currency must be supplied per event.
tuple[str, bytes]
tx_hash is the transaction hash as a hex string, without a 0x prefix with web3 7 or later (a base58 signature for a Solana-homed machine); data_hash is exactly 32 bytes.ValidationError, TypeError when value is not a plain int, ValueCapExceeded, RateLimitExceeded, RpcError.
batch_submit_events
Submits multiple events atomically through the peaq Batch precompile. All succeed or all revert.
list[dict | SubmitEventParams]
required
Non-empty list of event payloads. Items may be
SubmitEventParams instances or dicts with matching keys.list[str]
One transaction hash per input event. All hashes are identical (same batch tx).
ValidationError on empty list or invalid event; TypeError when an event’s value is not a plain int. ValueCapExceeded / RateLimitExceeded when operational limits hit. RpcError on revert or transport failure.
validate_submit_event_params
SubmitEventParams is a frozen dataclass (imported from peaq_os_sdk.types.events):
SubmitEventParams instance. Dict literals will raise AttributeError.
Errors: ValidationError: any field out of range. TypeError when value is not a plain int.
compute_data_hash
keccak256 digest of raw_data. Pair with submit_event’s data_hash output (also bytes) to compare on-chain payloads.
check_operational_limits
SubmitEventParams
required
Event with
machine_id and value.OperationalLimits
required
Configured
max_value_per_tx, rate_limit_max_events, rate_limit_window_seconds.EventTracker | None
required
Current rate-tracking state for the machine, or
None when tracking is disabled.ValueCapExceeded if value > max_value_per_tx. RateLimitExceeded when the event window is exceeded.
Queries
Read-only helpers backed by the off-chain MCR API server. Each function validates the DID, issues a singleGET through client.session, and returns a shape-checked TypedDict. The default per-request timeout is 30 seconds, enforced inside peaq_os_sdk.query.http_client.get_json; the public query_* functions do not expose an override.
On a tokenomics20 client all three go to the deployment’s 2.0 MCR server (mcr.peaq.xyz for peaq-mainnet) and client.api_url is not read. Machine DIDs are did:peaq:<decimal machine id>, operator DIDs stay did:peaq:0x<address>, machine_id is a lossless int. A malformed or non-canonical machine_id, or a response about a different machine or operator, raises ApiError BAD_RESPONSE. A deployment without a paired MCR (agung-2026-08-28) raises TokenomicsConfigError DEPLOYMENT_UNAVAILABLE before any HTTP. The MCR helpers need a tokenomics20 client. See API reference.
query_mcr
Fetches the Machine Credit Rating for a machine DID. See GET /mcr/{did}.
str
required
Machine DID,
did:peaq:<decimal machine id>.TypedDict
Snake_case keys:
did: str, machine_id: int, mcr_score: int (0–100), mcr: str ("AAA" | "AA" | "A" | "BBB" | "BB" | "B" | "NR" | "Provisioned"), bond_status: str ("bonded" | "unbonded"), negative_flag: bool, event_count: int, revenue_event_count: int, activity_event_count: int, revenue_trend: str | None ("up" | "stable" | "down" | "insufficient"; None means not computable, never substitute "stable"), total_revenue: float (USD cents, the sum of the revenue events worth at least 1,000 USD cents; divide by 100 for display; never None), average_revenue_per_event: float | None (USD cents, rounded to 2 decimals; None when not computable), last_updated: int | None, mcr_degraded: bool (True when revenue for a peaq-homed machine was converted at a stale stored FX rate; always False for a Solana-homed machine). Both nullable keys are always present; test the value, not membership. On a tokenomics20 client two optional keys appear only for a machine homed away from peaq: home_chain (protocol chain ordinal, Solana is 5, SOLANA_PROTOCOL_CHAIN_ID) and rating_unavailable (any non-empty value means the score is a floor). Details: MCR API compatibility.mcr_score is always an int; the MCR API returns 0 for a Provisioned or NR machine. A None or non-integer mcr_score raises ApiError BAD_RESPONSE; rating_unavailable carries the reason an unscored machine has no rating.
Errors: ValidationError if did is not a valid machine DID (did:peaq:<decimal machine id>). ApiError with code in NOT_FOUND (HTTP 404), SERVICE_UNAVAILABLE (503), SERVER_ERROR (other 5xx), HTTP_ERROR (other non-2xx), BAD_RESPONSE (malformed body), TIMEOUT, NETWORK_ERROR. 400 is INVALID_REQUEST, 401 and 403 are UNAUTHORIZED, 409 is MACHINE_HOMED_ELSEWHERE or CONFLICT (MCR_HTTP_ERROR_CODE), and the error carries http_status, server_code, server_message, operation, home_protocol_chain_id, retryable. See errors.
query_machine
Fetches the full machine profile (NFT Metadata JSON v1.0) and validates the response shape against a strict TypedDict. The SDK raises BAD_RESPONSE if the server payload does not match the schema. See GET /machine/{did}.
str
required
Machine DID,
did:peaq:<decimal machine id>.TypedDict
Top-level keys:
schema_version: str, name: str, peaqos: PeaqosData. PeaqosData always carries machine_id: int, did: str, operator: str | None, mcr: str, mcr_score: int, bond_status: str, negative_flag: bool, event_count: int, data_visibility: str, documentation_url: str | None. The MCR API returns data_visibility: "private" for every machine and no event rows or partner data; data_api: str is present when the machine’s DID carries a peaq-data-api service endpoint. event_data: list[EventEntry], partner_data: dict[str, Any], and partner_data_error: str stay optional in the type; the MCR API does not return them. Use "data_api" in profile["peaqos"] (etc.) to test for presence rather than truthiness. On a tokenomics20 client a machine homed away from peaq adds optional home_chain, rating_unavailable, owner (base58 on Solana, never pass it to an EVM validator), controller, machine_type, relocating; operator stays a did:peaq:0x… DID or None. Details: MCR API compatibility.ValidationError on invalid DID. ApiError with the same codes as query_mcr; BAD_RESPONSE if any required field is missing, has the wrong type, or is out of range.
query_operator_machines
Fetches the fleet of machines managed by a proxy operator. Each entry is individually validated. See GET /operator/{did}/machines.
str
required
Operator DID. Must start with
did:peaq:0x.TypedDict
Keys:
operator_did: str, machines: list[OperatorMachine], and pagination: Pagination. Each OperatorMachine has did: str, machine_id: int, mcr_score: int (0–100; a None or non-integer score raises BAD_RESPONSE), mcr: str, and negative_flag: bool. Pagination carries offset: int, limit: int, and total: int.ValidationError on invalid DID. ApiError with the same codes as query_mcr; BAD_RESPONSE if the body or any machines entry is malformed.
Verify
Experimental, beta: the Verify surface lives inpeaq_os_sdk.verify, is not re-exported from the package root (there is no client.verify), and may change without a major version bump. It ships an API read client and three pure chip preflight functions, with no attester, submission, anchoring or hardware code. Reads need no [solana] extra. Verify on peaq mainnet serves peaq-homed (EVM) machines; a Solana-homed machine returns 503 VERIFY_READ_UNAVAILABLE, raised as VerifyTransportError with cause_category == "unavailable". Available from peaq-os-sdk 0.10.0.
VerifyReadClient
Reads one machine’s record from the Verify API. The API is authoritative: the client validates the response and returns it as frozen dataclasses; it does not read the registry, an RPC or a DID service.
str
required
HTTPS origin of the Verify API, no path, query or credentials. There is no default. Construction opens no connection; call
close() when done.RegistryMachineId
required
From
registry_machine_id(123): an int in 1..2**256-1. A DID, an address or 0 raises VerifyValidationError before any request.threading.Event
Set it from another thread to abort the call; the result is
VerifyTransportError with cause_category == "canceled".EvmMachineVerification | SolanaMachineVerification
Frozen.
machine_id, machine_did, home_chain (EvmHomeChain(chain_id) or SolanaHomeChain(genesis_hash)), did_controller and operator (kind plus address in the home chain’s native kind), and kyb.status / chip.status, each "unverified" | "verified" | "expired" | "revoked". Python exposes the two topics directly on the record where the wire format and the JS SDK nest them under verification. No aggregate flag.machine_id, machine_did, did_controller.address and operator.address are typed wrapper objects (RegistryMachineId, MachineDid, DidControllerAddress, OperatorAddress), not plain strings: read .value for the string (machine_did.value, did_controller.address.value, operator.address.value) and machine_id.value for the int.GET /v1/verify/machines/{machineId} with a five-second deadline and a 4096-byte response ceiling, follows no redirect, sends no credentials and keeps no cache. Nothing retries.
Chip preflight
Three functions that run on the machine and turn a challenge plus the chip’s leaf certificate and two signatures into the canonicalpeaq.verify.chip-evidence/1 document. They need no chip access, no network, no key and no file of yours: the pinned Infineon ECC Root CA 2 and CA306 intermediate certificates ship inside the package. A platform adapter reads the certificate from the OPTIGA Trust M Express object 0xE0E0 and asks key 0xE0F0 to sign; the DID controller’s wallet signs the controller message. Fixed profile infineon-optiga-trust-m-express-ca306/1, trust bundle infineon-optiga-trust-m-express-ca306-roots/1; no other chip, root or curve. EVM controller and chain ID only.
sign_chip and sign_controller are yours: the SDK never invokes the chip or a wallet. ChipPreflightEvidence exposes the fixed identifiers (protocol, profile, evidence_schema, trust_bundle), revocation_status == "not_evaluated" (the SDK checked no revocation list), evidence_hash, chip_ref and evidence_bytes(). Every stage rechecks now < expires_at <= now + 300 and the certificate validity, so run all three right after the challenge. A VerifyFreshnessError needs a new challenge, a new ChipPreflightContext and all three stages again; after any other failure, correct the rejected input and call the failed stage again.
Preflight success means the material is locally valid. It does not consume the challenge, does not submit anything, and does not set
chip.status to verified: the onboarding service submits the bytes with POST /v1/verify/chip/evidence, and chip.status reads verified once peaq records the chip attestation. The full flow is in Verify a chip, end to end.Error classes
Constants
Tokenomics 2.0 tiers and activation defaults
Tokenomics 2.0 tiers and activation defaults
Machine status (Tokenomics 1.0)
Machine status (Tokenomics 1.0)
MCR ratings (Python-only)
MCR ratings (Python-only)
Solana and MCR API
Solana and MCR API
Event types, trust levels & chain IDs
Event types, trust levels & chain IDs
Identical to the JS SDK:
EVENT_TYPE_REVENUE, EVENT_TYPE_ACTIVITY, TRUST_SELF_REPORTED, TRUST_ON_CHAIN_VERIFIABLE, TRUST_HARDWARE_SIGNED, DID_ATTR_*, DID_MAX_NAME_BYTES, DID_MAX_VALUE_BYTES, SUPPORTED_CHAINS, LAYERZERO_EIDS, DEFAULT_API_URL. Same values, Python-idiomatic names.Data visibility (Python-only)
Data visibility (Python-only)
data_visibility= on write_machine_did_attributes. The SDK rejects any other value with ValidationError before sending; using one of these constants avoids typos.Wallet import chains & passphrase env
Wallet import chains & passphrase env
import_wallet(..., chain=IMPORT_CHAIN_SOLANA). The JS SDK exports identical constants. See JS Constants.
