Implementing Last-Agent Routing for Continuity in Multi-Session Customer Service Journeys
What This Guide Covers
This guide details the architectural implementation of last-agent routing to maintain continuity across fragmented customer interactions. You will configure custom routing attributes, queue routing rules, and Architect flows to reliably match returning callers or chat users to their previous agent, with deterministic fallback logic when the original agent is unavailable or the affinity window has expired.
Prerequisites, Roles & Licensing
- Licensing Tier: Genesys Cloud CX 2 or higher. CX 1 restricts custom routing attributes to a limited quota and caps queue concurrency. Multi-session continuity requires unlimited attribute evaluation and advanced routing rule prioritization.
- Granular Permissions:
Routing > Queue > EditRouting > Routing Attribute > EditArchitect > Flow > EditUser > User > ReadInteraction > Interaction > Edit
- OAuth Scopes:
routing:queue:write,routing:attribute:write,architect:flow:edit,interaction:interaction:read,user:user:read - External Dependencies: Customer database or CRM with session correlation capability, webhook endpoint for attribute persistence, time-synced NTP infrastructure across all routing nodes.
The Implementation Deep-Dive
1. Designing the Correlation Key and Custom Attribute Schema
The routing engine evaluates attributes in memory. If you inject unbounded strings or high-cardinality identifiers, you degrade the matching algorithm and increase latency during peak concurrency. We design a fixed-length, normalized correlation key that survives across interaction lifecycles.
Create a custom routing attribute that stores the agent affinity. We do not use the native last_agent_id field for multi-session journeys because it resets on interaction termination and lacks TTL control. Instead, we build a custom attribute with explicit expiration handling.
API Payload: Create Routing Attribute
POST /api/v2/routing/attributes
Content-Type: application/json
Authorization: Bearer <access_token>
{
"name": "customer_last_agent_id",
"type": "string",
"description": "Stores the UUID of the agent who handled the previous interaction for continuity routing",
"is_public": false,
"default_value": ""
}
We also create a timestamp attribute to enforce affinity decay:
{
"name": "last_agent_affinity_timestamp",
"type": "long",
"description": "Epoch milliseconds of the last successful handoff to the affinity agent",
"is_public": false,
"default_value": 0
}
The Trap: Using phone numbers or email addresses as direct routing keys. Phone numbers contain country codes, formatting variations, and carrier porting changes. Email addresses are case-sensitive and often contain tracking parameters. When these values drift, the routing engine fails to match the attribute, forcing every returning customer into cold routing. This increases average handle time by 18 to 24 percent and destroys the continuity promise.
Architectural Reasoning: We normalize the identifier at the ingress point. The Architect flow hashes the customer identifier using SHA-256 and strips non-alphanumeric characters before writing to the custom attribute. This guarantees consistent indexing. The routing engine treats string attributes as exact matches. A normalized key ensures the in-memory index remains compact and evaluation time stays under 5 milliseconds per interaction.
2. Configuring Queue Routing Rules for Agent Affinity
Queue routing rules dictate how the matching algorithm selects an available agent. We configure the queue to evaluate the custom attribute before falling back to standard skill-based routing. The routing engine processes rules sequentially. We place the affinity rule at a controlled priority level to prevent deadlocks.
Retrieve the existing queue configuration via the API, modify the routing section, and apply the updated payload.
API Payload: Update Queue Routing Configuration
PUT /api/v2/routing/queues/{queueId}
Content-Type: application/json
Authorization: Bearer <access_token>
{
"routing": {
"type": "skills",
"skills_filter": "AND",
"use_oldest_interaction_first": true,
"use_longest_idle_first": true,
"rules": [
{
"name": "Last Agent Affinity",
"description": "Route to the agent who handled the previous session if available",
"type": "custom_attribute",
"custom_attribute_name": "customer_last_agent_id",
"priority": 1,
"enabled": true
},
{
"name": "Primary Skill Routing",
"description": "Standard skill-based routing when affinity is unavailable",
"type": "skills",
"priority": 2,
"enabled": true
}
]
}
}
The Trap: Setting the affinity rule as the absolute highest priority without an availability check. When the last agent is offline, on a break, or actively on another call, the routing engine still attempts to match them. This forces the interaction into a retry loop or increases queue occupancy while the engine waits for the agent to become available. The result is inflated wait times and higher abandonment rates.
Architectural Reasoning: The routing engine automatically filters out agents who are offline, in wrap-up, or on a call. However, we must explicitly configure the queue to use use_oldest_interaction_first and use_longest_idle_first as tiebreakers. When multiple agents share the same affinity attribute value (rare but possible in team-based routing), the tiebreakers prevent routing starvation. We also enable use_longest_idle_first to distribute load evenly among agents who successfully handled previous sessions.
3. Building the Architect Flow for Attribute Ingestion and Evaluation
The routing engine only evaluates attributes that exist on the interaction object before it enters the queue. We must inject the custom attributes at the earliest possible stage. The Architect flow reads the customer identifier, queries the persistence layer, and applies the routing attributes using the Set Interaction Attributes block.
Configure the flow to execute the following sequence:
- Gather Customer Identifier: Extract phone number, email, or CRM ID from the ingress channel.
- Normalize and Hash: Apply string manipulation blocks to standardize the identifier.
- Query Persistence Layer: Use an HTTP Request block to call your CRM or session database. The response returns the
last_agent_idandaffinity_timestamp. - Set Interaction Attributes: Apply the values to the interaction scope.
- Route to Queue: Transfer the interaction to the target queue.
Architect Block Configuration: Set Interaction Attributes
{
"type": "setInteractionAttributes",
"settings": {
"attributes": [
{
"name": "customer_last_agent_id",
"value": "{{http_response.last_agent_id}}"
},
{
"name": "last_agent_affinity_timestamp",
"value": "{{http_response.affinity_timestamp}}"
}
],
"scope": "interaction"
}
}
The Trap: Overwriting routing attributes mid-flow or failing to merge attributes from the initial interaction with the current one. If you place the Set Interaction Attributes block after a transfer or after a long wait block, the routing engine may have already attempted matching with empty values. The interaction then drops into standard routing, breaking continuity.
Architectural Reasoning: Attributes are scoped to the interaction lifecycle. The routing engine performs its initial matching pass the moment the interaction enters the queue. We inject attributes before the queue block to guarantee evaluation. We also use the scope: interaction setting rather than scope: session because session scope persists across multiple interactions and can cause attribute leakage between unrelated customer journeys. Interaction scope isolates the routing context and prevents cross-contamination.
4. Implementing TTL Management and Fallback Routing Logic
Infinite affinity degrades routing efficiency. If an agent leaves the organization, changes roles, or lacks updated product knowledge, forcing continuity harms the customer experience. We implement a time-to-live (TTL) model that expires affinity after a configurable window, typically 24 to 72 hours depending on industry compliance requirements.
We enforce TTL at two layers: the routing rule evaluation and the Architect flow. The routing rule checks the timestamp attribute. If the timestamp exceeds the TTL threshold, the rule returns false, and the interaction falls through to standard skill routing.
Architect Block Configuration: TTL Evaluation
{
"type": "condition",
"settings": {
"conditions": [
{
"type": "attribute",
"attribute": {
"name": "last_agent_affinity_timestamp",
"type": "long"
},
"operator": "greaterThan",
"value": "{{current_time_millis}} - 259200000"
}
],
"true_path": "affinity_active",
"false_path": "affinity_expired"
}
}
When the affinity expires, we clear the custom attribute to prevent stale routing attempts:
{
"type": "setInteractionAttributes",
"settings": {
"attributes": [
{
"name": "customer_last_agent_id",
"value": ""
},
{
"name": "last_agent_affinity_timestamp",
"value": 0
}
],
"scope": "interaction"
}
}
The Trap: Relying solely on the routing engine to handle expired affinity without clearing the attribute. The routing engine evaluates the custom attribute rule, finds a non-empty value, and attempts to match the agent. If the agent is unavailable, the rule fails and falls back. This adds unnecessary evaluation cycles and increases routing latency. More critically, if the agent returns to the queue later, the stale attribute may incorrectly route new interactions to them, bypassing updated skill requirements.
Architectural Reasoning: We clear expired attributes at the flow level before queue entry. This reduces routing engine load and guarantees deterministic fallback. We also log the TTL expiration event to a custom analytics bucket. This data feeds into workforce management models that measure continuity success rates versus first-call resolution metrics. The combination of flow-level TTL enforcement and queue-level fallback creates a resilient routing topology that adapts to agent availability and business policy changes.
Validation, Edge Cases & Troubleshooting
Edge Case 1: Routing Deadlock on Agent Status Changes
The failure condition: Interactions accumulate in the queue with high occupancy. Average wait time exceeds 15 minutes. Abandonment rate spikes during peak hours. The routing dashboard shows the affinity rule firing repeatedly but failing to connect.
The root cause: The last agent is stuck in a prolonged wrap-up state, on a system-initiated break, or experiencing softphone connectivity issues. The routing engine marks the agent as unavailable, but the affinity rule continues to prioritize them due to a misconfigured queue setting. When use_longest_idle_first is disabled, the engine does not rotate to other qualified agents, causing queue stagnation.
The solution: Enable use_longest_idle_first and use_oldest_interaction_first in the queue configuration. Set a maximum retry threshold in the routing rule using a custom attribute counter. If the affinity rule fails to match after three evaluation cycles, the flow clears the attribute and forces immediate fallback to skill-based routing. Monitor agent status transitions via the User Presence API to detect prolonged wrap-up states and trigger automatic affinity expiration.
Edge Case 2: Cross-Channel Attribute Scoping Failure
The failure condition: A customer initiates a voice call, receives last-agent routing, and successfully connects. The same customer later initiates a chat session from the same device. The chat routes to a completely different agent. Continuity is broken across channels.
The root cause: Voice and chat interactions use separate interaction contexts. The custom attribute written during the voice flow does not automatically propagate to the chat ingress point. The chat flow queries the persistence layer but fails to retrieve the last_agent_id due to a mismatched correlation key format or an unhandled channel-specific identifier.
The solution: Standardize the correlation key across all ingress channels. Use a unified customer identifier stored in your CRM or session database. The Architect flow for each channel must execute the same normalization and hashing logic before querying the persistence layer. Implement a shared webhook endpoint that accepts the normalized key and returns the affinity data regardless of channel type. Validate attribute propagation by routing a test interaction through voice, then immediately routing a chat interaction using the same identifier. Verify that the customer_last_agent_id attribute populates correctly in the chat interaction payload before queue entry.