Search code examples
twiliotwilio-apitwilio-programmable-voice

Twilio: Put a call on hold in warm-transfer


I'm implementing warm-transfer in my App suggested by Twilio.
I need all this feature as follows:
https://www.twilio.com/docs/voice/tutorials/warm-transfer

I downloaded this sample from Github to check if this approach will be suitable:
https://github.com/TwilioDevEd/warm-transfer-csharp

Now the problem I'm facing is, I cannot put the first caller on hold listening to some music while 1st agent calls to 2nd agent and tell them about caller's problem and hang up themselves(i.e. 1st agent)

I have added this piece of code in the sample code to put caller on hold:

public async Task<ActionResult> CallAgent2(string agentId)
    {
        var call = await _callsRepository.FindByAgentIdAsync(agentId);
        var participant = ParticipantResource.Update(
            pathConferenceSid: call.ConferenceId,
            pathCallSid: call.ConferenceId,
            hold: true,
            holdUrl: new System.Uri("http://twimlets.com/holdmusic?Bucket=com.twilio.music.classical")
        );

        var callBackUrl = GetConnectConfereceUrlForAgent(agentId, call.ConferenceId);
        _callCreator.CallAgent("agent2", callBackUrl);
        return new EmptyResult();
    }

But I'm getting error of "Error 20404" by Twilio.
Please let me know how can I achieve this or if I can use some other better approach to fulfill my requirement.


Solution

  • Twilio developer evangelist here.

    You are getting a 20404 error because you are trying to reference a resource that doesn't exist by passing a conference SID as the parameter that needs a call SID.

    Conferences and calls are different resources, which is why to refer to a participant in a conference you need the conference SID and the participant's call SID.

    You have the Call SID, which is confusingly referred to as the conference ID, but that is because it used as the friendly name when creating the TwiML to dial someone into a conference.

    Since it is the friendly name, this means we can look up the conference by filtering by the friendly name.

    var conferences = ConferenceResource.Read(
        friendlyName: conferenceId,
        status: ConferenceResource.StatusEnum.InProgress
    );
    

    This returns all the in progress conferences with the friendly name the same as the call SID. This will be at most one conference. You can then use the conference SID, along with the call SID to update the participant. Try something like this:

    public async Task<ActionResult> CallAgent2(string agentId)
    {
        var call = await _callsRepository.FindByAgentIdAsync(agentId);
        var conferences = ConferenceResource.Read(
            friendlyName: conferenceId,
            status: ConferenceResource.StatusEnum.InProgress
        );
        var conference = conferences[0];
        var participant = ParticipantResource.Update(
            pathConferenceSid: conference.Sid,
            pathCallSid: call.ConferenceId,
            hold: true,
            holdUrl: new System.Uri("http://twimlets.com/holdmusic?Bucket=com.twilio.music.classical")
        );
    
        var callBackUrl = GetConnectConfereceUrlForAgent(agentId, call.ConferenceId);
        _callCreator.CallAgent("agent2", callBackUrl);
        return new EmptyResult();
    }