Skip to main content
Use client.Events to receive instance events in real time without exposing a public URL. For HTTP callbacks, see Webhooks.

Common events

EventDescription
MessageNew incoming message or message event.
ReadReceiptRead/delivery update.
PresenceUser presence.
ChatPresenceChat presence.
HistorySyncHistory synchronization.
ConnectedInstance connected to WhatsApp.
DisconnectedInstance disconnected.
GroupParticipantsAddParticipants added to group.
GroupParticipantsRemoveParticipants removed from group.
AllAll subscribed events.
Use the exported constants: vzaps.EventMessage, vzaps.EventConnected, etc.

Subscribe to realtime

sub, err := client.Events.Subscribe(ctx, vzaps.EventSubscribeRequest{
	InstanceID:    "VZ...",
	InstanceToken: "instance-token",
	Events:        []vzaps.EventType{vzaps.EventMessage, vzaps.EventReadReceipt, vzaps.EventConnected, vzaps.EventDisconnected},
	Reconnect:     true,
	MaxRetries:    10,
	RetryDelay:    time.Second,
})
Return: EventSubscription — object with on(), close(), and automatic reconnect when configured. Options:
FieldTypeRequiredDescription
InstanceIDstringYesInstance to watch.
InstanceTokenstringYesInstance token.
Events[]EventTypeNoEvent list. If omitted, uses events subscribed on the instance.
ReconnectboolNoReconnect automatically. Default: true.
MaxRetriesintNoMaximum retry attempts.
RetryDelaytime.DurationNoDelay between retries.
LastEventIDstringNoResume cursor.
Pass the same context.Context used for the subscribe call; cancellation stops reconnection attempts.

Register handlers

sub.OnOpen(func() {
	fmt.Println("Realtime connected")
})

sub.On(vzaps.EventMessage, func(event vzaps.Event) {
	fmt.Println(event.ID)
	fmt.Println(event.InstanceID)
	fmt.Printf("%#v\n", event.Data)
})

sub.On(vzaps.EventAll, func(event vzaps.Event) {
	fmt.Println("Received event:", event.Type)
})

sub.OnError(func(err error) {
	fmt.Println("Realtime error:", err)
})

Close subscription

sub.Close()
Return: Promise<void> after the WebSocket closes. In long-running processes:
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt)
<-sigCh
sub.Close()

Event envelope

Every event received by the SDK has this shape:
{
  "id": "evt_01J...",
  "type": "Message",
  "instance_id": "VZ...",
  "created_at": "2026-06-23T22:57:17.000Z",
  "data": {
    "type": "Message",
    "media_url": "https://cdn.example.com/media/image.jpg"
  }
}
Fields:
FieldDescription
idEvent identifier. Use for deduplication.
typeEvent type.
instance_idSource instance.
created_atEvent creation date.
dataEvent payload.
data.media_urlMedia URL when the incoming event contains media and the platform provides the file.
In Go, access fields via event.ID, event.Type, event.InstanceID, event.CreatedAt, and event.Data.

Delivery and ack

Delivery is at-least-once. Your app should process events idempotently. After the handler finishes, the SDK automatically sends an ack. Recommendations:
  • store event.ID if your automation performs external effects;
  • ignore events that were already processed;
  • use LastEventID when reconnecting if you want to reduce gaps;
  • keep handlers fast and move long-running work to your own queue.

Realtime or webhook?

ScenarioRecommendation
Bot, dashboard, or app with immediate consumptionRealtime
Backend with public URL and HTTP pipelineWebhook
Do not want to expose a public URLRealtime
Need to reprocess deliveries via logsWebhook