npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@openserv-labs/client

v2.4.7

Published

OpenServ Platform Client - Manage agents, workflows, tasks, and triggers via the OpenServ API

Readme

OpenServ Platform Client

npm version License: MIT TypeScript

A TypeScript client for interacting with the OpenServ Platform API. Manage agents, workflows, tasks, and triggers programmatically.

Note: This is the platform client for API operations. If you want to build AI agents, see @openserv-labs/sdk.

Installation

npm install @openserv-labs/client

Quick Start

import { PlatformClient } from '@openserv-labs/client'

const client = new PlatformClient({
  apiKey: process.env.OPENSERV_USER_API_KEY
})

// List all agents
const agents = await client.agents.list()

// Create a workflow
const workflow = await client.workflows.create({
  name: 'My Workflow',
  goal: 'Process data automatically',
  agentIds: [123, 456]
})

Authentication

API Key Authentication

const client = new PlatformClient({
  apiKey: 'your-api-key'
})

Or set the OPENSERV_USER_API_KEY environment variable:

const client = new PlatformClient() // Uses OPENSERV_USER_API_KEY env var

Wallet Authentication (SIWE)

Authenticate using an Ethereum wallet (EIP-4361):

const client = new PlatformClient()
const apiKey = await client.authenticate(process.env.WALLET_PRIVATE_KEY)

API Reference

Agents

// List all agents
const agents = await client.agents.list()

// Get agent by ID
const agent = await client.agents.get({ id: 123 })

// Search your own agents by name/description
const myAgents = await client.agents.searchOwned({ query: 'my-agent' })

// Search all marketplace agents (semantic search)
const marketplaceResults = await client.agents.listMarketplace({ search: 'data processing' })

// Create an agent
// endpoint_url is optional when using @openserv-labs/sdk v2.0.0+ (auto-set by run())
const agent = await client.agents.create({
  name: 'My Agent',
  capabilities_description: 'Agent capabilities description',
  endpoint_url: 'https://my-agent.example.com' // Optional for dev, required for production
})

// Update an agent
await client.agents.update({
  id: 123,
  name: 'Updated Name',
  capabilities_description: 'Updated description',
  endpoint_url: 'https://new-endpoint.example.com' // Only if changing the endpoint
})

// Delete an agent
await client.agents.delete({ id: 123 })

// Get agent API key
const apiKey = await client.agents.getApiKey({ id: 123 })

// Generate and save auth token for agent security
const { authToken, authTokenHash } = await client.agents.generateAuthToken()
await client.agents.saveAuthToken({ id: 123, authTokenHash })

// List marketplace agents (public agents from other developers)
const marketplace = await client.agents.listMarketplace({
  search: 'data processing', // Optional search query
  page: 1,
  pageSize: 20,
  showPrivateAgents: true // Include your own private agents
})

console.log(`Found ${marketplace.total} agents`)
for (const agent of marketplace.items) {
  console.log(`${agent.name} by ${agent.author_name}`)
}

Workflows

// Create a workflow
const workflow = await client.workflows.create({
  name: 'Data Pipeline',
  goal: 'Process and analyze data',
  agentIds: [123, 456]
})

// Get a workflow
const workflow = await client.workflows.get({ id: 789 })

// List all workflows
const workflows = await client.workflows.list()

// Update a workflow
await client.workflows.update({
  id: 789,
  name: 'Updated Pipeline',
  goal: 'New goal'
})

// Delete a workflow
await client.workflows.delete({ id: 789 })

// Set workflow to running state
await client.workflows.setRunning({ id: 789 })

// Create a fully configured workflow with triggers, tasks, and auto-generated edges
const pipeline = await client.workflows.create({
  name: 'Data Pipeline',
  goal: 'Process and analyze data',
  triggers: [triggers.webhook({ waitForCompletion: true, timeout: 300 })],
  tasks: [
    { name: 'ingest', agentId: 123, description: 'Ingest the data' },
    { name: 'analyze', agentId: 456, description: 'Analyze the results' }
  ]
  // Edges auto-generated: trigger -> ingest -> analyze
})

