BizNode BizNode Docs
v1 · Public API

BizNode handles — the universal AI service primitive

A handle is a named, pay-per-call AI service. Every handle has a clickable URL: https://app.1bz.biz/h/<bot>-<handle>. That URL works in any DM, post, email, SMS, QR code — no per-platform SDK to install. Billing is on-chain DZIT (a gas credit), paid per call, split 70/20/10 between provider, referrer, platform.

30-second quickstart

List every public handle in the network — no auth, no key, one curl:

curl -s "https://biznode.1bz.biz/api_public.php?action=handles&limit=20" \
  | python -m json.tool | head

Open any handle directly by dropping its slug into the URL bar:

open https://app.1bz.biz/h/biznode_bot-askai
open https://app.1bz.biz/h/biznode_bot-ping

No SDK. No platform registration. Share these URLs anywhere — Slack, Discord, WhatsApp, LinkedIn, email — they just work.

Tutorial — share a service in 3 minutes

There is no special bot infrastructure to set up. Any service in the BizNode network is reachable through a single Telegram deep link of the form https://t.me/biznode_bot?start=<subdomain>_<handle>. Click → mother bot routes → first 2-10 invocations free → DZIT charged after. We will walk through the FV (KYC verification) subdomain end-to-end.

1. Pick a service

Browse the public catalog at app.1bz.biz/handles. For this tutorial we use FV (face & voice verification). The handles available on FV today:

  • verify_kyc — full KYC pass: ID document + selfie + liveness
  • face_match — compare two faces, return a similarity score
  • askai_fv — ask the FV knowledge base any KYC / compliance question

2. Build the deep link

The pattern is always the same:

https://t.me/biznode_bot?start=<subdomain>_<handle>

For FV, you have two useful entry points:

# Subdomain landing — opens FV's full handle catalog
https://t.me/biznode_bot?start=fv_main

# Specific handle — jumps straight into KYC
https://t.me/biznode_bot?start=fv_verify_kyc

That URL is the integration. No SDK, no webhook to register, no per-platform adapter.

3. Pin it somewhere

Drop the URL into any channel where your customer already is:

Telegram channel description / pinned message

Verify any customer in 30 seconds — KYC, face match, ID extract.
First 2 invocations free, then 5 DZIT each.
👉 https://t.me/biznode_bot?start=fv_main

WhatsApp / Instagram / Facebook DM — paste the same URL. Telegram's mobile deep link opens the app directly:

https://t.me/biznode_bot?start=fv_verify_kyc

Sister-site CTA button — drop one line of HTML into any landing page:

<a href="https://t.me/biznode_bot?start=fv_main" class="cta">
  Verify customer →
</a>

QR code — generate a QR of the URL with any free generator (qr-code-generator.com, qrcode-monkey.com, etc.) and print it on a business card, poster, or product packaging:

QR encodes:  https://t.me/biznode_bot?start=fv_main
Camera scan → Telegram opens → handle fires

4. What the user sees

  1. Click the link → Telegram opens with a Start button on @biznode_bot.
  2. First time only: the bot asks for an email, sends a 6-digit code, the user pastes the code back, account is verified.
  3. The bot runs the handle (verify_kyc) and returns the result in the same chat — no app switch, no separate website.
  4. A footer line tells the user the cost: Cost: FREE (1 use left) while inside the free quota, then Cost: 5.0 DZIT on paid invocations.

5. What you (the operator) see

  • Email + Telegram notification: Handle Invoked followed by Payment Released, both stamped with a workflow ID (WFID) for reconciliation.
  • Free-quota usage is tracked per (user, bot, handle) — once a user exhausts their free calls, every subsequent invocation is paid.
  • Paid invocations split DZIT 70% provider / 20% referrer / 10% platform, settled on Polygon and visible in your DZIT transaction history.

