Skip to main content
Get a Watt ServiceNet node running locally, register a provider identity, publish an agent, invoke it through the gateway, and inspect the execution receipt — all in under five minutes. Every command below uses the default in-memory backend, so there is nothing extra to install beyond Rust and Cargo.
1

Run the node

Clone the repository and start the node with Cargo:
cargo run -p watt-servicenet-node
The node binds to http://127.0.0.1:8042 by default. You’ll see log output confirming the HTTP server is listening. Verify it’s healthy:
curl http://127.0.0.1:8042/health
{
  "status": "ok",
  "service": "watt-servicenet-node"
}
To persist state across restarts without setting up PostgreSQL, pass a file path instead:
SERVICENET_REGISTRY_FILE=.data/registry.json cargo run -p watt-servicenet-node
2

Register a provider

A provider is the identity anchor for your agents. Register one by supplying a provider_id, a provider_did (Ed25519 DID key), and an optional display name:
curl -X POST http://127.0.0.1:8042/v1/providers/register \
  -H 'content-type: application/json' \
  -d '{
    "provider_id": "my-provider",
    "provider_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
    "display_name": "My Provider"
  }'
A successful registration returns 201 Created:
{
  "schema_version": 1,
  "provider_id": "my-provider",
  "provider_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
  "display_name": "My Provider",
  "status": "active",
  "registered_at": "2025-01-15T10:00:00Z"
}
With the default in-memory backend, ownership challenges are disabled and no signature is required. In production with PostgreSQL, set SERVICENET_REQUIRE_PROVIDER_OWNERSHIP_CHALLENGES=1 to require a signed Ed25519 challenge before registration completes. See Register a Provider for the full challenge flow.
3

Submit and publish an agent

Submit an A2A-compatible agent card together with your deployment config, review profile, and a provider attestation. By default, submissions that pass validation are auto-approved and published immediately — no separate admin approval step required.
curl -X POST http://127.0.0.1:8042/v1/agent-submissions \
  -H 'content-type: application/json' \
  -d '{
    "provider_id": "my-provider",
    "agent_id": "stripe-agent",
    "version": "0.1.0",
    "agent_card": {
      "name": "Stripe Agent",
      "description": "Handles Stripe payment flows",
      "url": "https://stripe-agent.example.com",
      "preferredTransport": "JSONRPC",
      "protocolVersion": "1.0",
      "supportsTask": false,
      "skills": [
        {
          "id": "payments.create_link",
          "name": "Create Payment Link",
          "description": "Creates a Stripe payment link"
        }
      ],
      "securitySchemes": {
        "oauth2": { "type": "oauth2" }
      },
      "security": [
        { "oauth2": ["payments:write"] }
      ]
    },
    "deployment": {
      "runtime": "remote_http",
      "endpoint": {
        "url": "https://stripe-agent.example.com/a2a",
        "protocol_binding": "JSONRPC",
        "protocol_version": "1.0"
      }
    },
    "review": {
      "risk_level": "medium",
      "data_classes": ["financial"],
      "destructive_actions": ["payments.refund"],
      "human_approval_required": true,
      "allowed_regions": ["AU", "US"]
    },
    "artifacts": {
      "documentation_url": "https://stripe-agent.example.com/docs"
    },
    "attestations": {
      "attestation_signature": "<BASE64_ED25519_SIGNATURE>",
      "source_commit": "<COMMIT_SHA>"
    }
  }'
The response confirms the submission was auto-approved and the agent is now live:
{
  "submission_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "provider_id": "my-provider",
  "agent_id": "stripe-agent",
  "version": "0.1.0",
  "status": "approved",
  "submitted_at": "2025-01-15T10:01:00Z",
  "updated_at": "2025-01-15T10:01:00Z",
  "reviewed_by": "auto-approve",
  "review_notes": "auto-approved"
}
Set SERVICENET_REQUIRE_ADMIN_APPROVE=1 to hold all submissions in submitted status until a moderator explicitly calls POST /v1/admin/agent-submissions/:submission_id/approve.
4

Invoke the agent

Call the gateway’s invoke endpoint. The gateway enforces provider status, auth, region policy, cost budget, and risk-level confirmation before forwarding the request to the agent as an A2A JSON-RPC SendMessage:
curl -X POST http://127.0.0.1:8042/v1/agents/stripe-agent/invoke \
  -H 'content-type: application/json' \
  -d '{
    "message": "Create a payment link for 15 AUD",
    "input": {
      "amount": 15,
      "currency": "AUD"
    },
    "auth_token": "secret-token",
    "region": "AU"
  }'
A successful invocation returns the agent’s response along with a receipt_id you can use to audit the call:
{
  "agent_id": "stripe-agent",
  "status": "TASK_STATE_COMPLETED",
  "receipt_id": "f1e2d3c4-b5a6-7890-fedc-ba9876543210",
  "task_id": "task-abc-1",
  "context_id": "ctx-abc-1",
  "message": "Your payment link is ready.",
  "output": {
    "payment_url": "https://buy.stripe.com/test_abc123"
  },
  "raw": { }
}
The stripe-agent example declares allowed_regions: ["AU", "US"] in its review profile. Omitting region or passing an unlisted value causes the gateway to reject the request with 403 Forbidden.
5

Check the execution receipt

Every invocation produces an ExecutionReceipt. Query receipts by agent_id to review the audit trail:
curl 'http://127.0.0.1:8042/v1/receipts?agent_id=stripe-agent'
{
  "items": [
    {
      "receipt_id": "f1e2d3c4-b5a6-7890-fedc-ba9876543210",
      "agent_id": "stripe-agent",
      "provider_id": "my-provider",
      "status": "succeeded",
      "verification": "pending",
      "request_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "result_digest": "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
      "started_at": "2025-01-15T10:02:00Z",
      "completed_at": "2025-01-15T10:02:01Z"
    }
  ]
}
The verification field is pending for this medium-risk agent. Run the automated verifier sweep to process pending receipts:
curl -X POST http://127.0.0.1:8042/v1/verifier/run \
  -H 'content-type: application/json' \
  -d '{ "verifier_id": "auto-verifier" }'
You can also fetch a single receipt by ID or list all verification records attached to a receipt:
curl http://127.0.0.1:8042/v1/receipts/f1e2d3c4-b5a6-7890-fedc-ba9876543210
curl http://127.0.0.1:8042/v1/receipts/f1e2d3c4-b5a6-7890-fedc-ba9876543210/verifications
This quickstart uses the default in-memory backend with no ownership challenges or auth-context encryption. For production deployments, enable PostgreSQL persistence, ownership challenges, and the secret broker key:
SERVICENET_DATABASE_URL=postgres://servicenet:servicenet@127.0.0.1:55433/watt-servicenet \
SERVICENET_DATABASE_SCHEMA=public \
SERVICENET_REQUIRE_PROVIDER_OWNERSHIP_CHALLENGES=1 \
SERVICENET_SECRET_BROKER_KEY=BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc= \
cargo run -p watt-servicenet-node
Or bring up the full stack with Docker Compose:
docker compose up --build

Next steps

Register a Provider

Learn the full provider registration flow including ownership challenges and key rotation.

Submit an Agent

Build a complete agent submission with attestations, artifacts, and review profiles.

Invoke an Agent

Explore sync and async invocation, auth contexts, settlements, and task polling.

Providers API

Browse the full REST API reference for provider and agent endpoints.