Skip to main content
PUT
PUT /machine/{key}/monetization

Endpoint

Sets a machine’s monetization state (opt in or opt out). This is the MCR API’s only signature-verified write endpoint: the caller proves authority with a signature over a canonical message. For a peaq-homed machine the signature is (personal_sign), and the machine’s owner or its controller (set in MachineRegistry) may sign. For a Solana-homed machine the signature is Ed25519, and only the owner recorded on the machine account may sign. No on-chain transaction is made. Opting in requires the machine to be , and a peaq-homed machine must also be available (not deactivated or paused). Opting out is always allowed (a machine can always exit), so it skips those checks.

Path parameters

string
required
Machine DID (did:peaq:<decimal machine id>) or the bare decimal machine ID. An address-form DID (did:peaq:0x...) or a raw address returns 400 INVALID_REQUEST.

Request body

boolean
required
true to opt in, false to opt out. Must be a JSON boolean (not "true" or 1).
integer
required
Unix seconds when the message was signed. Must be a positive JSON integer inside the freshness window (see below).
string
required
The EIP-191 signature: 0x followed by exactly 130 hex characters (65 bytes). When signer_pubkey is present, a base58 Ed25519 signature of at most 88 characters instead.
string
For a machine homed on Solana: the owner’s base58 Ed25519 public key (at most 44 characters). When present, the server verifies signature as a base58 Ed25519 signature by this key over the Solana canonical message instead of EIP-191, and only the machine’s owner may sign. Sending it for a peaq-homed machine returns 403 UNAUTHORIZED_SIGNER. null is rejected with 400 INVALID_REQUEST; omit the field for the EIP-191 path.

Canonical message

The client must build and sign this exact string, byte for byte. Fields are LF-separated (\n) with no trailing newline. For a peaq-homed machine (EIP-191):
  • registry is the server’s MachineRegistry address, lowercased. The server publishes it, with chain_id, at GET /.well-known/peaq-monetization.
  • chain_id is the chain the server reads from. Together with the registry it binds the signature to one deployment, so a signature captured on one chain does not authorize the same action on another.
  • machine_id is the decimal machine ID. Even when the URL key is a DID, the signed message uses the resolved decimal ID.
  • opted_in is the lowercase string true or false, matching the body field.
Sign it with personal_sign (JS) or eth_account’s encode_defunct(text=message) (Python). For a Solana-homed machine (Ed25519, with signer_pubkey in the body), the registry and chain_id lines are replaced by audience and home_chain:
  • audience is the chain ID of the server’s deployment (the chain_id published at GET /.well-known/peaq-monetization), so a signature cannot be replayed against another deployment that serves the same machine.
  • home_chain is the machine’s home protocol chain ordinal (5 for Solana), so a signature cannot be replayed if the machine relocates.
Sign the UTF-8 bytes of this exact text with the owner’s Ed25519 key, with no transaction and no envelope (what a wallet’s plain signMessage produces), and send the signature base58-encoded. Both SDKs refuse a Solana-homed write before signing (SOLANA_MONETIZATION_UNVERIFIED), so this path is for direct HTTP calls. See Monetization opt-in.

Freshness window

The timestamp must fall within the freshness window: up to 300 seconds in the past and 30 seconds of future clock skew. Replaying an old signature after the window closes is rejected, and within the window a strictly newer timestamp is required to overwrite a previously applied decision (see STALE_SIGNATURE).

Response

200 OK

Error responses

Errors use a coded envelope: {"detail": {"code", "message"}}. Branch on code, never on message. Two responses carry no code: a body that is not valid JSON returns 422 with detail as a list of validation objects, and a caller over the rate limit gets 429 with the body {"error": "Rate limit exceeded: 90 per 1 minute"}.

Example

Response

SDK and CLI support

For a peaq-homed machine both SDKs wrap this endpoint, building and signing the canonical message for you: see the opt-in SDK reference (optIn / optOut in JS, opt_in / opt_out in Python). The CLI exposes it as peaqos monetize opt-in | opt-out. For a Solana-homed machine the SDKs refuse before signing (SOLANA_MONETIZATION_UNVERIFIED); use the direct HTTP flow above.