// Sync workflow configuration (update existing)
await client.workflows.sync({
  id: 789,
  triggers: [triggers.webhook({ waitForCompletion: true })],
  tasks: [{ name: 'process', agentId: 123, description: 'Process data' }]
})

Tasks

// Create a task
const task = await client.tasks.create({
  workflowId: 789,
  agentId: 123,
  description: 'Process the data',
  body: 'Additional task details',
  dependencies: [456] // Optional task dependencies
})

// Get a task
const task = await client.tasks.get({ workflowId: 789, id: 1 })

// List tasks in a workflow
const tasks = await client.tasks.list({ workflowId: 789 })

// Update a task
await client.tasks.update({
  workflowId: 789,
  id: 1,
  description: 'Updated description',
  status: 'in-progress'
})

// Delete a task
await client.tasks.delete({ workflowId: 789, id: 1 })

Triggers

Use the triggers factory to create type-safe trigger configs, then pass them to workflows.create() or workflow.sync():

import { triggers } from '@openserv-labs/client'

// Webhook trigger
const workflow = await client.workflows.create({
  name: 'My Workflow',
  goal: 'Process requests',
  triggers: [triggers.webhook({ waitForCompletion: true, timeout: 300 })],
  tasks: [{ name: 'process', agentId: 123, description: 'Handle the request' }]
})

// x402 (paid) trigger
const paidWorkflow = await client.workflows.create({
  name: 'Paid Service',
  goal: 'Premium AI service',
  triggers: [triggers.x402({
    name: 'AI Research Assistant',
    description: 'Get comprehensive research reports on any topic powered by AI',
    price: '0.01',
    input: { query: { type: 'string', description: 'Research topic or question' } }
  })],
  tasks: [{ name: 'research', agentId: 123, description: 'Research the topic' }]
})

// Cron (scheduled) trigger
triggers.cron({ schedule: '0 9 * * *', timezone: 'America/New_York' })

// Manual trigger
triggers.manual()

Low-level Triggers API

For managing individual triggers on existing workflows:

// Get a trigger
const trigger = await client.triggers.get({ workflowId: 789, id: 'trigger-id' })

// List triggers
const allTriggers = await client.triggers.list({ workflowId: 789 })

// Activate a trigger
await client.triggers.activate({ workflowId: 789, id: 'trigger-id' })

// Fire a trigger manually
await client.triggers.fire({
  workflowId: 789,
  id: 'trigger-id',
  input: JSON.stringify({ query: 'test' })
})

// Delete a trigger
await client.triggers.delete({ workflowId: 789, id: 'trigger-id' })

Payments (x402)

Pay for and execute x402-protected workflows programmatically.

Note: Set WALLET_PRIVATE_KEY in your environment. The client uses it automatically for x402 payments using the x402 protocol.

// Pay and execute an x402 workflow - just set WALLET_PRIVATE_KEY env var
const client = new PlatformClient()
const result = await client.payments.payWorkflow({
  triggerUrl: 'https://api.openserv.ai/webhooks/x402/trigger/...',
  input: { prompt: 'Generate a summary' }
})

console.log(`Response: ${JSON.stringify(result.response)}`)

The payWorkflow method handles the entire x402 payment flow automatically:

  1. Creates a payment-enabled fetch wrapper using your wallet
  2. Makes a request to the trigger URL
  3. Automatically handles the 402 Payment Required response
  4. Signs and submits the USDC payment on Base
  5. Retries the request with payment proof
  6. Returns the workflow response

Discover x402 services

// List available paid services on the platform
const services = await client.payments.discoverServices()

for (const service of services) {
  console.log(`${service.name}: $${service.x402Pricing}`)
  console.log(`URL: ${service.webhookUrl}`)
  console.log(`By: ${service.ownerDisplayName}`)
}

Get trigger preflight info

// Get pricing and input schema before paying
const preflight = await client.payments.getTriggerPreflight({
  token: 'abc123def456' // Extract from webhook URL
})