Common variations

  • Verified vs unverified users: every link works the same — a verified user invokes the handle immediately, an unverified user gets the email-OTP gate first and then the handle auto-fires on success.
  • Multiple subdomains in one channel: pin all 9 ready-made cards from the reference list docs/BIZNODE_DEEP_LINK_CARDS.md (FV, DX, UBC, Fax, CopyGuard, IPVault, DZIT, SmartPDF, BizChannel) — one card per service, copy-paste ready.
  • Track which channel a user came from: append &utm_source=<channel> after the start payload, e.g. ?start=fv_main&utm_source=instagram_bio. Telegram passes the parameter through to the bot's payload parser so you can attribute conversions.

The handle URL pattern

Every public handle has a stable, shareable URL:

https://app.1bz.biz/h/<bot-name>-<handle-name>

You can also use the UUID if you already have it:

https://app.1bz.biz/h/<handle-uuid>

Pasted URLs auto-render a per-handle preview card in Facebook, LinkedIn, Slack, Discord and WhatsApp. Clicks land on the handle's form; first-time users sign in with an email magic link (30-min expiry), then invoke.

If the URL is issued from a BizNode Telegram bot (e.g. a button from @biznode_bot), it carries a signed chat_id param. Clicks skip email login — the user's Telegram identity is auto-recognised.

API endpoints

MethodEndpointAuthPurpose
GET biznode.1bz.biz/api_public.php?action=handles none Public handle catalog. Filter with &industry=, &q=, &bot_id=, &limit=.
GET biznode.1bz.biz/api_public.php?action=bots none Public bot directory.
POST app.1bz.biz/api/app/auth/request none Send a magic-link email for web login. Body: {"email":"…"}.
POST app.1bz.biz/api/app/auth/verify none Exchange magic-link token for a JWT. Body: {"email":"…","token":"…"}.
GET app.1bz.biz/api/app/me JWT bearer Current user: email, balance, tier, bot_id.
GET app.1bz.biz/api/app/handles JWT bearer Catalog with JWT context. Filter with ?node=, ?bot_name=, ?industry=.
POST app.1bz.biz/api/app/invoke JWT bearer Invoke a handle. Body: {"handle_id":"…","input_data":{…}}. Deducts DZIT (or consumes free quota), returns {ok, result, balance, wfid, telegram_pushed}.

Authentication

Today, authenticated endpoints require a user JWT obtained via the magic-link flow. Two-step:

# 1. Request magic link — user receives email with a one-time click URL
curl -s -X POST https://app.1bz.biz/api/app/auth/request \
  -H 'Content-Type: application/json' \
  -d '{"email":"user@example.com"}'

# 2. User clicks the email link → your frontend extracts ?token &email,
#    posts to verify and receives a JWT (sub=email, 14-day HS256)
curl -s -X POST https://app.1bz.biz/api/app/auth/verify \
  -H 'Content-Type: application/json' \
  -d '{"email":"user@example.com","token":"<from URL>"}'
# -> {"ok":true,"token":"eyJ..."}

API keys (server-to-server): coming soon. For now, obtain a user JWT and reuse it for 14 days.

Telegram users — in-chat email OTP: if a user opens a handle via t.me/biznode_bot?start=<subdomain>_<handle> and their chat_id is not yet linked to an email, @biznode_bot asks for their email in-chat, emails a one-time code, the user replies with the code, and the original handle auto-fires with the result returned to the same chat. No channel-switch, no magic link. Verified users skip this entirely.

Integrate with Slack

Slash command /biznode <handle> replies with a Block Kit button that opens the handle on BizNode. No backend state needed — the URL IS the integration.

from slack_bolt import App
import os, urllib.parse

app = App(token=os.environ["SLACK_BOT_TOKEN"],
          signing_secret=os.environ["SLACK_SIGNING_SECRET"])

