Skip to main content

hxtp-go (Go SDK)

The hxtp-go library is for high-performance backend services that need to talk to Hestia Labs devices and cloud APIs using HxTP/3.1.

Installation​

go get github.com/hestialabs/hxtp-go

Quick Start​

package main

import (
"fmt"
"github.com/hestialabs/hxtp-go/client"
)

func main() {
c := client.NewClient(client.ClientConfig{
BaseURL: "https://api.hestialabs.in/api/v1",
Token: "your-api-token",
DeviceId: "your-device-id",
ClientId: "my-app",
Secret: "your-private-key-hex", // Ed25519 private key
})

resp, err := c.SendCommand("target-device-id", "toggle_led", map[string]interface{}{
"brightness": 100,
}, false)

if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Command sent! %v\n", resp["message_id"])
}

How It Works​

Ed25519-Only Signing​

Commands are signed using Ed25519 — the same technology used in modern secure systems. Every message carries a digital signature that proves it came from you.

// This happens automatically when sending commands
sig, err := crypto.SignEd25519(privateKeyHex, canonicalString)

Lifecycle​

The client tracks where it is in its conversation with the cloud:

StateMeaning
IDLEJust created, not connected yet.
HELLO_SENTConnected, waiting for cloud to respond.
ACTIVEFully operational — can send commands.
DISCONNECTEDConnection lost.

Using the Admin API​

The Go SDK also lets you manage devices, homes, and firmware:

// List all devices
devices, _ := c.ListDevices()

// Get device details
device, _ := c.GetDevice("device-uuid")

// Register a new device
result, _ := c.RegisterDevice("temperature-sensor", "home-uuid", nil)

// Check firmware updates
fw, _ := c.CheckFirmwareUpdate("esp32", "1.0.0", nil)

Low-Level Protocol Usage​

Build a Canonical String​

import "github.com/hestialabs/hxtp-go/protocol"

canonical, err := protocol.BuildCanonical(protocol.Message{
Version: "HxTP/3.1",
DeviceId: "device-uuid",
TenantId: "tenant-uuid",
ClientId: "client-uuid",
MessageId: "msg-uuid",
RequestId: "req-uuid",
SequenceNumber: 1,
Timestamp: 1708444800,
Nonce: "unique-nonce",
MessageType: "command",
PayloadHash: "sha256-of-params",
})

Sign and Verify​

import "github.com/hestialabs/hxtp-go/crypto"

// Sign
sig, err := crypto.SignEd25519(privateKeyHex, canonical)

// Derive public key from private key
pubKey, err := crypto.PublicKeyFromSeed(privateKeyHex)

// Verify
valid, err := crypto.VerifyEd25519(pubKeyHex, canonical, sig)

Hash​

hash := crypto.ComputeSha256Hex(payloadData)
// Returns 64-char lowercase hex

Canonical Fields (HxTP/3.1)​

FieldTypeDescription
VersionstringProtocol version ("HxTP/3.1")
DeviceIdstringDevice UUID
TenantIdstringTenant UUID
ClientIdstringClient UUID
MessageIdstringMessage UUID
RequestIdstringRequest UUID
SequenceNumberint64Monotonic counter
Timestampint64Unix epoch milliseconds
NoncestringUnique random string
MessageTypestringEnum (state, command, hello, etc.)
PayloadHashstringSHA-256 hex of parameters

Full Example​

package main

import (
"fmt"
"log"

"github.com/hestialabs/hxtp-go/client"
)

func main() {
c := client.NewClient(client.ClientConfig{
BaseURL: "https://api.hestialabs.in/api/v1",
Token: "your-auth-token",
DeviceId: "my-device",
ClientId: "my-backend",
Secret: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
})

// List devices via Cloud API
resp, err := c.ListDevices()
if err != nil {
log.Fatalf("ListDevices failed: %v", err)
}
devices := resp["devices"].([]interface{})
fmt.Printf("Devices found: %d\n", len(devices))

// Send signed command
cmdResp, err := c.SendCommand(
"device-uuid",
"toggle_led",
map[string]interface{}{"value": true},
false,
)
if err != nil {
log.Fatalf("SendCommand failed: %v", err)
}
fmt.Printf("Command dispatched. ID: %s\n", cmdResp["message_id"])
}