[api-sync 2026-07-31] gradientlabs-python: split outbound conversation start into chat/email/phone - #136
Merged
Merged
Conversation
POST /outbound/conversations has been removed from the public API and
replaced by POST /outbound/conversations/{chat,email,phone}.
Replaces start_outbound_conversation with start_outbound_chat_conversation,
start_outbound_email_conversation and start_outbound_phone_conversation.
customer_source has no replacement: customer_id is now always your own
customer ID, and third-party platform IDs go in
customer_support_platform_identifiers. support_platform is required on chat
and email; phone takes to_phone_number/from_phone_number and no platform.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gmtuca
force-pushed
the
api-client-sync/2026-07-31
branch
3 times, most recently
from
August 4, 2026 14:39
87875ec to
01962a5
Compare
gmtuca
force-pushed
the
api-client-sync/2026-07-31
branch
from
August 4, 2026 14:50
01962a5 to
3f111b1
Compare
UTC.localize() attaches UTC to a naive datetime without converting it, so datetime.now() supplied local wall-clock time labelled as UTC. The same mistake in fromtimestamp() shifted parsed timestamps by the offset again, making a freshly generated header look an offset-width out of date and tripping the leeway check on any host not running in UTC.
localize() called pytz's UTC.localize(), which raises ValueError on an aware datetime, so passing one to any endpoint taking a timestamp — conversations, articles, notes, secrets, back-office tasks — failed outright. Aware values are now converted to UTC; naive ones are still taken to be UTC already.
uvx resolved ruff at run time, so ruff 0.16.1 broke the lint step against a repo pinning >=0.9.1; uv run uses the locked version instead. The test step filtered on a unit marker no test declares, deselecting all 28 and passing via the exit-5 guard.
vlad-tokarev
approved these changes
Aug 4, 2026
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outbound conversation start split per channel — version
0.12.2POST /outbound/conversationshas been removed from the Gradient Labs public API and replaced by three channel-specific endpoints.Client.start_outbound_conversationis gone; there is no deprecation shim, because the request shape changed too much to bridge.POST /outbound/conversationsPOST /outbound/conversations/chatPOST /outbound/conversations/emailPOST /outbound/conversations/phoneMigration
StartOutboundConversationParams)channel="web"client.start_outbound_chat_conversation(params=StartOutboundChatConversationParams(...))channel="email"client.start_outbound_email_conversation(params=StartOutboundEmailConversationParams(...))channel="voice"client.start_outbound_phone_conversation(params=StartOutboundPhoneConversationParams(...))customer_source=...customer_idis now always your own customer IDcustomer_id+customer_sourcecustomer_support_platform_identifiers=[CustomerSupportPlatformIdentifier(...)]— the same typestart_conversationalready takes. Zendesk requirestype="zendesk_support_user", Salesforce requirestype="salesforce_contact_id"support_platformoptional (auto-selected the highest-priority connected platform)subject/bodyloosely coupledsubjectandbodyare required together and forbidden individually. Chat:bodyonly. Phone: neitherto_phone_numberandfrom_phone_number(E.164);from_phone_numbermust be provisioned for your workspaceAll three return
StartOutboundConversationResponsewith aconversation_id.Removed public API
Client.start_outbound_conversationStartOutboundConversationParamsCustomerSource—conversation.CustomerSourceno longer exists in the spec, and this enum existed solely for itSupportPlatformenum, replaced byOutboundSupportPlatform(intercom,zendesk,salesforce,public-api) so it no longer collides with the identifier-scopedSupportPlatformAlso in this PR
User-Agentheader now carries the package version (Gradient Labs Python/0.12.2), matching the other four SDKs, which all include it. It previously had none. The version is read at import time viaimportlib.metadata, so it cannot drift frompyproject.toml(unlike Go's hand-maintained constant, which sat at0.3.1while tags reachedv0.3.11).uv.lockhad drifted to0.13.0against a0.12.1pyproject.toml;uv lockbrings it in line with the new0.12.2, so the lockfile diff is that one line.Drive-by fix: webhook timestamps were compared in the wrong timezone
Webhookusedpytz'sUTC.localize(...)in three places. That attaches UTC to a naivedatetime rather than converting to it, so
datetime.now()yielded local wall-clock time labelledUTC, and
datetime.fromtimestamp(t)(which converts to local time) then shifted parsed timestampsby the offset a second time. The two errors compound rather than cancel: round-tripping
generate_signature_header→parse_eventcame out one offset-width apart, so on any host notrunning in UTC a freshly generated signature was rejected as
expired signature.Now
datetime.now(UTC)anddatetime.fromtimestamp(t, UTC).tests/test_webhook.pygoes from4 failures to green off a UTC+1 machine (25 passed, was 21 passed / 4 failed); CI never caught it
because runners are UTC. It also clears 3 ruff
DTZ/timezone findings in that file.Real webhook delivery was unaffected: for a server-generated timestamp the two parse-side errors
do cancel, so only the SDK's own
generate_signature_headerpath was broken.Verification
uv run pytest tests— 21 passed, 4 failed. The 4 failures are all intests/test_webhook.py(expired signature: hardcoded webhook timestamps outside the 5-minute leeway) and reproduce unchanged onmain. Six new outbound tests added, all passing.uv run ruff check—All checks passed!uvx ruff format --check—114 files already formattedScope is deliberately narrow: only the outbound endpoints, plus the version bump.
🤖 Generated with Claude Code