@app.command("/biznode")
def biznode_cmd(ack, command, respond):
    ack()
    text = (command.get("text") or "").strip() or "askai"
    # text is the handle slug, e.g. "biznode_bot-askai" or just "askai"
    if "-" not in text:
        text = f"biznode_bot-{text}"
    url = f"https://app.1bz.biz/h/{urllib.parse.quote(text)}"
    respond(blocks=[
        {"type": "section",
         "text": {"type": "mrkdwn",
                  "text": f"Run *{text}* on BizNode (pay-per-call with DZIT):"}},
        {"type": "actions", "elements": [
            {"type": "button", "url": url,
             "text": {"type": "plain_text", "text": "Open handle \u2197"},
             "style": "primary"}]}])

if __name__ == "__main__":
    app.start(int(os.environ.get("PORT", 3000)))

Integrate with Discord

Slash command /biznode posts a message with a link button (button style 5).

import discord, os
from discord import app_commands
from discord.ui import View, Button

intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)

@tree.command(name="biznode", description="Invoke a BizNode handle")
@app_commands.describe(handle="Handle slug, e.g. biznode_bot-askai")
async def biznode(interaction: discord.Interaction, handle: str = "askai"):
    slug = handle if "-" in handle else f"biznode_bot-{handle}"
    url = f"https://app.1bz.biz/h/{slug}"
    view = View()
    view.add_item(Button(label="Open handle", url=url, style=discord.ButtonStyle.link))
    await interaction.response.send_message(
        f"Run **{slug}** on BizNode (pay-per-call with DZIT):",
        view=view, ephemeral=True)

@client.event
async def on_ready():
    await tree.sync()

client.run(os.environ["DISCORD_BOT_TOKEN"])

Integrate with WhatsApp Business

Send an interactive CTA URL button via Meta Cloud API. Requires a WABA phone number ID + access token.

import os, requests

PHONE_ID = os.environ["WA_PHONE_NUMBER_ID"]
TOKEN    = os.environ["WA_ACCESS_TOKEN"]

def send_handle_button(to_phone_e164: str, handle_slug: str = "biznode_bot-askai"):
    url = f"https://graph.facebook.com/v19.0/{PHONE_ID}/messages"
    body = {
        "messaging_product": "whatsapp",
        "recipient_type": "individual",
        "to": to_phone_e164,
        "type": "interactive",
        "interactive": {
            "type": "cta_url",
            "body": {"text": f"Run *{handle_slug}* on BizNode. Pay-per-call with DZIT."},
            "action": {
                "name": "cta_url",
                "parameters": {
                    "display_text": "Open handle",
                    "url": f"https://app.1bz.biz/h/{handle_slug}"}}}}
    r = requests.post(url, json=body,
                      headers={"Authorization": f"Bearer {TOKEN}"}, timeout=15)
    r.raise_for_status()
    return r.json()

Integrate with Node / Express

A webhook that emails a customer a personalised BizNode handle link — works with any mail provider that accepts HTML:

import express from "express";
import nodemailer from "nodemailer";

const app = express();
app.use(express.json());

const transport = nodemailer.createTransport({
  host: process.env.SMTP_HOST, port: 587,
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS }});

app.post("/lead", async (req, res) => {
  const { email, handle = "biznode_bot-askai" } = req.body;
  const url = `https://app.1bz.biz/h/${encodeURIComponent(handle)}`;
  await transport.sendMail({
    from: process.env.SMTP_USER, to: email,
    subject: "Try our AI service — first 10 calls free",
    html: `<p>Run <b>${handle}</b> on BizNode:</p>
           <p><a href="${url}" style="background:#0ea5e9;color:#fff;
               padding:10px 18px;border-radius:8px;text-decoration:none">
               Open handle \u2197</a></p>`});
  res.json({ ok: true });
});

app.listen(3000);

Vanilla Python — list handles from the catalog

import requests

CATALOG = "https://biznode.1bz.biz/api_public.php"

