Getting Started
Install a Hanzo ZT SDK and establish your first zero-trust connection
Getting Started
Get up and running with Hanzo ZT in minutes. Choose your language, authenticate, and dial your first service.
Prerequisites
- A Hanzo account at hanzo.id with a positive balance
- An API key (
HANZO_API_KEY) or JWT token fromdev login
Install the SDK
cargo add hanzo-ztgo get github.com/hanzozt/sdk-golangnpm install @hanzo/ztpip install hanzo-ztFetchContent_Declare(
hanzo_zt
GIT_REPOSITORY https://github.com/hanzozt/zt-sdk-cpp.git
GIT_TAG main
)
FetchContent_MakeAvailable(hanzo_zt)
target_link_libraries(your_target PRIVATE hanzo_zt)cc -o app app.c -lzt -lzt_zapSet Your Credentials
All ZT SDKs resolve authentication from the environment:
# Option 1: API key (simplest)
export HANZO_API_KEY="your-api-key-from-hanzo.id"
# Option 2: Login via CLI (stores JWT in ~/.hanzo/auth.json)
dev loginThe credential resolution order for all SDKs is:
HANZO_API_KEYenvironment variable~/.hanzo/auth.jsonfile (created bydev login)
Connect and Dial
use hanzo_zt::{ZtContext, ConfigBuilder, HanzoJwtCredentials};
#[tokio::main]
async fn main() -> hanzo_zt::Result<()> {
let creds = HanzoJwtCredentials::resolve()?;
let config = ConfigBuilder::new()
.controller_url("https://zt-api.hanzo.ai")
.credentials(creds)
.billing(true)
.build()?;
let ctx = ZtContext::new(config).await?;
ctx.authenticate().await?;
// Dial a service through the ZT fabric
let conn = ctx.dial("echo-service").await?;
conn.send(b"Hello, ZT!").await?;
let response = conn.recv().await?;
println!("Response: {}", String::from_utf8_lossy(&response));
conn.close().await?;
Ok(())
}package main
import (
"context"
"fmt"
"log"
"github.com/hanzozt/sdk-golang/auth/hanzo"
"github.com/hanzozt/sdk-golang/zt"
)
func main() {
ctx := context.Background()
creds, err := hanzo.Resolve()
if err != nil {
log.Fatal(err)
}
config := zt.NewConfigBuilder().
ControllerURL("https://zt-api.hanzo.ai").
Credentials(creds).
Billing(true).
Build()
ztCtx, err := zt.NewContext(ctx, config)
if err != nil {
log.Fatal(err)
}
if err := ztCtx.Authenticate(ctx); err != nil {
log.Fatal(err)
}
conn, err := ztCtx.Dial(ctx, "echo-service")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
conn.Write([]byte("Hello, ZT!"))
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
fmt.Printf("Response: %s\n", buf[:n])
}import { ZtContext, HanzoAuth, ZtConfig } from '@hanzo/zt';
const auth = HanzoAuth.resolve();
const config: ZtConfig = {
controllerUrl: 'https://zt-api.hanzo.ai',
credentials: auth,
billing: true,
};
const ctx = await ZtContext.create(config);
await ctx.authenticate();
const conn = await ctx.dial('echo-service');
await conn.send(Buffer.from('Hello, ZT!'));
const response = await conn.recv();
console.log('Response:', response.toString());
await conn.close();import asyncio
from hanzozt import ZtContext, ConfigBuilder
from hanzozt.auth import HanzoJwtCredentials
async def main():
creds = HanzoJwtCredentials.resolve()
config = (
ConfigBuilder()
.controller_url("https://zt-api.hanzo.ai")
.credentials(creds)
.billing(True)
.build()
)
ctx = await ZtContext.create(config)
await ctx.authenticate()
conn = await ctx.dial("echo-service")
await conn.send(b"Hello, ZT!")
response = await conn.recv()
print(f"Response: {response.decode()}")
await conn.close()
asyncio.run(main())What Happens Under the Hood
When you call dial("echo-service"), the SDK performs these steps automatically:
- Auth - Presents your JWT to the ZT controller via ext-jwt authentication
- Identity - Controller issues an x509 mTLS certificate for your identity
- Billing - Checks your balance via the Hanzo Commerce API (no free tier)
- Resolve - Looks up edge routers for the target service
- Connect - Establishes an mTLS tunnel through the ZT fabric with NAT traversal
- Ready - Returns a bidirectional connection for send/recv
Use ZAP Transport (Optional)
For Cap'n Proto RPC over ZT, use the ZAP transport:
use hanzo_zt::ZtTransport;
let transport = ZtTransport::new("https://zt-api.hanzo.ai", "my-service").await?;
// Use with ZAP client - implements the Transport trait
transport.send(b"zap-frame").await?;
let frame = transport.recv().await?;Next Steps
- Learn about the Architecture and network topology
- Explore the SDK documentation for your language
- Set up MCP integration for AI tool calling