Ring Out does not hang up using DELETE

  • 2
  • Problem
  • Updated 2 years ago
  • Acknowledged
Stopping a call does NOT work using the API explorer or our own code referencing the Sandbox or our code referencing Production.  The Response code is 204 ("No content") and and the response headers are correct.

So, the DELETE method syntax and permissions are correct and the response is correct, but it does not hang up.

Anyone else having this problem?

Here is the Response from the Ring Out using API Explorer

{  "uri": "https://platform.devtest.ringcentral.com/restapi/v1.0/account/134133004/extension/134133004/ringout/...;,
  "id": 62,
  "status": {
    "callStatus": "InProgress",
    "callerStatus": "InProgress",
    "calleeStatus": "InProgress"
  }
}

Here is the code for the DELETE method using API Explorer

https://platform.devtest.ringcentral.com/restapi/v1.0/account/~/extension/~/ringout/62


Here is the Response Headers for the DELETE method
{
  "date": "Thu, 07 Apr 2016 19:09:12 GMT",
"routingkey": "SJC12P01JWS02, SJC12P01PAS01",
"content-language": "en",
"content-type": "application/json; charset=UTF-8"
}
Photo of Dave Welch

Dave Welch

  • 420 Points 250 badge 2x thumb

Posted 2 years ago

  • 2
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,622 Points 5k badge 2x thumb
Apologies for our API Explorer being out of sync with the API Developer Guide (which is more comprehensive, official, and shows the response body as empty on a DELETE to the route you provided).

https://developers.ringcentral.com/api-docs/latest/index.html#!#RefRingOut.html

I will take a look at the RingOut and canceling a RingOut and if I am able to recreate your experience will create an issue with our engineering team to inspect/resolve appropriately.

If I am unable to recreate, I may have some additional inquiries.

Thanks for providing the headers and request/response information.
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,622 Points 5k badge 2x thumb
I've seen a thread of email going on about this inquiry, before I provide any more information on this, I have a question:

1. I see the state of the call is "InProgress", but when you initiate the DELETE request, is that being done before/during/after any leg of the call has been connected, and if yes, at which leg and what is the state (if observing the presence notifications) please?

The reason I ask is because currently, if the state of the call switches to "Ringing" that is considered as connected according to our current implementation and cannot be canceled. It seems this might need some improvement, but I'm trying to gather as much information as possible.
Photo of Dave Welch

Dave Welch

  • 420 Points 250 badge 2x thumb
I am trying to hangup the call.  This might happen at any point in the calling process.
From your previous comment, it seems that I misunderstood the purpose of this method.  If DELETE only works to stop a call before it has been answered, how do we hangup a call once it is answered?
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,622 Points 5k badge 2x thumb
The person on the call would be required to hangup the call, AFAIK that is the only way, but I will ask around.
Photo of Dave Welch

Dave Welch

  • 420 Points 250 badge 2x thumb
A long time ago I wrote a dialer that did not automatically disconnect a zombie call and a call was placed to Afghanistan for several days.  The bill was in the thousands.  Also, for totally hands free calling within an application, we would like to automatically hangup when the last page is entered.
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,622 Points 5k badge 2x thumb
Are you willing/able to share the code you wrote for that Dave?
Photo of Dave Welch

Dave Welch

  • 420 Points 250 badge 2x thumb
      public String StopCall(Terminal _t)        {
            String sBody = String.Empty;
            byte[] byteBody = null;
            try
            {
                byteBody = new byte[2] { 123, 125 };
                SendReceive("DELETE", "/restapi/v1.0/account/~/extension/~/ringout/" + _t.CallId, "Bearer", _t.Access_Token, byteBody);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return String.Empty;
        }

      private void SendReceive(String method, String uri, String tokenType, String authcode, byte[] byteBody)
        {

            Stream sResponse = null;
            Stream sRequest = null;
            StreamReader srResponse = null;
            HttpWebResponse HttpWResp = null;
            String sBody = String.Empty;
            ASCIIEncoding encoding = new ASCIIEncoding();
            HttpWebRequest HttpWReq = null;
            try
            {
                HttpWReq = (HttpWebRequest)WebRequest.Create(baseURL + uri);
                HttpWReq.Method = method;
                HttpWReq.KeepAlive = true;
                if (tokenType.Trim().Length > 0 && authcode.Trim().Length > 0)
                {
                    HttpWReq.UserAgent = appName + "/" + appVersion;
                    HttpWReq.Headers[HttpRequestHeader.Authorization] = string.Format("{0} {1}", tokenType.Trim(), authcode.Trim());
                }
                if (HttpWReq.Method == "POST")
                {
                    if (HttpWReq.RequestUri.ToString().Contains("oauth/"))
                    {
                        HttpWReq.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
                    }
                    else
                    {
                        HttpWReq.ContentType = "application/json";
                    }

                    HttpWReq.ContentLength = byteBody.Length;

                    //Add parameters to the Body - Go figure
                    //Task<sRequest>HttpWReq.GetRequestStreamAsync();
                    sRequest = HttpWReq.GetRequestStream();
                    sRequest.Write(byteBody, 0, byteBody.Length);
                    //Console.WriteLine(sBody);
                }
                if (HttpWReq.Method == "DELETE")
                {
                    HttpWReq.Accept = "application/json";
                    HttpWReq.ContentType = "application/json; charset=UTF-8";
                    HttpWReq.Headers.Add("X-HTTP-Method-Override", "DELETE");

                }              
 //Send Request and Get the Response
                HttpWResp = (HttpWebResponse)HttpWReq.GetResponse();
                switch (HttpWResp.StatusCode.ToString())
                {
                    case "OK": //== HttpStatusCode.OK)

                        sResponse = HttpWResp.GetResponseStream();

                        srResponse = new StreamReader(sResponse);
                        String s = srResponse.ReadToEnd();

                        jt = JToken.Parse(s);
                        break;
                    case "NoContent":// Output from DELETE
                        break;
                    default:
                        break;

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(String.Format("{0} {1}", ex.Message, ex.GetType().FullName));
            }
            finally
            {
                if (HttpWResp != null)
                {
                    HttpWResp.Close();
                }
                else
                {
                    HttpWReq.Abort();
                }
            }

        }
Photo of Dave Welch

Dave Welch

  • 420 Points 250 badge 2x thumb
Probably the only thing that needs explanation is the Terminal Class.  This is an object that is instantiated for each extension and holds the relevant data like the CallId and the auth token 
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,622 Points 5k badge 2x thumb
Awesome! Thanks for sharing Dave!