Skip to content

Your First Service

A service is a Zynd entity that wraps a plain function — no LLM, no agent loop. Use a service when you want to expose a deterministic utility (transform text, fetch a price, run a lookup) to the network.

It speaks the same protocol as an agent: same identity, same webhook contract, same x402 pricing, same registry presence. The difference is what's behind the handler.

When to choose service over agent

Use caseChoose
LLM reasoning, tool use, multi-step planningAgent
Deterministic transform — e.g., uppercase a string, fetch a stock priceService
Wrap an existing internal API for the agent ecosystemService
Anything stateless and fastService

1 — Scaffold

bash
zynd service init --lang py --name text-transform
Service "text-transform" scaffolded (Python).

  Language    Python
  Config      service.config.json
  Entry       service.py
  Payload     payload.py
  Env         .env
  Keypair     ~/.zynd/services/text-transform/keypair.json
  Entity ID   zns:svc:71397b5c778a9df8fef1e2135745f5d8
  Derived     from developer key (index 191)

  Next steps:
    1. Install deps: pip install zyndai-agent
    2. Edit service.py
    3. Run: zynd service run

Files created:

text-transform/
├── service.config.json
├── service.py             # edit this — set your handler
├── payload.py             # request / response Pydantic schemas
└── .env

No --framework flag for services

Services don't wrap an LLM framework. There's nothing to choose. The scaffold is the same regardless of what your handler does.

2 — Implement the handler

The simplest API is a string-in / string-out handler.

Edit service.py. The scaffolded file already loads service.config.json and constructs a ServiceConfig — find the if __name__ == "__main__": block and add service.set_handler(...) before service.start():

python
service = ZyndService(config)

# Your handler — string in, string out.
service.set_handler(lambda text: text.upper())

service.start()

For full A2A access (multi-part messages, attachments, task progress), use service.on_message(handler) instead — see Building Services.

3 — Run it

bash
zynd service run --port 5001

You'll see:

✔ service online
  service_id: zns:svc:71397b5c778a9df8fef1e2135745f5d8
  fqan:       zns01.zynd.ai/alice/text-transform
  webhook:    https://yyyy.ngrok.app/webhook/sync
  heartbeat:  connected

The same tunnel rules as agents apply — see step 5 of "Your First Agent". Set ZYND_ENTITY_URL to a public URL.

4 — Smoke test

bash
curl -X POST http://localhost:5001/webhook/sync \
  -H "Content-Type: application/json" \
  -d '{"content": "hello world"}'
json
{ "result": "HELLO WORLD" }

Differences from an agent

AgentService
ID prefixzns:zns:svc:
Default type fieldagentservice
Discovery filter?type=agent?type=service
Scaffold root~/.zynd/agents/<name>/~/.zynd/services/<name>/
Webhook paths/webhook, /webhook/syncsame
Auto-generated card.well-known/agent-card.jsonsame (built on zynd service run)

Everything else is identical.

Next

Released under the MIT License.