The Go Voice SDK lives in package github.com/telequick/telequick-sdk/go/pkg/voice. It gives you the same two primitives as every other language binding — Calls (the control plane) and AudioBridge (the data plane) — plus Agents to bind a server-side AI agent to a live call. Everything keys off one identifier, a call’s Sid. The two planes have very different runtime requirements in Go, and it is worth knowing this up front:
Calls and Agents are pure Go — they speak the control-plane API over plain net/http, so they build and run anywhere Go does, with no C toolchain.AudioBridge is a cgo binding. It moves encoded audio over MoQT through the SDK’s native transport, so building code that touches AudioBridge needs CGO_ENABLED=1, a C toolchain, and the SDK’s native audio shared library on your linker/loader path. If you only place and manage calls — or attach an AI agent and let the engine own the media — you never touch the data plane and can build a pure-Go binary.

Install

go get github.com/telequick/telequick-sdk/go
import "github.com/telequick/telequick-sdk/go/pkg/voice"
The AudioBridge additionally uses the core package at github.com/telequick/telequick-sdk/go/pkg (the native MoQT client) under the hood; you rarely import it directly.

Construct the client

voice.New returns a *Voice scoped to one org. All three arguments are required — it returns an error if any is empty. Construct it once and reuse it; it is safe to share across goroutines.
baseURL
string
required
Control-plane API host, e.g. https://engine.telequick.dev. A trailing slash is trimmed for you.
apiKey
string
required
Your API key. It is sent as Authorization: Bearer <key> on every control-plane request.
orgID
string
required
The org (workspace) id every operation is scoped to.
package main

import (
	"log"
	"os"

	"github.com/telequick/telequick-sdk/go/pkg/voice"
)

func main() {
	v, err := voice.New(
		"https://engine.telequick.dev",
		os.Getenv("TELEQUICK_API_KEY"),
		"org_123",
	)
	if err != nil {
		log.Fatal(err)
	}

	// The three sub-clients are accessors (methods), not fields:
	calls  := v.Calls()
	agents := v.Agents()
	bridge := v.AudioBridge()
	_ = bridge
}
The Voice struct exposes a few fields you can set after construction:
RelayHost
string
default:"relay.telequick.dev"
Host for the AudioBridge MoQT session. Point it at your workspace relay.
HTTP
*http.Client
default:"http.DefaultClient"
Override to set timeouts, a proxy, or custom transport for control-plane calls.
v.RelayHost = "relay.telequick.dev"
v.HTTP = &http.Client{Timeout: 10 * time.Second}

Calls — the control plane

v.Calls() returns a *Calls. Every method maps to one control-plane RPC and returns a typed result or an error.

Originate

Originate dials To from From over the trunk you name. Pass Agent and the engine attaches that server-side voice agent automatically when the far end answers — you don’t open an AudioBridge yourself.
To
string
required
Destination in E.164, e.g. +15551234567.
From
string
required
Caller-ID presented on the outbound leg, in E.164. Must be a number your trunk is allowed to present.
TrunkID
string
required
The trunk to originate on. See SIP trunking.
Agent
string
Optional agent id. When set, the engine binds this server-side voice agent on answer and wires the audio bridge end-to-end.
RingTimeoutSec
int
default:"30"
Seconds to ring before giving up. Left at the zero value, the SDK sends 30.
call, err := v.Calls().Originate(voice.OriginateArgs{
	To:      "+15551234567",
	From:    "+15558675309",
	TrunkID: "trunk_main",
	Agent:   "healthcare-assistant", // optional
})
if err != nil {
	log.Fatal(err)
}
log.Println(call.Sid, call.Status) // "cs_…", "dialing"
Originate returns a *Call, which embeds CallData:
Sid
string
The universal call key.
Status
string
Lifecycle state, e.g. dialing, in_progress, completed.
To
string
Destination number.
From
string
Caller-ID.
StartedAt
string
Start timestamp.
TrunkID
string
Trunk the call was placed on (omitted when empty).
Agent
string
Bound agent id, if any (omitted when empty).

Get

Fetch the current state of a call by sid.
call, err := v.Calls().Get("cs_abc123")
if err != nil {
	log.Fatal(err)
}
log.Println(call.Status)

Transfer

