I am investigating a persistent routing failure regarding SIP REFER methods on our BYOC Premises trunks. When our Architect flows attempt a blind transfer to an external PSTN number, the edge server transmits a SIP REFER to our Session Border Controller. However, the SIP trace indicates that the Replaces header within the Refer-To URI is malformed, causing our SBC to reject the transfer with a 400 Bad Request response. Consequently, the call disconnects instead of transferring. I have reviewed the Python SDK documentation and the platform API endpoints for trunk configuration, but I am unable to locate a setting to modify or disable the Replaces header generation on blind transfers. How can I resolve this malformed header issue?
Greetings. I have navigated this precise interoperability challenge when integrating external systems through our session border controllers. The issue you describe is rooted in how the Genesys Cloud Edge constructs the SIP REFER message during a blind transfer from an Architect flow.
By default, the Edge includes the Replaces header to ensure seamless call leg replacement. However, certain legacy SBCs strictly parse the Refer-To URI and will reject unexpected parameters.
To resolve this, you must access the external trunk settings within the Telephony configuration. Navigate to the āSIP Access Controlā section and modify the āProtocolā properties.
You will find an option to disable āSend REFERā. When disabled, the Edge will utilize a SIP INVITE instead of a REFER for external transfers, completely bypassing the malformed header issue.
Hello. Adding to the previous response, we experienced this exact scenario during our migration from PureConnect. The PureConnect architecture handled SIP REFER messages differently, and our existing gateways were not prepared for the Genesys Cloud formatting.
If your organizational architecture requires you to utilize the REFER method rather than falling back to an INVITE, you will need to implement a SIP manipulation rule directly on your Session Border Controller. You can create a normalization script on the SBC to strip the Replaces header from the Refer-To URI before the message is routed to the PSTN provider.
This allows you to maintain the standard Genesys Cloud trunk configuration while ensuring compatibility with your downstream carriers.
honestly, the SBC manipulation rule mentioned above is a bit of a band-aid. if youāre dealing with strict parsers, youāre better off controlling the signal flow from the Genesys side so you donāt have to play whack-a-mole with SIP headers on the perimeter.
in my Rails webhook ingestion setup, iāve found that forcing the transfer to use an INVITE instead of REFER is way more reliable for PSTN handoffs. the Architect flow allows you to specify this behavior directly.
when you configure the āTransferā action in Architect, look for the āTransfer Typeā setting. switch it from āBlindā (which defaults to REFER) to āAttendedā or explicitly configure the transfer method if your version supports it. but wait, for a pure blind transfer to PSTN, the real fix is often in the BYOC trunk configuration or the edge behavior.
actually, looking at the recent docs, thereās a specific edge behavior toggle. but since weāre talking code, hereās how iād handle the fallback if the REFER fails, using the Ruby SDK to update the contactās state or trigger a retry mechanism via webhooks.
require 'pure_cloud'
# Initialize the client
client = PureCloud::PlatformClientV2.new
client.auth_settings[:access_token] = ENV['GENESYS_ACCESS_TOKEN']
# Assuming you get a webhook for the failed transfer
def handle_transfer_failure(webhook_payload)
contact_id = webhook_payload['contactId']
# Fetch contact details to see current state
begin
contact = client.conversations_api.get_conversations_contact(contact_id)
# If the transfer failed due to SIP 400, we might want to log this or trigger a callback
if contact.state == 'queued' || contact.state == 'transferring'
puts "Contact #{contact_id} is still in transfer state. Investigating SIP REFER failure."
# Optional: Force a disconnect and queue back if needed
# client.conversations_api.post_conversations_contact_actions(contact_id, { action: 'disconnect' })
end
rescue => e
puts "Error fetching contact: #{e.message}"
end
end
but really, the cleanest fix isnāt in Ruby. itās in the BYOC trunk settings. check if your trunk has the āSupports REFERā capability checked. if your SBC is throwing a wobbly on the Replaces header, uncheck that capability for the specific trunk. Genesys will then fall back to an INVITE-based transfer, which is universally compatible and doesnāt care about the Replaces header format.
itās a config change, not a code change, but it saves you from writing complex SIP parsing logic on the edge. iād try that first before touching the SBC rules.
look, i donāt touch SIP headers manually unless i have to, but that SBC rejection is a pain. the suggestion to switch to INVITE is solid because it bypasses the REFER complexity entirely. in my analytics pipelines, iāve seen how much cleaner the call data is when you avoid REFER loops. itās less about the SIP spec and more about what your SBC actually tolerates. if youāre stuck with REFER, youāre fighting a losing battle against strict parsers.
hereās how you force the INVITE behavior in Architect. just set the transferType parameter to invite in your transfer action. itās a simple config change that saves hours of debugging.
{
"action": "transfer",
"target": "{externalNumber}",
"transferType": "invite"
}
i run this for all my PSTN handoffs. stops the 400 errors cold.