Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.peaq.xyz/llms.txt

Use this file to discover all available pages before exploring further.

Revenue events (type 0) and activity events (type 1) feed the Machine Credit Rating. Every event is validated client-side, hashed, and submitted on-chain to the EventRegistry contract.

Event types

TypeValuePurposeExample
Revenue0Records economic value generated by the machineA claw machine collects $5.00 from a play session
Activity1Records operational activity with no direct revenueA weather sensor reports a telemetry ping

Trust levels

Each event carries a trust level describing how the data was attested. See Trust levels for the concept overview.
LevelValueMeaningNeeds source tx hash?
Self-reported0Machine self-reports. No external verification.No
On-chain verifiable1Event references a verifiable on-chain transaction.Yes
Hardware-signed2Event signed by tamper-resistant hardware.No

Currency and value units

currency is a first-class parameter on submitEvent / submit_event. Revenue events take a 3-10 char uppercase alphanumeric code (USD, HKD, JPY, …); activity events must pass "". The SDK applies a smart default when omitted on single-event submits (revenue → "USD", activity → ""); batchSubmitEvents / batch_submit_events requires it explicitly. value is an ISO 4217 minor-unit integer:
CurrencySubunit divisorExample
USD, HKD, EUR (and other 2-decimal currencies)100$1.23 → value: 123
JPY, KRW, VND (no subunits)1¥100 → value: 100
BHD, KWD, OMR (3-decimal)1000BD 1.234 → value: 1234
The MCR pipeline converts value to USD cents using the FX rate at timestamp. The converted amount surfaces on GET /machine/{did} as usd_value (USD cents integer) on revenue events when data_visibility is onchain. amount_status distinguishes "ok", "unsupported_currency" (currency not in the FX whitelist), and "fx_unavailable" (degraded FX feed). Non-"ok" rows score conservatively and surface mcr_degraded: true on GET /mcr/{did}. Activity events ignore the FX path entirely. They don’t accumulate revenue.

Validation

Call validateSubmitEventParams before submitting. It throws ValidationError on the first invalid field.
import {
  validateSubmitEventParams,
  computeDataHash,
  EVENT_TYPE_REVENUE,
  TRUST_SELF_REPORTED,
  SUPPORTED_CHAIN_IDS,
} from "@peaqos/peaq-os-sdk";

const params = {
  machineId: 1,
  eventType: EVENT_TYPE_REVENUE,      // 0
  value: 500,                          // $5.00 in cents
  currency: "USD",
  timestamp: Math.floor(Date.now() / 1000) - 10,
  rawData: new TextEncoder().encode(JSON.stringify({ session: "abc123" })),
  trustLevel: TRUST_SELF_REPORTED,     // 0
  sourceChainId: SUPPORTED_CHAIN_IDS.peaq, // 3338
  sourceTxHash: null,
  metadata: new Uint8Array([]),
};

// Throws ValidationError if any field is invalid
validateSubmitEventParams(params);

Validation rules

FieldConstraintError if violated
machineId / machine_idPositive integermachineId must be a positive integer
eventType / event_type0 or 1eventType must be 0 or 1
valueNon-negative integer (ISO 4217 minor units)value must be non-negative
currencyRevenue: ^[A-Z0-9]{3,10}$. Activity: must be "".currency must match ^[A-Z0-9]{3,10}$ / currency must be empty for activity events
trustLevel / trust_level0, 1, or 2trustLevel must be 0, 1, or 2
sourceChainId / source_chain_id0, 3338, or 8453sourceChainId must be a supported chain ID
rawData / raw_dataNon-empty when providedrawData must not be empty when provided
sourceTxHash / source_tx_hash0x-prefixed 32-byte hex (66 chars) when providedsourceTxHash must be a 0x-prefixed 32-byte hex string
timestampPositive integertimestamp must be a positive integer
sourceTxHash when trustLevel === 1RequiredsourceTxHash is required when trustLevel is 1
The contract additionally rejects metadata larger than 4096 bytes with a MetadataTooLarge revert. The SDK validators don’t enforce this client-side, so oversized payloads surface as a transaction failure (RuntimeError/RpcError with code: "MetadataTooLarge") rather than ValidationError.

Computing the data hash

The EventRegistry stores a keccak256 hash of the raw data, not the data itself. Compute it with computeDataHash (JS) or compute_data_hash (Python).
import { computeDataHash } from "@peaqos/peaq-os-sdk";

const rawData = new TextEncoder().encode(
  JSON.stringify({ session: "abc123", amount: 500 })
);
const hash = computeDataHash(rawData);
// hash: "0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658"
The hash is passed as the dataHash field in the on-chain MachineEvent struct. Consumers who need to verify the original data compare its keccak256 against the stored hash.

Submitting a revenue event (type 0)

import "dotenv/config";
import {
  PeaqosClient,
  validateSubmitEventParams,
  computeDataHash,
  EVENT_TYPE_REVENUE,
  TRUST_SELF_REPORTED,
  SUPPORTED_CHAIN_IDS,
} from "@peaqos/peaq-os-sdk";

const client = PeaqosClient.fromEnv();

const rawData = new TextEncoder().encode(
  JSON.stringify({ session: "abc123", amount: 500 })
);

