Skip to main content
Skills are the shared schema. Services are concrete provider instances from those schemas. Search ranks services against machine context and requirements. See the Machine Markets overview for base path, auth model, common envelopes, and error codes.

Types

type SkillSummary = {
  key: string;
  providerKey: string;
  label: string;
  description: string;
  serviceTypes: ServiceType[];
  operations: string[];
  executionMode: ExecutionMode;
  integrationStatus: IntegrationStatus;
};

type MarketService = {
  id: string;
  skillKey: string;
  providerKey: string;             // peaqOS adapter or gateway key
  companyName: string;             // underlying company (Tether, Google, Anthropic, ...)
  serviceType: ServiceType;
  name: string;
  description: string;
  operations: string[];
  pricing: {
    mode: "provider-defined" | "fixed" | "quote-required";
    amount?: number | null;
    currency?: string | null;
    rate?: string | null;          // e.g. "per_request", "per_1m_tokens"
    notes: string[];
  };
  payment: MarketOrder["payment"]; // copy of the rail recommendation
  endpoints: Array<{
    label?: string | null;
    operation?: string | null;
    url?: string | null;
    method?: string | null;        // HTTP method when applicable
    path?: string | null;
    providerName?: string | null;
    key?: string | null;
    protocols: string[];           // e.g. ["x402"], ["mpp"]
    networks: string[];            // e.g. ["base", "solana"]
  }>;
  endpoint?: {                     // legacy single-endpoint alias for endpoints[0]
    label?: string | null;
    operation?: string | null;
    url?: string | null;
    method?: string | null;
    path?: string | null;
    providerName?: string | null;
    key?: string | null;
    protocols: string[];
    networks: string[];
  } | null;
  consumption: {                   // canonical flow paths for this service
    adapterSetupPath: string;
    serviceDetailPath: string;
    marketSearchPath: string;
    orderPath: string;
    paymentIntentPath: string | null;
    paymentProofPath: string | null;
    orderExecutePath: string;
    confirmPath: string;
    directExecutePath: string | null;  // set for free read-only services
    requiredContext: string[];
    requiredRequestFields: string[];
    optionalRequestFields: string[];
    paymentFields: string[];
    instructions: string[];
  };
  executionMode: ExecutionMode;
  integrationStatus: IntegrationStatus;
  region: string;
  capabilities: string[];
  handoff?: {
    label: string;
    url: string;
    notes: string[];
  } | null;
  metadata: Record<string, unknown>;
};

type CatalogService = MarketService & {
  providerId: string;
  providerLabel: string;
  authType: "none" | "bearer" | "api-key" | "wallet" | "local";
  accessMode: "public" | "credentialed" | "partner-approved" | "whitelisted" | "local";
  distribution: "peaq-native" | "clawhub" | "openapi" | "mcp" | "docs-only";
  maturity: "reference" | "beta" | "production";
  kind: "runtime" | "reference";
  freshnessSeconds: number;
  requiresHumanEnablement: boolean;
  referenceUrl?: string;
  artifactUrl?: string;
};

type MarketQuote = {
  id: string;
  serviceId: string;
  skillKey: string;
  providerKey: string;
  executionMode: ExecutionMode;
  integrationStatus: IntegrationStatus;
  operation: string;
  score: number;
  reasons: string[];
  pricing: {
    mode: "provider-defined" | "fixed" | "quote-required";
    amount: number | null;
    currency: string | null;
    rate: string | null;
    notes: string[];
  };
  payment: {
    defaultRail: "not-required" | "x402" | "vault-stripe" | "escrow"
      | "offchain-record" | "external" | "onchain-escrow";
    supportedRails: MarketQuote["payment"]["defaultRail"][];
    required: boolean;
    provider: string | null;
    chain: string | null;
    token: string | null;
    walletAddress: string | null;
    externalUrl: string | null;
    notes: string[];
  };
  expiresAt: string;              // 15 minutes from search creation
};

