wavvon-sdk
Write programs that talk to a Wavvon hub: bots, apps with slash commands and buttons, event consumers, mini-app hosts, and receivers for outgoing webhooks.
A program on Wavvon is a client like any other: an Ed25519 keypair, the same
challenge-response login, the same permissions. There is no bot account. What
makes a program an app is a role carrying apps.register. The design this
package implements is
sdk.md (tier 1).
- Python 3.11 or later, asyncio, fully typed (
py.typed, checked withmypy --strict). - Depends on
httpx,websocketsandcryptography, plusattrs,python-dateutilandtyping-extensionsfor the generated REST models. - Apache-2.0, so a closed-source program can use it.
Install
pip install wavvon-sdk
The import package is wavvon.
Quick start
import asyncio, os
import uvicorn # any ASGI server; or call the handler from your own framework
from wavvon import WavvonClient, create_dispatch_handler, to_asgi
async def main() -> None:
async with WavvonClient(
"https://hub.example",
seed=os.environ["WAVVON_SEED"], # 32-byte Ed25519 seed, hex. Never sent anywhere.
invite_code=os.environ.get("WAVVON_INVITE"), # only needed the first time, on an invite-only hub
) as client:
info = await client.info()
app = to_asgi(
create_dispatch_handler(
hub_public_key=info["public_key"],
on_slash_command=lambda inv: {"reply": {"body": f"you said: {inv['args_raw']}"}},
)
)
await client.set_app_profile({"name": "Echo", "webhook_url": "https://bot.example/hook"})
await client.set_app_commands([{"name": "echo", "description": "Repeat after me"}])
events = client.connect() # after set_app_profile, see below
events.on("message", lambda e: print(e["message"].get("sender"), e["message"].get("content")))
events.on("unknown", lambda e: print("new frame type:", e["raw_type"]))
await uvicorn.Server(uvicorn.Config(app, port=8080)).serve()
asyncio.run(main())
A fuller one is examples/echo_bot.py.
Every REST route is a generated function under wavvon.rest.api; pass
client.rest and unwrap with ok(), which raises HubError on a refusal:
from wavvon import ok
from wavvon.rest.api.channels import list_channels
channels = ok(await list_channels.asyncio_detailed(client=client.rest))
What is in it
| Piece | Entry point |
|---|---|
| Login (challenge, sign, verify) that renews itself | WavvonClient, authenticate, identity_from_seed |
Every REST route, typed from openapi.yaml |
wavvon.rest.api.* with client=client.rest; ok() |
| Retry with backoff on 429, 5xx, timeouts | built into client.rest; fetch_with_retry |
| Capability checks | client.has_capability, client.require_capability |
| Keyset paging to the end of a list | paginate (async iterator) |
| WebSocket events with resume after reconnect | client.connect() -> EventStream |
| HTTP polling instead of a socket | client.poll_events, client.ack_events |
| App registration | set_app_profile, set_app_commands, set_app_subscriptions |
| Slash command and button webhooks | create_dispatch_handler, verify_dispatch, to_asgi |
| Outgoing webhook receiver | verify_outgoing_webhook |
| Mini-app host | EventStream.announce_app, dismiss_app, send_mini_app_message |
create_dispatch_handler returns a plain async (method, headers, body) -> WebhookResponse function, so it fits any framework; to_asgi wraps it for
uvicorn, hypercorn, Starlette or FastAPI.
Capabilities each feature needs
Hubs say what they support in GET /info capabilities. The SDK checks those
strings and never compares version numbers. A feature the hub does not
advertise raises UnsupportedByHubError.
| Feature | Capability |
|---|---|
set_app_profile, set_app_commands, set_app_subscriptions, embeds, game cards |
apps.register |
verify_dispatch / verify_outgoing_webhook (they require X-Wavvon-Signature-V1) |
webhooks.signedtimestamp |
Paging GET /users, /conversations/{id}/messages, /admin/reports |
list.cursor |
| Paging bans, mutes, invites, pending, conversations, pins, polls | list.cursor.lists |
ping / pong over the socket |
ws.ping |
Login, REST, the socket and polling need no capability.
Behaviour you can rely on
- A transient failure is never an answer. 429, 5xx, timeouts and dropped
connections are retried with capped exponential backoff and jitter. If the
budget runs out you get
HubUnavailableError, not an empty list or a 404. SetRetryOptions(max_attempts=math.inf)to wait forever. - Sessions renew themselves. A 401 triggers one fresh login and a retry.
client.on_state_changeandevents.on_state_changeshow when it is happening. - Unknown is delivered. A socket frame or dispatch type this version does
not model reaches you as
{"type": "unknown", "raw_type": ..., "raw": ...}. - Missed events are replayed. The event stream remembers the last
hub_eventseq and asks the hub to resume from it after every reconnect. If the gap is older than the hub keeps (72 hours) you getreplay_unavailable. Register the app profile beforeconnect(): the hub only pushes and replays events on a socket opened by a registered app. - The seed stays with you. No call sends a seed or private key anywhere.
Conformance
Every signed byte sequence is checked against the shared wire vectors in
Wavvon-server (crates/identity/wire-vectors.json): the auth challenge, the
Ed25519 dispatch signature, and the outgoing-webhook HKDF + HMAC. CI reads them
from Wavvon-server at commit eb11d75657ee8362dd42a7982fc5b13a3dcc4e68.
The REST client was generated from Wavvon-docs at the commit in src/wavvon/rest/SPEC_COMMIT.
Licence
Metadata
Release files for wavvon-sdk 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| wavvon_sdk-0.1.0.tar.gz | 205.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wavvon_sdk-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 901.8 kB
Release files / wavvon_sdk-0.1.0.tar.gz
| Download URL | wavvon_sdk-0.1.0.tar.gz |
|---|---|
| Size | 205.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1e5349c1b16a0d072fbb81d8b7992bf521490fcceaa9cd2fe9372c9b9f0e4c22
|
|
BLAKE2b-256 checksum How to use checksums |
fe83401ff743a94f2e47cefaf3157300db6dfb57e3ddfa047d8604552ed8c4b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / wavvon_sdk-0.1.0-py3-none-any.whl
| Download URL | wavvon_sdk-0.1.0-py3-none-any.whl |
|---|---|
| Size | 696.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
02c2262ef69557228e63c21c1cbc67ff14f543f79863de99d037b7dc149e4f25
|
|
BLAKE2b-256 checksum How to use checksums |
7c583e89899d016ff18094880c16b5eb2168bfd41247d702218dd620c62d3c1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logSecurity for wavvon-sdk 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for wavvon_sdk-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.