Added
- The SDKs can now read and change a running session's config, and read the webhook diagnostics —
GET/PATCH /sessions/{id}/config(0.14.5's headline feature), the cross-sessionGET /webhooks, andGET /webhooks/delivery-failureswere absent from all five SDKs whilesdk/README.mdclaimed every user-facing resource was exposed; that claim is now scoped to the exclusion list the SDK design doc actually states.
Fixed
-
The Go and Java SDKs can now send the explicit
nullthe session-config route needs — that route takes three states per field (an absent key leaves the value unchanged,nullclears it to the default, a value sets it), and neither SDK could emit the middle one: Go'somitemptyomits a nil pointer and Gson drops nulls by default, so restoringmaxReconnectAttemptsto unlimited — the one thing no in-range number can express — was unreachable. Both now carry explicitclear*flags. -
Three SDK response types dropped fields the API sends — the per-participant group result omitted
message, the product-send response omittedtimestamp, and Python's new 503 error class was not exported from the package root, so the documented import failed for exactly the class that was added. -
A running gateway now serves the same schema-valid OpenAPI document as the committed snapshot — the validity pass was added to the export script only, so
/api/docskept serving a document that fails validation whileopenapi.jsonwas clean; a test now holds both producers to the same passes in the same order. -
Two statements in the codebase that were not true — a load-bearing comment justified skipping a lookup on the grounds that PostgreSQL would raise a 500 against a uuid column, when
sessions.idisvarcharon both dialects and a malformed id simply matches nothing; and the webhook event table stated all 22 events are actively dispatched by the engines without saying that four of them fire on Baileys only, which the same document states 2 200 lines later. -
All five SDKs now give the retryable status a type of its own — every one classified
401,403,404,409,429and501into a dedicated error and let503fall through to the base class, which inverted the mapping against usefulness:501 Not Implementedis permanent and never worth retrying, while503is the transport failure a caller should retry — and 0.14.5 made it the standard answer for "WhatsApp never confirmed" across 47 of the 189 operations. -
⚠️ Breaking (SDK types only, no gateway change). Creating a group returns the summary shape, and the SDKs said otherwise —POST /groupsanswers{id, name, participantsCount, isAdmin?, linkedParentJID?}, but the four typed SDKs declared the DETAIL typeget()returns, soparticipants,description,ownerandcreatedAtwere typed as present on a response that never carries them. -
Four SDKs could not paginate the session list —
GET /api/sessionstakeslimitandoffset, and only the Go SDK exposed them; the other four sent a bare path and pinned the caller to the server default. -
A post-connect group-name hydration WhatsApp never answered no longer finishes without a word — the read shared the ambiguity
GET /sessions/{id}/groupswas bounded against in 0.14.5, where an unanswered query and an account with no groups both yield an empty result, but only the REST caller got a clock: the hydration step logged neither its success line nor its failure line, so group chats stayed unnamed with nothing to explain it. -
The published OpenAPI document is schema-valid again —
@nestjs/swaggerexpands an@All()route over its own method list, which includessearch, and the 3.0 Path Item Object has no field for it, so the ingress route contributed a key that made strict validators reject the whole 150-path document rather than just that route; the export now drops operations the specification cannot express, and nothing in the repository validated the document to catch it. -
⚠️ Breaking (SDK types only, no gateway change). Three response shapes the SDKs decoded into the wrong type — the four group membership writes answer with a per-participantresultsarray that a partial refusal is reported in, and all four typed SDKs declared only{success, message}, so a rejected member was indistinguishable from a fully applied batch;ContactRecorddeclaredpushnamewhere both engines emitpushName(which left Java's case-sensitive binder returning null for every contact), carried anisBusinessthe API never sends, and omittedisBlockedandprofilePicUrl; andsend-productanswers withidwhile the SDKs decodedmessageId.
Migration.addParticipants/removeParticipants/promoteParticipants/demoteParticipantsnow returnParticipantsResult— a superset of the old type, so existing reads ofsuccess/messagekeep compiling.ContactRecord.pushnamebecomespushNameandisBusinessis gone; both were always empty.sendProductreturnsProductMessageResponse { id }. -
A webhook a smart filter drops now leaves a trace — a condition on a field the event's payload does not carry cannot match, so a
senderfilter suppressed everymessage.ack,message.failedandmessage.reactionwhile the dispatch logged nothing, emitted no metric and recorded nothing in the delivery-failure table, which only tracks deliveries that were attempted; suppression is now logged at debug with the payload fields that were actually available, and the interaction is documented. -
Two webhook payload descriptions did not match what is sent —
session.qrwas documented as carrying the raw QR string when both engines render it to a PNG data URL before the event is dispatched, and the filter field list did not say that its fields exist on only some message events. -
Ten gaps where the published contract described less than the API actually accepts or returns — eleven operations carried a path template with no parameter to fill it, the plugin upload published no request body at all so the file it exists for was invisible, the statistics window selector was undocumented, the archived-media download and the config-UI route published a
200with no media type while every sibling binary route declares one, five plugin operations returned aPluginDtothe contract never named, and six nullable properties published astype: object— which also made the ranges declared beside two of them inert, since JSON Schema ignoresminimum/maximumon a non-numeric type.