Last updated 23 August 2026. Found by taking one agent from creation to a live carrier launch on four US networks. Every item here is reproducible, several cost days, and three cannot be undone.
contact.title is required even though the schema marks it optional.LAUNCH_STATE_FAILED. Branch on it and a rejection reads as still launching, forever.launchDetails is a complete set, not a delta. A second launch request silently drops every existing launch.requestVerification needs five required fields, and the partner and the brand are different parties.Google’s reference marks logoUri, heroUri and displayName as
“not modifiable after agent verification”. Both halves of that are misleading. The real locked set,
from their own rejection:
Contains invalid field paths for agent after verification:
description, logo_uri, hero_uri, color, privacy, terms_conditions,
emails, phone_numbers, websites
That is the whole info screen. And “after verification” means after it is requested:
an agent sitting at VERIFICATION_STATE_PENDING already refuses all of it, while an agent that
never requested still accepts a PATCH. Since agent deletion is deprecated, a wrong profile is a
support ticket rather than an edit. Get the profile final before you request verification —
it arrives earlier than anyone expects.
A hero uploaded as a palette-mode PNG (colour type 3, 128 colours) came back from
agent-logos.storage.googleapis.com with six colours, which erased every fine line in
the artwork. A second agent’s hero, an RGB PNG, was stored byte-identical with all 2691 colours.
Nothing warns you, the GET returns your URL rather than theirs, and by the time a handset shows it
the asset may already be frozen. Export true-colour PNG or JPEG, never palette, and compare the
stored copy against your source before requesting verification.
Contact.title carries no “Required” marker. requestLaunch returns
Agent’s contact title is required. The endpoint is the authority, not the page.
The documented LaunchState enum is UNSPECIFIED, UNLAUNCHED,
PENDING, LAUNCHED, REJECTED, SUSPENDED. There is no
FAILED and no DECLINED. Code that branches on those — ours did — sends the one
value that means no, REJECTED, into the default case. A carrier rejection then reads as a launch
still in flight for as long as anyone is willing to wait. VERIFICATION_STATE_FAILED does not exist
either.
launchDetails is a set, not a deltaLaunching on a second carrier means sending every region you are already launched on plus the new one. Send only the new one and the others are dropped, and the request succeeds. This is stated in the docs, in one sentence, and it is the kind of thing you find out months later.
AgentVerificationContact requires partnerName,
partnerEmailAddress, brandContactName, brandContactEmailAddress and
brandWebsiteUrl — all of them. The partner is you; the brand contact is someone at the customer
who can confirm you act for them, and Google emails that address a mandatory authorisation request. A shared
mailbox is a rejection. Note also that verification is not performed until a launch is requested, so waiting
for “verified” before requesting launch is a wait for nothing.
Google support told us submitting a launch request without a commercial agreement is sanctioned and is how you begin contractual discussions with a carrier. The API disagrees:
This network, United States: T-Mobile, requires an agreement with the
carrier to submit a launch request.
Same for AT&T, Verizon, Dish, Spectrum and Xfinity. Tracfone, Cape, ClearSky and Interop accepted the identical request. There is no way to open the conversation through Google, and no empirical path to learning a carrier’s bar — you cannot even fail informatively. AT&T additionally routes through its own gateway rather than Google’s, which is a separate integration.
Update a logo and the handset keeps showing the old one. Deleting the thread does not clear it. Toggling RCS
does not clear it. Re-inviting the tester does not clear it. It is a seven-day client-side cache, and on Android
you can force a refresh: search *xyzzy* in Google Messages to reveal the debug menu, then Debug →
RBM → Reload chatbot information. There is no iOS equivalent.
Agent deletion is deprecated for RBM — it is a support ticket, not an API call. Hosting region and use case are fixed at creation. Billing category is fixed at launch. The whole profile freezes on verification request. Brands can be deleted; agents cannot.
We hit all nine shipping Cadence, and every one of them was found by a rejection rather than by reading. Our own readiness check now enforces each one before a submission can be made, because a clean first submission clears in days and a rejection costs weeks.
You can run it against your own domain, free and without an account: cadencercs.com/readiness.html. It crawls your site, validates the disclosures carriers actually check, and generates the copy for whatever is missing.
Corrections welcome — support@cadencercs.com. Cadence is a service of Salus, Inc.
These are the traps inside the API. The one outside it is bigger: an approved agent still reaches nobody until a carrier agreement exists, and Google does not broker one. Once it does, replies can still vanish while sending looks fine, and your bill will not match your quote — RCS is billed by conversation, not by message.