From 32c84464475dbb3cbae0ca7a6d8fe6dd9f10b7d6 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:04:20 +0000 Subject: [PATCH 01/26] docs: add design spec for call answer + media stream Documents the plan to add POST /call/answer, POST /call/hangup, and a dedicated WebSocket bridge (GET /call/stream/:callId) built on the purpshell/meowcaller library, so an accepted call's audio/video can be piped to an external system (AI voice pipeline, recorder, etc). --- .../2026-07-29-call-answer-stream-design.md | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-29-call-answer-stream-design.md diff --git a/docs/superpowers/specs/2026-07-29-call-answer-stream-design.md b/docs/superpowers/specs/2026-07-29-call-answer-stream-design.md new file mode 100644 index 00000000..11c76756 --- /dev/null +++ b/docs/superpowers/specs/2026-07-29-call-answer-stream-design.md @@ -0,0 +1,135 @@ +# Design: Answer WhatsApp Calls + Bidirectional Media Stream + +Date: 2026-07-29 +Status: Approved for planning + +## Problem + +Evolution Go exposes `POST /call/reject` (see `pkg/call/handler/call_handler.go` and +`pkg/call/service/call_service.go`) but has no way to accept an incoming call or access +its audio/video. This is not a gap specific to Evolution Go: the underlying +`go.mau.fi/whatsmeow` client only parses call signaling (offer/accept/preaccept/ +transport/terminate) and can reject — it never implemented accepting a call or handling +the actual encrypted media stream. Building that from scratch means reverse-engineering +WhatsApp's proprietary call media protocol, which is a multi-year, multi-attempt effort +documented in `tulir/whatsmeow#555`. + +`github.com/purpshell/meowcaller` (MIT, actively maintained, pure Go, no CGO) already +did this work as an interoperability research project. It wraps a `*whatsmeow.Client` +and exposes: `OnIncomingCall`, `Call.Answer()`, `Call.Reject()`, `Call.Hangup()`, +`Call.AcceptVideo()`/`StartVideo()`, `Call.Play(AudioSource)`, `Call.Receive(AudioSink)`, +`Call.ReceiveVideo(VideoSink)`. Audio is delivered as 16 kHz mono `float32` PCM in +960-sample (60 ms) frames (`FrameSamples = 960`, `SampleRate = 16000` in `audio.go`); +video is H.264 Annex B access units (`VideoSink.WriteVideo([]byte)`). + +Goal: add generic infrastructure to Evolution Go so an incoming call can be answered and +its audio/video piped to an external system (an AI voice pipeline, a human operator +console, a recorder — Evolution Go stays agnostic to what's on the other end). This +mirrors how Evolution already lets Chatwoot/Typebot/OpenAI plug into messaging via +webhook/websocket/RabbitMQ/NATS — except the existing event producers are unidirectional, +fire-and-forget JSON events, unsuited to a sustained, low-latency, two-way audio/video +stream. This feature therefore needs its own dedicated channel, not a new event type +bolted onto the existing producers. + +Explicitly out of scope: no AI/STT/LLM/TTS logic lives in Evolution Go. This PR only +ships the plumbing; whatever consumes the stream is the caller's problem. + +## Constraint that shapes the architecture + +`meowcaller.NewClient(wa)` must be called **before** `wa.Connect()` — the doc comment on +`NewClient` is explicit: "Construct it before connecting whatsmeow so the raw call +adapter can be installed safely." In `pkg/whatsmeow/service/whatsmeow.go`, the +whatsmeow client is created and stored at lines 413–415 +(`client := whatsmeow.NewClient(...)`; `w.clientPointer[cd.Instance.Id] = client`), and +`.Connect()` is called later in several branches (lines ~507–559 and ~2061). This means +the meowcaller client cannot be lazily created inside `pkg/call/service` the way +`ensureClientConnected` currently lazily starts instances — it must be created in +`whatsmeow.go` at client-creation time, alongside `clientPointer`. + +## Components + +Following the existing Handler → Service → Repository convention +(`docs/wiki/desenvolvimento/contributing.md`): + +- **`pkg/whatsmeow/service`**: add `meowcallerPointer map[string]*meowcaller.Client` + alongside the existing `clientPointer`. Populated at the same point `clientPointer` is + populated, before `Connect()`. Exposes a getter so `pkg/call/service` can look up the + meowcaller client for an instance. +- **`pkg/call/service`**: add a call registry (`map[callID]*meowcaller.Call`, mutex- + guarded, matching the style of `CallRegistry` internal to meowcaller but scoped to + what Evolution Go needs: lookup by callID for answer/hangup/stream-attach). New + interface methods: + - `AnswerCall(data *AnswerCallStruct, instance *Instance) (*meowcaller.Call, error)` + - `HangupCall(data *HangupCallStruct, instance *Instance) error` + - `GetActiveCall(instanceId, callId string) (*meowcaller.Call, error)` — used by the + stream bridge. +- **`pkg/call/handler`**: new REST endpoints, same shape as the existing `RejectCall`: + - `POST /call/answer` — body `{callCreator, callId}`. Calls `AnswerCall`; if the + incoming call's `IsVideo()` is true, also calls `Call.AcceptVideo()`. + - `POST /call/hangup` — body `{callId}`. +- **`pkg/call/stream`** (new package): the WebSocket bridge. One connection per call. + Implements `meowcaller.AudioSink`/`VideoSink` (writes frames out to the socket) and + `meowcaller.AudioSource` (reads frames the remote client sends back, feeds + `Call.Play`). +- **`pkg/routes/routes.go`**: register `POST /call/answer`, `POST /call/hangup` in the + existing `/call` group (auth middleware applies, same as `/call/reject`), and + `GET /call/stream/:callId` as its own route (WS upgrade, can't sit behind the same + auth middleware chain — needs upgrade-compatible auth, see below). + +## Wire format (`GET /call/stream/:callId?apikey=...`) + +Modeled on Twilio Media Streams, since AI voice vendors' existing WhatsApp/Twilio +bridges already speak a message shape like this — minimizes adapter work for whoever +consumes it: + +```json +{"event": "start", "callId": "...", "sampleRate": 16000, "video": true} +{"event": "media", "track": "inbound", "payload": ""} +{"event": "media", "track": "outbound", "payload": ""} +{"event": "video", "track": "inbound", "payload": ""} +{"event": "stop", "reason": "hangup"} +``` + +The bridge converts `meowcaller`'s `[]float32` frames to PCM16LE for the `inbound` +track, and decodes base64 PCM16LE from `outbound` messages back to `[]float32` for +`Call.Play`. Video is inbound-only in this PR (receiving/recording the peer's video); +sending synthetic video back is not implemented (no known driver for it here — call +audio is the primary use case, video send can be a follow-up if someone needs it). + +## Auth + +WebSocket upgrades can't rely on custom headers from every possible client, so this +follows the existing pattern in `pkg/events/websocket/websocket_producer.go`: apikey as +a query parameter, validated against the instance before the upgrade completes. + +## Lifecycle / error handling + +- Remote hangs up → meowcaller's engine dispatches `CallTerminate` → bridge sends + `{"event":"stop","reason":"hangup"}` and closes the socket. +- Consumer's WebSocket closes (crash, disconnect) → bridge calls `Call.Hangup()` so the + WhatsApp call doesn't hang open with no one listening. +- `POST /call/answer` for an unknown/expired callId → `404`, same convention as + `RejectCall`'s error handling. +- `GET /call/stream/:callId` for a call not yet answered, or already terminated → + reject the upgrade with `4004`-equivalent close code. + +## Testing + +- Unit tests in `pkg/call/service` and `pkg/call/stream` against a small interface + wrapping the `meowcaller.Client`/`Call` types (mockable), covering answer/hangup/ + registry lookup and the PCM16LE ⇄ float32 conversion in the bridge. +- Manual validation (real WhatsApp test number, since this can't be meaningfully faked): + place a call to the number connected to a test instance, `POST /call/answer`, connect + a throwaway WS client that dumps the `inbound` track to a WAV file, confirm the + recording is intelligible speech. + +## PR plan + +Branch `feature/call-answer-stream` off `main` in the fork +(`RamonBritoDev/evolution-go`), Conventional Commits (`feat: ...`), PR against +`evolution-foundation/evolution-go` per `docs/wiki/desenvolvimento/contributing.md`. +The PR description calls out the new `meowcaller` dependency (MIT-licensed, compatible +with Evolution Go's Apache-2.0 license), links `meowcaller`'s `DISCLAIMER.md` (framed as +independent interoperability research, not affiliated with Meta, with explicit misuse +ground rules), and states clearly that this PR ships transport/plumbing only — no AI +logic — so reviewers aren't evaluating an opinionated AI stack. From 5e509a908c00dd822d9b275055596e74c561f305 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:14:57 +0000 Subject: [PATCH 02/26] docs: add implementation plan for call answer + media stream Task-by-task plan grounded in the actual codebase: exact insertion point for meowcaller.NewClient in whatsmeow.go (before Connect(), per the library's own constraint), a new pkg/call/registry leaf package to avoid an import cycle between call_service and whatsmeow_service, and a pkg/call/stream bridge implementing meowcaller's AudioSink/VideoSink/ AudioSource over a Twilio-Media-Streams-style WebSocket. --- .../plans/2026-07-29-call-answer-stream.md | 1241 +++++++++++++++++ 1 file changed, 1241 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-29-call-answer-stream.md diff --git a/docs/superpowers/plans/2026-07-29-call-answer-stream.md b/docs/superpowers/plans/2026-07-29-call-answer-stream.md new file mode 100644 index 00000000..21a8b77f --- /dev/null +++ b/docs/superpowers/plans/2026-07-29-call-answer-stream.md @@ -0,0 +1,1241 @@ +# Call Answer + Media Stream Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add `POST /call/answer`, `POST /call/hangup`, and a dedicated WebSocket bridge (`GET /call/stream/:callId`) to Evolution Go so an accepted WhatsApp call's audio/video can be piped to any external consumer (AI voice pipeline, recorder, human console). + +**Architecture:** `github.com/purpshell/meowcaller` wraps each instance's `*whatsmeow.Client` and is constructed the moment that client is created (before `.Connect()`), exactly like `pkg/whatsmeow/service` already tracks a `map[string]*whatsmeow.Client`. Incoming `*meowcaller.Call` handles are captured via `OnIncomingCall` into a small shared registry (`pkg/call/registry`), keyed by call ID and instance ID. `pkg/call/service` answers/hangs up calls by looking them up in that registry. A new `pkg/call/stream` package bridges a `*meowcaller.Call`'s audio/video sinks and source to a per-call WebSocket connection, using a Twilio-Media-Streams-style JSON envelope. + +**Tech Stack:** Go 1.25, gin, gorilla/websocket (already a dependency via `pkg/events/websocket`), `go.mau.fi/whatsmeow`, `github.com/purpshell/meowcaller` (new, MIT-licensed). + +## Global Constraints + +- `meowcaller.NewClient(wa)` MUST be called before `wa.Connect()` — this is a hard requirement from the library's own doc comment, not a style choice. +- No AI/STT/LLM/TTS logic in this repo — this PR ships transport/plumbing only (per approved design spec `docs/superpowers/specs/2026-07-29-call-answer-stream-design.md`). +- Video is inbound-only (record/forward the peer's video); outbound synthetic video is out of scope. +- Follow the existing Handler → Service → Repository convention and package-alias-as-name-with-underscore style already used throughout (`call_service`, `call_handler`, etc.) — see `docs/wiki/desenvolvimento/contributing.md`. +- Audio wire format: 16 kHz mono, 960-sample (60 ms) frames, `float32` inside the process (`meowcaller.SampleRate`, `meowcaller.FrameSamples`), PCM16LE + base64 on the wire. +- Run `make fmt` and `make lint` before every commit that touches Go files (repo convention). + +--- + +### Task 1: Add the `meowcaller` dependency and verify the build + +**Files:** +- Modify: `go.mod`, `go.sum` + +**Interfaces:** +- Produces: `github.com/purpshell/meowcaller` importable at `v0.0.0-...` (pseudo-version, no tagged releases yet), and `go.mau.fi/whatsmeow` bumped to at least `v0.0.0-20260722203353-e9a033b24933` (meowcaller's floor; Go's minimal version selection will pick the higher of the two requirements automatically). + +- [ ] **Step 1: Add the dependency** + +```bash +cd /home/rarosh/projetos/evolution-go +go get github.com/purpshell/meowcaller@latest +``` + +- [ ] **Step 2: Tidy and verify the whatsmeow bump didn't break anything** + +```bash +go mod tidy +go build ./... +``` + +Expected: exits 0. If it fails, the failures will be in `pkg/whatsmeow/service/whatsmeow.go` from whatsmeow API drift between the pinned versions (2026-06-30 → 2026-07-22) — read the compiler errors, they'll name the exact symbols that moved; fix those call sites before continuing (do not downgrade whatsmeow back down, meowcaller requires the newer floor). + +- [ ] **Step 3: Commit** + +```bash +git add go.mod go.sum +git commit -m "feat: add meowcaller dependency for WhatsApp call media" +``` + +--- + +### Task 2: Call registry (shared between whatsmeow_service and call_service) + +**Files:** +- Create: `pkg/call/registry/call_registry.go` +- Test: `pkg/call/registry/call_registry_test.go` + +**Interfaces:** +- Produces: + - `type CallRegistry struct` (opaque, all fields unexported) + - `func NewCallRegistry() *CallRegistry` + - `func (r *CallRegistry) Store(instanceID string, call *meowcaller.Call)` + - `func (r *CallRegistry) Get(instanceID, callID string) (*meowcaller.Call, bool)` — returns `false` if the call isn't registered *or* belongs to a different instance (this is the security boundary that keeps one instance's apikey from reaching into another instance's call) + - `func (r *CallRegistry) Delete(callID string)` + +This is its own leaf package (not inside `pkg/call/service`) specifically to avoid an import cycle: `pkg/call/service` already imports `pkg/whatsmeow/service`, and `pkg/whatsmeow/service` needs to write into this registry too — if the registry lived inside `pkg/call/service`, that would make `pkg/whatsmeow/service` import `pkg/call/service` while `pkg/call/service` imports `pkg/whatsmeow/service`, which Go rejects. + +- [ ] **Step 1: Write the failing test** + +```go +// pkg/call/registry/call_registry_test.go +package call_registry + +import ( + "testing" + + "github.com/purpshell/meowcaller" +) + +func TestStoreAndGet(t *testing.T) { + r := NewCallRegistry() + call := &meowcaller.Call{} + + r.Store("instance-a", call) + + got, ok := r.Get("instance-a", callIDOf(call)) + if !ok { + t.Fatal("expected call to be found") + } + if got != call { + t.Fatal("expected the same call pointer back") + } +} + +func TestGetWrongInstanceFails(t *testing.T) { + r := NewCallRegistry() + call := &meowcaller.Call{} + r.Store("instance-a", call) + + _, ok := r.Get("instance-b", callIDOf(call)) + if ok { + t.Fatal("expected lookup from a different instance to fail") + } +} + +func TestDeleteRemovesEntry(t *testing.T) { + r := NewCallRegistry() + call := &meowcaller.Call{} + r.Store("instance-a", call) + r.Delete(callIDOf(call)) + + _, ok := r.Get("instance-a", callIDOf(call)) + if ok { + t.Fatal("expected entry to be gone after Delete") + } +} + +// callIDOf mirrors what CallRegistry.Store keys entries by: meowcaller.Call.ID(). +// A zero-value *meowcaller.Call has an empty string ID, which is a perfectly valid +// (if degenerate) key for exercising Store/Get/Delete without a live call. +func callIDOf(call *meowcaller.Call) string { + return call.ID() +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `go test ./pkg/call/registry/... -v` +Expected: FAIL — `call_registry.go` doesn't exist yet, compile error `undefined: NewCallRegistry`. + +- [ ] **Step 3: Write the implementation** + +```go +// pkg/call/registry/call_registry.go +package call_registry + +import ( + "sync" + + "github.com/purpshell/meowcaller" +) + +// entry pairs a live call with the instance it belongs to, so Get can refuse to hand +// back a call to a caller authenticated as a different instance. +type entry struct { + instanceID string + call *meowcaller.Call +} + +// CallRegistry tracks in-progress meowcaller calls by call ID, scoped by instance. +// It is written from the whatsmeow event-handling goroutine (on incoming call) and +// read/written from HTTP handler goroutines (answer/hangup/stream), so all access is +// mutex-guarded. +type CallRegistry struct { + mu sync.RWMutex + entries map[string]entry +} + +// NewCallRegistry returns an empty registry. +func NewCallRegistry() *CallRegistry { + return &CallRegistry{entries: make(map[string]entry)} +} + +// Store records call under its own ID (meowcaller.Call.ID()), tagged with instanceID. +func (r *CallRegistry) Store(instanceID string, call *meowcaller.Call) { + r.mu.Lock() + defer r.mu.Unlock() + r.entries[call.ID()] = entry{instanceID: instanceID, call: call} +} + +// Get returns the call for callID, but only if it was stored under instanceID. +func (r *CallRegistry) Get(instanceID, callID string) (*meowcaller.Call, bool) { + r.mu.RLock() + defer r.mu.RUnlock() + e, ok := r.entries[callID] + if !ok || e.instanceID != instanceID { + return nil, false + } + return e.call, true +} + +// Delete removes callID regardless of which instance it belongs to. +func (r *CallRegistry) Delete(callID string) { + r.mu.Lock() + defer r.mu.Unlock() + delete(r.entries, callID) +} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `go test ./pkg/call/registry/... -v` +Expected: PASS (3 tests) + +- [ ] **Step 5: Commit** + +```bash +git add pkg/call/registry +git commit -m "feat: add call registry for tracking answerable meowcaller calls" +``` + +--- + +### Task 3: Wire meowcaller into `pkg/whatsmeow/service` + +**Files:** +- Modify: `pkg/whatsmeow/service/whatsmeow.go` + +**Interfaces:** +- Consumes: `call_registry.CallRegistry` from Task 2 (`Store`, `Delete`) +- Produces: `whatsmeowService.meowcallerPointer map[string]*meowcaller.Client` (internal, not part of the `WhatsmeowService` interface — nothing outside this file needs to reach into it), and `NewWhatsmeowService` gains one new parameter. + +No automated test for this task: it's wiring inside a 2800-line file that drives a live WhatsApp connection, already untested elsewhere in the repo for the same reason (`ClientData`/`MyClient` flow has zero existing test coverage). Verified by `go build` here and by the manual end-to-end test in Task 9. + +- [ ] **Step 1: Add the import** + +In `pkg/whatsmeow/service/whatsmeow.go`, add to the import block (alongside the other `github.com/evolution-foundation/evolution-go/...` and third-party imports): + +```go + call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" + "github.com/purpshell/meowcaller" +``` + +- [ ] **Step 2: Add the two new struct fields** + +Find the `whatsmeowService` struct (currently starts `type whatsmeowService struct {` around line 78). Add two fields, right after `clientPointer map[string]*whatsmeow.Client`: + +```go + clientPointer map[string]*whatsmeow.Client + meowcallerPointer map[string]*meowcaller.Client + callRegistry *call_registry.CallRegistry +``` + +- [ ] **Step 3: Add the new constructor parameter** + +Find `func NewWhatsmeowService(` (around line 2793). Add `callRegistry *call_registry.CallRegistry` as a new parameter right before `loggerWrapper *logger_wrapper.LoggerManager`: + +```go +func NewWhatsmeowService( + instanceRepository instance_repository.InstanceRepository, + authDB *sql.DB, + messageRepository message_repository.MessageRepository, + labelRepository label_repository.LabelRepository, + config *config.Config, + killChannel map[string](chan bool), + clientPointer map[string]*whatsmeow.Client, + rabbitmqProducer producer_interfaces.Producer, + webhookProducer producer_interfaces.Producer, + websocketProducer producer_interfaces.Producer, + sqliteDB *sql.DB, + exPath string, + mediaStorage storage_interfaces.MediaStorage, + natsProducer producer_interfaces.Producer, + callRegistry *call_registry.CallRegistry, + loggerWrapper *logger_wrapper.LoggerManager, +) WhatsmeowService { +``` + +And in the returned `&whatsmeowService{...}` literal in the same function, add two lines (right after `clientPointer: clientPointer,`): + +```go + clientPointer: clientPointer, + meowcallerPointer: make(map[string]*meowcaller.Client), + callRegistry: callRegistry, +``` + +- [ ] **Step 4: Construct the meowcaller client at the exact point whatsmeow's client is created** + +In `func (w whatsmeowService) StartClient(cd *ClientData)`, find this existing line (around line 413-415): + +```go + client := whatsmeow.NewClient(deviceStore, clientLog) + + w.clientPointer[cd.Instance.Id] = client +``` + +Change it to: + +```go + client := whatsmeow.NewClient(deviceStore, clientLog) + + w.clientPointer[cd.Instance.Id] = client + + // meowcaller.NewClient must run before client.Connect() — it installs the raw + // stanza adapter, and doing so after Connect() is a documented race. + meowcallerClient := meowcaller.NewClient(client) + w.meowcallerPointer[cd.Instance.Id] = meowcallerClient + instanceID := cd.Instance.Id + meowcallerClient.OnIncomingCall(func(call *meowcaller.Call) { + w.loggerWrapper.GetLogger(instanceID).LogInfo("[%s] meowcaller captured incoming call %s from %s", instanceID, call.ID(), call.Peer().String()) + w.callRegistry.Store(instanceID, call) + }) +``` + +(`instanceID` is captured into a local variable before the closure so the closure doesn't capture the loop-mutated `cd` — `cd` itself isn't reused in a loop here, but this keeps the closure's captured value explicit and independent of whatever happens to `cd` later in this same function.) + +- [ ] **Step 5: Clean up the registry when whatsmeow itself reports the call ended** + +Find the existing `case *events.CallTerminate:` block (around line 1939): + +```go + case *events.CallTerminate: + doWebhook = true + postMap["event"] = "CallTerminate" + mycli.loggerWrapper.GetLogger(mycli.userID).LogInfo("[%s] Got call terminate %+v", mycli.userID, evt) +``` + +Add one line so a call that's never answered (or whose stream socket never connects) doesn't leak in the registry forever: + +```go + case *events.CallTerminate: + doWebhook = true + postMap["event"] = "CallTerminate" + mycli.loggerWrapper.GetLogger(mycli.userID).LogInfo("[%s] Got call terminate %+v", mycli.userID, evt) + mycli.service.(*whatsmeowService).callRegistry.Delete(evt.CallID) +``` + +Note the `mycli.service.(*whatsmeowService)` type assertion: `mycli.service` is typed as the `WhatsmeowService` interface (see the `MyClient` struct's `service WhatsmeowService` field), which doesn't expose `callRegistry` — and it shouldn't, nothing outside this file needs to touch the registry directly. The type assertion is safe here because `mycli.service` is always set to `&w` (a `*whatsmeowService`) at construction (see the existing `service: &w,` in the `&MyClient{...}` literal a few dozen lines above `StartClient`'s call-event switch) and this code lives in the same package. + +- [ ] **Step 6: Build just this package** + +```bash +go build ./pkg/whatsmeow/service/... +``` + +Expected: exits 0. (Don't run `go build ./...` yet — `cmd/evolution-go/main.go` still calls the old-arity `NewWhatsmeowService` and won't compile until Task 8 fixes that call site.) + +- [ ] **Step 7: Commit** + +```bash +git add pkg/whatsmeow/service/whatsmeow.go +git commit -m "feat: capture incoming meowcaller calls into the call registry" +``` + +--- + +### Task 4: `AnswerCall` / `HangupCall` / `GetActiveCall` in `pkg/call/service` + +**Files:** +- Modify: `pkg/call/service/call_service.go` + +**Interfaces:** +- Consumes: `call_registry.CallRegistry.Get`/`Delete` (Task 2); `whatsmeow_service.NewWhatsmeowService`'s new `callRegistry` param (Task 3, for the constructor wiring done in Task 8) +- Produces: + - `type AnswerCallStruct struct { CallCreator types.JID; CallID string }` (JSON: `callCreator`, `callId`) + - `type HangupCallStruct struct { CallID string }` (JSON: `callId`) + - `CallService.AnswerCall(data *AnswerCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error)` + - `CallService.HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error` + - `CallService.GetActiveCall(instanceId, callId string) (*meowcaller.Call, error)` — used by `pkg/call/stream` (Task 7) + +No automated test here: `*meowcaller.Call`'s exported methods (`Answer`, `Hangup`, `AcceptVideo`) all dereference an unexported, unset-from-outside-the-package `eng *engine` field — calling them on a zero-value `&meowcaller.Call{}` (the only kind of `Call` this package can construct in a test) panics with a nil pointer dereference. There is no seam to inject a fake without forking meowcaller. This is exactly the kind of external, un-mockable dependency the design spec's Testing section already called out — verified instead by the manual real-call test in Task 9. + +- [ ] **Step 1: Add imports** + +In `pkg/call/service/call_service.go`, add to the import block: + +```go + call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" + "github.com/purpshell/meowcaller" +``` + +- [ ] **Step 2: Add the new struct types** + +Right after the existing `RejectCallStruct` definition: + +```go +type RejectCallStruct struct { + CallCreator types.JID `json:"callCreator"` + CallID string `json:"callId"` +} + +type AnswerCallStruct struct { + CallCreator types.JID `json:"callCreator"` + CallID string `json:"callId"` +} + +type HangupCallStruct struct { + CallID string `json:"callId"` +} +``` + +- [ ] **Step 3: Add `callRegistry` to the service struct and constructor** + +```go +type callService struct { + clientPointer map[string]*whatsmeow.Client + whatsmeowService whatsmeow_service.WhatsmeowService + callRegistry *call_registry.CallRegistry + loggerWrapper *logger_wrapper.LoggerManager +} +``` + +```go +func NewCallService( + clientPointer map[string]*whatsmeow.Client, + whatsmeowService whatsmeow_service.WhatsmeowService, + callRegistry *call_registry.CallRegistry, + loggerWrapper *logger_wrapper.LoggerManager, +) CallService { + return &callService{ + clientPointer: clientPointer, + whatsmeowService: whatsmeowService, + callRegistry: callRegistry, + loggerWrapper: loggerWrapper, + } +} +``` + +- [ ] **Step 4: Extend the `CallService` interface** + +```go +type CallService interface { + RejectCall(data *RejectCallStruct, instance *instance_model.Instance) error + AnswerCall(data *AnswerCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) + HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error + GetActiveCall(instanceId, callId string) (*meowcaller.Call, error) +} +``` + +- [ ] **Step 5: Implement the three methods** + +Add after the existing `RejectCall` method: + +```go +func (c *callService) AnswerCall(data *AnswerCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return nil, errors.New("no pending call with that id") + } + + if err := call.Answer(); err != nil { + logger.LogError("[%s] error answering call: %v", instance.Id, err) + return nil, err + } + + if call.IsVideo() { + if err := call.AcceptVideo(); err != nil { + c.loggerWrapper.GetLogger(instance.Id).LogError("[%s] answered call but failed to accept video: %v", instance.Id, err) + } + } + + return call, nil +} + +func (c *callService) HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + + err := call.Hangup() + c.callRegistry.Delete(data.CallID) + if err != nil { + logger.LogError("[%s] error hanging up call: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) GetActiveCall(instanceId, callId string) (*meowcaller.Call, error) { + call, ok := c.callRegistry.Get(instanceId, callId) + if !ok { + return nil, errors.New("no active call with that id") + } + return call, nil +} +``` + +- [ ] **Step 6: Build just this package** + +```bash +go build ./pkg/call/service/... +``` + +Expected: exits 0. (Don't run `go build ./...` yet — `cmd/evolution-go/main.go` still calls the old 3-argument `NewCallService` and won't compile until Task 8 fixes that call site; building only this package sidesteps that known, temporary gap.) + +- [ ] **Step 7: Commit** + +```bash +git add pkg/call/service/call_service.go +git commit -m "feat: add AnswerCall, HangupCall, GetActiveCall to call service" +``` + +--- + +### Task 5: `AnswerCall` / `HangupCall` handlers in `pkg/call/handler` + +**Files:** +- Modify: `pkg/call/handler/call_handler.go` + +**Interfaces:** +- Consumes: `call_service.CallService.AnswerCall`, `.HangupCall` (Task 4) +- Produces: `CallHandler.AnswerCall(ctx *gin.Context)`, `CallHandler.HangupCall(ctx *gin.Context)` + +- [ ] **Step 1: Extend the `CallHandler` interface** + +```go +type CallHandler interface { + RejectCall(ctx *gin.Context) + AnswerCall(ctx *gin.Context) + HangupCall(ctx *gin.Context) +} +``` + +- [ ] **Step 2: Implement `AnswerCall`** + +Add after the existing `RejectCall` method, following its exact shape: + +```go +// Answer call +// @Summary Answer call +// @Description Answer an incoming call and (if it's a video call) accept its video +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.AnswerCallStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/answer [post] +func (g *callHandler) AnswerCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.AnswerCallStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + _, err = g.callService.AnswerCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} +``` + +- [ ] **Step 3: Implement `HangupCall`** + +```go +// Hangup call +// @Summary Hangup call +// @Description Hangup an active call +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.HangupCallStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/hangup [post] +func (g *callHandler) HangupCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.HangupCallStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.HangupCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} +``` + +- [ ] **Step 4: Build just this package** + +```bash +go build ./pkg/call/handler/... +``` + +Expected: exits 0. + +- [ ] **Step 5: Commit** + +```bash +git add pkg/call/handler/call_handler.go +git commit -m "feat: add answer and hangup call HTTP handlers" +``` + +--- + +### Task 6: Register the new routes + +**Files:** +- Modify: `pkg/routes/routes.go` + +**Interfaces:** +- Consumes: `call_handler.CallHandler.AnswerCall`, `.HangupCall` (Task 5) + +- [ ] **Step 1: Add the two routes to the existing `/call` group** + +Find (around line 192-198): + +```go + routes = eng.Group("/call") + { + routes.Use(r.authMiddleware.Auth) + { + routes.POST("/reject", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.RejectCall) + } + } +``` + +Change to: + +```go + routes = eng.Group("/call") + { + routes.Use(r.authMiddleware.Auth) + { + routes.POST("/reject", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.RejectCall) + routes.POST("/answer", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.AnswerCall) + routes.POST("/hangup", r.callHandler.HangupCall) + } + } +``` + +(`/answer`'s body has a `callCreator` field, same shape as `/reject`, so it gets the same `ValidateNumberField()` call for consistency with its sibling route — note this middleware validates a field literally named `number`, which neither `/reject` nor `/answer` actually send, so in practice it's a no-op passthrough for both; that's pre-existing behavior in this file, not something this task changes. `/hangup`'s body has no JID-shaped field, so it gets no JID middleware, matching how routes without JID fields elsewhere in this file skip it too.) + +`GET /call/stream/:callId` is intentionally **not** added here — it needs query-string apikey auth (WebSocket clients can't always set custom headers), which doesn't fit `authMiddleware.Auth`'s header-only check. Task 7 registers it directly on the `*gin.Engine`, the same way `pkg/passkey/handler` already registers its own public routes outside this file (see `passkey_handler.RegisterRoutes(r, whatsmeowService)` in `cmd/evolution-go/main.go`). + +- [ ] **Step 2: Build just this package** + +```bash +go build ./pkg/routes/... +``` + +Expected: exits 0. + +- [ ] **Step 3: Commit** + +```bash +git add pkg/routes/routes.go +git commit -m "feat: register call answer and hangup routes" +``` + +--- + +### Task 7: `pkg/call/stream` — the WebSocket media bridge + +**Files:** +- Create: `pkg/call/stream/codec.go` +- Test: `pkg/call/stream/codec_test.go` +- Create: `pkg/call/stream/bridge.go` +- Create: `pkg/call/stream/handler.go` + +**Interfaces:** +- Consumes: `call_service.CallService.GetActiveCall` (Task 4); `instance_service.InstanceService.GetInstanceByToken` (existing); `meowcaller.SampleRate`, `meowcaller.AudioSink`, `meowcaller.AudioSource`, `meowcaller.VideoSink`, `meowcaller.Call.{Receive,ReceiveVideo,Play,OnEnd,Hangup,IsVideo,ID}` (external library) +- Produces: `call_stream.RegisterRoutes(r *gin.Engine, callService call_service.CallService, instanceService instance_service.InstanceService)` + +#### Part A: pure PCM16LE ⇄ float32 conversion (TDD, no I/O) + +- [ ] **Step 1: Write the failing test** + +```go +// pkg/call/stream/codec_test.go +package call_stream + +import "testing" + +func TestPCM16RoundTrip(t *testing.T) { + frame := []float32{0, 0.5, -0.5, 1, -1, 0.25} + + pcm := pcm16FromFloat32(frame) + if len(pcm) != len(frame)*2 { + t.Fatalf("expected %d bytes, got %d", len(frame)*2, len(pcm)) + } + + back := float32FromPCM16(pcm) + if len(back) != len(frame) { + t.Fatalf("expected %d samples back, got %d", len(frame), len(back)) + } + + for i, want := range frame { + got := back[i] + diff := got - want + if diff < 0 { + diff = -diff + } + if diff > 0.001 { + t.Errorf("sample %d: want %v, got %v (diff %v)", i, want, got, diff) + } + } +} + +func TestPCM16ClampsOutOfRange(t *testing.T) { + frame := []float32{2.0, -2.0} // out of [-1, 1] range + pcm := pcm16FromFloat32(frame) + back := float32FromPCM16(pcm) + + if back[0] < 0.99 { + t.Errorf("expected clamp to max positive, got %v", back[0]) + } + if back[1] > -0.99 { + t.Errorf("expected clamp to max negative, got %v", back[1]) + } +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `go test ./pkg/call/stream/... -v` +Expected: FAIL — `pcm16FromFloat32`/`float32FromPCM16` undefined. + +- [ ] **Step 3: Write the implementation** + +```go +// pkg/call/stream/codec.go +package call_stream + +import "encoding/binary" + +// pcm16FromFloat32 converts one mono PCM frame (as meowcaller delivers it: float32 +// samples in [-1, 1]) into little-endian 16-bit PCM bytes, clamping out-of-range +// samples the same way meowcaller's own WAVRecorder does. +func pcm16FromFloat32(frame []float32) []byte { + out := make([]byte, len(frame)*2) + for i, s := range frame { + v := s * 32768.0 + if v > 32767 { + v = 32767 + } else if v < -32768 { + v = -32768 + } + binary.LittleEndian.PutUint16(out[2*i:], uint16(int16(v))) + } + return out +} + +// float32FromPCM16 converts little-endian 16-bit PCM bytes (as sent by a stream +// consumer) back into mono float32 samples in [-1, 1] for meowcaller.Call.Play. +func float32FromPCM16(b []byte) []float32 { + n := len(b) / 2 + out := make([]float32, n) + for i := 0; i < n; i++ { + v := int16(binary.LittleEndian.Uint16(b[2*i:])) + out[i] = float32(v) / 32768.0 + } + return out +} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `go test ./pkg/call/stream/... -v` +Expected: PASS (2 tests) + +- [ ] **Step 5: Commit** + +```bash +git add pkg/call/stream/codec.go pkg/call/stream/codec_test.go +git commit -m "feat: add PCM16LE/float32 conversion for call media stream" +``` + +#### Part B: the bridge (implements AudioSink + VideoSink + AudioSource) + +- [ ] **Step 1: Write the bridge** + +```go +// pkg/call/stream/bridge.go +package call_stream + +import ( + "encoding/base64" + "io" + "sync" + + "github.com/gorilla/websocket" + "github.com/purpshell/meowcaller" +) + +// wsMessage is the JSON envelope carried over the stream socket, modeled on Twilio +// Media Streams so existing AI-voice integrations need minimal adapting. +type wsMessage struct { + Event string `json:"event"` + CallID string `json:"callId,omitempty"` + SampleRate int `json:"sampleRate,omitempty"` + Video bool `json:"video,omitempty"` + Track string `json:"track,omitempty"` + Payload string `json:"payload,omitempty"` + Reason string `json:"reason,omitempty"` +} + +// bridge adapts one WebSocket connection to meowcaller's AudioSink (Call.Receive), +// VideoSink (Call.ReceiveVideo), and AudioSource (Call.Play) interfaces, so a single +// object plugs a call's media straight into the socket in both directions. +type bridge struct { + conn *websocket.Conn + writeMu sync.Mutex + incoming chan []float32 + closed chan struct{} + closeOnce sync.Once +} + +func newBridge(conn *websocket.Conn) *bridge { + return &bridge{ + conn: conn, + // ~3 seconds of buffering at one 60ms frame per slot before frames start + // getting dropped — enough slack for scheduling jitter without unbounded growth. + incoming: make(chan []float32, 50), + closed: make(chan struct{}), + } +} + +func (b *bridge) writeJSON(msg wsMessage) error { + b.writeMu.Lock() + defer b.writeMu.Unlock() + return b.conn.WriteJSON(msg) +} + +// writeStart sends the initial handshake message once the socket is up. +func (b *bridge) writeStart(callID string, video bool) { + _ = b.writeJSON(wsMessage{ + Event: "start", + CallID: callID, + SampleRate: meowcaller.SampleRate, + Video: video, + }) +} + +// WriteFrame implements meowcaller.AudioSink: one decoded mono frame from the peer. +func (b *bridge) WriteFrame(frame []float32) error { + payload := base64.StdEncoding.EncodeToString(pcm16FromFloat32(frame)) + return b.writeJSON(wsMessage{Event: "media", Track: "inbound", Payload: payload}) +} + +// WriteVideo implements meowcaller.VideoSink: one Annex-B H.264 access unit. +func (b *bridge) WriteVideo(accessUnit []byte) error { + payload := base64.StdEncoding.EncodeToString(accessUnit) + return b.writeJSON(wsMessage{Event: "video", Track: "inbound", Payload: payload}) +} + +// ReadFrame implements meowcaller.AudioSource: frames the consumer sent back over the +// socket, decoded by readLoop and handed here on demand. +func (b *bridge) ReadFrame() ([]float32, error) { + select { + case frame, ok := <-b.incoming: + if !ok { + return nil, io.EOF + } + return frame, nil + case <-b.closed: + return nil, io.EOF + } +} + +// Close satisfies AudioSink/VideoSink/AudioSource's shared Close() error method. Safe +// to call more than once (from the call's OnEnd callback and from readLoop exiting). +func (b *bridge) Close() error { + b.closeOnce.Do(func() { + _ = b.writeJSON(wsMessage{Event: "stop", Reason: "hangup"}) + close(b.closed) + _ = b.conn.Close() + }) + return nil +} + +// readLoop blocks reading consumer-sent media messages until the connection closes +// (by either side) or send Close(). Every non-media message is ignored rather than +// erroring, so the wire format can grow new event types without breaking old clients. +func (b *bridge) readLoop() { + for { + var msg wsMessage + if err := b.conn.ReadJSON(&msg); err != nil { + b.Close() + return + } + if msg.Event != "media" || msg.Track != "outbound" { + continue + } + raw, err := base64.StdEncoding.DecodeString(msg.Payload) + if err != nil { + continue + } + frame := float32FromPCM16(raw) + select { + case b.incoming <- frame: + case <-b.closed: + return + default: + // Consumer is sending audio faster than the call can play it out; drop + // the frame rather than block the socket read loop. + } + } +} +``` + +- [ ] **Step 2: Build** + +```bash +go build ./pkg/call/stream/... +``` + +Expected: exits 0. + +- [ ] **Step 3: Commit** + +```bash +git add pkg/call/stream/bridge.go +git commit -m "feat: add WebSocket bridge implementing meowcaller media interfaces" +``` + +#### Part C: the HTTP/WS handler + +- [ ] **Step 1: Write the handler** + +```go +// pkg/call/stream/handler.go +package call_stream + +import ( + "net/http" + + call_service "github.com/evolution-foundation/evolution-go/pkg/call/service" + instance_service "github.com/evolution-foundation/evolution-go/pkg/instance/service" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { return true }, +} + +// RegisterRoutes mounts GET /call/stream/:callId directly on the engine, bypassing the +// header-based authMiddleware chain used by pkg/routes: WebSocket clients (especially +// browser-based ones) can't always set a custom apikey header on the upgrade request, +// so auth here is a query parameter instead, resolved the same way authMiddleware.Auth +// resolves it. This mirrors how pkg/passkey/handler.RegisterRoutes already registers +// its own routes directly on *gin.Engine for the same "doesn't fit the standard +// middleware chain" reason. +func RegisterRoutes(r *gin.Engine, callService call_service.CallService, instanceService instance_service.InstanceService) { + r.GET("/call/stream/:callId", serveStream(callService, instanceService)) +} + +func serveStream(callService call_service.CallService, instanceService instance_service.InstanceService) gin.HandlerFunc { + return func(ctx *gin.Context) { + instance, err := instanceService.GetInstanceByToken(ctx.Query("apikey")) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "not authorized"}) + return + } + + callID := ctx.Param("callId") + call, err := callService.GetActiveCall(instance.Id, callID) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + + conn, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil) + if err != nil { + return + } + + b := newBridge(conn) + call.OnEnd(func(reason string) { b.Close() }) + call.Receive(b) + call.ReceiveVideo(b) + call.Play(b) + + b.writeStart(callID, call.IsVideo()) + b.readLoop() // blocks until the socket closes, from either end + + _ = call.Hangup() + } +} +``` + +- [ ] **Step 2: Build just this package** + +```bash +go build ./pkg/call/stream/... +``` + +Expected: exits 0. + +- [ ] **Step 3: Commit** + +```bash +git add pkg/call/stream/handler.go +git commit -m "feat: add call stream HTTP/WebSocket handler" +``` + +--- + +### Task 8: Wire everything together in `main.go` + +**Files:** +- Modify: `cmd/evolution-go/main.go` + +**Interfaces:** +- Consumes: `call_registry.NewCallRegistry` (Task 2), `whatsmeow_service.NewWhatsmeowService`'s new param (Task 3), `call_service.NewCallService`'s new param (Task 4), `call_stream.RegisterRoutes` (Task 7) + +- [ ] **Step 1: Add imports** + +```go + call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" + call_stream "github.com/evolution-foundation/evolution-go/pkg/call/stream" +``` + +- [ ] **Step 2: Create the shared registry alongside `clientPointer`** + +Find (around line 87): + +```go + killChannel := make(map[string](chan bool)) + clientPointer := make(map[string]*whatsmeow.Client) +``` + +Change to: + +```go + killChannel := make(map[string](chan bool)) + clientPointer := make(map[string]*whatsmeow.Client) + callRegistry := call_registry.NewCallRegistry() +``` + +- [ ] **Step 3: Pass it into `NewWhatsmeowService`** + +Find the `whatsmeowService := whatsmeow_service.NewWhatsmeowService(...)` call (around line 165) and add `callRegistry,` as the new second-to-last argument (matching the parameter position added in Task 3 Step 3): + +```go + whatsmeowService := whatsmeow_service.NewWhatsmeowService( + instanceRepository, + authDB, + message_repository.NewMessageRepository(db), + labelRepository, + config, + killChannel, + clientPointer, + rabbitmqProducer, + webhookProducer, + websocketProducer, + sqliteDB, + exPath, + mediaStorage, + natsProducer, + callRegistry, + loggerWrapper, + ) +``` + +- [ ] **Step 4: Pass it into `NewCallService`** + +Find (around line 195): + +```go + callService := call_service.NewCallService(clientPointer, whatsmeowService, loggerWrapper) +``` + +Change to: + +```go + callService := call_service.NewCallService(clientPointer, whatsmeowService, callRegistry, loggerWrapper) +``` + +- [ ] **Step 5: Register the stream route** + +Find the existing: + +```go + passkey_handler.RegisterRoutes(r, whatsmeowService) +``` + +Add right after it: + +```go + call_stream.RegisterRoutes(r, callService, instanceService) +``` + +(`instanceService` is already constructed a few lines above this point in the same function.) + +- [ ] **Step 6: Build** + +```bash +go build ./... +``` + +Expected: exits 0 — this is the point where every wiring gap from Tasks 4-7 gets closed. + +- [ ] **Step 7: Run the full test suite** + +```bash +go test ./... +``` + +Expected: PASS across the repo (including the pre-existing 4 test files and the new tests from Tasks 2 and 7). + +- [ ] **Step 8: Format and lint** + +```bash +make fmt +make lint +``` + +Expected: both exit 0. If `make fmt` rewrites anything, re-run `go build ./...` and `go test ./...` once more before committing. + +- [ ] **Step 9: Commit** + +```bash +git add cmd/evolution-go/main.go +git commit -m "feat: wire call registry and stream route into main" +``` + +--- + +### Task 9: Manual end-to-end validation and PR prep + +**Files:** +- Modify: `docs/superpowers/plans/2026-07-29-call-answer-stream.md` (check off as validated) + +This is the step that actually proves the feature works — everything up to here only proves it compiles and the pure-logic pieces are correct. Do not open the PR before this passes. + +- [ ] **Step 1: Run the server locally against a real test instance** + +Follow the repo's existing local-run instructions (`README.md` / `docker/`) to start Evolution Go pointed at a WhatsApp test number you control, and confirm the instance shows `connected: true`. + +- [ ] **Step 2: Trigger an incoming call** + +From a second phone, place a WhatsApp voice call to the test number. Confirm (via logs) the line added in Task 3 Step 4 fires: + +``` +[] meowcaller captured incoming call from +``` + +- [ ] **Step 3: Answer it via the API** + +```bash +curl -X POST http://localhost:/call/answer \ + -H "apikey: " \ + -H "Content-Type: application/json" \ + -d '{"callCreator": "", "callId": ""}' +``` + +Expected: `{"message":"success"}`, and the call actually connects on the calling phone (no more "Connecting…"). + +- [ ] **Step 4: Connect a throwaway WS client and confirm audio** + +Use any small script (Python `websockets`, `wscat`, etc.) to connect to `ws://localhost:/call/stream/?apikey=`, write every `{"event":"media","track":"inbound",...}` message's decoded, base64-decoded, PCM16LE payload to a raw file, then convert that raw file to WAV (16-bit, mono, 16000 Hz) with any audio tool. Speak into the calling phone during the call. Confirm the resulting WAV is intelligible speech. + +- [ ] **Step 5: Confirm hangup behavior both ways** + +- Call `POST /call/hangup` with the same `callId` — confirm the call actually ends on the calling phone, and the WS connection receives `{"event":"stop","reason":"hangup"}` and closes. +- On a second test call, hang up from the *calling phone* instead — confirm the WS connection closes on its own (via `Call.OnEnd` → `bridge.Close()`) without needing `/call/hangup`. + +- [ ] **Step 6: Update Swagger** + +```bash +make swagger +git add docs/ +git commit -m "docs: regenerate swagger for call answer/hangup endpoints" +``` + +- [ ] **Step 7: Push the branch and open the PR** + +```bash +git push -u origin feature/call-answer-stream +gh pr create \ + --repo evolution-foundation/evolution-go \ + --title "feat: answer WhatsApp calls and stream their media over WebSocket" \ + --body "$(cat <<'EOF' +## Summary + +- Adds `POST /call/answer` and `POST /call/hangup`, alongside the existing `POST /call/reject`. +- Adds `GET /call/stream/:callId`, a dedicated per-call WebSocket that carries the + call's audio (and inbound video) as base64 PCM16LE/H.264 frames, in a JSON envelope + modeled on Twilio Media Streams. Sending `{"event":"media","track":"outbound",...}` + back over the same socket plays audio into the call (e.g. TTS output). +- This PR ships transport/plumbing only — no AI/STT/LLM/TTS logic lives here. What's on + the other end of the WebSocket (an AI voice pipeline, a recorder, a human console) is + entirely up to the consumer. + +## Why + +`go.mau.fi/whatsmeow` (this project's WhatsApp protocol library) has never implemented +accepting a call or handling its media — only rejecting. Building that from scratch is a +multi-year reverse-engineering effort (see `tulir/whatsmeow#555`). +[`purpshell/meowcaller`](https://github.com/purpshell/meowcaller) (MIT-licensed, pure Go, +actively maintained) already did that work as an independent interoperability research +project — see its [DISCLAIMER.md](https://github.com/purpshell/meowcaller/blob/main/DISCLAIMER.md) +for its scope and ground rules. This PR wires it into Evolution Go's existing per-instance +client lifecycle. + +## How it's wired + +`meowcaller.NewClient` is constructed the moment each instance's `*whatsmeow.Client` is +created, before `.Connect()` (required by the library). Incoming calls are captured via +`OnIncomingCall` into a small new `pkg/call/registry` package, scoped by instance so one +instance's apikey can't reach another instance's call. `pkg/call/service` answers/hangs +up by looking calls up in that registry. `pkg/call/stream` bridges a call's audio/video +sinks and source to the WebSocket. + +## Test plan + +- [x] Unit tests for the call registry (`pkg/call/registry`) and PCM16LE/float32 + conversion (`pkg/call/stream`) +- [x] `go build ./...` and `go test ./...` pass +- [x] `make fmt` / `make lint` clean +- [x] Manually verified against a real WhatsApp call: answered via the API, recorded + intelligible audio from the stream socket, confirmed hangup both via the API and + via the remote end hanging up first +EOF +)" +``` + +- [ ] **Step 8: Check off validation in this plan** + +Edit this file's Task 9 checkboxes to `[x]` once every step above has actually been run and passed, and commit that update too. + +--- + +## Self-Review Notes + +- **Spec coverage:** every section of `docs/superpowers/specs/2026-07-29-call-answer-stream-design.md` maps to a task — architecture/constraint (Task 3), components (Tasks 2, 4, 5, 6, 7), wire format (Task 7 Part B), auth (Task 7 Part C), lifecycle/error handling (Tasks 3 Step 5, 4 Step 5, 7 Part B `Close`/`OnEnd`), testing (Tasks 2, 7 Part A automated; Task 9 manual), PR plan (Task 9 Steps 6-7). +- **Type consistency checked:** `AnswerCallStruct`/`HangupCallStruct` (Task 4) match what Task 5's handlers bind into; `CallService` interface additions (Task 4 Step 4) match the concrete methods implemented in the same task and the calls made from Task 7's handler; `call_registry.CallRegistry`'s `Store(instanceID string, call *meowcaller.Call)`/`Get(instanceID, callID string)`/`Delete(callID string)` signatures are identical everywhere they're called (Tasks 3, 4). +- **No placeholders:** every step has complete, real code — the only two forward references (`NewCallService`'s call site in `main.go`, fixed in Task 8; the intermediate `go build` failures in Tasks 4-7) are explicitly called out as expected and temporary, with the exact fixing task named. From f6e4700cf7fb6c5e1146c5faeca983e37ed169db Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:16:41 +0000 Subject: [PATCH 03/26] chore: ignore local subagent-driven-development scratch dir --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 03ad15e9..0b52a157 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ coverage.* .idea/ .vscode/ .DS_Store +.superpowers/ From ad10bc346e489bcc82e26145d10395abf937a152 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:18:53 +0000 Subject: [PATCH 04/26] feat: add meowcaller dependency for WhatsApp call media --- go.mod | 20 ++++++++++---------- go.sum | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index c1c97f6a..6cf31761 100644 --- a/go.mod +++ b/go.mod @@ -21,10 +21,10 @@ require ( github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.3 github.com/vincent-petithory/dataurl v1.0.0 - go.mau.fi/whatsmeow v0.0.0-20260630180629-b572e5bcb92b - golang.org/x/exp v0.0.0-20260611194520-c48552f49976 + go.mau.fi/whatsmeow v0.0.0-20260722203353-e9a033b24933 + golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 golang.org/x/image v0.0.0-20211028202545-6944b10bf410 - golang.org/x/net v0.56.0 + golang.org/x/net v0.57.0 google.golang.org/protobuf v1.36.11 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gorm.io/driver/postgres v1.5.9 @@ -75,7 +75,7 @@ require ( github.com/nats-io/nuid v1.0.1 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect + github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -84,13 +84,13 @@ require ( github.com/ugorji/go/codec v1.2.12 // indirect github.com/vektah/gqlparser/v2 v2.5.27 // indirect go.mau.fi/libsignal v0.2.2 // indirect - go.mau.fi/util v0.9.10 // indirect + go.mau.fi/util v0.9.12-0.20260717235539-f9ffa7eca58d // indirect golang.org/x/arch v0.10.0 // indirect - golang.org/x/crypto v0.53.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/text v0.38.0 // indirect - golang.org/x/tools v0.46.0 // indirect + golang.org/x/crypto v0.54.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/text v0.40.0 // indirect + golang.org/x/tools v0.48.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.55.3 // indirect diff --git a/go.sum b/go.sum index c8e3eefc..dfc2018c 100644 --- a/go.sum +++ b/go.sum @@ -111,8 +111,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.45 h1:6KA/spDguL3KV8rnybG7ezSaE4SeMR3KC9VbUoAQaIk= -github.com/mattn/go-sqlite3 v1.14.45/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= +github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs= +github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.80 h1:2mdUHXEykRdY/BigLt3Iuu1otL0JTogT0Nmltg0wujk= @@ -134,8 +134,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM= -github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca h1:GHSUVE4yOgX4E7kTRzpxCPbCOYkd3Kj8Dgdod30OI1E= +github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= @@ -179,35 +179,35 @@ github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mau.fi/libsignal v0.2.2 h1:QV+XdzQkm3x3aSG7FcqfGSZuFXz83pRZPBFaPygHbOU= go.mau.fi/libsignal v0.2.2/go.mod h1:CRlIQg2J8uYTfDFvNoO8/KcZjs5cey0vbc6oj/bssY0= -go.mau.fi/util v0.9.10 h1:wzvz5iDHyqDXB8vgisD4d3SzucLXNM3iNY+1O1RoHtg= -go.mau.fi/util v0.9.10/go.mod h1:YQOxySn+ZE3qSYqNxvyX7Yi3suA8YK17PS6QqBREW7A= -go.mau.fi/whatsmeow v0.0.0-20260630180629-b572e5bcb92b h1:ZUk1ErarDNpnbosXR/MeOz2gkqA4S1bh8zjaSRj7N+Y= -go.mau.fi/whatsmeow v0.0.0-20260630180629-b572e5bcb92b/go.mod h1:9dmNTYZ/1pHjPw/bz+azBsGjAkcrZbqzMrKcvG5bJ8U= +go.mau.fi/util v0.9.12-0.20260717235539-f9ffa7eca58d h1:bUGRidYrauEwLoBvGLLPPQ0lgQUecT0z/ND+vHz07jM= +go.mau.fi/util v0.9.12-0.20260717235539-f9ffa7eca58d/go.mod h1:xunp/oIQfFD68HHcNHfG0pOiHkvEtDhTweeIwKJ//+Q= +go.mau.fi/whatsmeow v0.0.0-20260722203353-e9a033b24933 h1:7skZGs9q+rWKqYHok4ZufzhKpf6GmTKZnTjSm0aDtus= +go.mau.fi/whatsmeow v0.0.0-20260722203353-e9a033b24933/go.mod h1:Iy/xVSuVU2payR26MB1hv0UZUWRraEn4qKZ7+VRHulg= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= -golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M= -golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY= +golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= +golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 h1:qLvzZeaANDgyVOA8pyHCOStGlXn0rseXma+GQjeuv2g= +golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q= golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -215,8 +215,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -225,13 +225,13 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= -golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= From 404a7571acf296d10f8a1ca0be995bed9466bac9 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:21:23 +0000 Subject: [PATCH 05/26] =?UTF-8?q?docs:=20fix=20plan=20bug=20=E2=80=94=20go?= =?UTF-8?q?=20mod=20tidy=20strips=20unused=20meowcaller=20require?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 1 originally ran `go mod tidy` right after `go get`, before any .go file imports meowcaller. tidy removes require entries nothing imports, so it silently deleted the dependency the get had just added, and go build still passed (nothing references the module). Caught by the Task 1 reviewer, who checked go.mod directly instead of trusting the implementer's report. Moved the real tidy to Task 8, after Tasks 3/4/7 add actual imports. --- .../plans/2026-07-29-call-answer-stream.md | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/plans/2026-07-29-call-answer-stream.md b/docs/superpowers/plans/2026-07-29-call-answer-stream.md index 21a8b77f..8bf7503c 100644 --- a/docs/superpowers/plans/2026-07-29-call-answer-stream.md +++ b/docs/superpowers/plans/2026-07-29-call-answer-stream.md @@ -34,15 +34,30 @@ cd /home/rarosh/projetos/evolution-go go get github.com/purpshell/meowcaller@latest ``` -- [ ] **Step 2: Tidy and verify the whatsmeow bump didn't break anything** +- [ ] **Step 2: Verify the whatsmeow bump didn't break anything** + +**Do NOT run `go mod tidy` in this task.** No `.go` file imports `meowcaller` yet — that +starts in Task 3 — and `go mod tidy` removes `require` entries for modules nothing in +the module actually imports. Run it now and it will silently delete the line `go get` +just added, and `go build ./...` will still pass (nothing references the module, so its +absence doesn't break compilation) — meaning a clean build here is not proof the +dependency is actually present. Confirm it explicitly instead: + +```bash +grep meowcaller go.mod +``` + +Expected: one line, `github.com/purpshell/meowcaller v0.0.0-...`. If it's not there, the +`go get` in Step 1 didn't take — re-run it and check again before moving on. ```bash -go mod tidy go build ./... ``` Expected: exits 0. If it fails, the failures will be in `pkg/whatsmeow/service/whatsmeow.go` from whatsmeow API drift between the pinned versions (2026-06-30 → 2026-07-22) — read the compiler errors, they'll name the exact symbols that moved; fix those call sites before continuing (do not downgrade whatsmeow back down, meowcaller requires the newer floor). +(Task 8 Step 6-7, once `meowcaller` is actually imported by real code, is the right time to run `go mod tidy` — it will no longer have anything unused to strip.) + - [ ] **Step 3: Commit** ```bash @@ -1095,7 +1110,19 @@ Add right after it: (`instanceService` is already constructed a few lines above this point in the same function.) -- [ ] **Step 6: Build** +- [ ] **Step 6: Tidy modules now that `meowcaller` is actually imported, then build** + +This is the first point in the plan where real code imports `meowcaller` (Tasks 3, 4, +and 7 all added imports of it), so `go mod tidy` is now safe to run — it has something +to keep. Task 1 deliberately skipped this step for exactly that reason. + +```bash +go mod tidy +grep meowcaller go.mod +``` + +Expected: the `grep` still shows the `github.com/purpshell/meowcaller` line (confirming +`tidy` kept it now that it's actually used). ```bash go build ./... From 34e038cc2186eb9528efeaf2261a0dba2b4e2771 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:22:17 +0000 Subject: [PATCH 06/26] fix: actually add meowcaller to go.mod The previous commit (ad10bc3) claimed to add github.com/purpshell/meowcaller but ran go mod tidy immediately after go get, which silently stripped the require line since nothing imports the module yet. Re-added without running tidy (deferred to Task 8, once real imports exist). --- go.mod | 9 +++++++++ go.sum | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/go.mod b/go.mod index 6cf31761..0aab6def 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.22.0 // indirect github.com/goccy/go-json v0.10.3 // indirect + github.com/hajimehoshi/go-mp3 v0.3.4 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect @@ -76,6 +77,14 @@ require ( github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca // indirect + github.com/pion/datachannel v1.6.0 // indirect + github.com/pion/dtls/v3 v3.1.2 // indirect + github.com/pion/logging v0.2.4 // indirect + github.com/pion/opus v0.1.0 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/sctp v1.9.4 // indirect + github.com/pion/transport/v4 v4.0.1 // indirect + github.com/purpshell/meowcaller v0.0.0-20260726180203-6d9b7b2c1807 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/xid v1.6.0 // indirect diff --git a/go.sum b/go.sum index dfc2018c..7ef4e7df 100644 --- a/go.sum +++ b/go.sum @@ -69,6 +69,9 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hajimehoshi/go-mp3 v0.3.4 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68= +github.com/hajimehoshi/go-mp3 v0.3.4/go.mod h1:fRtZraRFcWb0pu7ok0LqyFhCUrPeMsGRSVop0eemFmo= +github.com/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -136,8 +139,24 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca h1:GHSUVE4yOgX4E7kTRzpxCPbCOYkd3Kj8Dgdod30OI1E= github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= +github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= +github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= +github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= +github.com/pion/opus v0.1.0 h1:GgK/a3DNDrffKjUFsK39rZKqfv7bQ2S2eqRKt0BnqAE= +github.com/pion/opus v0.1.0/go.mod h1:t5Xog2n682JnawoykACE6nKVmupFvmJvkpM7x6bTv6g= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/sctp v1.9.4 h1:cMxEu0F5tbP4qH07bKf1Zjf4rUih9LIo0qQt424e258= +github.com/pion/sctp v1.9.4/go.mod h1:N20Dq6LY+JvJDAh9VVh1JELngb2rQ8dPgds5yBWiPgw= +github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o= +github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/purpshell/meowcaller v0.0.0-20260726180203-6d9b7b2c1807 h1:SnLX76CnagumooXRm63BK9Rn2/e/Th6aWWJJKTqOk2k= +github.com/purpshell/meowcaller v0.0.0-20260726180203-6d9b7b2c1807/go.mod h1:kSME01MaSkwul6tSmExmgBWUOmfkw3DNpfnozsn01eE= github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -212,6 +231,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 79ab4f34388d5d731b638540f790b3f4566b0793 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:25:14 +0000 Subject: [PATCH 07/26] feat: add call registry for tracking answerable meowcaller calls --- pkg/call/registry/call_registry.go | 53 +++++++++++++++++++++++++ pkg/call/registry/call_registry_test.go | 52 ++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 pkg/call/registry/call_registry.go create mode 100644 pkg/call/registry/call_registry_test.go diff --git a/pkg/call/registry/call_registry.go b/pkg/call/registry/call_registry.go new file mode 100644 index 00000000..16a35f38 --- /dev/null +++ b/pkg/call/registry/call_registry.go @@ -0,0 +1,53 @@ +package call_registry + +import ( + "sync" + + "github.com/purpshell/meowcaller" +) + +// entry pairs a live call with the instance it belongs to, so Get can refuse to hand +// back a call to a caller authenticated as a different instance. +type entry struct { + instanceID string + call *meowcaller.Call +} + +// CallRegistry tracks in-progress meowcaller calls by call ID, scoped by instance. +// It is written from the whatsmeow event-handling goroutine (on incoming call) and +// read/written from HTTP handler goroutines (answer/hangup/stream), so all access is +// mutex-guarded. +type CallRegistry struct { + mu sync.RWMutex + entries map[string]entry +} + +// NewCallRegistry returns an empty registry. +func NewCallRegistry() *CallRegistry { + return &CallRegistry{entries: make(map[string]entry)} +} + +// Store records call under its own ID (meowcaller.Call.ID()), tagged with instanceID. +func (r *CallRegistry) Store(instanceID string, call *meowcaller.Call) { + r.mu.Lock() + defer r.mu.Unlock() + r.entries[call.ID()] = entry{instanceID: instanceID, call: call} +} + +// Get returns the call for callID, but only if it was stored under instanceID. +func (r *CallRegistry) Get(instanceID, callID string) (*meowcaller.Call, bool) { + r.mu.RLock() + defer r.mu.RUnlock() + e, ok := r.entries[callID] + if !ok || e.instanceID != instanceID { + return nil, false + } + return e.call, true +} + +// Delete removes callID regardless of which instance it belongs to. +func (r *CallRegistry) Delete(callID string) { + r.mu.Lock() + defer r.mu.Unlock() + delete(r.entries, callID) +} diff --git a/pkg/call/registry/call_registry_test.go b/pkg/call/registry/call_registry_test.go new file mode 100644 index 00000000..339a20ce --- /dev/null +++ b/pkg/call/registry/call_registry_test.go @@ -0,0 +1,52 @@ +package call_registry + +import ( + "testing" + + "github.com/purpshell/meowcaller" +) + +func TestStoreAndGet(t *testing.T) { + r := NewCallRegistry() + call := &meowcaller.Call{} + + r.Store("instance-a", call) + + got, ok := r.Get("instance-a", callIDOf(call)) + if !ok { + t.Fatal("expected call to be found") + } + if got != call { + t.Fatal("expected the same call pointer back") + } +} + +func TestGetWrongInstanceFails(t *testing.T) { + r := NewCallRegistry() + call := &meowcaller.Call{} + r.Store("instance-a", call) + + _, ok := r.Get("instance-b", callIDOf(call)) + if ok { + t.Fatal("expected lookup from a different instance to fail") + } +} + +func TestDeleteRemovesEntry(t *testing.T) { + r := NewCallRegistry() + call := &meowcaller.Call{} + r.Store("instance-a", call) + r.Delete(callIDOf(call)) + + _, ok := r.Get("instance-a", callIDOf(call)) + if ok { + t.Fatal("expected entry to be gone after Delete") + } +} + +// callIDOf mirrors what CallRegistry.Store keys entries by: meowcaller.Call.ID(). +// A zero-value *meowcaller.Call has an empty string ID, which is a perfectly valid +// (if degenerate) key for exercising Store/Get/Delete without a live call. +func callIDOf(call *meowcaller.Call) string { + return call.ID() +} From 4435c644868a22a204b04b785fb967cf36eed973 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:29:34 +0000 Subject: [PATCH 08/26] feat: capture incoming meowcaller calls into the call registry --- pkg/whatsmeow/service/whatsmeow.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/whatsmeow/service/whatsmeow.go b/pkg/whatsmeow/service/whatsmeow.go index 366f0edb..fc4aef8b 100644 --- a/pkg/whatsmeow/service/whatsmeow.go +++ b/pkg/whatsmeow/service/whatsmeow.go @@ -23,6 +23,7 @@ import ( _ "github.com/lib/pq" "github.com/patrickmn/go-cache" + "github.com/purpshell/meowcaller" "github.com/skip2/go-qrcode" "go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow/appstate" @@ -34,6 +35,7 @@ import ( "go.mau.fi/whatsmeow/types/events" waLog "go.mau.fi/whatsmeow/util/log" + call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" "github.com/evolution-foundation/evolution-go/pkg/config" producer_interfaces "github.com/evolution-foundation/evolution-go/pkg/events/interfaces" instance_model "github.com/evolution-foundation/evolution-go/pkg/instance/model" @@ -86,6 +88,8 @@ type whatsmeowService struct { killChannel map[string](chan bool) userInfoCache *cache.Cache clientPointer map[string]*whatsmeow.Client + meowcallerPointer map[string]*meowcaller.Client + callRegistry *call_registry.CallRegistry myClientPointer map[string]*MyClient rabbitmqProducer producer_interfaces.Producer webhookProducer producer_interfaces.Producer @@ -414,6 +418,16 @@ func (w whatsmeowService) StartClient(cd *ClientData) { w.clientPointer[cd.Instance.Id] = client + // meowcaller.NewClient must run before client.Connect() — it installs the raw + // stanza adapter, and doing so after Connect() is a documented race. + meowcallerClient := meowcaller.NewClient(client) + w.meowcallerPointer[cd.Instance.Id] = meowcallerClient + instanceID := cd.Instance.Id + meowcallerClient.OnIncomingCall(func(call *meowcaller.Call) { + w.loggerWrapper.GetLogger(instanceID).LogInfo("[%s] meowcaller captured incoming call %s from %s", instanceID, call.ID(), call.Peer().String()) + w.callRegistry.Store(instanceID, call) + }) + if cd.IsProxy { var proxyConfig ProxyConfig err := json.Unmarshal([]byte(cd.Instance.Proxy), &proxyConfig) @@ -1940,6 +1954,7 @@ func (mycli *MyClient) myEventHandler(rawEvt interface{}) { doWebhook = true postMap["event"] = "CallTerminate" mycli.loggerWrapper.GetLogger(mycli.userID).LogInfo("[%s] Got call terminate %+v", mycli.userID, evt) + mycli.service.(*whatsmeowService).callRegistry.Delete(evt.CallID) case *events.CallOfferNotice: doWebhook = true postMap["event"] = "CallOfferNotice" @@ -2805,6 +2820,7 @@ func NewWhatsmeowService( exPath string, mediaStorage storage_interfaces.MediaStorage, natsProducer producer_interfaces.Producer, + callRegistry *call_registry.CallRegistry, loggerWrapper *logger_wrapper.LoggerManager, ) WhatsmeowService { // Inicializar PollService de forma segura @@ -2820,6 +2836,8 @@ func NewWhatsmeowService( killChannel: killChannel, userInfoCache: cache.New(5*time.Minute, 10*time.Minute), clientPointer: clientPointer, + meowcallerPointer: make(map[string]*meowcaller.Client), + callRegistry: callRegistry, myClientPointer: make(map[string]*MyClient), rabbitmqProducer: rabbitmqProducer, webhookProducer: webhookProducer, From 5b0f9899c525c3e2889b6bfb2437de79fdf54744 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:34:28 +0000 Subject: [PATCH 09/26] feat: add AnswerCall, HangupCall, GetActiveCall to call service --- pkg/call/service/call_service.go | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index 3c14a948..b2c79158 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -5,21 +5,27 @@ import ( "errors" "time" + call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" instance_model "github.com/evolution-foundation/evolution-go/pkg/instance/model" logger_wrapper "github.com/evolution-foundation/evolution-go/pkg/logger" whatsmeow_service "github.com/evolution-foundation/evolution-go/pkg/whatsmeow/service" "github.com/gomessguii/logger" + "github.com/purpshell/meowcaller" "go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow/types" ) type CallService interface { RejectCall(data *RejectCallStruct, instance *instance_model.Instance) error + AnswerCall(data *AnswerCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) + HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error + GetActiveCall(instanceId, callId string) (*meowcaller.Call, error) } type callService struct { clientPointer map[string]*whatsmeow.Client whatsmeowService whatsmeow_service.WhatsmeowService + callRegistry *call_registry.CallRegistry loggerWrapper *logger_wrapper.LoggerManager } @@ -28,6 +34,15 @@ type RejectCallStruct struct { CallID string `json:"callId"` } +type AnswerCallStruct struct { + CallCreator types.JID `json:"callCreator"` + CallID string `json:"callId"` +} + +type HangupCallStruct struct { + CallID string `json:"callId"` +} + func (c *callService) ensureClientConnected(instanceId string) (*whatsmeow.Client, error) { client := c.clientPointer[instanceId] c.loggerWrapper.GetLogger(instanceId).LogInfo("[%s] Checking client connection status - Client exists: %v", instanceId, client != nil) @@ -82,14 +97,59 @@ func (c *callService) RejectCall(data *RejectCallStruct, instance *instance_mode return nil } +func (c *callService) AnswerCall(data *AnswerCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return nil, errors.New("no pending call with that id") + } + + if err := call.Answer(); err != nil { + logger.LogError("[%s] error answering call: %v", instance.Id, err) + return nil, err + } + + if call.IsVideo() { + if err := call.AcceptVideo(); err != nil { + c.loggerWrapper.GetLogger(instance.Id).LogError("[%s] answered call but failed to accept video: %v", instance.Id, err) + } + } + + return call, nil +} + +func (c *callService) HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + + err := call.Hangup() + c.callRegistry.Delete(data.CallID) + if err != nil { + logger.LogError("[%s] error hanging up call: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) GetActiveCall(instanceId, callId string) (*meowcaller.Call, error) { + call, ok := c.callRegistry.Get(instanceId, callId) + if !ok { + return nil, errors.New("no active call with that id") + } + return call, nil +} + func NewCallService( clientPointer map[string]*whatsmeow.Client, whatsmeowService whatsmeow_service.WhatsmeowService, + callRegistry *call_registry.CallRegistry, loggerWrapper *logger_wrapper.LoggerManager, ) CallService { return &callService{ clientPointer: clientPointer, whatsmeowService: whatsmeowService, + callRegistry: callRegistry, loggerWrapper: loggerWrapper, } } From d65497fc9171576ac319240c4646bc4cc40020a3 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:37:27 +0000 Subject: [PATCH 10/26] feat: add answer and hangup call HTTP handlers --- pkg/call/handler/call_handler.go | 72 ++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/pkg/call/handler/call_handler.go b/pkg/call/handler/call_handler.go index 550c3390..70b7bbd6 100644 --- a/pkg/call/handler/call_handler.go +++ b/pkg/call/handler/call_handler.go @@ -10,6 +10,8 @@ import ( type CallHandler interface { RejectCall(ctx *gin.Context) + AnswerCall(ctx *gin.Context) + HangupCall(ctx *gin.Context) } type callHandler struct { @@ -51,6 +53,76 @@ func (g *callHandler) RejectCall(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"message": "success"}) } +// Answer call +// @Summary Answer call +// @Description Answer an incoming call and (if it's a video call) accept its video +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.AnswerCallStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/answer [post] +func (g *callHandler) AnswerCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.AnswerCallStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + _, err = g.callService.AnswerCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + +// Hangup call +// @Summary Hangup call +// @Description Hangup an active call +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.HangupCallStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/hangup [post] +func (g *callHandler) HangupCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.HangupCallStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.HangupCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + func NewCallHandler( callService call_service.CallService, ) CallHandler { From a6ffe99ed1d4256f97d92e8ad026b1415eac0a91 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:39:27 +0000 Subject: [PATCH 11/26] feat: register call answer and hangup routes --- pkg/routes/routes.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 8e026a87..b179694a 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -194,6 +194,8 @@ func (r *Routes) AssignRoutes(eng *gin.Engine) { routes.Use(r.authMiddleware.Auth) { routes.POST("/reject", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.RejectCall) + routes.POST("/answer", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.AnswerCall) + routes.POST("/hangup", r.callHandler.HangupCall) } } routes = eng.Group("/community") From 887b0f5acd69108d0f701728d779c549d152572d Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:41:53 +0000 Subject: [PATCH 12/26] feat: add PCM16LE/float32 conversion for call media stream --- pkg/call/stream/codec.go | 33 +++++++++++++++++++++++++++ pkg/call/stream/codec_test.go | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 pkg/call/stream/codec.go create mode 100644 pkg/call/stream/codec_test.go diff --git a/pkg/call/stream/codec.go b/pkg/call/stream/codec.go new file mode 100644 index 00000000..52328e75 --- /dev/null +++ b/pkg/call/stream/codec.go @@ -0,0 +1,33 @@ +// pkg/call/stream/codec.go +package call_stream + +import "encoding/binary" + +// pcm16FromFloat32 converts one mono PCM frame (as meowcaller delivers it: float32 +// samples in [-1, 1]) into little-endian 16-bit PCM bytes, clamping out-of-range +// samples the same way meowcaller's own WAVRecorder does. +func pcm16FromFloat32(frame []float32) []byte { + out := make([]byte, len(frame)*2) + for i, s := range frame { + v := s * 32768.0 + if v > 32767 { + v = 32767 + } else if v < -32768 { + v = -32768 + } + binary.LittleEndian.PutUint16(out[2*i:], uint16(int16(v))) + } + return out +} + +// float32FromPCM16 converts little-endian 16-bit PCM bytes (as sent by a stream +// consumer) back into mono float32 samples in [-1, 1] for meowcaller.Call.Play. +func float32FromPCM16(b []byte) []float32 { + n := len(b) / 2 + out := make([]float32, n) + for i := 0; i < n; i++ { + v := int16(binary.LittleEndian.Uint16(b[2*i:])) + out[i] = float32(v) / 32768.0 + } + return out +} diff --git a/pkg/call/stream/codec_test.go b/pkg/call/stream/codec_test.go new file mode 100644 index 00000000..6806b1b8 --- /dev/null +++ b/pkg/call/stream/codec_test.go @@ -0,0 +1,42 @@ +// pkg/call/stream/codec_test.go +package call_stream + +import "testing" + +func TestPCM16RoundTrip(t *testing.T) { + frame := []float32{0, 0.5, -0.5, 1, -1, 0.25} + + pcm := pcm16FromFloat32(frame) + if len(pcm) != len(frame)*2 { + t.Fatalf("expected %d bytes, got %d", len(frame)*2, len(pcm)) + } + + back := float32FromPCM16(pcm) + if len(back) != len(frame) { + t.Fatalf("expected %d samples back, got %d", len(frame), len(back)) + } + + for i, want := range frame { + got := back[i] + diff := got - want + if diff < 0 { + diff = -diff + } + if diff > 0.001 { + t.Errorf("sample %d: want %v, got %v (diff %v)", i, want, got, diff) + } + } +} + +func TestPCM16ClampsOutOfRange(t *testing.T) { + frame := []float32{2.0, -2.0} // out of [-1, 1] range + pcm := pcm16FromFloat32(frame) + back := float32FromPCM16(pcm) + + if back[0] < 0.99 { + t.Errorf("expected clamp to max positive, got %v", back[0]) + } + if back[1] > -0.99 { + t.Errorf("expected clamp to max negative, got %v", back[1]) + } +} From e4c9472328b4e22f758fbbd6d8170023cb864e28 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:42:13 +0000 Subject: [PATCH 13/26] feat: add WebSocket bridge implementing meowcaller media interfaces --- pkg/call/stream/bridge.go | 126 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 pkg/call/stream/bridge.go diff --git a/pkg/call/stream/bridge.go b/pkg/call/stream/bridge.go new file mode 100644 index 00000000..00b02827 --- /dev/null +++ b/pkg/call/stream/bridge.go @@ -0,0 +1,126 @@ +// pkg/call/stream/bridge.go +package call_stream + +import ( + "encoding/base64" + "io" + "sync" + + "github.com/gorilla/websocket" + "github.com/purpshell/meowcaller" +) + +// wsMessage is the JSON envelope carried over the stream socket, modeled on Twilio +// Media Streams so existing AI-voice integrations need minimal adapting. +type wsMessage struct { + Event string `json:"event"` + CallID string `json:"callId,omitempty"` + SampleRate int `json:"sampleRate,omitempty"` + Video bool `json:"video,omitempty"` + Track string `json:"track,omitempty"` + Payload string `json:"payload,omitempty"` + Reason string `json:"reason,omitempty"` +} + +// bridge adapts one WebSocket connection to meowcaller's AudioSink (Call.Receive), +// VideoSink (Call.ReceiveVideo), and AudioSource (Call.Play) interfaces, so a single +// object plugs a call's media straight into the socket in both directions. +type bridge struct { + conn *websocket.Conn + writeMu sync.Mutex + incoming chan []float32 + closed chan struct{} + closeOnce sync.Once +} + +func newBridge(conn *websocket.Conn) *bridge { + return &bridge{ + conn: conn, + // ~3 seconds of buffering at one 60ms frame per slot before frames start + // getting dropped — enough slack for scheduling jitter without unbounded growth. + incoming: make(chan []float32, 50), + closed: make(chan struct{}), + } +} + +func (b *bridge) writeJSON(msg wsMessage) error { + b.writeMu.Lock() + defer b.writeMu.Unlock() + return b.conn.WriteJSON(msg) +} + +// writeStart sends the initial handshake message once the socket is up. +func (b *bridge) writeStart(callID string, video bool) { + _ = b.writeJSON(wsMessage{ + Event: "start", + CallID: callID, + SampleRate: meowcaller.SampleRate, + Video: video, + }) +} + +// WriteFrame implements meowcaller.AudioSink: one decoded mono frame from the peer. +func (b *bridge) WriteFrame(frame []float32) error { + payload := base64.StdEncoding.EncodeToString(pcm16FromFloat32(frame)) + return b.writeJSON(wsMessage{Event: "media", Track: "inbound", Payload: payload}) +} + +// WriteVideo implements meowcaller.VideoSink: one Annex-B H.264 access unit. +func (b *bridge) WriteVideo(accessUnit []byte) error { + payload := base64.StdEncoding.EncodeToString(accessUnit) + return b.writeJSON(wsMessage{Event: "video", Track: "inbound", Payload: payload}) +} + +// ReadFrame implements meowcaller.AudioSource: frames the consumer sent back over the +// socket, decoded by readLoop and handed here on demand. +func (b *bridge) ReadFrame() ([]float32, error) { + select { + case frame, ok := <-b.incoming: + if !ok { + return nil, io.EOF + } + return frame, nil + case <-b.closed: + return nil, io.EOF + } +} + +// Close satisfies AudioSink/VideoSink/AudioSource's shared Close() error method. Safe +// to call more than once (from the call's OnEnd callback and from readLoop exiting). +func (b *bridge) Close() error { + b.closeOnce.Do(func() { + _ = b.writeJSON(wsMessage{Event: "stop", Reason: "hangup"}) + close(b.closed) + _ = b.conn.Close() + }) + return nil +} + +// readLoop blocks reading consumer-sent media messages until the connection closes +// (by either side) or send Close(). Every non-media message is ignored rather than +// erroring, so the wire format can grow new event types without breaking old clients. +func (b *bridge) readLoop() { + for { + var msg wsMessage + if err := b.conn.ReadJSON(&msg); err != nil { + b.Close() + return + } + if msg.Event != "media" || msg.Track != "outbound" { + continue + } + raw, err := base64.StdEncoding.DecodeString(msg.Payload) + if err != nil { + continue + } + frame := float32FromPCM16(raw) + select { + case b.incoming <- frame: + case <-b.closed: + return + default: + // Consumer is sending audio faster than the call can play it out; drop + // the frame rather than block the socket read loop. + } + } +} From f905738130b983258ccfbcbef43db4cf79637e1b Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:42:34 +0000 Subject: [PATCH 14/26] feat: add call stream HTTP/WebSocket handler --- pkg/call/stream/handler.go | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 pkg/call/stream/handler.go diff --git a/pkg/call/stream/handler.go b/pkg/call/stream/handler.go new file mode 100644 index 00000000..fb29200f --- /dev/null +++ b/pkg/call/stream/handler.go @@ -0,0 +1,61 @@ +// pkg/call/stream/handler.go +package call_stream + +import ( + "net/http" + + call_service "github.com/evolution-foundation/evolution-go/pkg/call/service" + instance_service "github.com/evolution-foundation/evolution-go/pkg/instance/service" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { return true }, +} + +// RegisterRoutes mounts GET /call/stream/:callId directly on the engine, bypassing the +// header-based authMiddleware chain used by pkg/routes: WebSocket clients (especially +// browser-based ones) can't always set a custom apikey header on the upgrade request, +// so auth here is a query parameter instead, resolved the same way authMiddleware.Auth +// resolves it. This mirrors how pkg/passkey/handler.RegisterRoutes already registers +// its own routes directly on *gin.Engine for the same "doesn't fit the standard +// middleware chain" reason. +func RegisterRoutes(r *gin.Engine, callService call_service.CallService, instanceService instance_service.InstanceService) { + r.GET("/call/stream/:callId", serveStream(callService, instanceService)) +} + +func serveStream(callService call_service.CallService, instanceService instance_service.InstanceService) gin.HandlerFunc { + return func(ctx *gin.Context) { + instance, err := instanceService.GetInstanceByToken(ctx.Query("apikey")) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "not authorized"}) + return + } + + callID := ctx.Param("callId") + call, err := callService.GetActiveCall(instance.Id, callID) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + + conn, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil) + if err != nil { + return + } + + b := newBridge(conn) + call.OnEnd(func(reason string) { b.Close() }) + call.Receive(b) + call.ReceiveVideo(b) + call.Play(b) + + b.writeStart(callID, call.IsVideo()) + b.readLoop() // blocks until the socket closes, from either end + + _ = call.Hangup() + } +} From cf946d330e055b2089d06ba43c1c50e54931c1ca Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 13:50:06 +0000 Subject: [PATCH 15/26] feat: wire call registry and stream route into main Thread callRegistry through NewWhatsmeowService and NewCallService, and register call_stream.RegisterRoutes so the call-answering stack built in Tasks 2-7 is actually reachable. go mod tidy now keeps meowcaller as a direct dependency since real code imports it. --- cmd/evolution-go/main.go | 7 ++++++- go.mod | 2 +- go.sum | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmd/evolution-go/main.go b/cmd/evolution-go/main.go index 5234583f..9b27f475 100644 --- a/cmd/evolution-go/main.go +++ b/cmd/evolution-go/main.go @@ -22,7 +22,9 @@ import ( _ "modernc.org/sqlite" call_handler "github.com/evolution-foundation/evolution-go/pkg/call/handler" + call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" call_service "github.com/evolution-foundation/evolution-go/pkg/call/service" + call_stream "github.com/evolution-foundation/evolution-go/pkg/call/stream" chat_handler "github.com/evolution-foundation/evolution-go/pkg/chat/handler" chat_service "github.com/evolution-foundation/evolution-go/pkg/chat/service" community_handler "github.com/evolution-foundation/evolution-go/pkg/community/handler" @@ -85,6 +87,7 @@ func init() { func setupRouter(db *gorm.DB, authDB *sql.DB, sqliteDB *sql.DB, config *config.Config, conn *amqp.Connection, exPath string, runtimeCtx *core.RuntimeContext) *gin.Engine { killChannel := make(map[string](chan bool)) clientPointer := make(map[string]*whatsmeow.Client) + callRegistry := call_registry.NewCallRegistry() loggerWrapper := logger_wrapper.NewLoggerManager(config) @@ -177,6 +180,7 @@ func setupRouter(db *gorm.DB, authDB *sql.DB, sqliteDB *sql.DB, config *config.C exPath, mediaStorage, natsProducer, + callRegistry, loggerWrapper, ) instanceService := instance_service.NewInstanceService( @@ -192,7 +196,7 @@ func setupRouter(db *gorm.DB, authDB *sql.DB, sqliteDB *sql.DB, config *config.C messageService := message_service.NewMessageService(clientPointer, messageRepository, whatsmeowService, loggerWrapper) chatService := chat_service.NewChatService(clientPointer, whatsmeowService, loggerWrapper) groupService := group_service.NewGroupService(clientPointer, whatsmeowService, loggerWrapper) - callService := call_service.NewCallService(clientPointer, whatsmeowService, loggerWrapper) + callService := call_service.NewCallService(clientPointer, whatsmeowService, callRegistry, loggerWrapper) communityService := community_service.NewCommunityService(clientPointer, whatsmeowService, loggerWrapper) labelService := label_service.NewLabelService(clientPointer, whatsmeowService, labelRepository, loggerWrapper) newsletterService := newsletter_service.NewNewsletterService(clientPointer, whatsmeowService, loggerWrapper) @@ -224,6 +228,7 @@ func setupRouter(db *gorm.DB, authDB *sql.DB, sqliteDB *sql.DB, config *config.C // Passkey ceremony routes — PUBLIC (called by the browser extension from the // web.whatsapp.com origin, gated only by an opaque ephemeral token). passkey_handler.RegisterRoutes(r, whatsmeowService) + call_stream.RegisterRoutes(r, callService, instanceService) routes.NewRouter( auth_middleware.NewMiddleware(config, instanceService), diff --git a/go.mod b/go.mod index 0aab6def..f22e9703 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/minio/minio-go/v7 v7.0.80 github.com/nats-io/nats.go v1.39.0 github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/purpshell/meowcaller v0.0.0-20260726180203-6d9b7b2c1807 github.com/rabbitmq/amqp091-go v1.10.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/swaggo/files v1.0.1 @@ -84,7 +85,6 @@ require ( github.com/pion/randutil v0.1.0 // indirect github.com/pion/sctp v1.9.4 // indirect github.com/pion/transport/v4 v4.0.1 // indirect - github.com/purpshell/meowcaller v0.0.0-20260726180203-6d9b7b2c1807 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/xid v1.6.0 // indirect diff --git a/go.sum b/go.sum index 7ef4e7df..d235cd31 100644 --- a/go.sum +++ b/go.sum @@ -247,6 +247,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From efa07ee7612dd8dafe2192cada4e899a6bf8875a Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 14:23:41 +0000 Subject: [PATCH 16/26] fix: reject call via meowcaller instead of raw whatsmeow RejectCall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live validation against a real WhatsApp call showed the caller's side never learned the call was rejected — it kept ringing until WhatsApp's own ~90s timeout, because the raw whatsmeow client.RejectCall (called from a linked/companion device rather than the primary phone) doesn't reliably propagate as a proper decline over the call-signaling network. meowcaller's own call.Reject() goes through the same signaling path already proven correct for /call/answer and /call/hangup in this same manual validation. Since RejectCall now goes through the call registry like the other two, ensureClientConnected (and the context/time imports it needed) has no remaining caller and is removed as dead code. --- pkg/call/service/call_service.go | 50 ++++---------------------------- 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index b2c79158..37cd7455 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -1,9 +1,7 @@ package call_service import ( - "context" "errors" - "time" call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" instance_model "github.com/evolution-foundation/evolution-go/pkg/instance/model" @@ -43,52 +41,14 @@ type HangupCallStruct struct { CallID string `json:"callId"` } -func (c *callService) ensureClientConnected(instanceId string) (*whatsmeow.Client, error) { - client := c.clientPointer[instanceId] - c.loggerWrapper.GetLogger(instanceId).LogInfo("[%s] Checking client connection status - Client exists: %v", instanceId, client != nil) - - if client == nil { - c.loggerWrapper.GetLogger(instanceId).LogInfo("[%s] No client found, attempting to start new instance", instanceId) - err := c.whatsmeowService.StartInstance(instanceId) - if err != nil { - c.loggerWrapper.GetLogger(instanceId).LogError("[%s] Failed to start instance: %v", instanceId, err) - return nil, errors.New("no active session found") - } - - c.loggerWrapper.GetLogger(instanceId).LogInfo("[%s] Instance started, waiting 2 seconds...", instanceId) - time.Sleep(2 * time.Second) - - client = c.clientPointer[instanceId] - c.loggerWrapper.GetLogger(instanceId).LogInfo("[%s] Checking new client - Exists: %v, Connected: %v", - instanceId, - client != nil, - client != nil && client.IsConnected()) - - if client == nil || !client.IsConnected() { - c.loggerWrapper.GetLogger(instanceId).LogError("[%s] New client validation failed - Exists: %v, Connected: %v", - instanceId, - client != nil, - client != nil && client.IsConnected()) - return nil, errors.New("no active session found") - } - } else if !client.IsConnected() { - c.loggerWrapper.GetLogger(instanceId).LogError("[%s] Existing client is disconnected - Connected status: %v", - instanceId, - client.IsConnected()) - return nil, errors.New("client disconnected") - } - - c.loggerWrapper.GetLogger(instanceId).LogInfo("[%s] Client successfully validated - Connected: %v", instanceId, client.IsConnected()) - return client, nil -} - func (c *callService) RejectCall(data *RejectCallStruct, instance *instance_model.Instance) error { - client, err := c.ensureClientConnected(instance.Id) - if err != nil { - return err + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no pending call with that id") } - err = client.RejectCall(context.Background(), data.CallCreator, data.CallID) + err := call.Reject() + c.callRegistry.Delete(data.CallID) if err != nil { logger.LogError("[%s] error reject call: %v", instance.Id, err) return err From f63ba0bc421e7002d46ba6d11840ebc1021138ef Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 14:42:25 +0000 Subject: [PATCH 17/26] fix: don't call AcceptVideo for a call that starts as video MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live validation against a real WhatsApp video call showed AcceptVideo() failing with "no pending peer video upgrade" right after a successful Answer(). Per meowcaller's own doc comments, Answer() already negotiates whatever media the offer declared (audio, or audio+video if the call started as video) — AcceptVideo is for a different case: accepting a peer's mid-call request to upgrade an audio call to video (their Call.StartVideo), which isn't wired up here. The call still connects fine with video without it; the removed call was a no-op at best and a confusing logged error at worst. --- pkg/call/service/call_service.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index 37cd7455..71c4c14c 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -63,17 +63,16 @@ func (c *callService) AnswerCall(data *AnswerCallStruct, instance *instance_mode return nil, errors.New("no pending call with that id") } + // Answer negotiates media for whatever the offer already declared (audio, or + // audio+video if the call started as a video call) — no separate step needed. + // AcceptVideo is for a different case entirely: accepting a peer's request to + // upgrade an in-progress audio call to video (Call.StartVideo on their side), + // which isn't wired up here. if err := call.Answer(); err != nil { logger.LogError("[%s] error answering call: %v", instance.Id, err) return nil, err } - if call.IsVideo() { - if err := call.AcceptVideo(); err != nil { - c.loggerWrapper.GetLogger(instance.Id).LogError("[%s] answered call but failed to accept video: %v", instance.Id, err) - } - } - return call, nil } From 855ad758c6b8edcc0154d7ca0e38c50260b000d1 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 16:06:20 +0000 Subject: [PATCH 18/26] docs: regenerate swagger docs for call answer/hangup endpoints Needed --parseDependency --parseInternal for swag to resolve external types (go.mau.fi/whatsmeow/types.JID, gin.H) used throughout existing struct definitions -- without them swag aborts entirely and writes nothing, which the Makefile's swagger target doesn't surface (its success message prints unconditionally regardless of swag's exit code, since the command and echo are chained with ; not &&). --- docs/docs.go | 835 ++++++++++++++++++++++++++++++++-------------- docs/swagger.json | 835 ++++++++++++++++++++++++++++++++-------------- docs/swagger.yaml | 653 ++++++++++++++++++++++++------------ 3 files changed, 1618 insertions(+), 705 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 094912c0..1abcb16f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -15,6 +15,86 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/call/answer": { + "post": { + "description": "Answer an incoming call and (if it's a video call) accept its video", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Answer call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/hangup": { + "post": { + "description": "Hangup an active call", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Hangup call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/call/reject": { "post": { "description": "Reject call", @@ -35,7 +115,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_call_service.RejectCallStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct" } } ], @@ -75,7 +155,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -121,7 +201,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.HistorySyncRequestStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.HistorySyncRequestStruct" } } ], @@ -167,7 +247,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -213,7 +293,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -259,7 +339,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -305,7 +385,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -351,7 +431,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -397,7 +477,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct" } } ], @@ -443,7 +523,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.CreateCommunityStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.CreateCommunityStruct" } } ], @@ -489,7 +569,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct" } } ], @@ -535,7 +615,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.CreateGroupStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.CreateGroupStruct" } } ], @@ -581,7 +661,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupDescriptionStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupDescriptionStruct" } } ], @@ -627,7 +707,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInfoStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInfoStruct" } } ], @@ -673,7 +753,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInviteLinkStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInviteLinkStruct" } } ], @@ -719,7 +799,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.JoinGroupStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.JoinGroupStruct" } } ], @@ -765,7 +845,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.LeaveGroupStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.LeaveGroupStruct" } } ], @@ -869,7 +949,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupNameStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupNameStruct" } } ], @@ -915,7 +995,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.AddParticipantStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.AddParticipantStruct" } } ], @@ -961,7 +1041,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupPhotoStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupPhotoStruct" } } ], @@ -1007,7 +1087,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.UpdateGroupSettingsStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.UpdateGroupSettingsStruct" } } ], @@ -1082,7 +1162,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ConnectStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ConnectStruct" } } ], @@ -1128,7 +1208,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.CreateStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.CreateStruct" } } ], @@ -1254,7 +1334,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ForceReconnectStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ForceReconnectStruct" } } ], @@ -1438,7 +1518,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.PairStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.PairStruct" } } ], @@ -1491,7 +1571,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.SetProxyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.SetProxyStruct" } } ], @@ -1669,7 +1749,7 @@ const docTemplate = `{ "200": { "description": "Advanced settings retrieved successfully", "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings" } }, "400": { @@ -1718,7 +1798,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings" } } ], @@ -1770,7 +1850,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct" } } ], @@ -1816,7 +1896,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.EditLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.EditLabelStruct" } } ], @@ -1891,7 +1971,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct" } } ], @@ -1917,89 +1997,6 @@ const docTemplate = `{ } } }, - "/license/activate": { - "get": { - "description": "Exchanges an authorization code (from the registration callback) for an api_key and persists it. Provide the code via the query string.", - "produces": [ - "application/json" - ], - "tags": [ - "License" - ], - "summary": "Activate license", - "parameters": [ - { - "type": "string", - "description": "Authorization code from the registration callback", - "name": "code", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Activation result", - "schema": { - "$ref": "#/definitions/gin.H" - } - }, - "400": { - "description": "Missing code parameter", - "schema": { - "$ref": "#/definitions/gin.H" - } - } - } - } - }, - "/license/register": { - "get": { - "description": "Checks the GLOBAL_API_KEY with the licensing server. If not yet registered, initiates registration and returns a register_url. Accepts an optional redirect_uri for the post-registration redirect.", - "produces": [ - "application/json" - ], - "tags": [ - "License" - ], - "summary": "Register / get registration URL", - "parameters": [ - { - "type": "string", - "description": "Post-registration redirect URI", - "name": "redirect_uri", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Registration state (status/message or register_url)", - "schema": { - "$ref": "#/definitions/gin.H" - } - } - } - } - }, - "/license/status": { - "get": { - "description": "Returns whether the instance license is active, along with the instance id and a masked api key.", - "produces": [ - "application/json" - ], - "tags": [ - "License" - ], - "summary": "Get license status", - "responses": { - "200": { - "description": "License status ({status, instance_id, api_key?})", - "schema": { - "$ref": "#/definitions/gin.H" - } - } - } - } - }, "/message/delete": { "post": { "description": "Delete a message for everyone", @@ -2020,7 +2017,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStruct" } } ], @@ -2066,7 +2063,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.DownloadMediaStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.DownloadMediaStruct" } } ], @@ -2112,7 +2109,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.EditMessageStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.EditMessageStruct" } } ], @@ -2158,7 +2155,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkPlayedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MarkPlayedStruct" } } ], @@ -2204,7 +2201,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkReadStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MarkReadStruct" } } ], @@ -2250,7 +2247,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.ChatPresenceStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.ChatPresenceStruct" } } ], @@ -2296,7 +2293,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.ReactStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.ReactStruct" } } ], @@ -2342,7 +2339,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStatusStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStatusStruct" } } ], @@ -2388,7 +2385,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.CreateNewsletterStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.CreateNewsletterStruct" } } ], @@ -2434,7 +2431,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct" } } ], @@ -2480,7 +2477,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct" } } ], @@ -2555,7 +2552,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct" } } ], @@ -2601,7 +2598,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct" } } ], @@ -2818,7 +2815,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollResults" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.PollResults" } }, "400": { @@ -2862,7 +2859,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ButtonStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ButtonStruct" } } ], @@ -2908,7 +2905,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselStruct" } } ], @@ -2954,7 +2951,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ContactStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ContactStruct" } } ], @@ -3000,7 +2997,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LinkStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LinkStruct" } } ], @@ -3046,7 +3043,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ListStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ListStruct" } } ], @@ -3092,7 +3089,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LocationStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LocationStruct" } } ], @@ -3138,7 +3135,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.MediaStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.MediaStruct" } } ], @@ -3184,7 +3181,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.PollStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.PollStruct" } } ], @@ -3299,7 +3296,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StatusTextStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StatusTextStruct" } } ], @@ -3345,7 +3342,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StickerStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StickerStruct" } } ], @@ -3391,7 +3388,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.TextStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.TextStruct" } } ], @@ -3437,7 +3434,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct" } } ], @@ -3483,7 +3480,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct" } } ], @@ -3529,7 +3526,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.GetAvatarStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.GetAvatarStruct" } } ], @@ -3575,7 +3572,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct" } } ], @@ -3650,7 +3647,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct" } } ], @@ -3725,7 +3722,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct" } } ], @@ -3798,7 +3795,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.PrivacyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.PrivacyStruct" } } ], @@ -3838,7 +3835,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct" } } ], @@ -3884,7 +3881,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct" } } ], @@ -3930,7 +3927,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct" } } ], @@ -3976,7 +3973,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct" } } ], @@ -4008,7 +4005,26 @@ const docTemplate = `{ "type": "object", "additionalProperties": {} }, - "github_com_EvolutionAPI_evolution-go_pkg_call_service.RejectCallStruct": { + "github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct": { + "type": "object", + "properties": { + "callCreator": { + "$ref": "#/definitions/types.JID" + }, + "callId": { + "type": "string" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct": { "type": "object", "properties": { "callCreator": { @@ -4019,7 +4035,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct": { "type": "object", "properties": { "chat": { @@ -4027,7 +4043,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_chat_service.HistorySyncRequestStruct": { + "github_com_evolution-foundation_evolution-go_pkg_chat_service.HistorySyncRequestStruct": { "type": "object", "properties": { "count": { @@ -4038,7 +4054,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct": { + "github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct": { "type": "object", "properties": { "communityJid": { @@ -4052,7 +4068,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_community_service.CreateCommunityStruct": { + "github_com_evolution-foundation_evolution-go_pkg_community_service.CreateCommunityStruct": { "type": "object", "properties": { "communityName": { @@ -4060,7 +4076,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.AddParticipantStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.AddParticipantStruct": { "type": "object", "properties": { "action": { @@ -4077,7 +4093,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.CreateGroupStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.CreateGroupStruct": { "type": "object", "properties": { "groupName": { @@ -4091,7 +4107,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInfoStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInfoStruct": { "type": "object", "properties": { "groupJid": { @@ -4099,7 +4115,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInviteLinkStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInviteLinkStruct": { "type": "object", "properties": { "groupJid": { @@ -4110,7 +4126,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.JoinGroupStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.JoinGroupStruct": { "type": "object", "properties": { "code": { @@ -4118,7 +4134,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.LeaveGroupStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.LeaveGroupStruct": { "type": "object", "properties": { "groupJid": { @@ -4126,7 +4142,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupDescriptionStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupDescriptionStruct": { "type": "object", "properties": { "description": { @@ -4137,7 +4153,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupNameStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupNameStruct": { "type": "object", "properties": { "groupJid": { @@ -4148,7 +4164,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupPhotoStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupPhotoStruct": { "type": "object", "properties": { "groupJid": { @@ -4159,7 +4175,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.UpdateGroupSettingsStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.UpdateGroupSettingsStruct": { "type": "object", "properties": { "action": { @@ -4171,7 +4187,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings": { + "github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings": { "type": "object", "properties": { "alwaysOnline": { @@ -4194,7 +4210,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.ConnectStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.ConnectStruct": { "type": "object", "properties": { "immediate": { @@ -4223,11 +4239,11 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.CreateStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.CreateStruct": { "type": "object", "properties": { "advancedSettings": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings" }, "instanceId": { "type": "string" @@ -4236,14 +4252,14 @@ const docTemplate = `{ "type": "string" }, "proxy": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ProxyConfig" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ProxyConfig" }, "token": { "type": "string" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.ForceReconnectStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.ForceReconnectStruct": { "type": "object", "properties": { "number": { @@ -4251,7 +4267,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.PairStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.PairStruct": { "type": "object", "properties": { "phone": { @@ -4265,7 +4281,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.ProxyConfig": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.ProxyConfig": { "type": "object", "properties": { "host": { @@ -4285,7 +4301,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.SetProxyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.SetProxyStruct": { "type": "object", "required": [ "host", @@ -4309,7 +4325,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct": { + "github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct": { "type": "object", "properties": { "jid": { @@ -4320,7 +4336,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_label_service.EditLabelStruct": { + "github_com_evolution-foundation_evolution-go_pkg_label_service.EditLabelStruct": { "type": "object", "properties": { "color": { @@ -4337,7 +4353,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct": { + "github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct": { "type": "object", "properties": { "jid": { @@ -4351,7 +4367,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.ChatPresenceStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.ChatPresenceStruct": { "type": "object", "properties": { "delay": { @@ -4369,7 +4385,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.DownloadMediaStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.DownloadMediaStruct": { "type": "object", "properties": { "message": { @@ -4377,7 +4393,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.EditMessageStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.EditMessageStruct": { "type": "object", "properties": { "chat": { @@ -4391,7 +4407,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkPlayedStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MarkPlayedStruct": { "type": "object", "properties": { "id": { @@ -4405,7 +4421,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkReadStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MarkReadStruct": { "type": "object", "properties": { "id": { @@ -4419,7 +4435,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStatusStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStatusStruct": { "type": "object", "properties": { "id": { @@ -4427,7 +4443,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStruct": { "type": "object", "properties": { "chat": { @@ -4438,7 +4454,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.ReactStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.ReactStruct": { "type": "object", "properties": { "fromMe": { @@ -4458,7 +4474,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.CreateNewsletterStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.CreateNewsletterStruct": { "type": "object", "properties": { "description": { @@ -4469,7 +4485,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct": { "type": "object", "properties": { "key": { @@ -4477,7 +4493,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct": { "type": "object", "properties": { "before_id": { @@ -4491,7 +4507,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct": { "type": "object", "properties": { "jid": { @@ -4499,7 +4515,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollResults": { + "github_com_evolution-foundation_evolution-go_pkg_poll_model.PollResults": { "type": "object", "properties": { "optionCounts": { @@ -4521,18 +4537,18 @@ const docTemplate = `{ "voters": { "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.VoterInfo" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.VoterInfo" } }, "votes": { "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollVote" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.PollVote" } } } }, - "github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollVote": { + "github_com_evolution-foundation_evolution-go_pkg_poll_model.PollVote": { "type": "object", "properties": { "companyId": { @@ -4577,7 +4593,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_poll_model.VoterInfo": { + "github_com_evolution-foundation_evolution-go_pkg_poll_model.VoterInfo": { "type": "object", "properties": { "jid": { @@ -4600,7 +4616,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Button": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Button": { "type": "object", "properties": { "copyCode": { @@ -4669,14 +4685,14 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ButtonStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ButtonStruct": { "type": "object", "properties": { "buttons": { "description": "Buttons array. See combination rules on the parent type description.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Button" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Button" } }, "delay": { @@ -4722,7 +4738,7 @@ const docTemplate = `{ "description": "Quoted (reply-to) context.", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } ] }, @@ -4737,7 +4753,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselButtonStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselButtonStruct": { "type": "object", "properties": { "copyCode": { @@ -4772,7 +4788,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct": { "type": "object", "properties": { "text": { @@ -4782,7 +4798,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct": { "type": "object", "properties": { "imageUrl": { @@ -4806,14 +4822,14 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardStruct": { "type": "object", "properties": { "body": { "description": "Card body text (required).", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct" } ] }, @@ -4821,7 +4837,7 @@ const docTemplate = `{ "description": "Buttons shown on the card. See CarouselButtonStruct for combination rules.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselButtonStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselButtonStruct" } }, "footer": { @@ -4833,13 +4849,13 @@ const docTemplate = `{ "description": "Card header (media + title/subtitle).", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct" } ] } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselStruct": { "type": "object", "properties": { "body": { @@ -4851,7 +4867,7 @@ const docTemplate = `{ "description": "Cards displayed in order. At least one card is required.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardStruct" } }, "delay": { @@ -4877,13 +4893,13 @@ const docTemplate = `{ "description": "Quoted (reply-to) context.", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } ] } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ContactStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ContactStruct": { "type": "object", "properties": { "delay": { @@ -4908,14 +4924,14 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "vcard": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_utils.VCardStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_utils.VCardStruct" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LinkStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LinkStruct": { "type": "object", "properties": { "delay": { @@ -4946,7 +4962,7 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "text": { "type": "string" @@ -4959,7 +4975,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ListStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ListStruct": { "type": "object", "properties": { "buttonText": { @@ -5006,7 +5022,7 @@ const docTemplate = `{ "description": "Quoted (reply-to) context.", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } ] }, @@ -5014,7 +5030,7 @@ const docTemplate = `{ "description": "Sections with rows. At least one section with one row is required.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Section" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Section" } }, "title": { @@ -5024,7 +5040,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LocationStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LocationStruct": { "type": "object", "properties": { "address": { @@ -5061,11 +5077,11 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.MediaStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.MediaStruct": { "type": "object", "properties": { "caption": { @@ -5099,7 +5115,7 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "type": { "type": "string" @@ -5109,7 +5125,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.PollStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.PollStruct": { "type": "object", "properties": { "delay": { @@ -5146,11 +5162,11 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct": { "type": "object", "properties": { "messageId": { @@ -5161,7 +5177,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Row": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Row": { "type": "object", "properties": { "description": { @@ -5181,14 +5197,14 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Section": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Section": { "type": "object", "properties": { "rows": { "description": "Rows inside this section.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Row" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Row" } }, "title": { @@ -5198,7 +5214,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StatusTextStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StatusTextStruct": { "type": "object", "properties": { "id": { @@ -5209,7 +5225,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StickerStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StickerStruct": { "type": "object", "properties": { "delay": { @@ -5234,14 +5250,14 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "sticker": { "type": "string" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.TextStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.TextStruct": { "type": "object", "properties": { "delay": { @@ -5269,14 +5285,14 @@ const docTemplate = `{ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "text": { "type": "string" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct": { "type": "object", "properties": { "number": { @@ -5284,7 +5300,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct": { "type": "object", "properties": { "formatJid": { @@ -5298,7 +5314,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.GetAvatarStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.GetAvatarStruct": { "type": "object", "properties": { "number": { @@ -5309,7 +5325,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.PrivacyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.PrivacyStruct": { "type": "object", "properties": { "callAdd": { @@ -5335,7 +5351,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct": { "type": "object", "properties": { "image": { @@ -5343,7 +5359,7 @@ const docTemplate = `{ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_utils.VCardStruct": { + "github_com_evolution-foundation_evolution-go_pkg_utils.VCardStruct": { "type": "object", "properties": { "fullName": { @@ -5515,6 +5531,9 @@ const docTemplate = `{ "description": "Whether the chat is a group chat or broadcast list.", "type": "boolean" }, + "isNewsletterStatus": { + "type": "boolean" + }, "mediaType": { "type": "string" }, @@ -5636,11 +5655,26 @@ const docTemplate = `{ "types.VerifiedName": { "type": "object", "properties": { + "actualActors": { + "type": "integer" + }, "certificate": { "$ref": "#/definitions/waVnameCert.VerifiedNameCertificate" }, "details": { "$ref": "#/definitions/waVnameCert.VerifiedNameCertificate_Details" + }, + "hostStorage": { + "type": "integer" + }, + "privacyModeTS": { + "type": "string" + }, + "verifiedLevel": { + "type": "string" + }, + "version": { + "type": "integer" } } }, @@ -5726,6 +5760,28 @@ const docTemplate = `{ } } }, + "waAICommon.AIProvenance": { + "type": "object", + "properties": { + "c2PaMetadata": { + "$ref": "#/definitions/waAICommon.AIProvenance_Metadata" + }, + "iptcMetadata": { + "$ref": "#/definitions/waAICommon.AIProvenance_Metadata" + } + } + }, + "waAICommon.AIProvenance_Metadata": { + "type": "object", + "properties": { + "createdWithGenAi": { + "type": "boolean" + }, + "editedWithGenAi": { + "type": "boolean" + } + } + }, "waAICommon.AIRegenerateMetadata": { "type": "object", "properties": { @@ -5847,6 +5903,12 @@ const docTemplate = `{ "waAICommon.BotAgentDeepLinkMetadata": { "type": "object", "properties": { + "clientPublicKey": { + "type": "array", + "items": { + "type": "integer" + } + }, "token": { "type": "string" } @@ -5940,7 +6002,11 @@ const docTemplate = `{ 62, 63, 64, - 65 + 65, + 66, + 67, + 68, + 69 ], "x-enum-varnames": [ "BotCapabilityMetadata_UNKNOWN", @@ -6008,7 +6074,11 @@ const docTemplate = `{ "BotCapabilityMetadata_UNIFIED_RESPONSE_AI_CONTENT_SEARCH_ENABLED", "BotCapabilityMetadata_UNIFIED_RESPONSE_MARKDOWN_LINKS_ENABLED", "BotCapabilityMetadata_AI_RICH_RESPONSE_MAPS_V2_ENABLED", - "BotCapabilityMetadata_AI_SUBSCRIPTION_METERING_ENABLED" + "BotCapabilityMetadata_AI_SUBSCRIPTION_METERING_ENABLED", + "BotCapabilityMetadata_RICH_RESPONSE_SPORTS_WIDGET_ENABLED", + "BotCapabilityMetadata_AI_RICH_RESPONSE_ARTIFACTS_ENABLED", + "BotCapabilityMetadata_AI_RICH_RESPONSE_EMAIL_CALENDAR_ENABLED", + "BotCapabilityMetadata_AI_RICH_RESPONSE_REMINDERS_ENABLED" ] }, "waAICommon.BotCommandMetadata": { @@ -6259,6 +6329,17 @@ const docTemplate = `{ } } }, + "waAICommon.BotHistoryShareMetadata": { + "type": "object", + "properties": { + "participantsMetadata": { + "type": "array", + "items": { + "$ref": "#/definitions/waAICommon.BotGroupParticipantMetadata" + } + } + } + }, "waAICommon.BotImagineMetadata": { "type": "object", "properties": { @@ -6498,6 +6579,9 @@ const docTemplate = `{ "botGroupMetadata": { "$ref": "#/definitions/waAICommon.BotGroupMetadata" }, + "botHistoryShareMetadata": { + "$ref": "#/definitions/waAICommon.BotHistoryShareMetadata" + }, "botInfrastructureDiagnostics": { "$ref": "#/definitions/waAICommon.BotInfrastructureDiagnostics" }, @@ -6665,7 +6749,8 @@ const docTemplate = `{ 47, 54, 55, - 56 + 56, + 57 ], "x-enum-varnames": [ "BotMetricsEntryPoint_UNDEFINED_ENTRY_POINT", @@ -6715,7 +6800,8 @@ const docTemplate = `{ "BotMetricsEntryPoint_WEB_NAVIGATION_BAR", "BotMetricsEntryPoint_GROUP_MEMBER", "BotMetricsEntryPoint_CHATLIST_SEARCH", - "BotMetricsEntryPoint_NEW_CHAT_LIST" + "BotMetricsEntryPoint_NEW_CHAT_LIST", + "BotMetricsEntryPoint_CONTACTS_TAB" ] }, "waAICommon.BotMetricsMetadata": { @@ -7973,6 +8059,28 @@ const docTemplate = `{ "ADVEncryptionType_HOSTED" ] }, + "waAea.NonE2EEAttestation": { + "type": "object", + "properties": { + "accountType": { + "$ref": "#/definitions/waAea.NonE2EEAttestation_AccountType" + } + } + }, + "waAea.NonE2EEAttestation_AccountType": { + "type": "integer", + "format": "int32", + "enum": [ + 0, + 1, + 2 + ], + "x-enum-varnames": [ + "NonE2EEAttestation_E2EE", + "NonE2EEAttestation_HYBRID_E2EE", + "NonE2EEAttestation_NON_E2EE" + ] + }, "waCommon.LimitSharing": { "type": "object", "properties": { @@ -8356,6 +8464,23 @@ const docTemplate = `{ "BCallMessage_VIDEO" ] }, + "waE2E.BotHistoryShareSyncMetadata": { + "type": "object", + "properties": { + "botJID": { + "type": "string" + }, + "historyShareCutoffTimestamp": { + "type": "integer" + }, + "historyShareMessages": { + "type": "array", + "items": { + "$ref": "#/definitions/waE2E.HistoryShareMessageEntry" + } + } + } + }, "waE2E.ButtonsMessage": { "type": "object", "properties": { @@ -8495,6 +8620,9 @@ const docTemplate = `{ "type": "integer" } }, + "callReason": { + "type": "string" + }, "contextInfo": { "$ref": "#/definitions/waE2E.ContextInfo" }, @@ -8777,6 +8905,9 @@ const docTemplate = `{ "afterReadDuration": { "type": "integer" }, + "aiProvenance": { + "$ref": "#/definitions/waAICommon.AIProvenance" + }, "alwaysShowAdAttribution": { "type": "boolean" }, @@ -8873,6 +9004,9 @@ const docTemplate = `{ "groupSubject": { "type": "string" }, + "instagramThreadLink": { + "$ref": "#/definitions/waE2E.ContextInfo_InstagramThreadLink" + }, "isForwarded": { "type": "boolean" }, @@ -9034,6 +9168,9 @@ const docTemplate = `{ "items": { "type": "integer" } + }, + "unauthenticatedBusinessMetadata": { + "$ref": "#/definitions/waE2E.ContextInfo_BusinessInteractionPills_UnauthenticatedBusinessMetadata" } } }, @@ -9102,6 +9239,23 @@ const docTemplate = `{ "ContextInfo_BusinessInteractionPills_ORDER" ] }, + "waE2E.ContextInfo_BusinessInteractionPills_UnauthenticatedBusinessMetadata": { + "type": "object", + "properties": { + "businessCategory": { + "type": "string" + }, + "businessIsOpen": { + "type": "boolean" + }, + "businessIsOpenSnapshotMS": { + "type": "integer" + }, + "businessName": { + "type": "string" + } + } + }, "waE2E.ContextInfo_BusinessMessageForwardInfo": { "type": "object", "properties": { @@ -9371,6 +9525,14 @@ const docTemplate = `{ "ContextInfo_ForwardedNewsletterMessageInfo_LINK_CARD" ] }, + "waE2E.ContextInfo_InstagramThreadLink": { + "type": "object", + "properties": { + "URL": { + "type": "string" + } + } + }, "waE2E.ContextInfo_PairedMediaType": { "type": "integer", "format": "int32", @@ -9938,7 +10100,7 @@ const docTemplate = `{ "$ref": "#/definitions/waE2E.VideoEndCard" } }, - "faviconMMSMetadata": { + "faviconMmsMetadata": { "$ref": "#/definitions/waE2E.MMSThumbnailMetadata" }, "font": { @@ -10261,6 +10423,20 @@ const docTemplate = `{ } } }, + "waE2E.HistoryShareMessageEntry": { + "type": "object", + "properties": { + "messageSecretProof": { + "type": "array", + "items": { + "type": "integer" + } + }, + "stanzaID": { + "type": "string" + } + } + }, "waE2E.HistorySyncMessageAccessStatus": { "type": "object", "properties": { @@ -11137,6 +11313,26 @@ const docTemplate = `{ } } }, + "waE2E.MarkAsVerifiedAction": { + "type": "object", + "properties": { + "actionSeq": { + "type": "integer" + }, + "userJIDString": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verifiedIdentityKey": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, "waE2E.MediaDomainInfo": { "type": "object", "properties": { @@ -11469,6 +11665,9 @@ const docTemplate = `{ "splitPaymentMessage": { "$ref": "#/definitions/waE2E.SplitPaymentMessage" }, + "splitPaymentUpdateMessage": { + "$ref": "#/definitions/waE2E.SplitPaymentUpdateMessage" + }, "spoilerMessage": { "$ref": "#/definitions/waE2E.FutureProofMessage" }, @@ -11586,6 +11785,15 @@ const docTemplate = `{ "waE2E.MessageContextInfo": { "type": "object", "properties": { + "accountEncryptionAttestation": { + "$ref": "#/definitions/waAea.NonE2EEAttestation" + }, + "associatedPrimaryIdentityKey": { + "type": "array", + "items": { + "type": "integer" + } + }, "botMessageSecret": { "type": "array", "items": { @@ -11733,6 +11941,9 @@ const docTemplate = `{ "waE2E.MessageHistoryNotice": { "type": "object", "properties": { + "botHistoryShareSyncMetadata": { + "$ref": "#/definitions/waE2E.BotHistoryShareSyncMetadata" + }, "contextInfo": { "$ref": "#/definitions/waE2E.ContextInfo" }, @@ -11960,6 +12171,9 @@ const docTemplate = `{ "waE2E.PaymentExtendedMetadata": { "type": "object", "properties": { + "messageParamsJSON": { + "type": "string" + }, "platform": { "type": "string" }, @@ -12698,7 +12912,8 @@ const docTemplate = `{ 10, 11, 12, - 13 + 13, + 14 ], "x-enum-varnames": [ "PeerDataOperationRequestType_UPLOAD_STICKER", @@ -12714,7 +12929,8 @@ const docTemplate = `{ "PeerDataOperationRequestType_HISTORY_SYNC_CHUNK_RETRY", "PeerDataOperationRequestType_GALAXY_FLOW_ACTION", "PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_DELIVERED_TO", - "PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_REFRESH" + "PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_REFRESH", + "PeerDataOperationRequestType_CONTACT_REFRESH_REQUEST" ] }, "waE2E.PinInChatMessage": { @@ -13122,6 +13338,9 @@ const docTemplate = `{ "cloudApiThreadControlNotification": { "$ref": "#/definitions/waE2E.CloudAPIThreadControlNotification" }, + "coexStateSync": { + "$ref": "#/definitions/waServerSync.CoexStateSync" + }, "disappearingMode": { "$ref": "#/definitions/waE2E.DisappearingMode" }, @@ -13152,6 +13371,9 @@ const docTemplate = `{ "limitSharing": { "$ref": "#/definitions/waCommon.LimitSharing" }, + "markAsVerifiedAction": { + "$ref": "#/definitions/waE2E.MarkAsVerifiedAction" + }, "mediaNotifyMessage": { "$ref": "#/definitions/waE2E.MediaNotifyMessage" }, @@ -13167,6 +13389,9 @@ const docTemplate = `{ "requestWelcomeMessageMetadata": { "$ref": "#/definitions/waE2E.RequestWelcomeMessageMetadata" }, + "syncRequestMutationRetry": { + "$ref": "#/definitions/waE2E.SyncRequestMutationRetry" + }, "timestampMS": { "type": "integer" }, @@ -13208,7 +13433,10 @@ const docTemplate = `{ 31, 32, 34, - 35 + 35, + 36, + 37, + 38 ], "x-enum-varnames": [ "ProtocolMessage_REVOKE", @@ -13240,7 +13468,10 @@ const docTemplate = `{ "ProtocolMessage_AI_MEDIA_COLLECTION_MESSAGE", "ProtocolMessage_MESSAGE_UNSCHEDULE", "ProtocolMessage_CHAT_THEME_SETTING", - "ProtocolMessage_AI_METADATA_OPERATION" + "ProtocolMessage_AI_METADATA_OPERATION", + "ProtocolMessage_MARK_AS_VERIFIED_ACTION", + "ProtocolMessage_COEX_STATE_SYNC", + "ProtocolMessage_SYNC_REQUEST_MUTATION_RETRY" ] }, "waE2E.QuestionResponseMessage": { @@ -13534,6 +13765,17 @@ const docTemplate = `{ "SplitPaymentParticipant_PAID" ] }, + "waE2E.SplitPaymentUpdateMessage": { + "type": "object", + "properties": { + "participantJID": { + "type": "string" + }, + "splitID": { + "type": "string" + } + } + }, "waE2E.StatusNotificationMessage": { "type": "object", "properties": { @@ -13866,6 +14108,31 @@ const docTemplate = `{ } } }, + "waE2E.SyncRequestMutationRetry": { + "type": "object", + "properties": { + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/waE2E.SyncRequestMutationRetry_Collection" + } + }, + "count": { + "type": "integer" + } + } + }, + "waE2E.SyncRequestMutationRetry_Collection": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "storedSyncdVersion": { + "type": "integer" + } + } + }, "waE2E.TemplateButtonReplyMessage": { "type": "object", "properties": { @@ -14188,6 +14455,82 @@ const docTemplate = `{ "MediaRetryNotification_DECRYPTION_ERROR" ] }, + "waServerSync.CoexStateSync": { + "type": "object", + "properties": { + "collectionMutations": { + "type": "array", + "items": { + "$ref": "#/definitions/waServerSync.CoexStateSync_CollectionMutations" + } + } + } + }, + "waServerSync.CoexStateSync_CollectionMutations": { + "type": "object", + "properties": { + "collection": { + "type": "string" + }, + "mutations": { + "type": "array", + "items": { + "$ref": "#/definitions/waServerSync.CoexStateSync_Mutation" + } + } + } + }, + "waServerSync.CoexStateSync_Mutation": { + "type": "object", + "properties": { + "dirtyVersion": { + "type": "integer" + }, + "index": { + "$ref": "#/definitions/waServerSync.SyncdIndex" + }, + "operation": { + "$ref": "#/definitions/waServerSync.SyncdMutation_SyncdOperation" + }, + "value": { + "$ref": "#/definitions/waServerSync.SyncdValue" + } + } + }, + "waServerSync.SyncdIndex": { + "type": "object", + "properties": { + "blob": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "waServerSync.SyncdMutation_SyncdOperation": { + "type": "integer", + "format": "int32", + "enum": [ + 0, + 1 + ], + "x-enum-varnames": [ + "SyncdMutation_SET", + "SyncdMutation_REMOVE" + ] + }, + "waServerSync.SyncdValue": { + "type": "object", + "properties": { + "blob": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, "waStatusAttributions.StatusAttribution": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 7cfe913e..db08ff0a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7,6 +7,86 @@ "version": "1.0" }, "paths": { + "/call/answer": { + "post": { + "description": "Answer an incoming call and (if it's a video call) accept its video", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Answer call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/hangup": { + "post": { + "description": "Hangup an active call", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Hangup call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/call/reject": { "post": { "description": "Reject call", @@ -27,7 +107,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_call_service.RejectCallStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct" } } ], @@ -67,7 +147,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -113,7 +193,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.HistorySyncRequestStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.HistorySyncRequestStruct" } } ], @@ -159,7 +239,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -205,7 +285,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -251,7 +331,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -297,7 +377,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -343,7 +423,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct" } } ], @@ -389,7 +469,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct" } } ], @@ -435,7 +515,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.CreateCommunityStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.CreateCommunityStruct" } } ], @@ -481,7 +561,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct" } } ], @@ -527,7 +607,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.CreateGroupStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.CreateGroupStruct" } } ], @@ -573,7 +653,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupDescriptionStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupDescriptionStruct" } } ], @@ -619,7 +699,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInfoStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInfoStruct" } } ], @@ -665,7 +745,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInviteLinkStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInviteLinkStruct" } } ], @@ -711,7 +791,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.JoinGroupStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.JoinGroupStruct" } } ], @@ -757,7 +837,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.LeaveGroupStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.LeaveGroupStruct" } } ], @@ -861,7 +941,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupNameStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupNameStruct" } } ], @@ -907,7 +987,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.AddParticipantStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.AddParticipantStruct" } } ], @@ -953,7 +1033,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupPhotoStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupPhotoStruct" } } ], @@ -999,7 +1079,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.UpdateGroupSettingsStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.UpdateGroupSettingsStruct" } } ], @@ -1074,7 +1154,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ConnectStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ConnectStruct" } } ], @@ -1120,7 +1200,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.CreateStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.CreateStruct" } } ], @@ -1246,7 +1326,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ForceReconnectStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ForceReconnectStruct" } } ], @@ -1430,7 +1510,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.PairStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.PairStruct" } } ], @@ -1483,7 +1563,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.SetProxyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.SetProxyStruct" } } ], @@ -1661,7 +1741,7 @@ "200": { "description": "Advanced settings retrieved successfully", "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings" } }, "400": { @@ -1710,7 +1790,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings" } } ], @@ -1762,7 +1842,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct" } } ], @@ -1808,7 +1888,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.EditLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.EditLabelStruct" } } ], @@ -1883,7 +1963,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct" } } ], @@ -1909,89 +1989,6 @@ } } }, - "/license/activate": { - "get": { - "description": "Exchanges an authorization code (from the registration callback) for an api_key and persists it. Provide the code via the query string.", - "produces": [ - "application/json" - ], - "tags": [ - "License" - ], - "summary": "Activate license", - "parameters": [ - { - "type": "string", - "description": "Authorization code from the registration callback", - "name": "code", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Activation result", - "schema": { - "$ref": "#/definitions/gin.H" - } - }, - "400": { - "description": "Missing code parameter", - "schema": { - "$ref": "#/definitions/gin.H" - } - } - } - } - }, - "/license/register": { - "get": { - "description": "Checks the GLOBAL_API_KEY with the licensing server. If not yet registered, initiates registration and returns a register_url. Accepts an optional redirect_uri for the post-registration redirect.", - "produces": [ - "application/json" - ], - "tags": [ - "License" - ], - "summary": "Register / get registration URL", - "parameters": [ - { - "type": "string", - "description": "Post-registration redirect URI", - "name": "redirect_uri", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Registration state (status/message or register_url)", - "schema": { - "$ref": "#/definitions/gin.H" - } - } - } - } - }, - "/license/status": { - "get": { - "description": "Returns whether the instance license is active, along with the instance id and a masked api key.", - "produces": [ - "application/json" - ], - "tags": [ - "License" - ], - "summary": "Get license status", - "responses": { - "200": { - "description": "License status ({status, instance_id, api_key?})", - "schema": { - "$ref": "#/definitions/gin.H" - } - } - } - } - }, "/message/delete": { "post": { "description": "Delete a message for everyone", @@ -2012,7 +2009,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStruct" } } ], @@ -2058,7 +2055,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.DownloadMediaStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.DownloadMediaStruct" } } ], @@ -2104,7 +2101,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.EditMessageStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.EditMessageStruct" } } ], @@ -2150,7 +2147,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkPlayedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MarkPlayedStruct" } } ], @@ -2196,7 +2193,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkReadStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MarkReadStruct" } } ], @@ -2242,7 +2239,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.ChatPresenceStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.ChatPresenceStruct" } } ], @@ -2288,7 +2285,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.ReactStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.ReactStruct" } } ], @@ -2334,7 +2331,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStatusStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStatusStruct" } } ], @@ -2380,7 +2377,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.CreateNewsletterStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.CreateNewsletterStruct" } } ], @@ -2426,7 +2423,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct" } } ], @@ -2472,7 +2469,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct" } } ], @@ -2547,7 +2544,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct" } } ], @@ -2593,7 +2590,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct" } } ], @@ -2810,7 +2807,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollResults" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.PollResults" } }, "400": { @@ -2854,7 +2851,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ButtonStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ButtonStruct" } } ], @@ -2900,7 +2897,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselStruct" } } ], @@ -2946,7 +2943,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ContactStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ContactStruct" } } ], @@ -2992,7 +2989,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LinkStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LinkStruct" } } ], @@ -3038,7 +3035,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ListStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ListStruct" } } ], @@ -3084,7 +3081,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LocationStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LocationStruct" } } ], @@ -3130,7 +3127,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.MediaStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.MediaStruct" } } ], @@ -3176,7 +3173,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.PollStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.PollStruct" } } ], @@ -3291,7 +3288,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StatusTextStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StatusTextStruct" } } ], @@ -3337,7 +3334,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StickerStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StickerStruct" } } ], @@ -3383,7 +3380,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.TextStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.TextStruct" } } ], @@ -3429,7 +3426,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct" } } ], @@ -3475,7 +3472,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct" } } ], @@ -3521,7 +3518,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.GetAvatarStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.GetAvatarStruct" } } ], @@ -3567,7 +3564,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct" } } ], @@ -3642,7 +3639,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct" } } ], @@ -3717,7 +3714,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct" } } ], @@ -3790,7 +3787,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.PrivacyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.PrivacyStruct" } } ], @@ -3830,7 +3827,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct" } } ], @@ -3876,7 +3873,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct" } } ], @@ -3922,7 +3919,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct" } } ], @@ -3968,7 +3965,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct" } } ], @@ -4000,7 +3997,26 @@ "type": "object", "additionalProperties": {} }, - "github_com_EvolutionAPI_evolution-go_pkg_call_service.RejectCallStruct": { + "github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct": { + "type": "object", + "properties": { + "callCreator": { + "$ref": "#/definitions/types.JID" + }, + "callId": { + "type": "string" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct": { "type": "object", "properties": { "callCreator": { @@ -4011,7 +4027,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct": { "type": "object", "properties": { "chat": { @@ -4019,7 +4035,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_chat_service.HistorySyncRequestStruct": { + "github_com_evolution-foundation_evolution-go_pkg_chat_service.HistorySyncRequestStruct": { "type": "object", "properties": { "count": { @@ -4030,7 +4046,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct": { + "github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct": { "type": "object", "properties": { "communityJid": { @@ -4044,7 +4060,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_community_service.CreateCommunityStruct": { + "github_com_evolution-foundation_evolution-go_pkg_community_service.CreateCommunityStruct": { "type": "object", "properties": { "communityName": { @@ -4052,7 +4068,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.AddParticipantStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.AddParticipantStruct": { "type": "object", "properties": { "action": { @@ -4069,7 +4085,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.CreateGroupStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.CreateGroupStruct": { "type": "object", "properties": { "groupName": { @@ -4083,7 +4099,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInfoStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInfoStruct": { "type": "object", "properties": { "groupJid": { @@ -4091,7 +4107,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInviteLinkStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInviteLinkStruct": { "type": "object", "properties": { "groupJid": { @@ -4102,7 +4118,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.JoinGroupStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.JoinGroupStruct": { "type": "object", "properties": { "code": { @@ -4110,7 +4126,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.LeaveGroupStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.LeaveGroupStruct": { "type": "object", "properties": { "groupJid": { @@ -4118,7 +4134,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupDescriptionStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupDescriptionStruct": { "type": "object", "properties": { "description": { @@ -4129,7 +4145,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupNameStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupNameStruct": { "type": "object", "properties": { "groupJid": { @@ -4140,7 +4156,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupPhotoStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupPhotoStruct": { "type": "object", "properties": { "groupJid": { @@ -4151,7 +4167,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_group_service.UpdateGroupSettingsStruct": { + "github_com_evolution-foundation_evolution-go_pkg_group_service.UpdateGroupSettingsStruct": { "type": "object", "properties": { "action": { @@ -4163,7 +4179,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings": { + "github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings": { "type": "object", "properties": { "alwaysOnline": { @@ -4186,7 +4202,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.ConnectStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.ConnectStruct": { "type": "object", "properties": { "immediate": { @@ -4215,11 +4231,11 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.CreateStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.CreateStruct": { "type": "object", "properties": { "advancedSettings": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings" }, "instanceId": { "type": "string" @@ -4228,14 +4244,14 @@ "type": "string" }, "proxy": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ProxyConfig" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ProxyConfig" }, "token": { "type": "string" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.ForceReconnectStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.ForceReconnectStruct": { "type": "object", "properties": { "number": { @@ -4243,7 +4259,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.PairStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.PairStruct": { "type": "object", "properties": { "phone": { @@ -4257,7 +4273,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.ProxyConfig": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.ProxyConfig": { "type": "object", "properties": { "host": { @@ -4277,7 +4293,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_instance_service.SetProxyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_instance_service.SetProxyStruct": { "type": "object", "required": [ "host", @@ -4301,7 +4317,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct": { + "github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct": { "type": "object", "properties": { "jid": { @@ -4312,7 +4328,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_label_service.EditLabelStruct": { + "github_com_evolution-foundation_evolution-go_pkg_label_service.EditLabelStruct": { "type": "object", "properties": { "color": { @@ -4329,7 +4345,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct": { + "github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct": { "type": "object", "properties": { "jid": { @@ -4343,7 +4359,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.ChatPresenceStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.ChatPresenceStruct": { "type": "object", "properties": { "delay": { @@ -4361,7 +4377,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.DownloadMediaStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.DownloadMediaStruct": { "type": "object", "properties": { "message": { @@ -4369,7 +4385,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.EditMessageStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.EditMessageStruct": { "type": "object", "properties": { "chat": { @@ -4383,7 +4399,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkPlayedStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MarkPlayedStruct": { "type": "object", "properties": { "id": { @@ -4397,7 +4413,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkReadStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MarkReadStruct": { "type": "object", "properties": { "id": { @@ -4411,7 +4427,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStatusStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStatusStruct": { "type": "object", "properties": { "id": { @@ -4419,7 +4435,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStruct": { "type": "object", "properties": { "chat": { @@ -4430,7 +4446,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_message_service.ReactStruct": { + "github_com_evolution-foundation_evolution-go_pkg_message_service.ReactStruct": { "type": "object", "properties": { "fromMe": { @@ -4450,7 +4466,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.CreateNewsletterStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.CreateNewsletterStruct": { "type": "object", "properties": { "description": { @@ -4461,7 +4477,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct": { "type": "object", "properties": { "key": { @@ -4469,7 +4485,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct": { "type": "object", "properties": { "before_id": { @@ -4483,7 +4499,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct": { + "github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct": { "type": "object", "properties": { "jid": { @@ -4491,7 +4507,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollResults": { + "github_com_evolution-foundation_evolution-go_pkg_poll_model.PollResults": { "type": "object", "properties": { "optionCounts": { @@ -4513,18 +4529,18 @@ "voters": { "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.VoterInfo" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.VoterInfo" } }, "votes": { "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollVote" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.PollVote" } } } }, - "github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollVote": { + "github_com_evolution-foundation_evolution-go_pkg_poll_model.PollVote": { "type": "object", "properties": { "companyId": { @@ -4569,7 +4585,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_poll_model.VoterInfo": { + "github_com_evolution-foundation_evolution-go_pkg_poll_model.VoterInfo": { "type": "object", "properties": { "jid": { @@ -4592,7 +4608,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Button": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Button": { "type": "object", "properties": { "copyCode": { @@ -4661,14 +4677,14 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ButtonStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ButtonStruct": { "type": "object", "properties": { "buttons": { "description": "Buttons array. See combination rules on the parent type description.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Button" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Button" } }, "delay": { @@ -4714,7 +4730,7 @@ "description": "Quoted (reply-to) context.", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } ] }, @@ -4729,7 +4745,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselButtonStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselButtonStruct": { "type": "object", "properties": { "copyCode": { @@ -4764,7 +4780,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct": { "type": "object", "properties": { "text": { @@ -4774,7 +4790,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct": { "type": "object", "properties": { "imageUrl": { @@ -4798,14 +4814,14 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardStruct": { "type": "object", "properties": { "body": { "description": "Card body text (required).", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct" } ] }, @@ -4813,7 +4829,7 @@ "description": "Buttons shown on the card. See CarouselButtonStruct for combination rules.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselButtonStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselButtonStruct" } }, "footer": { @@ -4825,13 +4841,13 @@ "description": "Card header (media + title/subtitle).", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct" } ] } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselStruct": { "type": "object", "properties": { "body": { @@ -4843,7 +4859,7 @@ "description": "Cards displayed in order. At least one card is required.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardStruct" } }, "delay": { @@ -4869,13 +4885,13 @@ "description": "Quoted (reply-to) context.", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } ] } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ContactStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ContactStruct": { "type": "object", "properties": { "delay": { @@ -4900,14 +4916,14 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "vcard": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_utils.VCardStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_utils.VCardStruct" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LinkStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LinkStruct": { "type": "object", "properties": { "delay": { @@ -4938,7 +4954,7 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "text": { "type": "string" @@ -4951,7 +4967,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ListStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ListStruct": { "type": "object", "properties": { "buttonText": { @@ -4998,7 +5014,7 @@ "description": "Quoted (reply-to) context.", "allOf": [ { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } ] }, @@ -5006,7 +5022,7 @@ "description": "Sections with rows. At least one section with one row is required.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Section" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Section" } }, "title": { @@ -5016,7 +5032,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LocationStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LocationStruct": { "type": "object", "properties": { "address": { @@ -5053,11 +5069,11 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.MediaStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.MediaStruct": { "type": "object", "properties": { "caption": { @@ -5091,7 +5107,7 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "type": { "type": "string" @@ -5101,7 +5117,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.PollStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.PollStruct": { "type": "object", "properties": { "delay": { @@ -5138,11 +5154,11 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct": { "type": "object", "properties": { "messageId": { @@ -5153,7 +5169,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Row": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Row": { "type": "object", "properties": { "description": { @@ -5173,14 +5189,14 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Section": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Section": { "type": "object", "properties": { "rows": { "description": "Rows inside this section.", "type": "array", "items": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Row" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Row" } }, "title": { @@ -5190,7 +5206,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StatusTextStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StatusTextStruct": { "type": "object", "properties": { "id": { @@ -5201,7 +5217,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StickerStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StickerStruct": { "type": "object", "properties": { "delay": { @@ -5226,14 +5242,14 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "sticker": { "type": "string" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.TextStruct": { + "github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.TextStruct": { "type": "object", "properties": { "delay": { @@ -5261,14 +5277,14 @@ "type": "string" }, "quoted": { - "$ref": "#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct" + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct" }, "text": { "type": "string" } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct": { "type": "object", "properties": { "number": { @@ -5276,7 +5292,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct": { "type": "object", "properties": { "formatJid": { @@ -5290,7 +5306,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.GetAvatarStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.GetAvatarStruct": { "type": "object", "properties": { "number": { @@ -5301,7 +5317,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.PrivacyStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.PrivacyStruct": { "type": "object", "properties": { "callAdd": { @@ -5327,7 +5343,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct": { + "github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct": { "type": "object", "properties": { "image": { @@ -5335,7 +5351,7 @@ } } }, - "github_com_EvolutionAPI_evolution-go_pkg_utils.VCardStruct": { + "github_com_evolution-foundation_evolution-go_pkg_utils.VCardStruct": { "type": "object", "properties": { "fullName": { @@ -5507,6 +5523,9 @@ "description": "Whether the chat is a group chat or broadcast list.", "type": "boolean" }, + "isNewsletterStatus": { + "type": "boolean" + }, "mediaType": { "type": "string" }, @@ -5628,11 +5647,26 @@ "types.VerifiedName": { "type": "object", "properties": { + "actualActors": { + "type": "integer" + }, "certificate": { "$ref": "#/definitions/waVnameCert.VerifiedNameCertificate" }, "details": { "$ref": "#/definitions/waVnameCert.VerifiedNameCertificate_Details" + }, + "hostStorage": { + "type": "integer" + }, + "privacyModeTS": { + "type": "string" + }, + "verifiedLevel": { + "type": "string" + }, + "version": { + "type": "integer" } } }, @@ -5718,6 +5752,28 @@ } } }, + "waAICommon.AIProvenance": { + "type": "object", + "properties": { + "c2PaMetadata": { + "$ref": "#/definitions/waAICommon.AIProvenance_Metadata" + }, + "iptcMetadata": { + "$ref": "#/definitions/waAICommon.AIProvenance_Metadata" + } + } + }, + "waAICommon.AIProvenance_Metadata": { + "type": "object", + "properties": { + "createdWithGenAi": { + "type": "boolean" + }, + "editedWithGenAi": { + "type": "boolean" + } + } + }, "waAICommon.AIRegenerateMetadata": { "type": "object", "properties": { @@ -5839,6 +5895,12 @@ "waAICommon.BotAgentDeepLinkMetadata": { "type": "object", "properties": { + "clientPublicKey": { + "type": "array", + "items": { + "type": "integer" + } + }, "token": { "type": "string" } @@ -5932,7 +5994,11 @@ 62, 63, 64, - 65 + 65, + 66, + 67, + 68, + 69 ], "x-enum-varnames": [ "BotCapabilityMetadata_UNKNOWN", @@ -6000,7 +6066,11 @@ "BotCapabilityMetadata_UNIFIED_RESPONSE_AI_CONTENT_SEARCH_ENABLED", "BotCapabilityMetadata_UNIFIED_RESPONSE_MARKDOWN_LINKS_ENABLED", "BotCapabilityMetadata_AI_RICH_RESPONSE_MAPS_V2_ENABLED", - "BotCapabilityMetadata_AI_SUBSCRIPTION_METERING_ENABLED" + "BotCapabilityMetadata_AI_SUBSCRIPTION_METERING_ENABLED", + "BotCapabilityMetadata_RICH_RESPONSE_SPORTS_WIDGET_ENABLED", + "BotCapabilityMetadata_AI_RICH_RESPONSE_ARTIFACTS_ENABLED", + "BotCapabilityMetadata_AI_RICH_RESPONSE_EMAIL_CALENDAR_ENABLED", + "BotCapabilityMetadata_AI_RICH_RESPONSE_REMINDERS_ENABLED" ] }, "waAICommon.BotCommandMetadata": { @@ -6251,6 +6321,17 @@ } } }, + "waAICommon.BotHistoryShareMetadata": { + "type": "object", + "properties": { + "participantsMetadata": { + "type": "array", + "items": { + "$ref": "#/definitions/waAICommon.BotGroupParticipantMetadata" + } + } + } + }, "waAICommon.BotImagineMetadata": { "type": "object", "properties": { @@ -6490,6 +6571,9 @@ "botGroupMetadata": { "$ref": "#/definitions/waAICommon.BotGroupMetadata" }, + "botHistoryShareMetadata": { + "$ref": "#/definitions/waAICommon.BotHistoryShareMetadata" + }, "botInfrastructureDiagnostics": { "$ref": "#/definitions/waAICommon.BotInfrastructureDiagnostics" }, @@ -6657,7 +6741,8 @@ 47, 54, 55, - 56 + 56, + 57 ], "x-enum-varnames": [ "BotMetricsEntryPoint_UNDEFINED_ENTRY_POINT", @@ -6707,7 +6792,8 @@ "BotMetricsEntryPoint_WEB_NAVIGATION_BAR", "BotMetricsEntryPoint_GROUP_MEMBER", "BotMetricsEntryPoint_CHATLIST_SEARCH", - "BotMetricsEntryPoint_NEW_CHAT_LIST" + "BotMetricsEntryPoint_NEW_CHAT_LIST", + "BotMetricsEntryPoint_CONTACTS_TAB" ] }, "waAICommon.BotMetricsMetadata": { @@ -7965,6 +8051,28 @@ "ADVEncryptionType_HOSTED" ] }, + "waAea.NonE2EEAttestation": { + "type": "object", + "properties": { + "accountType": { + "$ref": "#/definitions/waAea.NonE2EEAttestation_AccountType" + } + } + }, + "waAea.NonE2EEAttestation_AccountType": { + "type": "integer", + "format": "int32", + "enum": [ + 0, + 1, + 2 + ], + "x-enum-varnames": [ + "NonE2EEAttestation_E2EE", + "NonE2EEAttestation_HYBRID_E2EE", + "NonE2EEAttestation_NON_E2EE" + ] + }, "waCommon.LimitSharing": { "type": "object", "properties": { @@ -8348,6 +8456,23 @@ "BCallMessage_VIDEO" ] }, + "waE2E.BotHistoryShareSyncMetadata": { + "type": "object", + "properties": { + "botJID": { + "type": "string" + }, + "historyShareCutoffTimestamp": { + "type": "integer" + }, + "historyShareMessages": { + "type": "array", + "items": { + "$ref": "#/definitions/waE2E.HistoryShareMessageEntry" + } + } + } + }, "waE2E.ButtonsMessage": { "type": "object", "properties": { @@ -8487,6 +8612,9 @@ "type": "integer" } }, + "callReason": { + "type": "string" + }, "contextInfo": { "$ref": "#/definitions/waE2E.ContextInfo" }, @@ -8769,6 +8897,9 @@ "afterReadDuration": { "type": "integer" }, + "aiProvenance": { + "$ref": "#/definitions/waAICommon.AIProvenance" + }, "alwaysShowAdAttribution": { "type": "boolean" }, @@ -8865,6 +8996,9 @@ "groupSubject": { "type": "string" }, + "instagramThreadLink": { + "$ref": "#/definitions/waE2E.ContextInfo_InstagramThreadLink" + }, "isForwarded": { "type": "boolean" }, @@ -9026,6 +9160,9 @@ "items": { "type": "integer" } + }, + "unauthenticatedBusinessMetadata": { + "$ref": "#/definitions/waE2E.ContextInfo_BusinessInteractionPills_UnauthenticatedBusinessMetadata" } } }, @@ -9094,6 +9231,23 @@ "ContextInfo_BusinessInteractionPills_ORDER" ] }, + "waE2E.ContextInfo_BusinessInteractionPills_UnauthenticatedBusinessMetadata": { + "type": "object", + "properties": { + "businessCategory": { + "type": "string" + }, + "businessIsOpen": { + "type": "boolean" + }, + "businessIsOpenSnapshotMS": { + "type": "integer" + }, + "businessName": { + "type": "string" + } + } + }, "waE2E.ContextInfo_BusinessMessageForwardInfo": { "type": "object", "properties": { @@ -9363,6 +9517,14 @@ "ContextInfo_ForwardedNewsletterMessageInfo_LINK_CARD" ] }, + "waE2E.ContextInfo_InstagramThreadLink": { + "type": "object", + "properties": { + "URL": { + "type": "string" + } + } + }, "waE2E.ContextInfo_PairedMediaType": { "type": "integer", "format": "int32", @@ -9930,7 +10092,7 @@ "$ref": "#/definitions/waE2E.VideoEndCard" } }, - "faviconMMSMetadata": { + "faviconMmsMetadata": { "$ref": "#/definitions/waE2E.MMSThumbnailMetadata" }, "font": { @@ -10253,6 +10415,20 @@ } } }, + "waE2E.HistoryShareMessageEntry": { + "type": "object", + "properties": { + "messageSecretProof": { + "type": "array", + "items": { + "type": "integer" + } + }, + "stanzaID": { + "type": "string" + } + } + }, "waE2E.HistorySyncMessageAccessStatus": { "type": "object", "properties": { @@ -11129,6 +11305,26 @@ } } }, + "waE2E.MarkAsVerifiedAction": { + "type": "object", + "properties": { + "actionSeq": { + "type": "integer" + }, + "userJIDString": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verifiedIdentityKey": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, "waE2E.MediaDomainInfo": { "type": "object", "properties": { @@ -11461,6 +11657,9 @@ "splitPaymentMessage": { "$ref": "#/definitions/waE2E.SplitPaymentMessage" }, + "splitPaymentUpdateMessage": { + "$ref": "#/definitions/waE2E.SplitPaymentUpdateMessage" + }, "spoilerMessage": { "$ref": "#/definitions/waE2E.FutureProofMessage" }, @@ -11578,6 +11777,15 @@ "waE2E.MessageContextInfo": { "type": "object", "properties": { + "accountEncryptionAttestation": { + "$ref": "#/definitions/waAea.NonE2EEAttestation" + }, + "associatedPrimaryIdentityKey": { + "type": "array", + "items": { + "type": "integer" + } + }, "botMessageSecret": { "type": "array", "items": { @@ -11725,6 +11933,9 @@ "waE2E.MessageHistoryNotice": { "type": "object", "properties": { + "botHistoryShareSyncMetadata": { + "$ref": "#/definitions/waE2E.BotHistoryShareSyncMetadata" + }, "contextInfo": { "$ref": "#/definitions/waE2E.ContextInfo" }, @@ -11952,6 +12163,9 @@ "waE2E.PaymentExtendedMetadata": { "type": "object", "properties": { + "messageParamsJSON": { + "type": "string" + }, "platform": { "type": "string" }, @@ -12690,7 +12904,8 @@ 10, 11, 12, - 13 + 13, + 14 ], "x-enum-varnames": [ "PeerDataOperationRequestType_UPLOAD_STICKER", @@ -12706,7 +12921,8 @@ "PeerDataOperationRequestType_HISTORY_SYNC_CHUNK_RETRY", "PeerDataOperationRequestType_GALAXY_FLOW_ACTION", "PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_DELIVERED_TO", - "PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_REFRESH" + "PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_REFRESH", + "PeerDataOperationRequestType_CONTACT_REFRESH_REQUEST" ] }, "waE2E.PinInChatMessage": { @@ -13114,6 +13330,9 @@ "cloudApiThreadControlNotification": { "$ref": "#/definitions/waE2E.CloudAPIThreadControlNotification" }, + "coexStateSync": { + "$ref": "#/definitions/waServerSync.CoexStateSync" + }, "disappearingMode": { "$ref": "#/definitions/waE2E.DisappearingMode" }, @@ -13144,6 +13363,9 @@ "limitSharing": { "$ref": "#/definitions/waCommon.LimitSharing" }, + "markAsVerifiedAction": { + "$ref": "#/definitions/waE2E.MarkAsVerifiedAction" + }, "mediaNotifyMessage": { "$ref": "#/definitions/waE2E.MediaNotifyMessage" }, @@ -13159,6 +13381,9 @@ "requestWelcomeMessageMetadata": { "$ref": "#/definitions/waE2E.RequestWelcomeMessageMetadata" }, + "syncRequestMutationRetry": { + "$ref": "#/definitions/waE2E.SyncRequestMutationRetry" + }, "timestampMS": { "type": "integer" }, @@ -13200,7 +13425,10 @@ 31, 32, 34, - 35 + 35, + 36, + 37, + 38 ], "x-enum-varnames": [ "ProtocolMessage_REVOKE", @@ -13232,7 +13460,10 @@ "ProtocolMessage_AI_MEDIA_COLLECTION_MESSAGE", "ProtocolMessage_MESSAGE_UNSCHEDULE", "ProtocolMessage_CHAT_THEME_SETTING", - "ProtocolMessage_AI_METADATA_OPERATION" + "ProtocolMessage_AI_METADATA_OPERATION", + "ProtocolMessage_MARK_AS_VERIFIED_ACTION", + "ProtocolMessage_COEX_STATE_SYNC", + "ProtocolMessage_SYNC_REQUEST_MUTATION_RETRY" ] }, "waE2E.QuestionResponseMessage": { @@ -13526,6 +13757,17 @@ "SplitPaymentParticipant_PAID" ] }, + "waE2E.SplitPaymentUpdateMessage": { + "type": "object", + "properties": { + "participantJID": { + "type": "string" + }, + "splitID": { + "type": "string" + } + } + }, "waE2E.StatusNotificationMessage": { "type": "object", "properties": { @@ -13858,6 +14100,31 @@ } } }, + "waE2E.SyncRequestMutationRetry": { + "type": "object", + "properties": { + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/waE2E.SyncRequestMutationRetry_Collection" + } + }, + "count": { + "type": "integer" + } + } + }, + "waE2E.SyncRequestMutationRetry_Collection": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "storedSyncdVersion": { + "type": "integer" + } + } + }, "waE2E.TemplateButtonReplyMessage": { "type": "object", "properties": { @@ -14180,6 +14447,82 @@ "MediaRetryNotification_DECRYPTION_ERROR" ] }, + "waServerSync.CoexStateSync": { + "type": "object", + "properties": { + "collectionMutations": { + "type": "array", + "items": { + "$ref": "#/definitions/waServerSync.CoexStateSync_CollectionMutations" + } + } + } + }, + "waServerSync.CoexStateSync_CollectionMutations": { + "type": "object", + "properties": { + "collection": { + "type": "string" + }, + "mutations": { + "type": "array", + "items": { + "$ref": "#/definitions/waServerSync.CoexStateSync_Mutation" + } + } + } + }, + "waServerSync.CoexStateSync_Mutation": { + "type": "object", + "properties": { + "dirtyVersion": { + "type": "integer" + }, + "index": { + "$ref": "#/definitions/waServerSync.SyncdIndex" + }, + "operation": { + "$ref": "#/definitions/waServerSync.SyncdMutation_SyncdOperation" + }, + "value": { + "$ref": "#/definitions/waServerSync.SyncdValue" + } + } + }, + "waServerSync.SyncdIndex": { + "type": "object", + "properties": { + "blob": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "waServerSync.SyncdMutation_SyncdOperation": { + "type": "integer", + "format": "int32", + "enum": [ + 0, + 1 + ], + "x-enum-varnames": [ + "SyncdMutation_SET", + "SyncdMutation_REMOVE" + ] + }, + "waServerSync.SyncdValue": { + "type": "object", + "properties": { + "blob": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, "waStatusAttributions.StatusAttribution": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 5c6fe8bb..6a18fb1a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2,26 +2,38 @@ definitions: gin.H: additionalProperties: {} type: object - github_com_EvolutionAPI_evolution-go_pkg_call_service.RejectCallStruct: + github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct: properties: callCreator: $ref: '#/definitions/types.JID' callId: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct: + github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct: + properties: + callId: + type: string + type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct: + properties: + callCreator: + $ref: '#/definitions/types.JID' + callId: + type: string + type: object + github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct: properties: chat: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_chat_service.HistorySyncRequestStruct: + github_com_evolution-foundation_evolution-go_pkg_chat_service.HistorySyncRequestStruct: properties: count: type: integer messageInfo: $ref: '#/definitions/types.MessageInfo' type: object - github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct: + github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct: properties: communityJid: type: string @@ -30,12 +42,12 @@ definitions: type: string type: array type: object - github_com_EvolutionAPI_evolution-go_pkg_community_service.CreateCommunityStruct: + github_com_evolution-foundation_evolution-go_pkg_community_service.CreateCommunityStruct: properties: communityName: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.AddParticipantStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.AddParticipantStruct: properties: action: $ref: '#/definitions/whatsmeow.ParticipantChange' @@ -46,7 +58,7 @@ definitions: type: string type: array type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.CreateGroupStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.CreateGroupStruct: properties: groupName: type: string @@ -55,50 +67,50 @@ definitions: type: string type: array type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInfoStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInfoStruct: properties: groupJid: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInviteLinkStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInviteLinkStruct: properties: groupJid: type: string reset: type: boolean type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.JoinGroupStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.JoinGroupStruct: properties: code: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.LeaveGroupStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.LeaveGroupStruct: properties: groupJid: $ref: '#/definitions/types.JID' type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupDescriptionStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupDescriptionStruct: properties: description: type: string groupJid: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupNameStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupNameStruct: properties: groupJid: type: string name: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupPhotoStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupPhotoStruct: properties: groupJid: type: string image: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_group_service.UpdateGroupSettingsStruct: + github_com_evolution-foundation_evolution-go_pkg_group_service.UpdateGroupSettingsStruct: properties: action: description: announcement, not_announcement, locked, unlocked @@ -106,7 +118,7 @@ definitions: groupJid: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings: + github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings: properties: alwaysOnline: type: boolean @@ -121,7 +133,7 @@ definitions: rejectCall: type: boolean type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_service.ConnectStruct: + github_com_evolution-foundation_evolution-go_pkg_instance_service.ConnectStruct: properties: immediate: type: boolean @@ -140,25 +152,25 @@ definitions: websocketEnable: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_service.CreateStruct: + github_com_evolution-foundation_evolution-go_pkg_instance_service.CreateStruct: properties: advancedSettings: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings' instanceId: type: string name: type: string proxy: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ProxyConfig' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ProxyConfig' token: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_service.ForceReconnectStruct: + github_com_evolution-foundation_evolution-go_pkg_instance_service.ForceReconnectStruct: properties: number: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_service.PairStruct: + github_com_evolution-foundation_evolution-go_pkg_instance_service.PairStruct: properties: phone: type: string @@ -167,7 +179,7 @@ definitions: type: string type: array type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_service.ProxyConfig: + github_com_evolution-foundation_evolution-go_pkg_instance_service.ProxyConfig: properties: host: type: string @@ -180,7 +192,7 @@ definitions: username: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_instance_service.SetProxyStruct: + github_com_evolution-foundation_evolution-go_pkg_instance_service.SetProxyStruct: properties: host: type: string @@ -196,14 +208,14 @@ definitions: - host - port type: object - github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct: + github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct: properties: jid: type: string labelId: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_label_service.EditLabelStruct: + github_com_evolution-foundation_evolution-go_pkg_label_service.EditLabelStruct: properties: color: type: integer @@ -214,7 +226,7 @@ definitions: name: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct: + github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct: properties: jid: type: string @@ -223,7 +235,7 @@ definitions: messageId: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.ChatPresenceStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.ChatPresenceStruct: properties: delay: description: |- @@ -238,12 +250,12 @@ definitions: state: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.DownloadMediaStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.DownloadMediaStruct: properties: message: $ref: '#/definitions/waE2E.Message' type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.EditMessageStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.EditMessageStruct: properties: chat: type: string @@ -252,7 +264,7 @@ definitions: messageId: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkPlayedStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.MarkPlayedStruct: properties: id: items: @@ -261,7 +273,7 @@ definitions: number: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkReadStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.MarkReadStruct: properties: id: items: @@ -270,19 +282,19 @@ definitions: number: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStatusStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStatusStruct: properties: id: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStruct: properties: chat: type: string messageId: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_message_service.ReactStruct: + github_com_evolution-foundation_evolution-go_pkg_message_service.ReactStruct: properties: fromMe: type: boolean @@ -295,19 +307,19 @@ definitions: reaction: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.CreateNewsletterStruct: + github_com_evolution-foundation_evolution-go_pkg_newsletter_service.CreateNewsletterStruct: properties: description: type: string name: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct: + github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct: properties: key: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct: + github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct: properties: before_id: type: integer @@ -316,12 +328,12 @@ definitions: jid: $ref: '#/definitions/types.JID' type: object - github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct: + github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct: properties: jid: $ref: '#/definitions/types.JID' type: object - github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollResults: + github_com_evolution-foundation_evolution-go_pkg_poll_model.PollResults: properties: optionCounts: additionalProperties: @@ -336,14 +348,14 @@ definitions: type: integer voters: items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.VoterInfo' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.VoterInfo' type: array votes: items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollVote' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.PollVote' type: array type: object - github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollVote: + github_com_evolution-foundation_evolution-go_pkg_poll_model.PollVote: properties: companyId: type: string @@ -373,7 +385,7 @@ definitions: voterPhone: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_poll_model.VoterInfo: + github_com_evolution-foundation_evolution-go_pkg_poll_model.VoterInfo: properties: jid: type: string @@ -388,7 +400,7 @@ definitions: votedAt: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Button: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Button: properties: copyCode: description: Code placed in the clipboard when type=copy. @@ -445,12 +457,12 @@ definitions: example: https://evolutionapi.com type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ButtonStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ButtonStruct: properties: buttons: description: Buttons array. See combination rules on the parent type description. items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Button' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Button' type: array delay: description: Typing delay (milliseconds) applied before sending the message. @@ -485,7 +497,7 @@ definitions: type: string quoted: allOf: - - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + - $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' description: Quoted (reply-to) context. title: description: Header title (required). @@ -495,7 +507,7 @@ definitions: description: Optional video URL used as header for reply-only buttons. type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselButtonStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselButtonStruct: properties: copyCode: description: Code placed in the clipboard when type=COPY. @@ -525,14 +537,14 @@ definitions: example: REPLY type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct: properties: text: description: Main text of the card. example: Card 1 - Oferta especial type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct: properties: imageUrl: description: Public URL to an image. Downloaded, uploaded to WhatsApp servers @@ -551,17 +563,17 @@ definitions: description: Public URL to a video. Used only when `imageUrl` is empty. type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardStruct: properties: body: allOf: - - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct' + - $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardBodyStruct' description: Card body text (required). buttons: description: Buttons shown on the card. See CarouselButtonStruct for combination rules. items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselButtonStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselButtonStruct' type: array footer: description: Optional footer rendered under the body. @@ -569,10 +581,10 @@ definitions: type: string header: allOf: - - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct' + - $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardHeaderStruct' description: Card header (media + title/subtitle). type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselStruct: properties: body: description: Optional message body shown above the cards. @@ -581,7 +593,7 @@ definitions: cards: description: Cards displayed in order. At least one card is required. items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselCardStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselCardStruct' type: array delay: description: Typing delay (milliseconds) applied before sending the message. @@ -601,10 +613,10 @@ definitions: type: string quoted: allOf: - - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + - $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' description: Quoted (reply-to) context. type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ContactStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ContactStruct: properties: delay: type: integer @@ -621,11 +633,11 @@ definitions: number: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' vcard: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_utils.VCardStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_utils.VCardStruct' type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LinkStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LinkStruct: properties: delay: type: integer @@ -646,7 +658,7 @@ definitions: number: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' text: type: string title: @@ -654,7 +666,7 @@ definitions: url: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ListStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ListStruct: properties: buttonText: description: Label of the button that opens the list. Defaults to "Ver Menu" @@ -691,19 +703,19 @@ definitions: type: string quoted: allOf: - - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + - $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' description: Quoted (reply-to) context. sections: description: Sections with rows. At least one section with one row is required. items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Section' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Section' type: array title: description: Header title (required). example: Nossos planos type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LocationStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LocationStruct: properties: address: type: string @@ -728,9 +740,9 @@ definitions: number: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.MediaStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.MediaStruct: properties: caption: type: string @@ -753,13 +765,13 @@ definitions: number: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' type: type: string url: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.PollStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.PollStruct: properties: delay: type: integer @@ -784,16 +796,16 @@ definitions: question: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct: properties: messageId: type: string participant: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Row: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Row: properties: description: description: Optional secondary line below the title. @@ -809,26 +821,26 @@ definitions: example: Plano Basico type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Section: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Section: properties: rows: description: Rows inside this section. items: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.Row' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.Row' type: array title: description: Section heading (optional; rendered as a group separator). example: Planos type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StatusTextStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StatusTextStruct: properties: id: type: string text: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StickerStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StickerStruct: properties: delay: type: integer @@ -845,11 +857,11 @@ definitions: number: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' sticker: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.TextStruct: + github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.TextStruct: properties: delay: type: integer @@ -868,16 +880,16 @@ definitions: number: type: string quoted: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.QuotedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.QuotedStruct' text: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct: + github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct: properties: number: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct: + github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct: properties: formatJid: type: boolean @@ -886,14 +898,14 @@ definitions: type: string type: array type: object - github_com_EvolutionAPI_evolution-go_pkg_user_service.GetAvatarStruct: + github_com_evolution-foundation_evolution-go_pkg_user_service.GetAvatarStruct: properties: number: type: string preview: type: boolean type: object - github_com_EvolutionAPI_evolution-go_pkg_user_service.PrivacyStruct: + github_com_evolution-foundation_evolution-go_pkg_user_service.PrivacyStruct: properties: callAdd: $ref: '#/definitions/types.PrivacySetting' @@ -910,12 +922,12 @@ definitions: status: $ref: '#/definitions/types.PrivacySetting' type: object - github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct: + github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct: properties: image: type: string type: object - github_com_EvolutionAPI_evolution-go_pkg_utils.VCardStruct: + github_com_evolution-foundation_evolution-go_pkg_utils.VCardStruct: properties: fullName: type: string @@ -1037,6 +1049,8 @@ definitions: isGroup: description: Whether the chat is a group chat or broadcast list. type: boolean + isNewsletterStatus: + type: boolean mediaType: type: string msgBotInfo: @@ -1119,10 +1133,20 @@ definitions: - PrivacySettingOff types.VerifiedName: properties: + actualActors: + type: integer certificate: $ref: '#/definitions/waVnameCert.VerifiedNameCertificate' details: $ref: '#/definitions/waVnameCert.VerifiedNameCertificate_Details' + hostStorage: + type: integer + privacyModeTS: + type: string + verifiedLevel: + type: string + version: + type: integer type: object types.WebAuthnResponse: properties: @@ -1177,6 +1201,20 @@ definitions: hatchMetadataSync: $ref: '#/definitions/waAICommon.HatchMetadataSync' type: object + waAICommon.AIProvenance: + properties: + c2PaMetadata: + $ref: '#/definitions/waAICommon.AIProvenance_Metadata' + iptcMetadata: + $ref: '#/definitions/waAICommon.AIProvenance_Metadata' + type: object + waAICommon.AIProvenance_Metadata: + properties: + createdWithGenAi: + type: boolean + editedWithGenAi: + type: boolean + type: object waAICommon.AIRegenerateMetadata: properties: messageKey: @@ -1261,6 +1299,10 @@ definitions: - BotAgeCollectionMetadata_WAFFLE waAICommon.BotAgentDeepLinkMetadata: properties: + clientPublicKey: + items: + type: integer + type: array token: type: string type: object @@ -1344,6 +1386,10 @@ definitions: - 63 - 64 - 65 + - 66 + - 67 + - 68 + - 69 format: int32 type: integer x-enum-varnames: @@ -1413,6 +1459,10 @@ definitions: - BotCapabilityMetadata_UNIFIED_RESPONSE_MARKDOWN_LINKS_ENABLED - BotCapabilityMetadata_AI_RICH_RESPONSE_MAPS_V2_ENABLED - BotCapabilityMetadata_AI_SUBSCRIPTION_METERING_ENABLED + - BotCapabilityMetadata_RICH_RESPONSE_SPORTS_WIDGET_ENABLED + - BotCapabilityMetadata_AI_RICH_RESPONSE_ARTIFACTS_ENABLED + - BotCapabilityMetadata_AI_RICH_RESPONSE_EMAIL_CALENDAR_ENABLED + - BotCapabilityMetadata_AI_RICH_RESPONSE_REMINDERS_ENABLED waAICommon.BotCommandMetadata: properties: commandDescription: @@ -1586,6 +1636,13 @@ definitions: botFbid: type: string type: object + waAICommon.BotHistoryShareMetadata: + properties: + participantsMetadata: + items: + $ref: '#/definitions/waAICommon.BotGroupParticipantMetadata' + type: array + type: object waAICommon.BotImagineMetadata: properties: imagineType: @@ -1748,6 +1805,8 @@ definitions: $ref: '#/definitions/waAICommon.BotDocumentMessageMetadata' botGroupMetadata: $ref: '#/definitions/waAICommon.BotGroupMetadata' + botHistoryShareMetadata: + $ref: '#/definitions/waAICommon.BotHistoryShareMetadata' botInfrastructureDiagnostics: $ref: '#/definitions/waAICommon.BotInfrastructureDiagnostics' botLinkedAccountsMetadata: @@ -1875,6 +1934,7 @@ definitions: - 54 - 55 - 56 + - 57 format: int32 type: integer x-enum-varnames: @@ -1926,6 +1986,7 @@ definitions: - BotMetricsEntryPoint_GROUP_MEMBER - BotMetricsEntryPoint_CHATLIST_SEARCH - BotMetricsEntryPoint_NEW_CHAT_LIST + - BotMetricsEntryPoint_CONTACTS_TAB waAICommon.BotMetricsMetadata: properties: destinationEntryPoint: @@ -2800,6 +2861,22 @@ definitions: x-enum-varnames: - ADVEncryptionType_E2EE - ADVEncryptionType_HOSTED + waAea.NonE2EEAttestation: + properties: + accountType: + $ref: '#/definitions/waAea.NonE2EEAttestation_AccountType' + type: object + waAea.NonE2EEAttestation_AccountType: + enum: + - 0 + - 1 + - 2 + format: int32 + type: integer + x-enum-varnames: + - NonE2EEAttestation_E2EE + - NonE2EEAttestation_HYBRID_E2EE + - NonE2EEAttestation_NON_E2EE waCommon.LimitSharing: properties: initiatedByMe: @@ -3054,6 +3131,17 @@ definitions: - BCallMessage_UNKNOWN - BCallMessage_AUDIO - BCallMessage_VIDEO + waE2E.BotHistoryShareSyncMetadata: + properties: + botJID: + type: string + historyShareCutoffTimestamp: + type: integer + historyShareMessages: + items: + $ref: '#/definitions/waE2E.HistoryShareMessageEntry' + type: array + type: object waE2E.ButtonsMessage: properties: buttons: @@ -3152,6 +3240,8 @@ definitions: items: type: integer type: array + callReason: + type: string contextInfo: $ref: '#/definitions/waE2E.ContextInfo' conversionData: @@ -3346,6 +3436,8 @@ definitions: $ref: '#/definitions/waE2E.ActionLink' afterReadDuration: type: integer + aiProvenance: + $ref: '#/definitions/waAICommon.AIProvenance' alwaysShowAdAttribution: type: boolean botMessageSharingInfo: @@ -3410,6 +3502,8 @@ definitions: type: array groupSubject: type: string + instagramThreadLink: + $ref: '#/definitions/waE2E.ContextInfo_InstagramThreadLink' isForwarded: type: boolean isGroupStatus: @@ -3519,6 +3613,8 @@ definitions: items: type: integer type: array + unauthenticatedBusinessMetadata: + $ref: '#/definitions/waE2E.ContextInfo_BusinessInteractionPills_UnauthenticatedBusinessMetadata' type: object waE2E.ContextInfo_BusinessInteractionPills_EntryPoint: enum: @@ -3575,6 +3671,17 @@ definitions: - ContextInfo_BusinessInteractionPills_ABOUT - ContextInfo_BusinessInteractionPills_SHOP - ContextInfo_BusinessInteractionPills_ORDER + waE2E.ContextInfo_BusinessInteractionPills_UnauthenticatedBusinessMetadata: + properties: + businessCategory: + type: string + businessIsOpen: + type: boolean + businessIsOpenSnapshotMS: + type: integer + businessName: + type: string + type: object waE2E.ContextInfo_BusinessMessageForwardInfo: properties: businessOwnerJID: @@ -3762,6 +3869,11 @@ definitions: - ContextInfo_ForwardedNewsletterMessageInfo_UPDATE - ContextInfo_ForwardedNewsletterMessageInfo_UPDATE_CARD - ContextInfo_ForwardedNewsletterMessageInfo_LINK_CARD + waE2E.ContextInfo_InstagramThreadLink: + properties: + URL: + type: string + type: object waE2E.ContextInfo_PairedMediaType: enum: - 0 @@ -4155,7 +4267,7 @@ definitions: items: $ref: '#/definitions/waE2E.VideoEndCard' type: array - faviconMMSMetadata: + faviconMmsMetadata: $ref: '#/definitions/waE2E.MMSThumbnailMetadata' font: $ref: '#/definitions/waE2E.ExtendedTextMessage_FontType' @@ -4379,6 +4491,15 @@ definitions: paramOneof: description: "Types that are valid to be assigned to ParamOneof:\n\n\t*HighlyStructuredMessage_HSMLocalizableParameter_Currency\n\t*HighlyStructuredMessage_HSMLocalizableParameter_DateTime" type: object + waE2E.HistoryShareMessageEntry: + properties: + messageSecretProof: + items: + type: integer + type: array + stanzaID: + type: string + type: object waE2E.HistorySyncMessageAccessStatus: properties: completeAccessGranted: @@ -4976,6 +5097,19 @@ definitions: thumbnailWidth: type: integer type: object + waE2E.MarkAsVerifiedAction: + properties: + actionSeq: + type: integer + userJIDString: + type: string + verified: + type: boolean + verifiedIdentityKey: + items: + type: integer + type: array + type: object waE2E.MediaDomainInfo: properties: e2EeMediaKey: @@ -5198,6 +5332,8 @@ definitions: $ref: '#/definitions/waE2E.SenderKeyDistributionMessage' splitPaymentMessage: $ref: '#/definitions/waE2E.SplitPaymentMessage' + splitPaymentUpdateMessage: + $ref: '#/definitions/waE2E.SplitPaymentUpdateMessage' spoilerMessage: $ref: '#/definitions/waE2E.FutureProofMessage' statusAddYours: @@ -5289,6 +5425,12 @@ definitions: - MessageAssociation_POLL_ADD_OPTION waE2E.MessageContextInfo: properties: + accountEncryptionAttestation: + $ref: '#/definitions/waAea.NonE2EEAttestation' + associatedPrimaryIdentityKey: + items: + type: integer + type: array botMessageSecret: items: type: integer @@ -5387,6 +5529,8 @@ definitions: type: object waE2E.MessageHistoryNotice: properties: + botHistoryShareSyncMetadata: + $ref: '#/definitions/waE2E.BotHistoryShareSyncMetadata' contextInfo: $ref: '#/definitions/waE2E.ContextInfo' messageHistoryMetadata: @@ -5539,6 +5683,8 @@ definitions: - PaymentBackground_DEFAULT waE2E.PaymentExtendedMetadata: properties: + messageParamsJSON: + type: string platform: type: string type: @@ -6045,6 +6191,7 @@ definitions: - 11 - 12 - 13 + - 14 format: int32 type: integer x-enum-varnames: @@ -6062,6 +6209,7 @@ definitions: - PeerDataOperationRequestType_GALAXY_FLOW_ACTION - PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_DELIVERED_TO - PeerDataOperationRequestType_BUSINESS_BROADCAST_INSIGHTS_REFRESH + - PeerDataOperationRequestType_CONTACT_REFRESH_REQUEST waE2E.PinInChatMessage: properties: key: @@ -6334,6 +6482,8 @@ definitions: $ref: '#/definitions/waE2E.ChatThemeSetting' cloudApiThreadControlNotification: $ref: '#/definitions/waE2E.CloudAPIThreadControlNotification' + coexStateSync: + $ref: '#/definitions/waServerSync.CoexStateSync' disappearingMode: $ref: '#/definitions/waE2E.DisappearingMode' editedMessage: @@ -6354,6 +6504,8 @@ definitions: $ref: '#/definitions/waE2E.LIDMigrationMappingSyncMessage' limitSharing: $ref: '#/definitions/waCommon.LimitSharing' + markAsVerifiedAction: + $ref: '#/definitions/waE2E.MarkAsVerifiedAction' mediaNotifyMessage: $ref: '#/definitions/waE2E.MediaNotifyMessage' memberLabel: @@ -6364,6 +6516,8 @@ definitions: $ref: '#/definitions/waE2E.PeerDataOperationRequestResponseMessage' requestWelcomeMessageMetadata: $ref: '#/definitions/waE2E.RequestWelcomeMessageMetadata' + syncRequestMutationRetry: + $ref: '#/definitions/waE2E.SyncRequestMutationRetry' timestampMS: type: integer type: @@ -6401,6 +6555,9 @@ definitions: - 32 - 34 - 35 + - 36 + - 37 + - 38 format: int32 type: integer x-enum-varnames: @@ -6434,6 +6591,9 @@ definitions: - ProtocolMessage_MESSAGE_UNSCHEDULE - ProtocolMessage_CHAT_THEME_SETTING - ProtocolMessage_AI_METADATA_OPERATION + - ProtocolMessage_MARK_AS_VERIFIED_ACTION + - ProtocolMessage_COEX_STATE_SYNC + - ProtocolMessage_SYNC_REQUEST_MUTATION_RETRY waE2E.QuestionResponseMessage: properties: key: @@ -6633,6 +6793,13 @@ definitions: x-enum-varnames: - SplitPaymentParticipant_PENDING - SplitPaymentParticipant_PAID + waE2E.SplitPaymentUpdateMessage: + properties: + participantJID: + type: string + splitID: + type: string + type: object waE2E.StatusNotificationMessage: properties: originalMessageKey: @@ -6857,6 +7024,22 @@ definitions: rmrSource: type: string type: object + waE2E.SyncRequestMutationRetry: + properties: + collections: + items: + $ref: '#/definitions/waE2E.SyncRequestMutationRetry_Collection' + type: array + count: + type: integer + type: object + waE2E.SyncRequestMutationRetry_Collection: + properties: + name: + type: string + storedSyncdVersion: + type: integer + type: object waE2E.TemplateButtonReplyMessage: properties: contextInfo: @@ -7077,6 +7260,56 @@ definitions: - MediaRetryNotification_SUCCESS - MediaRetryNotification_NOT_FOUND - MediaRetryNotification_DECRYPTION_ERROR + waServerSync.CoexStateSync: + properties: + collectionMutations: + items: + $ref: '#/definitions/waServerSync.CoexStateSync_CollectionMutations' + type: array + type: object + waServerSync.CoexStateSync_CollectionMutations: + properties: + collection: + type: string + mutations: + items: + $ref: '#/definitions/waServerSync.CoexStateSync_Mutation' + type: array + type: object + waServerSync.CoexStateSync_Mutation: + properties: + dirtyVersion: + type: integer + index: + $ref: '#/definitions/waServerSync.SyncdIndex' + operation: + $ref: '#/definitions/waServerSync.SyncdMutation_SyncdOperation' + value: + $ref: '#/definitions/waServerSync.SyncdValue' + type: object + waServerSync.SyncdIndex: + properties: + blob: + items: + type: integer + type: array + type: object + waServerSync.SyncdMutation_SyncdOperation: + enum: + - 0 + - 1 + format: int32 + type: integer + x-enum-varnames: + - SyncdMutation_SET + - SyncdMutation_REMOVE + waServerSync.SyncdValue: + properties: + blob: + items: + type: integer + type: array + type: object waStatusAttributions.StatusAttribution: properties: actionURL: @@ -7170,6 +7403,58 @@ info: title: Evolution GO version: "1.0" paths: + /call/answer: + post: + consumes: + - application/json + description: Answer an incoming call and (if it's a video call) accept its video + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Answer call + tags: + - Call + /call/hangup: + post: + consumes: + - application/json + description: Hangup an active call + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Hangup call + tags: + - Call /call/reject: post: consumes: @@ -7181,7 +7466,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_call_service.RejectCallStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct' produces: - application/json responses: @@ -7207,7 +7492,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct' produces: - application/json responses: @@ -7237,7 +7522,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.HistorySyncRequestStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.HistorySyncRequestStruct' produces: - application/json responses: @@ -7267,7 +7552,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct' produces: - application/json responses: @@ -7297,7 +7582,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct' produces: - application/json responses: @@ -7327,7 +7612,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct' produces: - application/json responses: @@ -7357,7 +7642,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct' produces: - application/json responses: @@ -7387,7 +7672,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_chat_service.BodyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct' produces: - application/json responses: @@ -7417,7 +7702,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct' produces: - application/json responses: @@ -7447,7 +7732,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.CreateCommunityStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.CreateCommunityStruct' produces: - application/json responses: @@ -7477,7 +7762,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_community_service.AddParticipantStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_community_service.AddParticipantStruct' produces: - application/json responses: @@ -7507,7 +7792,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.CreateGroupStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.CreateGroupStruct' produces: - application/json responses: @@ -7537,7 +7822,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupDescriptionStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupDescriptionStruct' produces: - application/json responses: @@ -7567,7 +7852,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInfoStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInfoStruct' produces: - application/json responses: @@ -7597,7 +7882,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.GetGroupInviteLinkStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.GetGroupInviteLinkStruct' produces: - application/json responses: @@ -7627,7 +7912,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.JoinGroupStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.JoinGroupStruct' produces: - application/json responses: @@ -7657,7 +7942,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.LeaveGroupStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.LeaveGroupStruct' produces: - application/json responses: @@ -7725,7 +8010,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupNameStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupNameStruct' produces: - application/json responses: @@ -7755,7 +8040,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.AddParticipantStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.AddParticipantStruct' produces: - application/json responses: @@ -7785,7 +8070,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.SetGroupPhotoStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.SetGroupPhotoStruct' produces: - application/json responses: @@ -7816,7 +8101,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_group_service.UpdateGroupSettingsStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_group_service.UpdateGroupSettingsStruct' produces: - application/json responses: @@ -7850,7 +8135,7 @@ paths: "200": description: Advanced settings retrieved successfully schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings' "400": description: Invalid instance ID schema: @@ -7881,7 +8166,7 @@ paths: name: settings required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_model.AdvancedSettings' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_model.AdvancedSettings' produces: - application/json responses: @@ -7934,7 +8219,7 @@ paths: name: instance required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ConnectStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ConnectStruct' produces: - application/json responses: @@ -7965,7 +8250,7 @@ paths: name: instance required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.CreateStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.CreateStruct' produces: - application/json responses: @@ -8048,7 +8333,7 @@ paths: name: instance required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.ForceReconnectStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.ForceReconnectStruct' produces: - application/json responses: @@ -8170,7 +8455,7 @@ paths: name: instance required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.PairStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.PairStruct' produces: - application/json responses: @@ -8233,7 +8518,7 @@ paths: name: proxy required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_instance_service.SetProxyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_instance_service.SetProxyStruct' produces: - application/json responses: @@ -8320,7 +8605,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct' produces: - application/json responses: @@ -8350,7 +8635,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.EditLabelStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.EditLabelStruct' produces: - application/json responses: @@ -8399,7 +8684,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct' produces: - application/json responses: @@ -8418,64 +8703,6 @@ paths: summary: Add label to message tags: - Label - /license/activate: - get: - description: Exchanges an authorization code (from the registration callback) - for an api_key and persists it. Provide the code via the query string. - parameters: - - description: Authorization code from the registration callback - in: query - name: code - required: true - type: string - produces: - - application/json - responses: - "200": - description: Activation result - schema: - $ref: '#/definitions/gin.H' - "400": - description: Missing code parameter - schema: - $ref: '#/definitions/gin.H' - summary: Activate license - tags: - - License - /license/register: - get: - description: Checks the GLOBAL_API_KEY with the licensing server. If not yet - registered, initiates registration and returns a register_url. Accepts an - optional redirect_uri for the post-registration redirect. - parameters: - - description: Post-registration redirect URI - in: query - name: redirect_uri - type: string - produces: - - application/json - responses: - "200": - description: Registration state (status/message or register_url) - schema: - $ref: '#/definitions/gin.H' - summary: Register / get registration URL - tags: - - License - /license/status: - get: - description: Returns whether the instance license is active, along with the - instance id and a masked api key. - produces: - - application/json - responses: - "200": - description: License status ({status, instance_id, api_key?}) - schema: - $ref: '#/definitions/gin.H' - summary: Get license status - tags: - - License /message/delete: post: consumes: @@ -8487,7 +8714,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStruct' produces: - application/json responses: @@ -8518,7 +8745,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.DownloadMediaStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.DownloadMediaStruct' produces: - application/json responses: @@ -8548,7 +8775,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.EditMessageStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.EditMessageStruct' produces: - application/json responses: @@ -8578,7 +8805,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkPlayedStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MarkPlayedStruct' produces: - application/json responses: @@ -8608,7 +8835,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MarkReadStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MarkReadStruct' produces: - application/json responses: @@ -8638,7 +8865,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.ChatPresenceStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.ChatPresenceStruct' produces: - application/json responses: @@ -8669,7 +8896,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.ReactStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.ReactStruct' produces: - application/json responses: @@ -8699,7 +8926,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_message_service.MessageStatusStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_message_service.MessageStatusStruct' produces: - application/json responses: @@ -8729,7 +8956,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.CreateNewsletterStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.CreateNewsletterStruct' produces: - application/json responses: @@ -8759,7 +8986,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct' produces: - application/json responses: @@ -8789,7 +9016,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterInviteStruct' produces: - application/json responses: @@ -8838,7 +9065,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterMessagesStruct' produces: - application/json responses: @@ -8868,7 +9095,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_newsletter_service.GetNewsletterStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_newsletter_service.GetNewsletterStruct' produces: - application/json responses: @@ -9019,7 +9246,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_poll_model.PollResults' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_poll_model.PollResults' "400": description: Bad Request schema: @@ -9058,7 +9285,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ButtonStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ButtonStruct' produces: - application/json responses: @@ -9104,7 +9331,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.CarouselStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.CarouselStruct' produces: - application/json responses: @@ -9134,7 +9361,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ContactStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ContactStruct' produces: - application/json responses: @@ -9164,7 +9391,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LinkStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LinkStruct' produces: - application/json responses: @@ -9201,7 +9428,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.ListStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.ListStruct' produces: - application/json responses: @@ -9231,7 +9458,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.LocationStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.LocationStruct' produces: - application/json responses: @@ -9261,7 +9488,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.MediaStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.MediaStruct' produces: - application/json responses: @@ -9291,7 +9518,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.PollStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.PollStruct' produces: - application/json responses: @@ -9368,7 +9595,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StatusTextStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StatusTextStruct' produces: - application/json responses: @@ -9398,7 +9625,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.StickerStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.StickerStruct' produces: - application/json responses: @@ -9428,7 +9655,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_sendMessage_service.TextStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_sendMessage_service.TextStruct' produces: - application/json responses: @@ -9458,7 +9685,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.ChatLabelStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.ChatLabelStruct' produces: - application/json responses: @@ -9488,7 +9715,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_label_service.MessageLabelStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_label_service.MessageLabelStruct' produces: - application/json responses: @@ -9518,7 +9745,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.GetAvatarStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.GetAvatarStruct' produces: - application/json responses: @@ -9548,7 +9775,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct' produces: - application/json responses: @@ -9597,7 +9824,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct' produces: - application/json responses: @@ -9646,7 +9873,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.CheckUserStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.CheckUserStruct' produces: - application/json responses: @@ -9694,7 +9921,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.PrivacyStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.PrivacyStruct' produces: - application/json responses: @@ -9720,7 +9947,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct' produces: - application/json responses: @@ -9750,7 +9977,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct' produces: - application/json responses: @@ -9780,7 +10007,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.SetProfilePictureStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.SetProfilePictureStruct' produces: - application/json responses: @@ -9810,7 +10037,7 @@ paths: name: message required: true schema: - $ref: '#/definitions/github_com_EvolutionAPI_evolution-go_pkg_user_service.BlockStruct' + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_user_service.BlockStruct' produces: - application/json responses: From 60b2a8f4e7a4732f9e1f77e6b998e963c6ae4276 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 14:14:49 +0000 Subject: [PATCH 19/26] spike: add POST /call/dial for outbound calls (experimental) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not part of the reviewed answer-call plan/design — user asked to try placing an outbound video call live during manual validation. Exposes meowcaller.Client.CallWithOptions via GetMeowcallerClient (new on WhatsmeowService) + CallService.DialCall, registering the resulting call so /call/hangup and /call/stream work on it too. Kept on its own branch (feature/call-dial-spike) rather than mixed into feature/call-answer-stream. --- pkg/call/handler/call_handler.go | 36 ++++++++++++++++++++++++++++++ pkg/call/service/call_service.go | 30 +++++++++++++++++++++++++ pkg/routes/routes.go | 1 + pkg/whatsmeow/service/whatsmeow.go | 15 +++++++++++++ 4 files changed, 82 insertions(+) diff --git a/pkg/call/handler/call_handler.go b/pkg/call/handler/call_handler.go index 70b7bbd6..dc9c094c 100644 --- a/pkg/call/handler/call_handler.go +++ b/pkg/call/handler/call_handler.go @@ -12,6 +12,7 @@ type CallHandler interface { RejectCall(ctx *gin.Context) AnswerCall(ctx *gin.Context) HangupCall(ctx *gin.Context) + DialCall(ctx *gin.Context) } type callHandler struct { @@ -123,6 +124,41 @@ func (g *callHandler) HangupCall(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"message": "success"}) } +// Dial call +// @Summary Place an outbound call +// @Description Spike/experimental: places an outbound call, not part of the reviewed answer-call plan +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.DialCallStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/dial [post] +func (g *callHandler) DialCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.DialCallStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + call, err := g.callService.DialCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success", "callId": call.ID()}) +} + func NewCallHandler( callService call_service.CallService, ) CallHandler { diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index 71c4c14c..56f39a3b 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -1,6 +1,7 @@ package call_service import ( + "context" "errors" call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" @@ -18,6 +19,7 @@ type CallService interface { AnswerCall(data *AnswerCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error GetActiveCall(instanceId, callId string) (*meowcaller.Call, error) + DialCall(data *DialCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) } type callService struct { @@ -41,6 +43,15 @@ type HangupCallStruct struct { CallID string `json:"callId"` } +// DialCallStruct is a spike/experimental addition, outside the reviewed +// answer-call plan: it places an OUTBOUND call rather than answering an +// inbound one. Number accepts anything meowcaller.Client.Call accepts (a +// phone number, a phone JID, or an @lid JID). +type DialCallStruct struct { + Number string `json:"number"` + Video bool `json:"video"` +} + func (c *callService) RejectCall(data *RejectCallStruct, instance *instance_model.Instance) error { call, ok := c.callRegistry.Get(instance.Id, data.CallID) if !ok { @@ -99,6 +110,25 @@ func (c *callService) GetActiveCall(instanceId, callId string) (*meowcaller.Call return call, nil } +// DialCall places an outbound call and registers it so /call/stream and +// /call/hangup can act on it just like an answered inbound call. +func (c *callService) DialCall(data *DialCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) { + meowcallerClient, err := c.whatsmeowService.GetMeowcallerClient(instance.Id) + if err != nil { + return nil, err + } + + call, err := meowcallerClient.CallWithOptions(context.Background(), data.Number, meowcaller.CallOptions{Video: data.Video}) + if err != nil { + logger.LogError("[%s] error dialing call: %v", instance.Id, err) + return nil, err + } + + c.callRegistry.Store(instance.Id, call) + + return call, nil +} + func NewCallService( clientPointer map[string]*whatsmeow.Client, whatsmeowService whatsmeow_service.WhatsmeowService, diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index b179694a..63668840 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -196,6 +196,7 @@ func (r *Routes) AssignRoutes(eng *gin.Engine) { routes.POST("/reject", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.RejectCall) routes.POST("/answer", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.AnswerCall) routes.POST("/hangup", r.callHandler.HangupCall) + routes.POST("/dial", r.callHandler.DialCall) } } routes = eng.Group("/community") diff --git a/pkg/whatsmeow/service/whatsmeow.go b/pkg/whatsmeow/service/whatsmeow.go index fc4aef8b..80a1a1b0 100644 --- a/pkg/whatsmeow/service/whatsmeow.go +++ b/pkg/whatsmeow/service/whatsmeow.go @@ -65,6 +65,11 @@ type WhatsmeowService interface { UpdateInstanceAdvancedSettings(instanceId string) error GetPollService() poll_service.PollService // NOVO: Acesso ao serviço de polls + // GetMeowcallerClient returns the per-instance meowcaller client used to place + // and answer WhatsApp calls. Returns an error if the instance has no active + // meowcaller client (i.e. its whatsmeow client was never started). + GetMeowcallerClient(instanceId string) (*meowcaller.Client, error) + // Passkey (WebAuthn) pairing bridge — read by the public ceremony endpoint, // written by the whatsmeow event goroutine. PasskeyCeremonyStore() *ceremony.Store @@ -2857,6 +2862,16 @@ func (w *whatsmeowService) GetPollService() poll_service.PollService { return w.pollService } +// GetMeowcallerClient returns the meowcaller client for instanceId, if its +// whatsmeow client has been started. +func (w *whatsmeowService) GetMeowcallerClient(instanceId string) (*meowcaller.Client, error) { + client, ok := w.meowcallerPointer[instanceId] + if !ok || client == nil { + return nil, fmt.Errorf("no active meowcaller client for instance %s", instanceId) + } + return client, nil +} + // PasskeyCeremonyStore exposes the shared ceremony store so the public HTTP // polling endpoint can read the current stage for a given ceremony token. func (w *whatsmeowService) PasskeyCeremonyStore() *ceremony.Store { From 14991cddb2bbdba1ceadbfbd3ecf7546cfdac49a Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 14:48:08 +0000 Subject: [PATCH 20/26] spike: add reaction, add-participant, screen share, hand-raise endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continuing experimental call-control coverage on this spike branch: POST /call/react, POST /call/participant/add, POST /call/screenshare, POST /call/handraise, wrapping meowcaller's SendReaction/AddParticipant/ StartScreenShare-StopScreenShare/SetHandRaised. Same pattern as DialCall — registry lookup by callId, thin handler, no new tests (same un-mockable *meowcaller.Call constraint as the rest of this file). --- pkg/call/handler/call_handler.go | 144 +++++++++++++++++++++++++++++++ pkg/call/service/call_service.go | 81 +++++++++++++++++ pkg/routes/routes.go | 4 + 3 files changed, 229 insertions(+) diff --git a/pkg/call/handler/call_handler.go b/pkg/call/handler/call_handler.go index dc9c094c..36fa61f6 100644 --- a/pkg/call/handler/call_handler.go +++ b/pkg/call/handler/call_handler.go @@ -13,6 +13,10 @@ type CallHandler interface { AnswerCall(ctx *gin.Context) HangupCall(ctx *gin.Context) DialCall(ctx *gin.Context) + ReactCall(ctx *gin.Context) + AddParticipant(ctx *gin.Context) + ScreenShareCall(ctx *gin.Context) + HandRaiseCall(ctx *gin.Context) } type callHandler struct { @@ -159,6 +163,146 @@ func (g *callHandler) DialCall(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"message": "success", "callId": call.ID()}) } +// React to a call +// @Summary Send a call reaction +// @Description Spike/experimental: sends an emoji reaction into an active call +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.ReactCallStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/react [post] +func (g *callHandler) ReactCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.ReactCallStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.ReactCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + +// Add participant to a call +// @Summary Add a participant to an active call +// @Description Spike/experimental: adds a participant, upgrading a 1:1 call into a group call +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.AddParticipantStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/participant/add [post] +func (g *callHandler) AddParticipant(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.AddParticipantStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.AddParticipant(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + +// Toggle screen share +// @Summary Start or stop screen sharing in a call +// @Description Spike/experimental: toggles this client's screen share state +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.ScreenShareStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/screenshare [post] +func (g *callHandler) ScreenShareCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.ScreenShareStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.ScreenShareCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + +// Toggle hand raise +// @Summary Raise or lower hand in a call +// @Description Spike/experimental: toggles this client's hand-raised state +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.HandRaiseStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/handraise [post] +func (g *callHandler) HandRaiseCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.HandRaiseStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.HandRaiseCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + func NewCallHandler( callService call_service.CallService, ) CallHandler { diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index 56f39a3b..7858ff29 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -20,6 +20,10 @@ type CallService interface { HangupCall(data *HangupCallStruct, instance *instance_model.Instance) error GetActiveCall(instanceId, callId string) (*meowcaller.Call, error) DialCall(data *DialCallStruct, instance *instance_model.Instance) (*meowcaller.Call, error) + ReactCall(data *ReactCallStruct, instance *instance_model.Instance) error + AddParticipant(data *AddParticipantStruct, instance *instance_model.Instance) error + ScreenShareCall(data *ScreenShareStruct, instance *instance_model.Instance) error + HandRaiseCall(data *HandRaiseStruct, instance *instance_model.Instance) error } type callService struct { @@ -52,6 +56,29 @@ type DialCallStruct struct { Video bool `json:"video"` } +// The following structs are all spike/experimental additions, outside the reviewed +// answer-call plan, for call-control features requested during live manual testing. + +type ReactCallStruct struct { + CallID string `json:"callId"` + Emoji string `json:"emoji"` +} + +type AddParticipantStruct struct { + CallID string `json:"callId"` + Number string `json:"number"` +} + +type ScreenShareStruct struct { + CallID string `json:"callId"` + Start bool `json:"start"` +} + +type HandRaiseStruct struct { + CallID string `json:"callId"` + Raised bool `json:"raised"` +} + func (c *callService) RejectCall(data *RejectCallStruct, instance *instance_model.Instance) error { call, ok := c.callRegistry.Get(instance.Id, data.CallID) if !ok { @@ -129,6 +156,60 @@ func (c *callService) DialCall(data *DialCallStruct, instance *instance_model.In return call, nil } +func (c *callService) ReactCall(data *ReactCallStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + if err := call.SendReaction(data.Emoji); err != nil { + logger.LogError("[%s] error sending call reaction: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) AddParticipant(data *AddParticipantStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + if err := call.AddParticipant(context.Background(), data.Number); err != nil { + logger.LogError("[%s] error adding call participant: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) ScreenShareCall(data *ScreenShareStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + var err error + if data.Start { + err = call.StartScreenShare(nil) + } else { + err = call.StopScreenShare() + } + if err != nil { + logger.LogError("[%s] error toggling call screen share: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) HandRaiseCall(data *HandRaiseStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + if err := call.SetHandRaised(data.Raised); err != nil { + logger.LogError("[%s] error setting call hand-raise state: %v", instance.Id, err) + return err + } + return nil +} + func NewCallService( clientPointer map[string]*whatsmeow.Client, whatsmeowService whatsmeow_service.WhatsmeowService, diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 63668840..804cb119 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -197,6 +197,10 @@ func (r *Routes) AssignRoutes(eng *gin.Engine) { routes.POST("/answer", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.AnswerCall) routes.POST("/hangup", r.callHandler.HangupCall) routes.POST("/dial", r.callHandler.DialCall) + routes.POST("/react", r.callHandler.ReactCall) + routes.POST("/participant/add", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.AddParticipant) + routes.POST("/screenshare", r.callHandler.ScreenShareCall) + routes.POST("/handraise", r.callHandler.HandRaiseCall) } } routes = eng.Group("/community") From 77290fc7f98679975d49e443727e4d4bf7a10c06 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 14:52:35 +0000 Subject: [PATCH 21/26] spike: wire outbound video (screen share/camera) into the stream bridge Explicitly out of scope in the reviewed plan (video was inbound-only there) -- added to test whether content sent via Call.SendVideo actually reaches the peer during a StartScreenShare-toggled call. Consumer sends {"event":"video","track":"outbound","payload":""} over the same /call/stream socket. --- pkg/call/stream/bridge.go | 14 ++++++++++++++ pkg/call/stream/handler.go | 1 + 2 files changed, 15 insertions(+) diff --git a/pkg/call/stream/bridge.go b/pkg/call/stream/bridge.go index 00b02827..71a1d85c 100644 --- a/pkg/call/stream/bridge.go +++ b/pkg/call/stream/bridge.go @@ -31,6 +31,7 @@ type bridge struct { incoming chan []float32 closed chan struct{} closeOnce sync.Once + sendVideo func([]byte) error } func newBridge(conn *websocket.Conn) *bridge { @@ -106,6 +107,19 @@ func (b *bridge) readLoop() { b.Close() return } + if msg.Event == "video" && msg.Track == "outbound" { + raw, err := base64.StdEncoding.DecodeString(msg.Payload) + if err != nil || b.sendVideo == nil { + continue + } + // Spike/experimental: outbound video was explicitly out of scope in the + // reviewed plan (video is inbound-only there). Added here to test + // screen-share/camera content actually reaching the peer. + if err := b.sendVideo(raw); err != nil { + continue + } + continue + } if msg.Event != "media" || msg.Track != "outbound" { continue } diff --git a/pkg/call/stream/handler.go b/pkg/call/stream/handler.go index fb29200f..e6176af0 100644 --- a/pkg/call/stream/handler.go +++ b/pkg/call/stream/handler.go @@ -48,6 +48,7 @@ func serveStream(callService call_service.CallService, instanceService instance_ } b := newBridge(conn) + b.sendVideo = call.SendVideo call.OnEnd(func(reason string) { b.Close() }) call.Receive(b) call.ReceiveVideo(b) From cc069f1bd9f67ce6817f703922ba4e5fd7261709 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 14:57:53 +0000 Subject: [PATCH 22/26] spike: request video upgrade before sending outbound video Live test showed SendVideo() calls succeeding with no error but never rendering on the peer's screen. meowcaller's StartVideo doc comment explains why: "outbound video remains gated until the peer acknowledges the transition" -- SendVideo alone doesn't request the upgrade, it just feeds a source that stays gated shut until StartVideo is called and acknowledged. Lazily calls StartVideo() on the first outbound video message so there's no separate step to remember. --- pkg/call/stream/bridge.go | 25 +++++++++++++++++++------ pkg/call/stream/handler.go | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/pkg/call/stream/bridge.go b/pkg/call/stream/bridge.go index 71a1d85c..92693c11 100644 --- a/pkg/call/stream/bridge.go +++ b/pkg/call/stream/bridge.go @@ -26,12 +26,14 @@ type wsMessage struct { // VideoSink (Call.ReceiveVideo), and AudioSource (Call.Play) interfaces, so a single // object plugs a call's media straight into the socket in both directions. type bridge struct { - conn *websocket.Conn - writeMu sync.Mutex - incoming chan []float32 - closed chan struct{} - closeOnce sync.Once - sendVideo func([]byte) error + conn *websocket.Conn + writeMu sync.Mutex + incoming chan []float32 + closed chan struct{} + closeOnce sync.Once + sendVideo func([]byte) error + startVideo func() error + startVideoOnce sync.Once } func newBridge(conn *websocket.Conn) *bridge { @@ -115,6 +117,17 @@ func (b *bridge) readLoop() { // Spike/experimental: outbound video was explicitly out of scope in the // reviewed plan (video is inbound-only there). Added here to test // screen-share/camera content actually reaching the peer. + // + // meowcaller's StartVideo doc comment: "Outbound video remains gated + // until the peer acknowledges the transition" -- so the upgrade must be + // requested before any SendVideo call has an effect. Lazily triggered on + // the first outbound video message so callers don't need a separate + // endpoint/step to remember. + b.startVideoOnce.Do(func() { + if b.startVideo != nil { + _ = b.startVideo() + } + }) if err := b.sendVideo(raw); err != nil { continue } diff --git a/pkg/call/stream/handler.go b/pkg/call/stream/handler.go index e6176af0..ed8377b0 100644 --- a/pkg/call/stream/handler.go +++ b/pkg/call/stream/handler.go @@ -49,6 +49,7 @@ func serveStream(callService call_service.CallService, instanceService instance_ b := newBridge(conn) b.sendVideo = call.SendVideo + b.startVideo = call.StartVideo call.OnEnd(func(reason string) { b.Close() }) call.Receive(b) call.ReceiveVideo(b) From a4d8e69716d6f2607d39198eb0863e4551bfdf19 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 15:03:38 +0000 Subject: [PATCH 23/26] spike: don't call StartVideo on a call that already has video Live testing showed calling StartVideo() (an audio->video upgrade request) on a call that already declared video in its offer doesn't just no-op -- it dropped the call entirely. Only wire the lazy StartVideo trigger up when the call actually needs the upgrade (call.IsVideo() is false at stream-attach time). --- pkg/call/stream/handler.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/call/stream/handler.go b/pkg/call/stream/handler.go index ed8377b0..957a6efd 100644 --- a/pkg/call/stream/handler.go +++ b/pkg/call/stream/handler.go @@ -49,7 +49,13 @@ func serveStream(callService call_service.CallService, instanceService instance_ b := newBridge(conn) b.sendVideo = call.SendVideo - b.startVideo = call.StartVideo + // StartVideo requests an audio->video upgrade. Calling it on a call that + // already has video (declared in the original offer) doesn't just no-op -- + // live testing showed it can drop the call entirely. Only wire it up when + // there's an actual upgrade to request. + if !call.IsVideo() { + b.startVideo = call.StartVideo + } call.OnEnd(func(reason string) { b.Close() }) call.Receive(b) call.ReceiveVideo(b) From 35cfd30871825ec24376f9f2c7503ce4e7c03cdf Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 15:33:25 +0000 Subject: [PATCH 24/26] spike: retry AddParticipant with backoff on usync timeout Live testing showed AddParticipant's internal usync lookup reliably timing out while a call is already active, even for numbers already resolved earlier in the same session -- while the identical resolve succeeds instantly with no call in progress. Retrying 3x with a 2s gap to test whether this is transient network contention on the shared connection rather than a hard block. --- pkg/call/service/call_service.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index 7858ff29..2a7b59ff 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -3,6 +3,7 @@ package call_service import ( "context" "errors" + "time" call_registry "github.com/evolution-foundation/evolution-go/pkg/call/registry" instance_model "github.com/evolution-foundation/evolution-go/pkg/instance/model" @@ -173,11 +174,24 @@ func (c *callService) AddParticipant(data *AddParticipantStruct, instance *insta if !ok { return errors.New("no active call with that id") } - if err := call.AddParticipant(context.Background(), data.Number); err != nil { - logger.LogError("[%s] error adding call participant: %v", instance.Id, err) - return err - } - return nil + // Spike/experimental: live testing showed the usync lookup AddParticipant does + // internally reliably times out while a call is already active (it works fine + // with no call in progress), even for numbers resolved moments earlier in the + // same session. Retrying with a short backoff to see whether it's transient + // network contention rather than a hard block. + var err error + for attempt := 1; attempt <= 3; attempt++ { + err = call.AddParticipant(context.Background(), data.Number) + if err == nil { + return nil + } + c.loggerWrapper.GetLogger(instance.Id).LogError("[%s] add participant attempt %d/3 failed: %v", instance.Id, attempt, err) + if attempt < 3 { + time.Sleep(2 * time.Second) + } + } + logger.LogError("[%s] error adding call participant after 3 attempts: %v", instance.Id, err) + return err } func (c *callService) ScreenShareCall(data *ScreenShareStruct, instance *instance_model.Instance) error { From 4bd8818da7fa50274835837dcbc25169482bc345 Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 16:20:28 +0000 Subject: [PATCH 25/26] spike: add video upgrade/enabled/orientation endpoints POST /call/video/upgrade (Call.StartVideo/StopVideo), POST /call/video/enabled (Call.SetVideoEnabled), POST /call/video/orientation (Call.SetVideoOrientation). Same registry- lookup + thin-handler pattern as the rest of this spike branch. --- pkg/call/handler/call_handler.go | 108 +++++++++++++++++++++++++++++++ pkg/call/service/call_service.go | 63 ++++++++++++++++++ pkg/routes/routes.go | 3 + 3 files changed, 174 insertions(+) diff --git a/pkg/call/handler/call_handler.go b/pkg/call/handler/call_handler.go index 36fa61f6..fbfa436f 100644 --- a/pkg/call/handler/call_handler.go +++ b/pkg/call/handler/call_handler.go @@ -17,6 +17,9 @@ type CallHandler interface { AddParticipant(ctx *gin.Context) ScreenShareCall(ctx *gin.Context) HandRaiseCall(ctx *gin.Context) + VideoUpgradeCall(ctx *gin.Context) + VideoEnabledCall(ctx *gin.Context) + VideoOrientationCall(ctx *gin.Context) } type callHandler struct { @@ -303,6 +306,111 @@ func (g *callHandler) HandRaiseCall(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"message": "success"}) } +// Toggle video upgrade +// @Summary Start or stop sending outbound video mid-call +// @Description Spike/experimental: requests an audio<->video upgrade (Call.StartVideo/StopVideo) +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.VideoUpgradeStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/video/upgrade [post] +func (g *callHandler) VideoUpgradeCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.VideoUpgradeStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.VideoUpgradeCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + +// Toggle video enabled +// @Summary Mute or unmute outbound video without renegotiating the upgrade +// @Description Spike/experimental: wraps Call.SetVideoEnabled +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.VideoEnabledStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/video/enabled [post] +func (g *callHandler) VideoEnabledCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.VideoEnabledStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.VideoEnabledCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + +// Set video orientation +// @Summary Announce this client's camera orientation +// @Description Spike/experimental: wraps Call.SetVideoOrientation (0-3 quarter turns clockwise) +// @Tags Call +// @Accept json +// @Produce json +// @Param message body call_service.VideoOrientationStruct true "Call data" +// @Success 200 {object} gin.H "success" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /call/video/orientation [post] +func (g *callHandler) VideoOrientationCall(ctx *gin.Context) { + getInstance := ctx.MustGet("instance") + + instance, ok := getInstance.(*instance_model.Instance) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"}) + return + } + + var data *call_service.VideoOrientationStruct + err := ctx.ShouldBindBodyWithJSON(&data) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err = g.callService.VideoOrientationCall(data, instance) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"message": "success"}) +} + func NewCallHandler( callService call_service.CallService, ) CallHandler { diff --git a/pkg/call/service/call_service.go b/pkg/call/service/call_service.go index 2a7b59ff..0594760e 100644 --- a/pkg/call/service/call_service.go +++ b/pkg/call/service/call_service.go @@ -25,6 +25,9 @@ type CallService interface { AddParticipant(data *AddParticipantStruct, instance *instance_model.Instance) error ScreenShareCall(data *ScreenShareStruct, instance *instance_model.Instance) error HandRaiseCall(data *HandRaiseStruct, instance *instance_model.Instance) error + VideoUpgradeCall(data *VideoUpgradeStruct, instance *instance_model.Instance) error + VideoEnabledCall(data *VideoEnabledStruct, instance *instance_model.Instance) error + VideoOrientationCall(data *VideoOrientationStruct, instance *instance_model.Instance) error } type callService struct { @@ -80,6 +83,24 @@ type HandRaiseStruct struct { Raised bool `json:"raised"` } +// VideoUpgradeStruct requests turning this client's camera on or off mid-call. +// Start=true calls Call.StartVideo (audio->video upgrade, gated until the peer +// acknowledges); Start=false calls Call.StopVideo (drop outbound video, keep audio). +type VideoUpgradeStruct struct { + CallID string `json:"callId"` + Start bool `json:"start"` +} + +type VideoEnabledStruct struct { + CallID string `json:"callId"` + Enabled bool `json:"enabled"` +} + +type VideoOrientationStruct struct { + CallID string `json:"callId"` + Orientation int `json:"orientation"` +} + func (c *callService) RejectCall(data *RejectCallStruct, instance *instance_model.Instance) error { call, ok := c.callRegistry.Get(instance.Id, data.CallID) if !ok { @@ -224,6 +245,48 @@ func (c *callService) HandRaiseCall(data *HandRaiseStruct, instance *instance_mo return nil } +func (c *callService) VideoUpgradeCall(data *VideoUpgradeStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + var err error + if data.Start { + err = call.StartVideo() + } else { + err = call.StopVideo() + } + if err != nil { + logger.LogError("[%s] error toggling call video upgrade: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) VideoEnabledCall(data *VideoEnabledStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + if err := call.SetVideoEnabled(data.Enabled); err != nil { + logger.LogError("[%s] error setting call video enabled state: %v", instance.Id, err) + return err + } + return nil +} + +func (c *callService) VideoOrientationCall(data *VideoOrientationStruct, instance *instance_model.Instance) error { + call, ok := c.callRegistry.Get(instance.Id, data.CallID) + if !ok { + return errors.New("no active call with that id") + } + if err := call.SetVideoOrientation(data.Orientation); err != nil { + logger.LogError("[%s] error setting call video orientation: %v", instance.Id, err) + return err + } + return nil +} + func NewCallService( clientPointer map[string]*whatsmeow.Client, whatsmeowService whatsmeow_service.WhatsmeowService, diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 804cb119..13a855f1 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -201,6 +201,9 @@ func (r *Routes) AssignRoutes(eng *gin.Engine) { routes.POST("/participant/add", r.jidValidationMiddleware.ValidateNumberField(), r.callHandler.AddParticipant) routes.POST("/screenshare", r.callHandler.ScreenShareCall) routes.POST("/handraise", r.callHandler.HandRaiseCall) + routes.POST("/video/upgrade", r.callHandler.VideoUpgradeCall) + routes.POST("/video/enabled", r.callHandler.VideoEnabledCall) + routes.POST("/video/orientation", r.callHandler.VideoOrientationCall) } } routes = eng.Group("/community") From 51ca5e1588b1def67ca78d945e85f8642198f8fe Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Wed, 29 Jul 2026 16:20:51 +0000 Subject: [PATCH 26/26] docs: regenerate swagger docs for spike call-control endpoints --- docs/docs.go | 408 ++++++++++++++++++++++++++++++++++++++++++++++ docs/swagger.json | 408 ++++++++++++++++++++++++++++++++++++++++++++++ docs/swagger.yaml | 267 ++++++++++++++++++++++++++++++ 3 files changed, 1083 insertions(+) diff --git a/docs/docs.go b/docs/docs.go index 1abcb16f..1ca78fb8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -55,6 +55,86 @@ const docTemplate = `{ } } }, + "/call/dial": { + "post": { + "description": "Spike/experimental: places an outbound call, not part of the reviewed answer-call plan", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Place an outbound call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.DialCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/handraise": { + "post": { + "description": "Spike/experimental: toggles this client's hand-raised state", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Raise or lower hand in a call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.HandRaiseStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/call/hangup": { "post": { "description": "Hangup an active call", @@ -95,6 +175,86 @@ const docTemplate = `{ } } }, + "/call/participant/add": { + "post": { + "description": "Spike/experimental: adds a participant, upgrading a 1:1 call into a group call", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Add a participant to an active call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.AddParticipantStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/react": { + "post": { + "description": "Spike/experimental: sends an emoji reaction into an active call", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Send a call reaction", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.ReactCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/call/reject": { "post": { "description": "Reject call", @@ -135,6 +295,166 @@ const docTemplate = `{ } } }, + "/call/screenshare": { + "post": { + "description": "Spike/experimental: toggles this client's screen share state", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Start or stop screen sharing in a call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.ScreenShareStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/video/enabled": { + "post": { + "description": "Spike/experimental: wraps Call.SetVideoEnabled", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Mute or unmute outbound video without renegotiating the upgrade", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoEnabledStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/video/orientation": { + "post": { + "description": "Spike/experimental: wraps Call.SetVideoOrientation (0-3 quarter turns clockwise)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Announce this client's camera orientation", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoOrientationStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/video/upgrade": { + "post": { + "description": "Spike/experimental: requests an audio\u003c-\u003evideo upgrade (Call.StartVideo/StopVideo)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Start or stop sending outbound video mid-call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoUpgradeStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/chat/archive": { "post": { "description": "Archive a chat", @@ -4005,6 +4325,17 @@ const docTemplate = `{ "type": "object", "additionalProperties": {} }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.AddParticipantStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "number": { + "type": "string" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct": { "type": "object", "properties": { @@ -4016,6 +4347,28 @@ const docTemplate = `{ } } }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.DialCallStruct": { + "type": "object", + "properties": { + "number": { + "type": "string" + }, + "video": { + "type": "boolean" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.HandRaiseStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "raised": { + "type": "boolean" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct": { "type": "object", "properties": { @@ -4024,6 +4377,17 @@ const docTemplate = `{ } } }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.ReactCallStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "emoji": { + "type": "string" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct": { "type": "object", "properties": { @@ -4035,6 +4399,50 @@ const docTemplate = `{ } } }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.ScreenShareStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "start": { + "type": "boolean" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.VideoEnabledStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.VideoOrientationStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "orientation": { + "type": "integer" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.VideoUpgradeStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "start": { + "type": "boolean" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index db08ff0a..d1a2f65c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -47,6 +47,86 @@ } } }, + "/call/dial": { + "post": { + "description": "Spike/experimental: places an outbound call, not part of the reviewed answer-call plan", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Place an outbound call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.DialCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/handraise": { + "post": { + "description": "Spike/experimental: toggles this client's hand-raised state", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Raise or lower hand in a call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.HandRaiseStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/call/hangup": { "post": { "description": "Hangup an active call", @@ -87,6 +167,86 @@ } } }, + "/call/participant/add": { + "post": { + "description": "Spike/experimental: adds a participant, upgrading a 1:1 call into a group call", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Add a participant to an active call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.AddParticipantStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/react": { + "post": { + "description": "Spike/experimental: sends an emoji reaction into an active call", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Send a call reaction", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.ReactCallStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/call/reject": { "post": { "description": "Reject call", @@ -127,6 +287,166 @@ } } }, + "/call/screenshare": { + "post": { + "description": "Spike/experimental: toggles this client's screen share state", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Start or stop screen sharing in a call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.ScreenShareStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/video/enabled": { + "post": { + "description": "Spike/experimental: wraps Call.SetVideoEnabled", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Mute or unmute outbound video without renegotiating the upgrade", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoEnabledStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/video/orientation": { + "post": { + "description": "Spike/experimental: wraps Call.SetVideoOrientation (0-3 quarter turns clockwise)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Announce this client's camera orientation", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoOrientationStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, + "/call/video/upgrade": { + "post": { + "description": "Spike/experimental: requests an audio\u003c-\u003evideo upgrade (Call.StartVideo/StopVideo)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Call" + ], + "summary": "Start or stop sending outbound video mid-call", + "parameters": [ + { + "description": "Call data", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoUpgradeStruct" + } + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/gin.H" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/gin.H" + } + } + } + } + }, "/chat/archive": { "post": { "description": "Archive a chat", @@ -3997,6 +4317,17 @@ "type": "object", "additionalProperties": {} }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.AddParticipantStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "number": { + "type": "string" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct": { "type": "object", "properties": { @@ -4008,6 +4339,28 @@ } } }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.DialCallStruct": { + "type": "object", + "properties": { + "number": { + "type": "string" + }, + "video": { + "type": "boolean" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.HandRaiseStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "raised": { + "type": "boolean" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct": { "type": "object", "properties": { @@ -4016,6 +4369,17 @@ } } }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.ReactCallStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "emoji": { + "type": "string" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct": { "type": "object", "properties": { @@ -4027,6 +4391,50 @@ } } }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.ScreenShareStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "start": { + "type": "boolean" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.VideoEnabledStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.VideoOrientationStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "orientation": { + "type": "integer" + } + } + }, + "github_com_evolution-foundation_evolution-go_pkg_call_service.VideoUpgradeStruct": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "start": { + "type": "boolean" + } + } + }, "github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6a18fb1a..3f6e7337 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2,6 +2,13 @@ definitions: gin.H: additionalProperties: {} type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.AddParticipantStruct: + properties: + callId: + type: string + number: + type: string + type: object github_com_evolution-foundation_evolution-go_pkg_call_service.AnswerCallStruct: properties: callCreator: @@ -9,11 +16,32 @@ definitions: callId: type: string type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.DialCallStruct: + properties: + number: + type: string + video: + type: boolean + type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.HandRaiseStruct: + properties: + callId: + type: string + raised: + type: boolean + type: object github_com_evolution-foundation_evolution-go_pkg_call_service.HangupCallStruct: properties: callId: type: string type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.ReactCallStruct: + properties: + callId: + type: string + emoji: + type: string + type: object github_com_evolution-foundation_evolution-go_pkg_call_service.RejectCallStruct: properties: callCreator: @@ -21,6 +49,34 @@ definitions: callId: type: string type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.ScreenShareStruct: + properties: + callId: + type: string + start: + type: boolean + type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.VideoEnabledStruct: + properties: + callId: + type: string + enabled: + type: boolean + type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.VideoOrientationStruct: + properties: + callId: + type: string + orientation: + type: integer + type: object + github_com_evolution-foundation_evolution-go_pkg_call_service.VideoUpgradeStruct: + properties: + callId: + type: string + start: + type: boolean + type: object github_com_evolution-foundation_evolution-go_pkg_chat_service.BodyStruct: properties: chat: @@ -7429,6 +7485,59 @@ paths: summary: Answer call tags: - Call + /call/dial: + post: + consumes: + - application/json + description: 'Spike/experimental: places an outbound call, not part of the reviewed + answer-call plan' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.DialCallStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Place an outbound call + tags: + - Call + /call/handraise: + post: + consumes: + - application/json + description: 'Spike/experimental: toggles this client''s hand-raised state' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.HandRaiseStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Raise or lower hand in a call + tags: + - Call /call/hangup: post: consumes: @@ -7455,6 +7564,59 @@ paths: summary: Hangup call tags: - Call + /call/participant/add: + post: + consumes: + - application/json + description: 'Spike/experimental: adds a participant, upgrading a 1:1 call into + a group call' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.AddParticipantStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Add a participant to an active call + tags: + - Call + /call/react: + post: + consumes: + - application/json + description: 'Spike/experimental: sends an emoji reaction into an active call' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.ReactCallStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Send a call reaction + tags: + - Call /call/reject: post: consumes: @@ -7481,6 +7643,111 @@ paths: summary: Reject call tags: - Call + /call/screenshare: + post: + consumes: + - application/json + description: 'Spike/experimental: toggles this client''s screen share state' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.ScreenShareStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Start or stop screen sharing in a call + tags: + - Call + /call/video/enabled: + post: + consumes: + - application/json + description: 'Spike/experimental: wraps Call.SetVideoEnabled' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoEnabledStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Mute or unmute outbound video without renegotiating the upgrade + tags: + - Call + /call/video/orientation: + post: + consumes: + - application/json + description: 'Spike/experimental: wraps Call.SetVideoOrientation (0-3 quarter + turns clockwise)' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoOrientationStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Announce this client's camera orientation + tags: + - Call + /call/video/upgrade: + post: + consumes: + - application/json + description: 'Spike/experimental: requests an audio<->video upgrade (Call.StartVideo/StopVideo)' + parameters: + - description: Call data + in: body + name: message + required: true + schema: + $ref: '#/definitions/github_com_evolution-foundation_evolution-go_pkg_call_service.VideoUpgradeStruct' + produces: + - application/json + responses: + "200": + description: success + schema: + $ref: '#/definitions/gin.H' + "500": + description: Internal server error + schema: + $ref: '#/definitions/gin.H' + summary: Start or stop sending outbound video mid-call + tags: + - Call /chat/archive: post: consumes: