I'm trying to use Twilio to connect workers through a kind of Walkie Talkie (all the workers get a JWT to make browser calls using the Javascript SDK), for this I use the Twiml verb conference, when the worker press the conference button in the browser it sends a list of the active workers (except for the one who started the conference), I use the callSid as the name of the conference to make it unique and the CallResource to put every worker into the conference.
However, the workers in the list start listening the wait music for a conference room, but the caller automatically end the connection as soon as it is open, it doesn't even ends the conference, I don't know what's wrong with the code, I'm following the documentation for conferences in https://www.twilio.com/docs/voice/twiml/conference
Here is the method that's called when a conference needs to be created:
public VoiceResponse ConferenceTalk(List<string> recipients, string caller, string callSid)
{
TwilioClient.Init(my_account_sid, my_auth_token);
var confName = $"wt_{callSid}";
foreach (var recipient in recipients)
{
CallResource.Create(
url: new Uri($"{this.publicUrl}/Conference/WtConference/{confName}"),
to: new Twilio.Types.Client($"client:{recipient}"),
from: new Twilio.Types.Client(caller));
}
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference(confName,
startConferenceOnEnter: true,
endConferenceOnExit: true);
response.Append(dial);
return response;
}
Here is the endpoint the CallResource target with the url attribute:
[HttpPost]
public TwiMLResult WtConference()
{
var confName = Request.Url.Segments[Request.Url.Segments.Length - 1];
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference(confName);
response.Append(dial);
return TwiML(response);
}
I feel like the time all of this takes to happen might be causing your issues here. And the Twilio Voice SDK may not be the best product for this. I'd have to see maybe a video showing how the interaction works to fully commit to this.
In the meantime, I might try to speed up people joining the conference by sending the TwiML for the conference in the API call, not waiting for the webhook. e.g.:
public VoiceResponse ConferenceTalk(List<string> recipients, string caller, string callSid)
{
TwilioClient.Init(my_account_sid, my_auth_token);
var confName = $"wt_{callSid}";
var outboundResponse = new VoiceResponse();
var outboundDial = new Dial();
outboundDial.Conference(confName);
outboundResponse.Append(outboudDial);
foreach (var recipient in recipients)
{
CallResource.Create(
twiml outboundResponse,
to: new Twilio.Types.Client($"client:{recipient}"),
from: new Twilio.Types.Client(caller));
}
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference(confName,
startConferenceOnEnter: true,
endConferenceOnExit: true);
response.Append(dial);
return response;
}
I say that Twilio Voice might not be best for this because on the Twilio back end, this is going through a whole stack that is built for making phone calls. Outbound calls are made at a rate of 1 call per second, so that might be slowing the calling of your list down.
You could consider the Twilio Video SDK for this instead (you can make audio only calls with the Twilio Video product). For this you would need to be able to trigger each of workers joining a room that was then used to distribute the audio. There aren't limits on calls per second, workers would just need to connect to a room and your application would be able to control who could talk at any one time.
Related
I am currently working on a C# Windows Form project that requires the user to pay prior to any processing taking place. I am using the Square .Net SDK for payment processing and have successfully managed to get a payment through to the sandbox environment using the Checkout URL generated by the Checkout API. My question is whether there is a simple way to get whether the payment process has been completed. Right now, I am just polling the API with the same order (with identical idempotency keys) and waiting for it to return an error that the order is no longer valid. Here is the backbone of my current code:
var bodyOrderLineItems = new List<CreateOrderRequestLineItem>();
long totalCost = 100;
var charge0 = new Money.Builder().Amount(totalCost).Currency("USD").Build();
bodyOrderLineItems.Add(new CreateOrderRequestLineItem.Builder("1").Name("Incredibly Valuable Product").BasePriceMoney(charge0).Build());
var order = new CreateOrderRequest.Builder()
.ReferenceId("reference_id")
.LineItems(bodyOrderLineItems)
.Build();
var body = new CreateCheckoutRequest.Builder("Test_iKey4", order)
.AskForShippingAddress(false)
.Build();
var checkoutApi = client.CheckoutApi;
try
{
CreateCheckoutResponse result = checkoutApi.CreateCheckout(locationsString, body);
System.Diagnostics.Process.Start(result.Checkout.CheckoutPageUrl);
while (true)
{
System.Threading.Thread.Sleep(5000);
//while payment hasn't gone through
try
{
result = checkoutApi.CreateCheckout(locationsString, body);
}
catch (ApiException e)
{
MessageBox.Show(e.Errors[0].Detail);
break;
}
}
MessageBox.Show("Payment Must Have Gone Through");
}
catch (ApiException e) { MessageBox.Show(e.Errors[0].Detail); };
Is this a valid approach? While this does seem to work, I feel like I am flooding the api with requests. I am pretty inexperienced with the Square API, so any help would be appreciated.
Typically the Checkout API is used within a website, as it includes a parameter redirect_url so that when the payment is complete, the user is redirected back to your side and it includes url parameters such as the transaction id. If you don't have a website, you can instead sign up for webhooks. The PAYMENT_UPDATED webhook will be sent out when a payment has been processed, so you do not need to do polling; just listen for the webhook.
I am using Visual studio. This is for Asp.net web application (.net framework)
this solution as a webcore application is acceptable as well.
I would like to be able to enter the information for message and to phone number dynamically , but i dont know how to "pause" the program so that this can happen. I understand the dynamic part, and can use Javascript to do that,
Basically what I want is an app that brings up a webpage where the end user enters the to number and the message, and then clicks send to send.
I thought it would be simple, but not so much :(
I have the quick start code for C# as -
// Install the C# / .NET helper library from twilio.com/docs/csharp/install
using System;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
class Program
{
static void Main(string[] args)
{
// Find your Account Sid and Token at twilio.com/console
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const string authToken = "your_auth_token";
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
body: "Join Earth's mightiest heroes. Like Kevin Bacon.",
from: new Twilio.Types.PhoneNumber("+15017122661"),
to: new Twilio.Types.PhoneNumber("+15558675310")
);
Console.WriteLine(message.Sid);
}
}
Okay I'm going to assume you want to send SMS. Further, I'm going to assume you're using Asp.Net MVC. Twilio voice is a little bit more complex, as Twilio calls back several times to get voice scripts and update statuses. More complex if you need phone tree behavior.
SMS Callbacks happen more than once too, but they're calling the same callback URL over and over, nothing fancy there.
The flow should look like this:
Web interface -> Asp.Net MVC Controller Action -> Database -> Twilio
I'll leave the web interface to you, and give some examples of the backend stuff.
You'll want a database, with one table 'Message'
Message should have these columns (at a minimum, you may need more):
message_id_pk
twilio_sid (nullable)
message_content (160 character limit if you want to keep messages in one SMS segment, this has considerations on operating cost)
status (nullable)
recipient_phone
Controller Action:
[Authorize] //assuming you'll want to have users authenticate before they can send the sms
[RequireHttps]
public async Task<ActionResult> SendSMS(
[Bind(Include = "message_id_pk, message_content, recipient_phone"] Message message)
{
db.Messages.Add(message);
TwilioSmsSender.SendSMS(message);
return RedirectToAction("Success");
}
And in TwilioSender.cs
public static void SendSMS(Message message)
{
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const string authToken = "your_auth_token";
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
body: message.message_content,
from: new Twilio.Types.PhoneNumber("+15017122661"), //note: you can let your Twilio Messaging service handle the phone number, I recommend you look into that
to: new Twilio.Types.PhoneNumber(message.recipient_phone)
statusCallback: new Uri(TwilioCallBackController.SMSCallBackURL)
);
message.twilio_sid = message.Sid;
db.SaveChanges();
}
And in TwilioCallBackController.cs (You need to handle callbacks from Twilio here)
[ValidateTwilioRequest]
public ActionResult TwilioSMSCallback()
{
string sid = Request.Form["SmsSid"];
List<Message> msg = db.Message.Where(x=> x.twilio_sid == sid).ToListAsync();
if(msg.Count > 0)
{
Message message = msg.First();
message.status = Request.Form["SmsStatus"];
}
}
I am building an application where a user will call my Twilio Number. After connecting, Twilio will call another user and connect the two parties. However, the number displayed for the second party should be Twilio's number (or no caller ID), not the user's number.
I tired adding SIP header such as privacy = full & p-asserted-identity="anonymous" but none is working.
Code I am using for the callback:
[HttpPost]
public async Task<ActionResult> Connect(string from, string to)
{
//var outgoingPhoneNumber = await GatherOutgoingPhoneNumberAsync(from, to);
var response = new TwilioResponse();
response.Say("Please wait while we contact the other party");
response.Dial("+14085993263", new { });
return TwiML(response);
}
Is there anyway to do that?
Twilio developer evangelist here.
You're very close to the solution, but what want to do is add a callerid attribute to the Dial verb. That way, you can either add your Twilio number, or your own business' verified number. To do that just change your code to the following:
[HttpPost]
public async Task<ActionResult> Connect(string from, string to)
{
var response = new TwilioResponse();
response.Say("Please wait while we contact the other party");
response.Dial("+14085993263", new { callerId = "+1234567890" });
return TwiML(response);
}
Make sure you replace callerId with the number you wish to use. The caller ID can only be one of your Twilio numbers or a verified number as stated above.
Hope this helps you
The stripe.com API only returns active subscriptions. I want to verify when I delete a subscription.
So this is going to return an error. I am not sure how to code for it.
I would prefer to make this call based on the subscriptionId. Will this cause an exception or will it return an error code?
Retrieving a subscription
var subscriptionService = new StripeSubscriptionService();
StripeSubscription stripeSubscription = subscriptionService.Get(*subscriptionId*);
Another options which is somewhat of a hack is to return all the subscriptions for the given customer and test to see if the subscriptionId was returned.
List all subscriptions for a customer
var subscriptionService = new StripeSubscriptionService();
IEnumerable<StripeSubscription> responses = subscriptionService .List(*customerId*);
foreach( var response in responses )
{
if (response.subscriptionId == subscriptionId)
{
// subscription exists and was not deleted
exit;
}
}
Per their documentation, https://stripe.com/docs/api they have 2 different APIs. You're trying to use the RESTful API, which is for retrieving information on demand.
They also have a WebHooks API, which requires you have an endpoint listening on your site which can accept event notifications. You configure these through your Dashboard with them.
The event type you're looking for specifically is probably the customer.subscription.deleted event, but there's a lot more you can do with them and I'd encourage you to explore all of those Webhooks.
I can't offer a code sample, as I don't use their service.
The strip.net example shows the subscriptionService.Cancel as a methed:
var subscriptionService = new StripeSubscriptionService();
subscriptionService.Cancel(*customerId*, *subscriptionId*);
But you can also use it as a function and it returns the subscription object.
var subscriptionService = new StripeSubscriptionService();
StripeSubscription stripeSubscription = subscriptionService.Cancel(*customerId*, *subscriptionId*);
If (stripeSubscription.Status != "canceled")
{
//subscription not cancelled
// take action
}
Per Stripe API docs:
Returns:
The canceled subscription object. Its subscription status will be set to "canceled" unless you've set at_period_end to true when canceling, in which case the status will remain "active" but the cancel_at_period_end attribute will change to true.One of the fiels is .status , witch is set to canceled.
I'm working with the Nest API, which supports REST Streaming via Firebase. I have REST working, however I cannot get it to stream correctly. This is very important for my app, and REST just isn't effective for what I want to do.
I'm using Hammock for the requests, and here's the code:
public class NestAPI
{
private RestClient client { get; set; }
public NestAPI()
{
this.client = new RestClient();
this.client.Authority = "https://developer-api.nest.com/";
this.client.HasElevatedPermissions = true;
}
public void BeginStreaming()
{
RestRequest request = new RestRequest();
request.AddParameter("auth", App.accessToken);
request.RetryPolicy = new RetryPolicy() { RetryCount = 3 };
//Enables streaming
//request.AddHeader("Accept", "text/event-stream");
//request.StreamOptions = new StreamOptions() { Duration = new TimeSpan(96, 0, 0), ResultsPerCallback = 1 };
this.client.BeginRequest<object>(request, new RestCallback<object>(this.StreamCompletedEvent));
}
private void StreamCompletedEvent(RestRequest request, RestResponse<object> response, object userState)
{
//TO DO: check for errors first
string json = response.Content;
}
public void EndStreaming()
{
this.client.CancelStreaming();
}
}
This code works and does return JSON, however I can't seem to enable streaming. When I uncomment the lines below "Enables streaming", the callback event never fires. It's important to note that authentication is done using the uri parameter, "auth".
Unfortunately, there doesn't seem to be Firebase libraries available, and REST is my only option. I want to know when JSON properties change and want to set different values while streaming.
I'm not familiar with Hammock, but can you make sure that it's set to follow redirects? The streaming endpoint typically issues HTTP 307 to get inform the client of the correct server to connect to.
I've never used Hammock, but looking through source code (briefly) it appears you need to set it up as a streaming request with StreamOptions. Twitter has some open source that uses this here https://github.com/camertron/twitter-windows/blob/master/Source/Twitter/Classes/API/Streaming/UserStream.cs.
The way you have Hammock configured here it's waiting for an entire request to complete before calling your callback. This will (almost) never happen with a streaming request as the server keeps the connection open to push new results.