Reputation: 201
I'm following the Quickstart Guide using a python deployment on Heroku and am able to place calls just fine. It's the receiving that I'm having problems with. I've not modified any of the init or delegate logic for either the TVOIncomingCall
instance or the PKPushRegistry
. And indeed, when I compile, the log says "pushRegistry:didUpdatePushCredentials:forType"
and "Successfully registered for VoIP push notifications."
This makes me think my incoming handler on my server.py is the problem.
My question is this: What's the proper way, in python, to fire off the VoIP push notification to notify the user of an incoming call? I've enabled VoIP Services in my app and generated a VoIP services certificate (.p12) and received a valid PUSH_CREDENTIAL_SID
for my efforts, but what to do with it?
The Quickstart says to hit my server's 'placeCall' endpoint, so I update my Twilio number's incoming path and point it accordingly in the dashboard, but this results in "An Application Error has occurred" response whenever anyone calls my Twilio number.
Here is the relevant code from my server.py:
import os
from flask import Flask, request
from twilio.jwt.access_token import AccessToken, VoiceGrant
from twilio.rest import Client
import twilio.twiml
ACCOUNT_SID = 'ACxxxxxxxx'
API_KEY = 'SKxxxxxxxxxxxxxxxx'
API_KEY_SECRET = 'xxxxxxxxxxxxxxxx'
PUSH_CREDENTIAL_SID = 'CRxxxxxxxxxxxxxxxx'
APP_SID = 'APxxxxxxxxxxxxxxxx'
ACCOUNT_AUTH = 'xxxxxxxxxxxxxxxx'
IDENTITY = 'MyApp' #not literally
app = Flask(__name__)
@app.route('/accessToken')
def token():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
grant = VoiceGrant(
push_credential_sid = push_credential_sid,
outgoing_application_sid = app_sid
)
token = AccessToken(account_sid, api_key, api_key_secret, IDENTITY)
token.add_grant(grant)
return str(token)
@app.route('/placeCall', methods=['GET', 'POST'])
def placeCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
CALLER_ID = request.values.get('From')
IDENTITY = request.values.get('To')
#client = Client(api_key, api_key_secret, account_sid)
client = Client(api_key, api_key_secret, account_sid, app_sid, push_credential_sid)
call = client.calls.create(to='client:' + IDENTITY, from_= 'client:' + CALLER_ID)
return str(call.sid)
My Identity
value is clearly wrong. I would think it would need to equal a reference to an app instance somehow. In the quickstart python example, IDENTITY = 'voice_test'
Also, where does the PUSH_CREDENTIAL_SID
come into play?
Thanks in advance.
UPDATE
______
As per @philnash's comment, I've nested the client
noun inside the dial
verb. Here's my new /incoming
endpoint:
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
CALLER_ID = request.values.get('From')
resp = twilio.twiml.Response()
resp.dial(client = IDENTITY, callerId = CALLER_ID, record = "record-from-answer-dual")
return str(resp)
This now results in a 'Schema validation warning' in the debugger stating 'unknown or unexpected nested elements' as a possible cause. Am I registering the client incorrectly? The old SDK allowed you to explicitly pass in your clientName as a parameter.
The IDENTITY
string in my server.py is:
client
noun of the dial
verb.Upvotes: 2
Views: 728
Reputation: 73029
Twilio developer evangelist here.
The /placeCall
endpoint is not for your Twilio number's incoming call webhook. In the example it is used to simply generate a call to your client.
Instead, your incoming call webhook should point at an endpoint that will return some TwiML instructing Twilio to dial your client. TwiML is just a subset of XML and the elements you will need are <Dial>
with a nested <Client>
. Your endpoint should return something like:
<Response>
<Dial>
<Client>YOUR_CLIENT_NAME</Client>
</Dial>
</Response>
Let me know if this helps at all.
Update
Based on the update in the question, we now need to generate this TwiML in Python. You can nest TwiML with the Twilio Python helper library using Python's with
syntax. I believe this should work:
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
CALLER_ID = request.values.get('From')
resp = twilio.twiml.Response()
with resp.dial(callerId = CALLER_ID, record = "record-from-answer-dual") as dial:
dial.client(IDENTITY)
return str(resp)
Upvotes: 1
Reputation: 3811
Update the PUSH_CREDENTIAL_SID
value in the application server's server.py
file with your new push credential SID. It goes with the following constants at the top of the file:
ACCOUNT_SID = 'AC***'
API_KEY = 'SK***'
API_KEY_SECRET = '***'
PUSH_CREDENTIAL_SID = 'CR***'
APP_SID = 'AP***'
And in your placeCall
function:
def placeCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
It seems like you're also missing the APP_SID
from above which is the reference to TwiML app that contains some call instructions.
Upvotes: 0