console.log(`Price: ${preflight.x402Pricing}`)
console.log(`Pay to: ${preflight.x402WalletAddress}`)
console.log(`Input schema: ${JSON.stringify(preflight.jsonSchema)}`)

ERC-8004 (Agent Identity)

ERC-8004 is an on-chain agent identity standard. The registerOnChain method handles the entire flow in a single call -- building the agent card, uploading to IPFS, and registering on-chain.

Note: The wallet used for registerOnChain must have ETH for gas on the target chain (Base mainnet by default).

// Register an agent on-chain in one call
const result = await client.erc8004.registerOnChain({
  workflowId: 123,
  privateKey: process.env.WALLET_PRIVATE_KEY!,
  name: 'My AI Agent',
  description: 'An agent that does amazing things',
})

console.log(result.agentId)         // "8453:42"
console.log(result.txHash)          // "0xabc..."
console.log(result.ipfsCid)         // "bafkrei..."
console.log(result.agentCardUrl)     // "https://gateway.pinata.cloud/ipfs/bafkrei..."
console.log(result.blockExplorerUrl) // "https://basescan.org/tx/0xabc..."
console.log(result.scanUrl)          // "https://www.8004scan.io/agents/base/42"

Under the hood, registerOnChain does the following:

  1. Reads the workspace wallet and callable triggers
  2. Builds the ERC-8004 agent card JSON (with services and wallet info)
  3. Uploads the agent card to IPFS via a presigned Pinata URL
  4. Registers on-chain (first deploy) or updates the URI (re-deploy)
  5. Saves the deployment state back to the platform

Re-deploying (updating an existing registration) uses the same call -- it automatically detects whether the workspace already has an erc8004AgentId and uploads a fresh agent card with the latest name, description, services, and wallet info, then updates the on-chain URI to point to it. No new token is minted; only the metadata changes.

Supported Chains

registerOnChain defaults to Base mainnet (chainId: 8453). You can target any supported chain:

// Deploy on a different chain
const result = await client.erc8004.registerOnChain({
  workflowId: 123,
  privateKey: process.env.WALLET_PRIVATE_KEY!,
  chainId: 42161,                              // Arbitrum One
  rpcUrl: 'https://arb1.arbitrum.io/rpc',
  name: 'My Agent',
})

Mainnets: Ethereum (1), Base (8453), Polygon (137), Arbitrum One (42161), Celo (42220), Gnosis (100), Scroll (534352), Taiko (167000), BNB Smart Chain (56)

Testnets: Ethereum Sepolia (11155111), Base Sepolia (84532), Polygon Amoy (80002), Arbitrum Sepolia (421614), Celo Alfajores (44787), Scroll Sepolia (534351), BNB Testnet (97)

You can also query supported chains programmatically:

import { listErc8004ChainIds, getErc8004Chain } from '@openserv-labs/client'

const mainnets = listErc8004ChainIds('mainnet')  // [1, 8453, 137, ...]
const testnets = listErc8004ChainIds('testnet')  // [11155111, 84532, ...]

const baseConfig = getErc8004Chain(8453)
console.log(baseConfig?.contracts.IDENTITY_REGISTRY)
// "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"

Low-level ERC-8004 Operations

For more control over individual steps, use the lower-level methods directly:

// Generate a web3 wallet for the workspace
const wallet = await client.workflows.generateWallet({ id: 123 })
console.log('Wallet address:', wallet.address)

// Import an existing wallet
const imported = await client.workflows.importWallet({
  id: 123,
  address: '0x...',
  network: 'base',
  chainId: 8453,
  privateKey: '0x...'
})

// Get the workspace wallet
const existing = await client.workflows.getWallet({ id: 123 })
console.log(existing.deployed, existing.erc8004AgentId)

// Delete the workspace wallet
await client.workflows.deleteWallet({ id: 123 })

// Get a presigned IPFS URL for uploading the agent card
const { url } = await client.erc8004.presignIpfsUrl({ workflowId: 123 })
// Upload agent card to IPFS within 60 seconds using the signed URL

