"""THE VERBATIM ANCHOR — Genesys Cloud tokens model, as published. Transcribed from https://help.genesys.cloud/articles/genesys-cloud-tokens-model/ **last updated 2026-07-12**. Feature names and rate strings below are the article's own wording, character for character. VERBATIM — DO NOT EDIT. A vendor republication is a deliberate **re-anchoring**, not a patch (docs/Calculator_Pattern_V1-00.md): 1. diff the published table against this file 2. update the meters AND bump RATE_CARD_SOURCE_DATE in the same edit 3. update the pins in tests/test_rate_card.py in the same commit 4. re-execute the notebook 5. report the cost moves honestly 6. Show-first — the user sees the rate diff before it lands Never partially re-anchor; never bump the date without the pins. Negotiated or contracted values NEVER land here. They are the overlay, and they live in the notebook's ``engagement-data`` cell — this file is the vendor's record, not the client's deal. """ from __future__ import annotations from .meters import LicenceModel, Meter, MeterBasis, Tier RATE_CARD_SOURCE: str = "https://help.genesys.cloud/articles/genesys-cloud-tokens-model/" RATE_CARD_SOURCE_DATE: str = "2026-07-12" # Every meter below is published on the same page on the same date, so the # source pair is spelled out once here and passed explicitly. Explicit beats # a splat: this file is diffed against the article by eye. _URL = RATE_CARD_SOURCE _DATE = RATE_CARD_SOURCE_DATE #: The published meter table, verbatim. Twenty rows, in the article's order. METERS_VERBATIM: tuple[Meter, ...] = ( Meter( key="bots_voice", feature="Bots (Voice)", published_rate="17 minutes per token", basis=MeterBasis.VOICE_MINUTES, rate=1.0 / 17.0, tier=Tier.BOT, unit_label="bot minutes", note=( "Genesys rounds up each call to the next 15-second increment " "(clarified 2026-07-12)." ), source_url=_URL, source_date=_DATE, ), Meter( key="bots_digital", feature="Bots (Digital)", published_rate="51 sessions per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 51.0, tier=Tier.BOT, unit_label="sessions", source_url=_URL, source_date=_DATE, ), Meter( key="virtual_agent", feature="Virtual Agent", published_rate="0.5 tokens per Virtual Agent interaction", basis=MeterBasis.TOKENS_PER_UNIT, rate=0.5, tier=Tier.VIRTUAL_AGENT, unit_label="interactions", source_url=_URL, source_date=_DATE, ), Meter( key="agentic_virtual_agent", feature="Agentic Virtual Agent", published_rate="1.2 tokens per interaction", basis=MeterBasis.TOKENS_PER_UNIT, rate=1.2, tier=Tier.AGENTIC_VIRTUAL_AGENT, unit_label="interactions", source_url=_URL, source_date=_DATE, ), Meter( key="agent_copilot_named", feature="Agent Copilot [named]", published_rate="40 tokens per user", basis=MeterBasis.PER_USER_PER_MONTH, per_user_named=40.0, per_user_concurrent=60.0, unit_label="users", note="Enabling Copilot makes Supervisor summaries and insights free.", source_url=_URL, source_date=_DATE, ), Meter( key="agent_copilot_concurrent", feature="Agent Copilot [concurrent]", published_rate="60 tokens per user", basis=MeterBasis.PER_USER_PER_MONTH, per_user_named=40.0, per_user_concurrent=60.0, unit_label="users", note="The concurrent-licence face of the same meter.", source_url=_URL, source_date=_DATE, ), Meter( key="ai_scoring", feature="AI Scoring", published_rate="20 evaluations per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 20.0, unit_label="evaluations", source_url=_URL, source_date=_DATE, ), Meter( key="ai_translate", feature="AI Translate", published_rate="2 translations per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 2.0, unit_label="translations", source_url=_URL, source_date=_DATE, ), Meter( key="ai_summary_and_insights", feature="AI Summary and Insights", published_rate="50 summaries/insights per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 50.0, unit_label="summaries", note=( "Free when Agent Copilot is enabled — see " "COPILOT_COVERS_SUMMARY_RULE." ), source_url=_URL, source_date=_DATE, ), Meter( key="apple_messages_for_business", feature="Apple Messages for Business", published_rate="400 inbound or outbound messages per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="messages", source_url=_URL, source_date=_DATE, ), Meter( key="facebook_messenger", feature="Facebook Messenger", published_rate="400 messages per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="messages", source_url=_URL, source_date=_DATE, ), Meter( key="instagram_direct_messaging", feature="Instagram Direct Messaging", published_rate="400 messages per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="messages", source_url=_URL, source_date=_DATE, ), Meter( key="whatsapp_messaging", feature="WhatsApp Messaging", published_rate="400 messages per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="messages", source_url=_URL, source_date=_DATE, ), Meter( key="x_direct_messaging", feature="X Direct Messaging", published_rate="400 messages per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="messages", source_url=_URL, source_date=_DATE, ), Meter( key="genesys_cloud_social", feature="Genesys Cloud Social", published_rate="400 social post ingestions per channel per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="post ingestions", source_url=_URL, source_date=_DATE, ), Meter( key="social_post_responses", feature="Social Post Responses", published_rate="400 outbound messages per channel per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 400.0, unit_label="outbound messages", source_url=_URL, source_date=_DATE, ), Meter( key="predictive_routing", feature="Predictive Routing", published_rate="17 routes per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 17.0, unit_label="routes", source_url=_URL, source_date=_DATE, ), Meter( key="speech_and_text_analytics_named", feature="Speech and Text Analytics [named]", published_rate="30 tokens per user", basis=MeterBasis.PER_USER_PER_MONTH, per_user_named=30.0, per_user_concurrent=45.0, unit_label="users", source_url=_URL, source_date=_DATE, ), Meter( key="speech_and_text_analytics_concurrent", feature="Speech and Text Analytics [concurrent]", published_rate="45 tokens per user", basis=MeterBasis.PER_USER_PER_MONTH, per_user_named=30.0, per_user_concurrent=45.0, unit_label="users", note="The concurrent-licence face of the same meter.", source_url=_URL, source_date=_DATE, ), Meter( key="genesys_cloud_copilot", feature="Genesys Cloud Copilot", published_rate="20 AI actions per token", basis=MeterBasis.UNITS_PER_TOKEN, rate=1.0 / 20.0, unit_label="AI actions", note="Genesys Cloud knowledge queries are not charged.", source_url=_URL, source_date=_DATE, ), ) #: Published as included at no token cost. Shown on stage as explicit $0 #: lines — a zero the vendor put in writing is a finding, not an omission. ZERO_RATED_VERBATIM: tuple[Meter, ...] = ( Meter( key="predictive_engagement", feature="Predictive Engagement", published_rate="No charge for token usage", basis=MeterBasis.ZERO_RATED, unit_label="interactions", source_url=_URL, source_date=_DATE, ), Meter( key="knowledge_queries", feature="Genesys Cloud knowledge queries", published_rate="no charge for Genesys Cloud knowledge queries", basis=MeterBasis.ZERO_RATED, unit_label="queries", source_url=_URL, source_date=_DATE, ), ) #: "Named organizations receive 250 tokens; concurrent organizations receive #: 350 tokens" per month. FREE_TOKENS_PER_MONTH: dict[LicenceModel, int] = { LicenceModel.NAMED: 250, LicenceModel.CONCURRENT: 350, } #: "These tokens renew each month and do not carry over to future months." ALLOWANCE_CARRIES_OVER: bool = False #: "Genesys rounds up each call to the next 15-second increment." #: Clarified in the 2026-07-12 revision. Applied PER CALL, then summed. VOICE_BOT_ROUNDUP_SECONDS: int = 15 #: The published highest-tier rule, verbatim. Renders on stage. HIGHEST_TIER_RULE: str = ( "In cases where an interaction uses multiple AI resources, such as bot " "flows, virtual agents, and agentic virtual agents, Genesys bases charges " "on the highest tier (price) resource that Genesys Cloud uses during the " "interaction." ) #: The published Copilot exclusion, verbatim. Renders on stage. COPILOT_COVERS_SUMMARY_RULE: str = ( "if you enable Agent Copilot simultaneously, then Supervisor Copilot " "summaries and insights do not consume tokens" ) #: List price per token. The article points to the pricing hub and cites #: "USD 1.00 to JPY 120 per token by currency". LIST_PRICE_BY_CURRENCY: dict[str, float] = {"USD": 1.00, "JPY": 120.0} #: Every meter by key — the consumption table plus the zero-rated lines. METERS: dict[str, Meter] = { m.key: m for m in METERS_VERBATIM + ZERO_RATED_VERBATIM } def meter(key: str) -> Meter: """Look up a published meter, with a useful error when the key is wrong.""" try: return METERS[key] except KeyError: raise KeyError( f"{key!r} is not a published Genesys meter. Known keys: " f"{', '.join(sorted(METERS))}" ) from None def per_user_meter(licence: LicenceModel, family: str) -> Meter: """The Copilot / STA meter face matching ``licence``. ``family`` is ``"agent_copilot"`` or ``"speech_and_text_analytics"``. Both rates live on both faces, so this is presentation sugar — it picks the row whose published wording matches the licence being modelled. """ return meter(f"{family}_{licence.value}") def rate_card_rows() -> list[dict[str, str]]: """The published table as display rows, in publication order.""" return [ { "Feature": m.feature, "Published rate": m.published_rate, "Confidence": m.confidence.icon, "Source": m.source_date or "", } for m in METERS_VERBATIM + ZERO_RATED_VERBATIM ]