const params = {
  machineId: 1,
  eventType: EVENT_TYPE_REVENUE,
  value: 500,                       // $5.00 in cents
  currency: "USD",
  timestamp: Math.floor(Date.now() / 1000) - 10,
  rawData,
  trustLevel: TRUST_SELF_REPORTED,
  sourceChainId: SUPPORTED_CHAIN_IDS.peaq,
  sourceTxHash: null,
  metadata: new Uint8Array([]),
};

validateSubmitEventParams(params);

const { txHash, dataHash } = await client.submitEvent(params);
console.log("Submitted revenue event:", { txHash, dataHash });

Submitting an activity event (type 1)

Activity events record operational telemetry with no direct revenue value.
import "dotenv/config";
import {
  PeaqosClient,
  validateSubmitEventParams,
  computeDataHash,
  EVENT_TYPE_ACTIVITY,
  TRUST_SELF_REPORTED,
  SUPPORTED_CHAIN_IDS,
} from "@peaqos/peaq-os-sdk";

const client = PeaqosClient.fromEnv();

const rawData = new TextEncoder().encode(
  JSON.stringify({ type: "heartbeat", uptimeSeconds: 86400 })
);

const params = {
  machineId: 1,
  eventType: EVENT_TYPE_ACTIVITY, // 1
  value: 0,                       // No revenue
  currency: "",                   // activity events must be empty
  timestamp: Math.floor(Date.now() / 1000) - 10,
  rawData,
  trustLevel: TRUST_SELF_REPORTED,
  sourceChainId: SUPPORTED_CHAIN_IDS.peaq,
  sourceTxHash: null,
  metadata: new Uint8Array([]),
};

validateSubmitEventParams(params);

const { txHash, dataHash } = await client.submitEvent(params);
console.log("Submitted activity event:", { txHash, dataHash });

Cross-chain revenue pattern

When a machine earns revenue on another chain (e.g., Base), reference the source transaction for on-chain verifiable trust (level 1).
import {
  validateSubmitEventParams,
  EVENT_TYPE_REVENUE,
  TRUST_ON_CHAIN_VERIFIABLE,
  SUPPORTED_CHAIN_IDS,
} from "@peaqos/peaq-os-sdk";

const params = {
  machineId: 1,
  eventType: EVENT_TYPE_REVENUE,
  value: 1200,                              // $12.00 in cents
  currency: "USD",
  timestamp: Math.floor(Date.now() / 1000) - 10,
  rawData: new TextEncoder().encode(JSON.stringify({ invoice: "INV-0042" })),
  trustLevel: TRUST_ON_CHAIN_VERIFIABLE, // 1
  sourceChainId: SUPPORTED_CHAIN_IDS.base, // 8453
  sourceTxHash: "0xa1b2c3d4e5f6789000000000000000000000000000000000000000000000a1b2",
  metadata: new Uint8Array([]),
};

validateSubmitEventParams(params);
// sourceTxHash is required when trustLevel is 1.
// The MCR system can verify this transaction on Base.

Supported chain IDs

ChainID
peaq (same-chain, or use 0)3338
Base8453

Operational limits

The SDK enforces per-transaction value caps and rate limits before submitting.
import { checkOperationalLimits } from "@peaqos/peaq-os-sdk";

checkOperationalLimits(
  { machineId: 1, value: 500 },
  {
    maxValuePerTx: 10000,
    rateLimitMaxEvents: 60,
    rateLimitWindowSeconds: 3600,
  },
  tracker, // EventTracker from previous submissions, or null
);
// Throws ValueCapExceeded if value > maxValuePerTx
// Throws RateLimitExceeded if count >= rateLimitMaxEvents within window
LimitError typeDescription
maxValuePerTx / max_value_per_txValueCapExceededSingle event value exceeds the per-transaction cap
rateLimitMaxEvents / rate_limit_max_eventsRateLimitExceededToo many events submitted within the rate-limit window
Set limits to 0 to disable (the default).

Error handling

submitEvent / submit_event raise four distinct error types. Validation and limit errors are local; RuntimeError (JS) / RpcError (Python) wraps every chain or RPC failure. JS collapses chain and HTTP errors into a single RuntimeError; Python keeps them separate (RpcError for chain, ApiError for HTTP).
import {
  ValidationError,
  ValueCapExceeded,
  RateLimitExceeded,
  RuntimeError,
} from "@peaqos/peaq-os-sdk";

try {
  const { txHash, dataHash } = await client.submitEvent(params);
} catch (err) {
  if (err instanceof ValidationError) {
    // Bad params: check err.field, err.constraint
  } else if (err instanceof ValueCapExceeded) {
    // Per-tx value cap tripped
  } else if (err instanceof RateLimitExceeded) {
    // Local rate limit tripped
  } else if (err instanceof RuntimeError) {
    // Chain/RPC failure: err.code carries the contract revert name
    // (e.g. "MetadataTooLarge", "MachineNotFound", "NotAuthorizedSubmitter")
    // or "TX_REVERTED" for unrecognized reverts
  } else {
    throw err;
  }
}
See SDK errors reference for the full code map and the cross-language equivalence between RuntimeError (JS) and RpcError/ApiError (Python).

Next steps