// Deploy to ERC-8004 (before on-chain registration)
await client.erc8004.deploy({
  workflowId: 123,
  erc8004AgentId: '',
  stringifiedAgentCard: JSON.stringify(registrationFile),
  walletAddress: '0x...',
  network: 'base',
  chainId: 8453,
  rpcUrl: 'https://mainnet.base.org'
})

// Deploy to ERC-8004 (after on-chain registration, with tx hash)
await client.erc8004.deploy({
  workflowId: 123,
  erc8004AgentId: '8453:42',
  stringifiedAgentCard: JSON.stringify(updatedRegistrationFile),
  latestDeploymentTransactionHash: '0xabc...',
  latestDeploymentTimestamp: new Date(),
  walletAddress: '0x...',
  network: 'base',
  chainId: 8453,
  rpcUrl: 'https://mainnet.base.org'
})

// Get callable triggers for on-chain service registration
const callableTriggers = await client.erc8004.getCallableTriggers({ workflowId: 123 })
for (const trigger of callableTriggers) {
  console.log(trigger.name, trigger.webEndpoint)
}

// Sign feedback auth for the reputation system
const { signature } = await client.workflows.signFeedbackAuth({
  id: 123,
  buyerAddress: '0xBuyer...'
})

Integrations

Manage integration connections for triggers and external services.

// List all integration connections for your account
const connections = await client.integrations.listConnections()

for (const conn of connections) {
  console.log(`${conn.integrationDisplayName} (${conn.integrationType})`)
  console.log(`  ID: ${conn.id}`)
  console.log(`  Integration: ${conn.integrationName}`)
}

// Create a custom integration connection
await client.integrations.connect({
  identifier: 'webhook-trigger',
  props: {} // Optional properties
})

// Get or create a connection (useful for trigger setup)
const connectionId = await client.integrations.getOrCreateConnection('webhook-trigger')

Web3 / USDC Top-up

Add credits to your account by paying with USDC.

Note: Set WALLET_PRIVATE_KEY in your environment. The client uses it automatically for payments and SIWE authentication.

// Simple one-liner - just set WALLET_PRIVATE_KEY env var
const client = new PlatformClient()
const result = await client.web3.topUp({ amountUsd: 10 })

console.log(`Transaction: ${result.txHash}`)
console.log(`Added ${result.creditsAdded} credits`)
console.log(`USDC spent: ${result.usdcAmount}`)
console.log(`Network: ${result.network}`)

The topUp method handles the entire flow:

  1. Fetches USDC configuration from the platform
  2. Checks your USDC balance
  3. Sends USDC to the platform's receiver address
  4. Waits for transaction confirmation
  5. Signs a verification message
  6. Verifies and adds credits to your account

Lower-level methods

For more control, use the individual methods:

// Get USDC top-up configuration
const config = await client.web3.getUsdcTopupConfig()
console.log(`Send USDC to ${config.receiverAddress} on ${config.network}`)
console.log(`Chain ID: ${config.chainId}`)
console.log(`USDC Contract: ${config.usdcContractAddress}`)
console.log(`Rate: 1 USDC = ${config.rateUsdcToCredits} credits`)

// After sending USDC manually, verify the transaction
const result = await client.web3.verifyUsdcTransaction({
  txHash: '0xabc123...',
  payerAddress: '0xYourWallet...', // Required for non-wallet-authenticated users
  signature: '0x...' // Sign "Verify USDC top-up: {txHash}"
})
console.log(`Added ${result.creditsAdded} credits`)

Workflow Object

When you retrieve a workflow, you get a Workflow object with helper methods:

const workflow = await client.workflows.get({ id: 789 })

// Access workflow properties
console.log(workflow.id, workflow.name, workflow.goal)
console.log(workflow.status) // 'draft', 'running', etc.
console.log(workflow.triggers) // Array of triggers
console.log(workflow.tasks) // Array of tasks
console.log(workflow.edges) // Graph edges
console.log(workflow.agents) // Assigned agents

