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:
| State | Meaning |
|---|---|
IDLE | Just created, not connected yet. |
HELLO_SENT | Connected, waiting for cloud to respond. |
ACTIVE | Fully operational â can send commands. |
DISCONNECTED | Connection 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)â
| Field | Type | Description |
|---|---|---|
| Version | string | Protocol version ("HxTP/3.1") |
| DeviceId | string | Device UUID |
| TenantId | string | Tenant UUID |
| ClientId | string | Client UUID |
| MessageId | string | Message UUID |
| RequestId | string | Request UUID |
| SequenceNumber | int64 | Monotonic counter |
| Timestamp | int64 | Unix epoch milliseconds |
| Nonce | string | Unique random string |
| MessageType | string | Enum (state, command, hello, etc.) |
| PayloadHash | string | SHA-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"])
}