type MarketSearch = {
  id: string;
  machineId: string;
  agentPairingId: string | null;
  request: Record<string, unknown>;   // original search body, provider credentials redacted
  normalizedTask: {
    serviceType: ServiceType;
    operation?: string;
    requiredCapabilities: string[];
    region?: string;
    allowExternalHandoff: boolean;
    requireNativeExecution: boolean;
  };
  status: "completed" | "no_match";
  quotes: MarketQuote[];
  createdAt: string;
};

Skills

GET /skills

type ListSkillsResponse = ListResponse<SkillSummary>;

GET /skills/:skillKey

type GetSkillResponse = ItemResponse<SkillSummary>;

GET /skills/:skillKey/manifest

Returns the full skill manifest, including per-operation input/output contracts. Use this when an or integrator needs the schema for a skill without resolving a market service first.
type OperationFieldSpec = {
  key: string;
  type: string;
  required?: boolean;
  description: string;
  example?: unknown;
  defaultFrom?: string;       // e.g. "service.metadata.feedId"
  enum?: string[];
  fields?: OperationFieldSpec[];
};

type OperationContract = {
  operation: string;
  summary?: string;
  inputFields: OperationFieldSpec[];
  outputFields: OperationFieldSpec[];
  exampleInput?: Record<string, unknown>;
  exampleOutput?: unknown;
  notes?: string[];
};

type SkillManifest = {
  key: string;
  providerKey: string;
  label: string;
  summary: string;
  listing: {
    direction: SkillDirection;
    scope: SkillScope;
    source: SkillSource;
    listedBy: string;
    lastVerifiedAt: string | null;
  };
  distribution: SkillDistribution;
  maturity: SkillMaturity;
  inputs: OperationFieldSpec[];
  outputs: OperationFieldSpec[];
  access: {
    accessMode: SkillAccessMode;
    requiredEnv: string[];
    requiresHumanEnablement: boolean;
    notes: string[];
  };
  usage: {
    operations: string[];
    referenceUrl?: string;
    artifactUrl?: string;
    handoff?: ExternalHandoff;
  };
  operationContracts?: OperationContract[];
};

type GetSkillManifestResponse = ItemResponse<SkillManifest>;
operationContracts also surfaces on MarketQuote.operationContract (single, optional) and on MarketService.operationContracts (full list) so downstream code can build a request without a second roundtrip.

Service catalog

GET /catalog

Returns the normalised backend service catalogue used by discovery and market service listing. companyName is the underlying service company or organisation; providerKey remains the peaqOS adapter or gateway.
type ListCatalogServicesQuery = {
  limit?: number;
  cursor?: string;
};

type ListCatalogServicesResponse = ListResponse<CatalogService>;

Adapter setup catalog

GET /market/adapter-credential-stack

Public endpoint that feeds the frontend “adapter setup” cards (the rich provider tiles on robotic.sh and the peaq app’s Services page). Data is backend-owned and repo-backed; the public API does not write. Adding or updating an adapter requires a PR to peaqos-orchestration that adds a registry entry and passes the metadata completeness tests; the PR template lives at .github/PULL_REQUEST_TEMPLATE/adapter-setup-catalog.md.
type ListAdapterServiceListingsQuery = {
  providerKey?: string;
  skillKey?: string;
  serviceType?: ServiceType;
  limit?: number;
  cursor?: string;
};

type ListAdapterServiceListingsResponse = ListResponse<AdapterServiceListing>;