// Sync configuration declaratively
await workflow.sync({
  triggers: [{ name: 'api', type: 'webhook' }],
  tasks: [{ name: 'work', agentId: 123, description: 'Do work' }],
  edges: [{ from: 'trigger:api', to: 'task:work' }]
})

// Start the workflow
await workflow.setRunning()

Provision API

The provision() function provides a simple way to deploy agents and workflows in one call. It's designed to work seamlessly with @openserv-labs/sdk for building AI agents.

About endpointUrl

The endpointUrl parameter is optional when using @openserv-labs/sdk v2.0.0+. Here's why:

  • Development: When you call run(agent) from the SDK, it automatically registers your agent with the OpenServ agents proxy (https://agents-proxy.openserv.ai), which tunnels requests to your local machine. No endpointUrl needed.
  • Production: If you're deploying your agent to a publicly accessible URL (e.g., your own server, cloud function, or container), provide the endpointUrl so the platform knows where to reach your agent.

Development Example (No endpointUrl)

When developing locally with the SDK, you can omit endpointUrl:

import { provision, triggers } from '@openserv-labs/client'
import { Agent, run } from '@openserv-labs/sdk'

// Step 1: Provision the agent and workflow (no endpointUrl needed for dev)
const result = await provision({
  agent: {
    name: 'my-agent',
    description: 'Handles API requests'
  },
  workflow: {
    name: 'api-workflow',
    trigger: triggers.webhook({
      input: { query: { type: 'string' } },
      waitForCompletion: true
    }),
    task: {
      description: 'Process incoming API requests and return results'
    }
  }
})

console.log(result.agentId) // Created agent ID
console.log(result.apiKey) // Agent API key
console.log(result.apiEndpoint) // Webhook URL to call

// Step 2: Create and run the agent (SDK auto-updates endpoint to agents-proxy)
const agent = new Agent({
  systemPrompt: 'You are a helpful assistant.'
})

run(agent) // Automatically connects to agents-proxy.openserv.ai

Production Example (With endpointUrl)

When deploying to production with a publicly accessible URL:

import { provision, triggers } from '@openserv-labs/client'

const result = await provision({
  agent: {
    name: 'my-agent',
    description: 'Handles API requests',
    endpointUrl: 'https://my-agent.example.com' // Your production URL
  },
  workflow: {
    name: 'api-workflow',
    trigger: triggers.webhook({
      input: { query: { type: 'string' } },
      waitForCompletion: true
    }),
    task: {
      description: 'Process incoming API requests and return results'
    }
  }
})

console.log(result.apiEndpoint) // Webhook URL to call

More Examples

import { provision, triggers, isProvisioned, getProvisionedInfo, clearProvisionedState } from '@openserv-labs/client'

// Provision with x402 (paid) trigger - include beautiful name and description
const paidResult = await provision({
  agent: {
    name: 'research-assistant',
    description: 'Premium AI research service',
    endpointUrl: 'https://research-agent.example.com' // Required for production
  },
  workflow: {
    name: 'research-workflow',
    trigger: triggers.x402({
      name: 'AI Research Assistant',
      description: 'Get comprehensive research reports on any topic powered by AI',
      price: '0.01',
      input: { prompt: { type: 'string', description: 'Research topic or question' } }
    }),
    task: {
      description: 'Process research requests and deliver comprehensive reports'
    }
  }
})

console.log(paidResult.paywallUrl) // Public paywall URL for payments

// Check if already provisioned (uses .openserv.json state file)
if (isProvisioned('my-agent', 'api-workflow')) {
  const info = getProvisionedInfo('my-agent', 'api-workflow')
  console.log('Already provisioned:', info)
}

// Clear provisioned state (does not delete from platform)
clearProvisionedState()

Provision with Cron Trigger

const cronResult = await provision({
  agent: {
    name: 'scheduled-agent',
    description: 'Runs scheduled tasks',
    endpointUrl: 'https://scheduled-agent.example.com' // Required for production
  },
  workflow: {
    name: 'daily-job',
    trigger: triggers.cron({
      schedule: '0 9 * * *', // Daily at 9 AM
      timezone: 'America/New_York'
    }),
    task: {
      description: 'Execute daily data processing and send reports'
    }
  }
})

Trigger Factory Functions

Use the triggers factory for type-safe trigger configuration:

import { triggers } from '@openserv-labs/client'

// Each factory accepts user-friendly params and returns a flat, typed config.

// Webhook trigger
triggers.webhook({
  name: 'Data Ingestion Webhook',
  description: 'Receives data from external systems for processing',
  input: { message: { type: 'string' } },
  waitForCompletion: true,
  timeout: 600
})
// { type: 'webhook', name: '...', waitForCompletion: true, timeout: 600, inputSchema: {...} }

// Cron trigger
triggers.cron({
  name: 'Daily Report Generator',
  description: 'Generates daily analytics reports every 6 hours',
  schedule: '0 */6 * * *',
  timezone: 'UTC'
})
// { type: 'cron', name: '...', schedule: '0 */6 * * *', timezone: 'UTC' }

// x402 (paid) trigger — name and description appear in the x402-services listing
triggers.x402({
  name: 'AI Research Assistant',
  description: 'Get comprehensive research reports on any topic powered by AI',
  price: '0.05',
  input: { prompt: { type: 'string', description: 'Research topic or question' } },
  timeout: 300,
  walletAddress: '0x...'
})
// { type: 'x402', name: '...', x402Pricing: '0.05', timeout: 300, x402WalletAddress: '0x...', inputSchema: {...} }

// Manual trigger
triggers.manual({
  name: 'Manual Test Trigger',
  description: 'For testing workflows manually'
})
// { type: 'manual', name: '...', description: '...' }

Environment Variables

| Variable | Description | Required | | ----------------------- | ------------------------------------- | ---------------------------- | | OPENSERV_USER_API_KEY | Your OpenServ user API key | For most API operations | | OPENSERV_API_URL | Custom API URL (for testing) | No | | WALLET_PRIVATE_KEY | Wallet private key for blockchain ops | For top-up and x402 payments |

Authentication options:

  • Use OPENSERV_USER_API_KEY for API key authentication
  • Use WALLET_PRIVATE_KEY for wallet-based (SIWE) authentication

For Web3 operations: Just set WALLET_PRIVATE_KEY - the client automatically uses it for blockchain transactions and handles SIWE authentication. No need to pass it explicitly in API calls.

Types

All types are exported for TypeScript users:

import type {
  // Domain types
  Agent,
  Workflow,
  WorkflowConfig,
  WorkflowData,
  Task,
  Trigger,
  TaskDefinition,
  EdgeDefinition,
  Edge,
  // Marketplace types
  MarketplaceAgent,
  MarketplaceAgentsResponse,
  Category,
  // Integration types
  IntegrationConnection,
  // Trigger config types
  TriggerConfig,
  WebhookTriggerConfig,
  X402TriggerConfig,
  CronTriggerConfig,
  ManualTriggerConfig,
  InputSchema,
  InputSchemaProperty,
  // API response types
  PaginatedResponse,
  IdResponse,
  ApiKeyResponse,
  NonceResponse,
  VerifyResponse,
  // Web3 types
  UsdcTopupConfig,
  UsdcTopupResult,
  UsdcVerifyRequest,
  UsdcVerifyResponse,
  // x402 Payment types
  X402PaymentRequest,
  X402PaymentResult,
  // ERC-8004 types
  Erc8004DeployRequest,
  RegisterOnChainResult,
  Erc8004ChainConfig,
  Web3Wallet,
  ImportWeb3WalletRequest,
  CallableTrigger,
  PresignIpfsUrlResponse,
  SignFeedbackAuthResponse,
  // Provision types
  ProvisionConfig,
  ProvisionResult,
  Logger
} from '@openserv-labs/client'

License

MIT License - see LICENSE for details.