Call.Transfer moves a live call. Pass exactly one of To (hand off to a PSTN number) or Agent (re-attach to a different server-side agent) — passing both, or neither, returns an error before any RPC is sent.
// Warm-transfer the caller to a human on the PSTN:
if err := call.Transfer(voice.TransferArgs{To: "+15558675309"}); err != nil {
	log.Fatal(err)
}

// …or re-point the call at a different AI agent:
err = call.Transfer(voice.TransferArgs{Agent: "billing-specialist"})
See AI ↔ human handoff for the end-to-end warm-handoff flow.

Hangup

if err := call.Hangup(); err != nil {
	log.Fatal(err)
}

Agents — attach an AI agent

v.Agents().Attach binds a server-side voice agent to a call that is already up. Use it when you originated a bare call (no Agent) and now want the engine to take over the conversation, or to attach an agent to an inbound call your backend just learned about.
if err := v.Agents().Attach(call.Sid, "healthcare-assistant"); err != nil {
	log.Fatal(err)
}
Once attached, the engine drives ASR/LLM/TTS (or a speech-to-speech provider) and owns both audio legs — you don’t open an AudioBridge. Configure what the agent does in the runtime docs.

AudioBridge — the data plane

Reach for the AudioBridge only when you want the raw encoded frames of a call in your Go process — for example to feed a bespoke media pipeline or a runtime the engine doesn’t natively host. When an agent is attached, you don’t need it. v.AudioBridge().Attach subscribes to the caller’s audio at the voice/<sid>/uplink track and opens a publisher on voice/<sid>/downlink for audio you send back. (See sessions, calls, tracks & streams for the track model.)
Called for every inbound frame from the caller. frame is the encoded payload; timestampUs is the frame’s microsecond timestamp. Required — Attach errors without it.
Codec
voice.Codec
default:"CodecOpus"
One of CodecOpus, CodecPCM16, CodecG711ULaw, CodecG711ALaw. Voice is audio-only — there is no video codec here.
SampleRate
uint32
default:"48000"
Sample rate of the downlink track.
Channels
uint8
default:"1"
Channel count (voice is mono).
FrameMs
uint16
default:"20"
Frame duration in milliseconds.
bridge, err := v.AudioBridge().Attach(call.Sid, voice.AudioBridgeOpts{
	Codec: voice.CodecOpus,
	OnUplink: func(frame []byte, timestampUs uint64) {
		// caller audio arrives here, frame by frame
		process(frame)
	},
})
if err != nil {
	log.Fatal(err)
}
defer bridge.Close()

// Push one encoded frame back to the caller:
bridge.PublishDownlink(reply) // []byte, timestamped for you
AudioBridge.Attach (and everything it returns) is the cgo path. It requires CGO_ENABLED=1, a C toolchain at build time, and the SDK’s native audio shared library at run time. The rest of this page (Calls, Agents) is pure Go.
PublishDownlink stamps each frame with the current time for you — you hand it just the encoded bytes. Always Close() the bridge when you’re done; it tears down the publisher, the subscription, and the underlying MoQT session.

Errors

Control-plane methods return a plain error. SDK-side validation failures (a missing field, an invalid Transfer combination) come back as *voice.Error; transport and remote failures surface the HTTP status or the control-plane error message. Handle them the usual Go way:
call, err := v.Calls().Originate(args)
if err != nil {
	var ve *voice.Error
	if errors.As(err, &ve) {
		// client-side validation problem — bad args
	}
	log.Printf("originate failed: %v", err)
	return
}

What the Go surface does not include yet

The Go binding is deliberately the two-primitives-plus-agents core. A few things present in other bindings are not in pkg/voice today — reach for the core package or another language where noted:
  • No live call-lifecycle event stream in pkg/voice. OnUplink delivers audio, not signalling events. For a native call-event stream (originate, answer, transfer, cleared) use the lower-level core client in github.com/telequick/telequick-sdk/go/pkg, which exposes an event callback over the native QUIC RPC plane. See the SDK events reference.
  • No human-agent softphone control channel. The browser/desktop agent control channel (login, presence, call-offer accept/reject) currently ships in the JavaScript SDK only.
  • No video. Voice tracks are audio-only.

Next steps

Calls API

The full control-plane contract behind Calls — originate, get, transfer, hangup.

Audio bridge

The MoQT track model and frame semantics the AudioBridge rides on.

Attach an agent

Bind a server-side AI agent and let the engine own the media.

Outbound calling

Originate, campaigns, and the paced dialer end to end.