type AdapterServiceListing = {
  providerKey: string;
  label: string;
  displayName: string;
  companyName: string;             // underlying company or organisation
  description: string;
  category:
    | "inference" | "vision" | "speech" | "navigation"
    | "positioning" | "translation" | "web" | "onchain"
    | "compute" | "storage";
  chains: Array<"base" | "solana" | "peaq" | "sui">;
  price: string;
  robotTypes: Array<"drones" | "amrs" | "humanoids" | "evs" | "arms" | "sensors">;
  serviceTypes: ServiceType[];
  skillKeys: string[];
  setupUrl: string;
  referenceUrl: string;
  serviceCatalogPath: string;      // fetch endpoint-level services for this adapter
  paymentRails: string[];
  authModes: string[];             // e.g. ["bearer", "api-key", "wallet"]
  setupComplexity: "low" | "medium" | "high";
  displayOrder: number;
  requiresCredentials: boolean;
  requiredFields: string[];
  optionalFields: string[];
  nativeExecutionAvailableWithCredentials: boolean;
  nativeExecutionNote: string;
  operatorAction: string;
  agentInstructions: string[];
};
Launch adapter registry: qvac (inference, Tether strategic), pay-sh (web), agentic-market (x402 services). Each entry carries a setupUrl pointing at the central robotic.sh catalog, a provider-specific referenceUrl, and a serviceCatalogPath you call to fetch the endpoint-level services that belong to the adapter. Those service records include callable endpoint URLs, pricing, , and consumption instructions. Frontend rendering uses category, robotTypes, chains, and setupComplexity for filter chips; displayOrder controls the card order on the page. requiresCredentials plus requiredFields / optionalFields drive the credential-entry modal.

Market services

GET /market/services

type ListMarketServicesQuery = {
  serviceType?: ServiceType;
  executionMode?: ExecutionMode;
  providerKey?: string;
  machineId?: string;     // include to filter against machine context
};

type ListMarketServicesResponse = ListResponse<MarketService>;

GET /market/services/:serviceId

type GetMarketServiceQuery = {
  machineId?: string;
};

type GetMarketServiceResponse = ItemResponse<MarketService>;

POST /market/services/:serviceId/execute

Directly executes a native, read-only service operation without creating a market order. Use this for free lookup or read operations. Paid, external-handoff, and state-changing operations must still flow through POST /market/orders. Requires an active peaqOS machine, an active Machine Agent pairing, and pairing session token auth when enabled.
type ExecuteMarketServiceRequest = {
  machineId: string;
  agentPairingId: string;
  operation: string;
  input?: Record<string, unknown>;
  budget?: {
    amount?: number;
    max?: number;
    currency?: string;
  };
  providerCredentials?: ProviderCredentials;
};

type ExecuteMarketServiceResponse = {
  service: MarketService & {
    operation: string;
    payment: MarketOrder["payment"];
  };
  execution: {
    task: Record<string, unknown>;
    route: Record<string, unknown>;
    outcome: Record<string, unknown>;
    run: Record<string, unknown>;
  };
};

POST /market/search

Submits a normalised search and returns a ranked MarketSearch with quotes. Required preconditions:
  • the machine is active
  • its identityRef is verified with an identity ownership proof
  • there is an active Machine Agent pairing for the machine
  • when PEAQOS_REQUIRE_AGENT_PAIRING_AUTH=true, the x-agent-pairing-token header is present
type SearchMarketRequest = {
  machineId: string;
  agentPairingId?: string;             // required if the machine has more than one active pairing
  serviceType: ServiceType;
  operation?: string;
  requiredCapabilities?: string[];
  region?: string;
  maxResults?: number;                 // integer 1-25, default 5
  allowExternalHandoff?: boolean;
  requireNativeExecution?: boolean;
  budget?: {
    amount?: number;                   // max acceptable cost; alias of `max`
    max?: number;                      // alias of `amount`
    currency?: string;                 // defaults to "USD"
  };
  providerCredentials?: ProviderCredentials; // redacted before persistence
};

type SearchMarketResponse = ItemResponse<MarketSearch>;
Errors: MACHINE_NOT_ACTIVE, MACHINE_IDENTITY_PROOF_REQUIRED, AGENT_PAIRING_REQUIRED, AGENT_PAIRING_INACTIVE, AGENT_AUTH_REQUIRED, AGENT_AUTH_INVALID, AGENT_AUTH_EXPIRED, AGENT_POLICY_DENIED, VALIDATION_ERROR.

GET /market/searches/:searchId

type GetMarketSearchResponse = ItemResponse<MarketSearch>;