def list_handles(query=None, industry=None, limit=50):
    params = {"action": "handles", "limit": limit}
    if query:    params["q"] = query
    if industry: params["industry"] = industry
    return requests.get(CATALOG, params=params, timeout=15).json()

for h in list_handles(query="ai", limit=20):
    slug = f"{h['bot_name'].lstrip('@')}-{h['handle_name']}"
    print(f"{slug:40s}  {h['dzit_cost']:>5.2f} DZIT  "
          f"https://app.1bz.biz/h/{slug}")

Pricing & DZIT

DZIT is BizNode's on-chain pay-per-call credit (Polygon). Every handle sets its own dzit_cost. Each successful invocation deducts from the caller's balance and splits:

  • 70% → the handle's provider (bot owner)
  • 20% → the referrer (e.g. the site/app that sent the user)
  • 10% → the BizNode platform

Free tier: public handles may declare a free_quota. Each user gets that many free calls per bot + handle before DZIT charging kicks in. Example: askai is 10 free calls per user per bot.

How charging works: The first N invocations of any handle are free per user (configurable per handle). Beyond that, DZIT is deducted from the user's account, with a 70/20/10 split between provider, referrer, and BizNode platform.

Topping up: users purchase DZIT credit packs from $10 to $10,000 via the BizNode dashboard. New web signups get 10 DZIT free.

Publish your own handle

Any registered BizNode bot can publish handles. Public handle registration costs 1 DZIT (one-time). After that, every invocation pays you 70% of its dzit_cost.

curl -s -X POST https://app.1bz.biz/api/handles/register \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <your JWT>' \
  -d '{
    "bot_id": "BZBOT-XXXXXX",
    "handle_name": "quote",
    "display_name": "Price quote",
    "description": "Return a one-line price quote for my service.",
    "is_public": 1,
    "dzit_cost": 2.0,
    "free_quota": 3,
    "fields_schema": [
      {"name":"service","type":"string","required":true},
      {"name":"region","type":"string","required":false}
    ],
    "handler_type": "llm"
  }'

Changelog

  • 2026-04-20 — Removed redirector multiplex. Reach any subdomain via a deep link directly: t.me/biznode_bot?start=<sub>_<handle>.
  • 2026-04-19 (evening) — Free-quota system live: every handle ships with a configurable free-call ceiling per user (typically 2-10 calls). Bot replies now surface Cost: FREE (X uses left) on free invocations, and the redundant "Payment Released" line is suppressed when no escrow is involved. DZIT is now deducted from the user's email-keyed account balance once free quota is exhausted, with the same 70/20/10 split. Subdomain redirector multiplex is live: 5 of 9 lightweight subdomain bots (@fvbiznode_bot, @dxbiznode_bot, @ubcbiznode_bot, @faxbiznode_bot, @copy_guardbot) reply to /start with a deep link back to @biznode_bot. Note: the FV brand bot's canonical handle is @fvbiznode_bot (no underscore).
  • 2026-04-19 — Phase 4 Mother-Bot: @biznode_bot now serves all 11 subdomains via /start <subdomain>_<handle> deep-link payloads (e.g. t.me/biznode_bot?start=fv_verify_kyc). The 9 subdomain brand bots (@fvbiznode_bot, @faxbiznode_bot, @copy_guardbot, etc.) run as a lightweight redirector multiplex and answer /start with a pre-filled link to the mother bot. Unverified Telegram users now complete email verification in-chat via OTP; the original handle auto-fires on success. Web, Telegram, and shareable-URL paths all settle through the same /api/handles/invoke pipeline with DZIT 70/20/10 split.
  • 2026-04-18 — Per-handle OG share cards, human-readable slugs, free-quota system (DB-driven), multi-platform docs.
  • 2026-04-17 — Phase 2 Week 1: Telegram↔app bridge (signed URL auto-login). Phase 1 complete.

Last updated: 2026-04-20 · Open issues? postmaster@1bz.biz