QivunaDevelopers

SDKs and test vectors

Two official SDKs cover the whole Bot API, long polling and webhooks, and the bot side of end-to-end encryption. Both are checked byte for byte against the same test vectors.

Not published yet The SDKs are complete and reviewed, but publishing them to npm and PyPI is still pending. The install commands below will work once they are published, and this page will say so.

Packages#

PackageRuntimeDependenciesInstall
@qivuna/bot-sdkNode.js 20.11+none (Node's built-in crypto)npm install @qivuna/bot-sdk
qivuna-bot-sdkPython 3.9+cryptography (pyca), tested with 46.0.5pip install qivuna-bot-sdk

Both include runnable examples: a plain echo bot and an encrypted echo bot (polling or webhook).

What they do for you#

Read the security section of each SDK's README before running an encrypted bot in production; the essentials are on Encrypted bots.

Quick start#

Node.js

import { Bot, FileStateStore } from "@qivuna/bot-sdk";

const bot = new Bot({ token: process.env.QIVUNA_BOT_TOKEN, store: new FileStateStore("./bot-state") });
bot.onMessage(async (ctx) => { if (ctx.text) await ctx.reply(ctx.text); });
await bot.startPolling();

Python

from qivuna_bot import Bot, FileStateStore

bot = Bot(TOKEN, FileStateStore("./bot-state"))

@bot.on_message
def echo(ctx):
    if ctx.text:
        ctx.reply(ctx.text)

bot.run_polling()

Webhook instead of polling (webhooks are not open yet; until then setWebhook answers 400 webhooks_disabled):

// Node.js + Express: the handler needs the RAW body
const handle = bot.webhookHandler({ secrets: [SECRET], encryptedPayload: false });
app.post("/qivuna", express.raw({ type: "*/*", limit: "1mb" }), async (req, res) => {
  const r = await handle({ headers: req.headers, body: req.body });
  res.status(r.status).set(r.headers).send(r.body);
});
# Python (WSGI: gunicorn, Flask's server …; or asgi_app for uvicorn)
from qivuna_bot import wsgi_app
app = wsgi_app(bot, [SECRET], encrypted_payload=False, path="/qivuna")

Set your endpoint's secrets before calling setWebhook, so that the ownership challenge verifies.

Test vectors#

Every byte format of the bot platform — pseudonymous ids, the token hash, webhook HMAC (single and dual), qbw1, pop, key certificates, user bot keys, return addresses, attachment records, QB1 requests and bot messages, s2 envelopes, fingerprints, strict Ed25519 and refused X25519 keys — has known-answer vectors, positives and negatives, generated by an independent reference implementation (Python, pyca cryptography 46.0.5).

sha256sum bots_vectors.json        # Linux
shasum -a 256 bots_vectors.json    # macOS

The vectors are normative. Where any prose, including these pages, disagrees with them, the vectors win. Both SDKs assert every bot-side vector and have a coverage test that fails if one is skipped; Qivuna's server and apps reproduce the same file. If you write your own implementation of the encrypted parts, reproduce every vector it touches, negatives included — in particular: refuse duplicate JSON keys, use strict cofactorless Ed25519, and refuse small-order X25519 keys.

The fixed random values in the vectors exist only to make them reproducible. Production code must draw all randomness from a CSPRNG and never accept it from callers.