GithubHelp home page GithubHelp logo

twilio-go's Introduction

twilio-go

Tests PkgGoDev Release

All the code here was generated by twilio-oai-generator by leveraging openapi-generator and twilio-oai. If you find an issue with the generation or the OpenAPI specs, please go ahead and open an issue or a PR against the relevant repositories.

๐Ÿš€ Feature Update

Twilio Go Helper Library's version 1.20.0 adds support for the application/json content type in the request body. See example here. Behind the scenes Go Helper is now auto-generated via OpenAPI with this release. This enables us to rapidly add new features and enhance consistency across versions and languages.

Documentation

The documentation for the Twilio API can be found here.

The Go library documentation can be found here.

Supported Go Versions

This library supports the following Go implementations:

  • Go 1.15
  • Go 1.16
  • Go 1.17
  • Go 1.18
  • Go 1.19
  • Go 1.20

Installation

The recommended way to install twilio-go is by using Go modules.

If you already have an initialized project, you can run the command below from your terminal in the project directory to install the library:

go get github.com/twilio/twilio-go

If you are starting from scratch in a new directory, you will first need to create a go.mod file for tracking dependencies such as twilio-go. This is similar to using package.json in a Node.js project or requirements.txt in a Python project. You can read more about mod files in the Go documentation. To create the file, run the following command in your terminal:

go mod init twilio-example

Once the module is initialized, you may run the installation command from above, which will update your go.mod file to include twilio-go.

Test your installation

Try sending yourself an SMS message by pasting the following code example into a sendsms.go file in the same directory where you installed twilio-go. Be sure to update the accountSid, authToken, and from phone number with values from your Twilio account. The to phone number can be your own mobile phone number.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
)

func main() {
	accountSid := "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	authToken := "f2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: accountSid,
		Password: authToken,
	})

	params := &twilioApi.CreateMessageParams{}
	params.SetTo("+15558675309")
	params.SetFrom("+15017250604")
	params.SetBody("Hello from Go!")

	resp, err := client.Api.CreateMessage(params)
	if err != nil {
		fmt.Println("Error sending SMS message: " + err.Error())
	} else {
		response, _ := json.Marshal(*resp)
		fmt.Println("Response: " + string(response))
	}
}

Save sendsms.go. In your terminal from the same directory, run:

go run sendsms.go

After a brief delay, you will receive the text message on your phone.

Warning It's okay to hardcode your credentials when testing locally, but you should use environment variables to keep them secret before committing any code or deploying to production. Check out How to Set Environment Variables for more information.

Use the helper library

API credentials

The Twilio RestClient needs your Twilio credentials. We recommend storing them as environment variables, so that you don't have to worry about committing and accidentally posting them somewhere public. See http://twil.io/secure for more details on how to store environment variables.

package main

import "github.com/twilio/twilio-go"

func main() {
	// This will look for `TWILIO_ACCOUNT_SID` and `TWILIO_AUTH_TOKEN` variables inside the current environment to initialize the constructor
	// You can find your Account SID and Auth Token at twilio.com/console
	// `TWILIO_ACCOUNT_SID` should be in format "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	client := twilio.NewRestClient()
}

If you don't want to use environment variables, you can also pass the credentials directly to the constructor as below.

package main

import "github.com/twilio/twilio-go"

func main() {
	accountSid := "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	authToken := "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: accountSid,
		Password: authToken,
	})
}

Use a Subaccount

Subaccounts in Twilio are just accounts that are "owned" by your account. Twilio users can create subaccounts to help separate Twilio account usage into different buckets.

If you wish to make API calls with a Subaccount, you can do so by setting the AccountSid field in the twilio.ClientParams:

package main

import "github.com/twilio/twilio-go"

func main() {
	// subaccountSid should also be in format "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	subaccountSid := os.Getenv("TWILIO_SUBACCOUNT_SID")
	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		AccountSid: subaccountSid,
	})
}

Use API Keys

Lastly, if you want to follow best practices and initialize your client using an API Key and Secret, instead of potentially exposing your account's AuthToken, use the following pattern:

package main

import (
	"os"

	"github.com/twilio/twilio-go"
)

func main() {
	accountSid := os.Getenv("TWILIO_ACCOUNT_SID")
	apiKey := os.Getenv("TWILIO_API_KEY")
	apiSecret := os.Getenv("TWILIO_API_SECRET")

	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username:   apiKey,
		Password:   apiSecret,
		AccountSid: accountSid,
	})
}

Specify a Region and/or Edge

package main

import (
	"github.com/twilio/twilio-go"
)

func main() {
	client := twilio.NewRestClient()
	client.SetRegion("au1")
	client.SetEdge("sydney")
}

This will result in the hostname transforming from api.twilio.com to api.sydney.au1.twilio.com.

A Twilio client constructed without these parameters will also look for TWILIO_REGION and TWILIO_EDGE variables inside the current environment.

Buy a phone number

package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
)

func main() {
	phoneNumber := "AVAILABLE_TWILIO_PHONE_NUMBER"

	client := twilio.NewRestClient()

	params := &twilioApi.CreateIncomingPhoneNumberParams{}
	params.SetPhoneNumber(phoneNumber)

	resp, err := client.Api.CreateIncomingPhoneNumber(params)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Phone Number Status: " + *resp.Status)
	}
}

Make a call

package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
	"os"
)

func main() {
	from := os.Getenv("TWILIO_FROM_PHONE_NUMBER")
	to := os.Getenv("TWILIO_TO_PHONE_NUMBER")

	client := twilio.NewRestClient()

	params := &twilioApi.CreateCallParams{}
	params.SetTo(to)
	params.SetFrom(from)
	params.SetUrl("http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient")

	resp, err := client.Api.CreateCall(params)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Call Status: " + *resp.Status)
		fmt.Println("Call Sid: " + *resp.Sid)
		fmt.Println("Call Direction: " + *resp.Direction)
	}
}

Get data about an existing Call

package main

import (
	"fmt"
	"os"

	"github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
)

func main() {
	accountSid := os.Getenv("TWILIO_ACCOUNT_SID")
	apiKey := os.Getenv("TWILIO_API_KEY")
	apiSecret := os.Getenv("TWILIO_API_SECRET")

	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username:   apiKey,
		Password:   apiSecret,
		AccountSid: accountSid,
	})

	params := &twilioApi.FetchCallParams{}

	resp, err := client.Api.FetchCall("CA42ed11f93dc08b952027ffbc406d0868", params)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Call Status: " + *resp.Status)
		fmt.Println("Call Sid: " + *resp.Sid)
		fmt.Println("Call Direction: " + *resp.Direction)
	}
}

Send Bulk Message

Try sending a message to multiple recipients with JSON request body support.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/twilio/twilio-go"
	previewMessaging "github.com/twilio/twilio-go/rest/preview_messaging/v1"
)

func main() {
	accountSid := "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	authToken := "f2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: accountSid,
		Password: authToken,
	})

	// create multiple recipients
	msg1 := previewMessaging.MessagingV1Message{To: "+XXXXXXXXXX"}
	msg2 := previewMessaging.MessagingV1Message{To: "+XXXXXXXXXX"}
	
	// create message request object
	req := &previewMessaging.CreateMessagesRequest{Messages: []previewMessaging.MessagingV1Message{msg1, msg2}, Body: "Hello from Go!", From: "+XXXXXXXXXX"}
	params := &previewMessaging.CreateMessagesParams{CreateMessagesRequest: req}

	resp, err := client.PreviewMessagingV1.CreateMessages(params)
	if err != nil {
		fmt.Println("Error sending SMS message: " + err.Error())
	} else {
		response, _ := json.Marshal(*resp)
		fmt.Println("Response: " + string(response))
	}
}

Iterate through records

This library also offers paging functionality. Collections such as calls and messages have ListXxx and StreamXxx functions that page under the hood. With both list and stream, you can specify the number of records you want to receive (limit) and the maximum size you want each page fetch to be (pageSize). The library will then handle the task for you.

List eagerly fetches all records and returns them as a list, whereas Stream streams the records and lazily retrieves the pages as you iterate over the collection. Also, List returns no records if any errors are encountered while paging, whereas Stream returns all records up until encountering an error. You can also page manually using the PageXxx function in each of the apis.

Use ListXxx or StreamXxx

package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
	"os"
)

func main() {
	from := os.Getenv("TWILIO_FROM_PHONE_NUMBER")

	client := twilio.NewRestClient()

	params := &twilioApi.ListMessageParams{}
	params.SetFrom(from)
	params.SetPageSize(20)
	params.SetLimit(100)

	resp, _ := client.Api.ListMessage(params)
	for record := range resp {
		fmt.Println("Body: ", *resp[record].Body)
	}

	channel, _ := client.Api.StreamMessage(params)
	for record := range channel {
		fmt.Println("Body: ", *record.Body)
	}
}

Use PageXxx

package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
	"net/url"
	"os"
)

func main() {
	from := os.Getenv("TWILIO_FROM_PHONE_NUMBER")

	client := twilio.NewRestClient()

	params := &twilioApi.ListMessageParams{}
	params.SetFrom(from)
	params.SetPageSize(20)

	var pageToken string
	var pageNumber string
	resp, err = client.Api.PageMessage(params, "", "")
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(resp.NextPageUri)
		u, _ := url.Parse(resp.NextPageUri)
		q := u.Query()
		pageToken = q.Get("PageToken")
		pageNumber = q.Get("Page")
	}

	resp, err := client.Api.PageMessage(params, pageToken, pageNumber)
	if err != nil {
		fmt.Println(err)
	} else {
		if resp != nil {
			fmt.Println(*resp.Messages[0].Body)
		}
	}
}

Handle Exceptions

If the Twilio API returns a 400 or a 500 level HTTP response, the twilio-go library will include information in the returned err value. 400-level errors are normal during API operation ("Invalid number", "Cannot deliver SMS to that number", for example) and should be handled appropriately.

package main

import (
	"fmt"
	"os"

	"github.com/twilio/twilio-go"
	twilioclient "github.com/twilio/twilio-go/client"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
)

func main() {
	phoneNumber := os.Getenv("TWILIO_PHONE_NUMBER")

	client := twilio.NewRestClient()

	params := &twilioApi.CreateIncomingPhoneNumberParams{}
	params.SetPhoneNumber(phoneNumber)

	resp, err := client.Api.CreateIncomingPhoneNumber(params)
	if err != nil {
		twilioError := err.(*twilioclient.TwilioRestError)
		fmt.Println(twilioError.Error())
	}
}

Generate TwiML

To control phone calls, your application needs to output TwiML.

Use the twiml package to easily create such responses.

package main

import (
	"fmt"
	"github.com/twilio/twilio-go/twiml"
)

func main() {
	//Construct Verbs
	dial := &twiml.VoiceDial{}
	say := &twiml.VoiceSay{
		Message:            "Welcome to Twilio!",
		Voice:              "woman",
		Language:           "en-gb",
		OptionalAttributes: map[string]string{"input": "test"},
	}
	pause := &twiml.VoicePause{
		Length: "10",
	}
	//Construct Noun
	queue := &twiml.VoiceQueue{
		Url: "www.twilio.com",
	}
	//Adding Queue to Dial
	dial.InnerElements = []twiml.Element{queue}

	//Adding all Verbs to twiml.Voice
	verbList := []twiml.Element{dial, say, pause}
	twimlResult, err := twiml.Voice(verbList)
	if err == nil {
		fmt.Println(twimlResult)
	} else {
		fmt.Println(err)
	}
}

This will print the following:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Dial>
        <Queue url="www.twilio.com"/>
    </Dial>
    <Say voice="woman" language="en-gb" input="test">Welcome to Twilio!</Say>
    <Pause length="10"/>
</Response>

Advanced Usage

Use the request validator

Validate that GET/POST Requests are coming from Twilio:

package main

import (
	"fmt"
	"os"

	"github.com/twilio/twilio-go/client"
)

func main() {
	// You can find your Auth Token at twilio.com/console
	// For this example: authToken := "12345"
	authToken := os.Getenv("TWILIO_AUTH_TOKEN")

	requestValidator := client.NewRequestValidator(authToken)

	// Twilio's request URL
	url := "https://mycompany.com/myapp.php?foo=1&bar=2"

	// Post variables in Twilio's request
	params := map[string]string{
		"CallSid": "CA1234567890ABCDE",
		"Caller":  "+12349013030",
		"Digits":  "1234",
		"From":    "+12349013030",
		"To":      "+18005551212",
	}

	// X-Twilio-Signature header attached to the request
	signature := "0/KCTR6DLpKmkAf8muzZqo1nDgQ="

	// Validate GET request
	fmt.Println(requestValidator.Validate(url, params, signature))

	// Example of the POST request
	Body := []byte(`{"property": "value", "boolean": true}`)
	theUrl := "https://mycompany.com/myapp.php?bodySHA256=0a1ff7634d9ab3b95db5c9a2dfe9416e41502b283a80c7cf19632632f96e6620"
	theSignature := "y77kIzt2vzLz71DgmJGsen2scGs="

	// Validate POST request
	fmt.Println(requestValidator.ValidateBody(theUrl, Body, theSignature))
}

Use standalone products

Don't want to import the top-level Twilio RestClient with access to the full suite of Twilio products? Use standalone product services instead:

package main

import (
	"github.com/twilio/twilio-go/client"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
	serverless "github.com/twilio/twilio-go/rest/serverless/v1"
	"os"
)

func main() {
	accountSid := os.Getenv("TWILIO_ACCOUNT_SID")
	authToken := os.Getenv("TWILIO_AUTH_TOKEN")

	// Create an instance of our default BaseClient implementation
	// You will need to provide your API credentials to the Client manually
	defaultClient := &client.Client{
		Credentials: client.NewCredentials(accountSid, authToken),
	}
	defaultClient.SetAccountSid(accountSid)

	coreApiService := twilioApi.NewApiServiceWithClient(defaultClient)
	serverlessApiService := serverless.NewApiServiceWithClient(defaultClient)
}

Other advanced examples

Build Access Tokens

This library supports access token generation for use in the Twilio Client SDKs.

Here's how you would generate a token for the Voice SDK:

package main

import (
	"os"
	"github.com/twilio/twilio-go/client/jwt"
)

accountSid := os.Getenv("TWILIO_ACCOUNT_SID")
applicationSid := os.Getenv("TWILIO_TWIML_APP_SID")
apiKey := os.Getenv("TWILIO_API_KEY")
apiSecret := os.Getenv("TWILIO_API_SECRET")
identity := "fake123"

params := jwt.AccessTokenParams{
	AccountSid: accountSid,
	SigningKeySid: apiKey,
	Secret: apiSecret,
	Identity: identity,
}

jwtToken := jwt.CreateAccessToken(params)
voiceGrant := &jwt.VoiceGrant{
	Incoming: jwt.Incoming{Allow: true},
	Outgoing: jwt.Outgoing{
		ApplicationSid: applicationSid,
	},
}

jwtToken.AddGrant(voiceGrant)
token, err := jwtToken.ToJwt()

Create Capability Tokens for TaskRouter v1:

package main

import (
	"os"
	"github.com/twilio/twilio-go/client/jwt/taskrouter"
)

AccountSid := os.Getenv("TWILIO_ACCOUNT_SID")
AuthToken := os.Getenv("TWILIO_AUTH_TOKEN")
WorkspaceSid := os.Getenv("TWILIO_WORKSPACE_SID")
ChannelID := os.Getenv("TWILIO_CHANNEL_ID")

Params = taskrouter.CapabilityTokenParams{
	AccountSid: AccountSid,
	AuthToken: AuthToken,
	WorkspaceSid: WorkspaceSid,
	ChannelID: ChannelID,
}

capabilityToken := taskrouter.CreateCapabilityToken(Params)
token, err := capabilityToken.ToJwt()

Local Usage

Building

To build twilio-go run:

go build ./...

Testing

To execute the test suite run:

go test ./...

Generating Local Documentation

To generate documentation, from the root directory:

godoc -http=localhost:{port number}

Then, navigate to http://localhost:{port number}/pkg/github.com/twilio/twilio-go in your local browser.

Example:

godoc -http=localhost:6060

http://localhost:6060/pkg/github.com/twilio/twilio-go

Docker Image

The Dockerfile present in this repository and its respective twilio/twilio-go Docker image are currently used by Twilio for testing purposes only.

Getting help

If you need help installing or using the library, please check the Twilio Support Help Center first, and file a support ticket if you don't find an answer to your question.

If you've instead found a bug in the library or would like new features added, go ahead and open issues or pull requests against this repo!

twilio-go's People

Contributors

avelincorreia avatar buchanaf avatar claudiachua avatar emford avatar eshanholtz avatar garethpaul avatar heyztb avatar jennifermah avatar kpritam avatar kridai avatar miguelgrinberg avatar natebrennand avatar pmcanseco avatar rakatyal avatar sbansla avatar shamigor avatar shwetha-manvinkurke avatar stern-shawn avatar thinkingserious avatar tiwarishubham635 avatar twilio-dx avatar wklock avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

twilio-go's Issues

Authenticating with API key while using a custom client

Issue Summary

I'm trying to authenticate with an API key and secret and at the same time use a custom underlying HTTP client. I have read the instructions on how to authenticate with API Keys here, and the instructions on how to use a custom HTTP client here. However, I can't seem to make these two work together.

Below is what I've tried:

Code Snippet

import (
	"net/http"
	"github.com/twilio/twilio-go"
	"github.com/twilio/twilio-go/client"
)

httpClient := http.DefaultClient
apiKey := "REDACTED"
apiSecret := "REDACTED"
accountSID := "REDACTED"

credentials := &client.Credentials{
	Username: apiKey,
	Password: apiSecret,
}

twilioClient := &client.Client{
	Credentials: credentials,
	HTTPClient:  cl,
}
twilioClient.SetAccountSid(accountSID)

restClient := twilio.NewRestClientWithParams(twilio.ClientParams{
	Username:   apiKey,
	Password:   apiSecret,
	AccountSid: accountSID,
	Client:     twilioClient,
})

I'm then using the RestClient like this:

import (
	api "github.com/twilio/twilio-go/rest/api/v2010"
)

p := &api.CreateMessageParams{}
p.SetTo("+123456789")
p.SetFrom("+123456789")
p.SetBody("Test")

resp, err := httpClient.Api.CreateMessage(p)

I've tried omitting the Account SID as well as swapping the API Key and the Account SID.

Exception/Log

Status: 401 - ApiError 20003: Authenticate (null) More info: https://www.twilio.com/docs/errors/20003

Technical details:

  • twilio-go version: v1.17.0
  • go version: 1.21.1

ListCall does not return ListCallResponse

Issue Summary

I'm using the ListCall api to retrieve calls related to a parent sid.

  1. ListCalldoes not return ListCallResponse
  2. ListCall throws an error if no call resources related to a parent sid is found
  3. PageCall is the one that returns ListCallResponse. see https://github.com/twilio/twilio-go/blob/main/rest/api/v2010/accounts_calls.go
  4. Your documentation states that ListCall will return ListCallResponse https://github.com/twilio/twilio-go/blob/main/rest/api/v2010/docs/AccountsCallsApi.md#listcall

I believe PageCall is the one I should be using, so is the documentation wrong?

Steps to Reproduce

Code Snippet

import (
        "github.com/twilio/twilio-go/client"
	apiv2010 "github.com/twilio/twilio-go/rest/api/v2010"
)
defaultClient := &client.Client{
	Credentials: client.NewCredentials(creds.AccountSID, creds.AuthToken),
}
defaultClient.SetAccountSid(creds.AccountSID)
client := apiv2010.NewApiServiceWithClient(defaultClient)
resp, err := client.ListCall(&apiv2010.ListCallParams{
	ParentCallSid: &sid,
})

Exception/Log

# paste exception/log here
could not retrieve payload from response

Technical details:

  • twilio-go version: v0.22.1
  • go version: 1.17

panic occurs when fetching messaging service for SID with trailing whitespace

Issue Summary

I use the following code to check if a messaging service is valid

_, err = twilioClient.MessagingV1.FetchService(p.TwilioConfig.MessagingServiceSid)
if err != nil {
  // handle error
}

If the MessageService SID contains trailing whitespace, then the library produces a panic.

Steps to Reproduce

  1. Create a Twilio Client
  2. Fetch Messaging Service with Messaging Service SID that has trailing whitespace

Code Snippet

_, err = twilioClient.MessagingV1.FetchService("MSabc123\t")
if err != nil {
  // handle error
}

Exception/Log

2022/10/13 15:15:12 http: panic serving 172.24.0.1:57074: runtime error: invalid memory address or nil pointer dereference
goroutine 69 [running]:
net/http.(*conn).serve.func1()
       /usr/local/go/src/net/http/server.go:1825 +0xbf
panic({0x113d760, 0x1ccfd00})
github.com/twilio/twilio-go/client.(*RequestHandler).BuildUrl(0xc00081b620, {0xc000098000?, 0xc000556e18?})
       /go/pkg/mod/github.com/twilio/[email protected]/client/request_handler.go:37 +0x4a
github.com/twilio/twilio-go/client.(*RequestHandler).sendRequest(0xc00081b620, {0x130c879, 0x3}, {0xc000098000?, 0xc000120450?}, 0x23?, 0xffffffffffffffff?)
       /go/pkg/mod/github.com/twilio/[email protected]/client/request_handler.go:27 +0x3d
github.com/twilio/twilio-go/client.(*RequestHandler).Get(...)
       /go/pkg/mod/github.com/twilio/[email protected]/client/request_handler.go:83
github.com/twilio/twilio-go/rest/messaging/v1.(*ApiService).FetchService(0xc00051c2a0, {0xc000120450?, 0xc000556f78?})
       /go/pkg/mod/github.com/twilio/[email protected]/rest/messaging/v1/services.go:219 +0xfc

Technical details:

  • twilio-go version: v0.18.2

Unable to import this

Issue Summary

I'm trying to use this in my code. After initializing my mod, I'm running

go get github.com/twilio/twilio-go

But getting the below response

go get: module github.com/twilio/twilio-go: Get "https://proxy.golang.org/github.com/twilio/twilio-go/@v/list": dial tcp: i/o timeout

Code Snippet

package main

import twilio "github.com/twilio/twilio-go"
import openapi "github.com/twilio/twilio-go/rest/api/v2010"
import "os"
import "fmt"

func main() {
client := twilio.NewRestClient()

params := &openapi.CreateMessageParams{}
params.SetTo(os.Getenv("To Number"))
params.SetFrom(os.Getenv("From Number"))
params.SetBody("Hello from Golang!")

_, err := client.ApiV2010.CreateMessage(params)
if err != nil {
    fmt.Println(err.Error())
} else {
    fmt.Println("SMS sent successfully!")
}

}

Exception/Log

go get: module github.com/twilio/twilio-go: Get "https://proxy.golang.org/github.com/twilio/twilio-go/@v/list": dial tcp: i/o timeout

400 when creating Studio Flow executions

Hi there,

Since upgrading to 1.22.0, we're not able to create Studio Flow executions: Status: 400 - ApiError 20001: Missing required parameter To in the post body (null) More info: https://www.twilio.com/docs/errors/20001

We're including a value for the To param in the request:

params := &twiliostudio.CreateExecutionParams{}
params.SetTo(to.String())

Any idea what might be causing this?

Update jwt dependency

Issue Summary

We plan update jwt to v4.5.0 in our project for fix security reason.

We can't do it, twilio-go depends on jwt v3.2.2+incompatible.

Please update jwt dependency in twilio-go.

See github.com/golang-jwt/jwt/v4

jwt v4.5.0 is backward compability with jwt 3.x.y.

CloudQuery Source Plugin?

Hi Team, hopefully this is right place to ask, if not, I'd appreciate if you can direct me.

I'm the founder of cloudquery.io, a high performance open source ELT framework.

Our users are interested in a Twilio plugin, but as we cannot maintain all the plugins ourselves, I was curious if this would be an interesting collaboration, where we would help implement an initial source plugin, and you will help maintain it.

This will give your users the ability to sync Twilio data to any of their datalakes/data-warehouses/databases easily using any of the growing list of CQ destination plugins.

Best,
Yevgeny

FetchNotification

I am trying to get the error code by calling FetchNotification. Shouldn't line 36 in accounts_notifications.go be:

path := "/2010-04-01/Accounts/{AccountSid}/Calls/{Sid}/Notifications.json"

instead of

path := "/2010-04-01/Accounts/{AccountSid}/Notifications/{Sid}.json"

path := "/2010-04-01/Accounts/{AccountSid}/Notifications/{Sid}.json"

ApiV2010AvailablePhoneNumberLocal latitude and longitud fields incorrectly mapped as float

Issue Summary

Getting the following error when calling *ApiV2010.ListAvailablePhoneNumberLocal(CountryCode string, params ListAvailablePhoneNumberLocalParams)

cannot unmarshal string into Go struct field ApiV2010AvailablePhoneNumberLocal.available_phone_numbers.latitude of type float32

Steps to Reproduce

  1. call ListAvailablePhoneNumberLocal operation
  2. see error returned

Code Snippet

c.twilioRestClient.ApiV2010.ListAvailablePhoneNumberLocal("US", &openapi2.ListAvailablePhoneNumberLocalParams{
		SmsEnabled:   aws.Bool(true),
		MmsEnabled:   aws.Bool(true),
		VoiceEnabled: aws.Bool(true),
		PageSize:     &amount,
		Limit:        &amount,
	})

Exception/Log

cannot unmarshal string into Go struct field ApiV2010AvailablePhoneNumberLocal.available_phone_numbers.latitude of type float32```

### Technical details:
* twilio-go version: 0.14.2
* go version: 1.16

Not found client/jwt

Issue Summary

I tried with go get github.com/twilio/twilio-go
then tried to use the generate accesstoken
like the code below

Code Snippet

package main

import 
(
	"os"
	"github.com/twilio/twilio-go/client/jwt"
)

accountSid := os.Getenv("TWILIO_ACCOUNT_SID")
applicationSid := os.Getenv("TWILIO_TWIML_APP_SID")
apiKey := os.Getenv("TWILIO_API_KEY")
apiSecret := os.Getenv("TWILIO_API_SECRET")
identity := "fake123"

params := jwt.AccessTokenParams{
    AccountSid:    accountSid,
    SigningKeySid: apiKey,
    Secret:        apiSecret,
    Identity:      identity,
}

jwtToken := jwt.CreateAccessToken(params)
voiceGrant := &jwt.VoiceGrant{
    Incoming: jwt.Incoming{Allow: true},
    Outgoing: jwt.Outgoing{
        ApplicationSid:    applicationSid,
        ApplicationParams: "",
    },
}

jwtToken.AddGrant(voiceGrant)
token, err := jwtToken.ToJwt()

Exception/Log

 github.com/twilio/twilio-go/client/jwt: module github.com/twilio/twilio-go/client@latest found (v0.0.0-20210629184628-bf0945b77d96), but does not contain package github.com/twili
o/twilio-go/client/jwt

Technical details:

  • twilio-go version: 0.14.2
  • go version: 1.16

Error response when sending SMS messages

Issue Summary

Yesterday when trying to send SMS messages, I got the following error:

Error sending SMS: error decoding the response for an HTTP error code: 503: invalid character '<' looking for beginning of value

This happened perhaps 6 or so times,, so I instrumented the Twilio code to get more information, but I've not been able to reproduce the issue since.

I think the error is being created here:

https://github.com/twilio/twilio-go/blob/main/client/client.go#L80

Technical details:

  • twilio-go version: v0.18.2
  • go version: 17.2

I'm in the processing of switching from github.com/kevinburke/twilio-go to this package, so would like to know if anyone else has seen this, or if its just a transient problem.

StreamServiceConversation always limited to 50 Conversations

Issue Summary

We have more than 50+ Conversations but the StreamServiceConversation returned channel only receives up to the default 50 conversations before closing the channel. The expectation is that the channel returned by StreamServiceConversation will close only after all conversations have been retrieved.

Steps to Reproduce

  1. Create more than 50 service conversations for a service
  2. Attempt to Stream (or List) all of the conversations in the service
  3. Notice that the Stream ends at 50.

Code Snippet

	conversations, err := client.ConversationsV1.StreamServiceConversation(*service.Sid, &conversations.ListServiceConversationParams{})
	if err != nil {
		return err
	}

Technical details:

  • twilio-go version: 0.13.0
  • go version: 1.16

Issue in go import

I have integrated the package but getting following error on go get

twilioClient.ApiV2010 undefined (type *twilio.RestClient has no field or method ApiV2010)

Technical details:

  • twilio-go version:
  • go version: 1.18.2

Messaging API and SubAccounts

Issue Summary

A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, or code examples.

Listing services does not seem to respect sub account configuration.

Steps to Reproduce

  1. I have a function that takes a sub account SID and returns a new client, basically just the docs:
func LoginSubAccount(sid string) *twilio.RestClient {
  return twilio.NewRestClientWithParams(twilio.ClientParams{
    AccountSid: sid,
  })
}
  1. Make a call to list services for the sub account:
params := &messaging.ListServiceParams{}
params.SetLimit(100)
client.MessagingV1.ListService(params)

Instead of seeing services for the sub account, I see services for the parent account.

Code Snippet

# paste code here

Exception/Log

# paste exception/log here

Technical details:

  • twilio-go version:
  • go version:

Sending SMS fails after upgrading to `1.22.0`

Issue Summary

Without any other code change, upgrading twilio-go to v1.22.0 from v1.21.1 errors out

Steps to Reproduce

  1. Use twilio-go version v1.21.1
  2. Call the function sendSMS (will succeed)
  3. change github.com/twilio/twilio-go v1.21.1 to github.com/twilio/twilio-go v1.22.2 in go.mod and do go mod tidy to install the upgraded version
  4. Call the function sendSMS (returns an error)

Code Snippet

import (
       "fmt"
       "github.com/twilio/twilio-go"
	twilioapi "github.com/twilio/twilio-go/rest/api/v2010"
)

func sendSMS(to, msg, callerID string) error {
	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: "<account-sid>",
		Password: "<auth-token>",
	})

	params := twilioapi.CreateMessageParams{}
	params.SetTo(to)
	params.SetFrom(callerID)
	params.SetBody(msg)

	if _, err := client.Api.CreateMessage(&params); err != nil {
		return fmt.Errorf("failed to send SMS to number %v : %w", number, err)
	}

	return nil

}

Exception/Log

<*errors.withStack | 0xc0000128b8>: 
error decoding the response for an HTTP error code: 400: invalid character '<' looking for beginning of value
            {
                error: <*errors.withMessage | 0xc00007af00>{
                    cause: <*json.SyntaxError | 0xc000012888>{
                        msg: "invalid character '<' looking for beginning of value",
                        Offset: 1,
                    },
                    msg: "error decoding the response for an HTTP error code: 400",
                },
                stack: [0xfedf5c8, 0xfee0145, 0xfee04f6, 0xfee22b1, 0xfee0b6a, 0xfee8015, 0xfefb0f9, 0xfd2615b, 0xfcaa3e1],
            }

Technical details:

  • twilio-go version: v1.22.0
  • go version: go1.22.0 darwin/amd64

Get Latest Sent Message Index

Issue Summary

Is there an API to get the last message that was sent to a conversation?

We're looking for a way to get (a rough) count of the number of messages in a conversation.

Technical details:

  • twilio-go version: master
  • go version: 1.16

ListServiceConversationMessage(): "could not retrieve payload from response"

Issue Summary

The ConversationsV1 REST API for ListServiceConversationMessage() returns the following error if no messages exist in the conversation:

| could not retrieve payload from response

However, we would expect the returned result to be either

  1. An empty slice instead with no error
  2. A Twilio-defined error API code from the list.

Steps to Reproduce

  1. Query any conversation that contains no messages

Code Snippet

messages, err := client.ConversationsV1.ListServiceConversationMessage(serviceSid, conversationUniqueName, &conversations.ListServiceConversationMessageParams{})

Exception/Log

# paste exception/log here

Technical details:

  • twilio-go version: v0.14.1
  • go version: go1.16 darwin/amd64

Data race after upgrade

Issue Summary

After upgrading from v0.21.0 to v0.24.0, I have a data race when running the below function with go run -race

Steps to Reproduce

  1. Run go run -race with a call to client.ApiV2010.ListAvailablePhoneNumberTollFree

Code Snippet

client := twilio.NewRestClientWithParams(twilio.ClientParams{
	Username: id,
	Password: token,
})
limit := 1
numbers, err := client.ApiV2010.ListAvailablePhoneNumberTollFree("US",
	&openapi.ListAvailablePhoneNumberTollFreeParams{
		PageSize: &limit,
	})

Exception/Log

WARNING: DATA RACE
Write at 0x00c0004c43e0 by goroutine 47:
  github.com/twilio/twilio-go/rest/api/v2010.(*ApiService).StreamAvailablePhoneNumberTollFree.func1()
      /var/lib/jenkins/go/pkg/mod/github.com/twilio/[email protected]/rest/api/v2010/accounts_available_phone_numbers_toll_free.go:293 +0x16d

Previous read at 0x00c0004c43e0 by goroutine 46:
  github.com/twilio/twilio-go/rest/api/v2010.(*ApiService).StreamAvailablePhoneNumberTollFree()
      /var/lib/jenkins/go/pkg/mod/github.com/twilio/[email protected]/rest/api/v2010/accounts_available_phone_numbers_toll_free.go:303 +0x574
  github.com/twilio/twilio-go/rest/api/v2010.(*ApiService).ListAvailablePhoneNumberTollFree()
      /var/lib/jenkins/go/pkg/mod/github.com/twilio/[email protected]/rest/api/v2010/accounts_available_phone_numbers_toll_free.go:250 +0x6e
  github.com/applieddataconsultants/dqm-api/twilio.(*Texter).AvailableNumber()
      /var/lib/jenkins/jobs/GH/jobs/dqm-api/branches/PR-147/workspace/twilio/texter.go:78 +0x144
  github.com/applieddataconsultants/dqm-api/twilio.TestTexter.func3()
      /var/lib/jenkins/jobs/GH/jobs/dqm-api/branches/PR-147/workspace/twilio/texter_test.go:44 +0x190
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1259 +0x22f
  testing.(*T).Runยทdwrapยท21()
      /usr/local/go/src/testing/testing.go:1306 +0x47

Goroutine 47 (running) created at:
  github.com/twilio/twilio-go/rest/api/v2010.(*ApiService).StreamAvailablePhoneNumberTollFree()
      /var/lib/jenkins/go/pkg/mod/github.com/twilio/[email protected]/rest/api/v2010/accounts_available_phone_numbers_toll_free.go:280 +0x567
  github.com/twilio/twilio-go/rest/api/v2010.(*ApiService).ListAvailablePhoneNumberTollFree()
      /var/lib/jenkins/go/pkg/mod/github.com/twilio/[email protected]/rest/api/v2010/accounts_available_phone_numbers_toll_free.go:250 +0x6e
  github.com/applieddataconsultants/dqm-api/twilio.(*Texter).AvailableNumber()
      /var/lib/jenkins/jobs/GH/jobs/dqm-api/branches/PR-147/workspace/twilio/texter.go:78 +0x144
  github.com/applieddataconsultants/dqm-api/twilio.TestTexter.func3()
      /var/lib/jenkins/jobs/GH/jobs/dqm-api/branches/PR-147/workspace/twilio/texter_test.go:44 +0x190
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1259 +0x22f
  testing.(*T).Runยทdwrapยท21()
      /usr/local/go/src/testing/testing.go:1306 +0x47

Goroutine 46 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1306 +0x726
  github.com/applieddataconsultants/dqm-api/twilio.TestTexter()
      /var/lib/jenkins/jobs/GH/jobs/dqm-api/branches/PR-147/workspace/twilio/texter_test.go:42 +0x7c5
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1259 +0x22f
  testing.(*T).Runยทdwrapยท21()
      /usr/local/go/src/testing/testing.go:1306 +0x47
==================
--- FAIL: TestTexter (2.38s)
    --- FAIL: TestTexter/AvailableNumber (0.53s)
        testing.go:1152: race detected during execution of test
    testing.go:1152: race detected during execution of test
FAIL

Technical details:

  • twilio-go version: v0.24.0
  • go version: v1.18.1

Seems to have been introduced here -> v0.22.1...v0.24.0#diff-de50900a25591183bfd66763d56b5c812f8a2240004a592c9205ae33bb1d3126R293

The request validator key sorting is broken

Issue Summary

According to docs, in order to validate signature POST form, fields have to be sorted by keys (like in Python twilio library code). However, twilio-go uses "keyvalue" concatenated pairs in sorting which leads to incorrect sorting and invalid signature.

Here is an actual line of golang lib code that sorts keyvalue concatenated chunks https://github.com/twilio/twilio-go/blob/main/client/request_validator.go#L38
Python code that sorts by keys https://github.com/twilio/twilio-python/blob/main/twilio/request_validator.py#L76

Steps to Reproduce

  1. Trigger incoming twilio request with fields
ReasonConferenceEnded=participant-with-bla
Reason=Participant
  1. Golang code concats keyvalues and sorts prefix "ReasonC" before "ReasonP", says signature is invalid
  2. Python code sorts key "Reason" before key "ReasonConferenceEnded", says signature is valid

Code Snippet

Concatenated string before hashing looks like:

go
<matching string beginning>...ReasonConferenceEndedparticipant-with-end-conference-on-exit-leftReasonParticipant Cxxxxxxxxxxxxxxxxxx1 with endConferenceOnExit left the conferenceSequenceNumber6StatusCallbackEventconference-endTimestampWed, 16 Feb 2022 16:11:53 +0000

py
<matching string beginning>...ReasonParticipant Cxxxxxxxxxxxxxxxxxx1 with endConferenceOnExit left the conferenceReasonConferenceEndedparticipant-with-end-conference-on-exit-leftSequenceNumber6StatusCallbackEventconference-endTimestampWed, 16 Feb 2022 16:11:53 +0000

Exception/Log

signature invalid in (rv *RequestValidator) Validate()

Technical details:

  • twilio-go version: v0.18.2
  • go version: go1.17.2 darwin/arm64

Example in the docs website is either wrong/outdated

Issue Summary

The docs https://www.twilio.com/docs/whatsapp/quickstart/go and the example in the README are not the same.
I could figure out how to use the example in the docs until I visited the repository only to realize that I was using the wrong method, in this case twilio.NewRestClient() instead of twilio.NewRestClientWithParams() to pass the token and SID.

Steps to Reproduce

  1. Visit https://www.twilio.com/docs/whatsapp/quickstart/go
  2. Visit the README here
  3. Compare the examples

Code Snippet

None

Exception/Log

# paste exception/log here

Technical details:

  • twilio-go version: N/A
  • go version: N/A

The request validator code doesn't work for `application/x-www-form-urlencoded` POST requests

Issue Summary

According to the docs the check here should only happen for application/json request https://github.com/twilio/twilio-go/blob/main/client/request_validator.go#L56 thus alway returning false for form encoded request since they don't send the bodySHA256 param.

Also according to the docs, the body params should be concatenated to the url. The code here https://github.com/twilio/twilio-go/blob/main/client/request_validator.go#L36 needs to be changed to

		paramSlc = append(paramSlc, fmt.Sprintf("%s%s", k, v[0]))

As it is now it will put [] around the values since url.Parse returns the value as an array. Ie instead of https://example.comparamvalue the result will be https://example.comparam[value]

Add automatic retry support for 429 responses

Issue Summary

When working in large production environments, it is quite easy to run into scenarios where the Twilio API returns a 429 due to rate limiting. The Node SDK added support for automatic retry with exponential backoff in twilio/twilio-node#886. It would be great if the Go SDK could add similar functionality.

503 responses from Twilio API cause a panic

Issue Summary

On Feb 14th 2024 the following occurred https://status.twilio.com/incidents/dhb0hj0dm9qf during this time saw some 503's from the Twilio API. This manifested as the following error in our Golang service (see Expection/Log section) causing the code to panic.

Steps to Reproduce

  1. Make a call to the Twilio API using the rest client in this library.
  2. Somehow force it to respond with 503
  3. See that in panics.

Exception/Log

"error":"error decoding the response for an HTTP error code: 503: invalid character 'o' in literal null (expecting 'u')","errorVerbose":"invalid character 'o' in literal null (expecting 'u')\nerror decoding the response for an HTTP error code: 503\[ngithub.com/twilio/twilio-go/client.(*Client](http://ngithub.com/twilio/twilio-go/client.(*Client)).doWithErr\n\[tgithub.com/twilio/[email protected]/client/client.go:81\ngithub.com/twilio/twilio-go/client.(*Client](http://tgithub.com/twilio/[email protected]/client/client.go:81%5Cngithub.com/twilio/twilio-go/client.(*Client)).SendRequest\n\[tgithub.com/twilio/[email protected]/client/client.go:139\ngithub.com/twilio/twilio-go/client.(*RequestHandler](http://tgithub.com/twilio/[email protected]/client/client.go:139%5Cngithub.com/twilio/twilio-go/client.(*RequestHandler)).sendRequest\n\[tgithub.com/twilio/[email protected]/client/request_handler.go:32\ngithub.com/twilio/twilio-go/client.(*RequestHandler](http://tgithub.com/twilio/[email protected]/client/request_handler.go:32%5Cngithub.com/twilio/twilio-go/client.(*RequestHandler)).Get\n\[tgithub.com/twilio/[email protected]/client/request_handler.go:91\ngithub.com/twilio/twilio-go/rest/api/v2010.(*ApiService](http://tgithub.com/twilio/[email protected]/client/request_handler.go:91%5Cngithub.com/twilio/twilio-go/rest/api/v2010.(*ApiService)).FetchCall\n\[tgithub.com/twilio/[email protected]/rest/api/v2010/accounts_calls.go:443](http://tgithub.com/twilio/[email protected]/rest/api/v2010/accounts_calls.go:443)

Technical details:

  • twilio-go version: v1.16.1
  • go version: v1.21.7

ssml tags are capitalized causing errors on twillio ml apps

Issue Summary

The twiml.VoiceProsody struct does not generate the right xml tag for prosody. ssml docs

Steps to Reproduce

  1. create a new struct for twiml.VoiceProsody
  2. observe that the tag is and not as per twillio documentation

Technical details:

  • twilio-go version: v1.10.0
  • go version: 1.20

All SSML tags are malformed and do not work with Twilio

Issue Summary

Currently all SSML tags are malformed. They are either capitalized for example the proper <emphasis> is instead generated as <Emphasis> or <say-as> is generated as <SayAs>. These generate an error code of 12200 XML Validation warning and the call fails.

Steps to Reproduce

Create a twiml with any function that is designed to inject an SSML tag.

Code Snippet

        say := &twiml.VoiceSay{}
	say.InnerElements = []twiml.Element{
		&twiml.VoiceP{Words: "This will generate the wrong SSML"}
	}

	hangup := &twiml.VoiceHangup{}

	return []twiml.Element{say, hangup}

Technical details:

  • twilio-go version: All versions since Oct 2, 2022
  • go version: All versions

Simple example leaking goroutines

Hi,

Running uber-go/goleak, I found that this example

Run go test ./internal/ -race -v -count=1

Code Snippet

func TestR(t *testing.T) {
	defer goleak.VerifyNone(t)

	client := twilio.NewRestClientWithParams(
		twilio.ClientParams{
			Username: "mydata",
			Password: "mydata",
		},
	)

	params := &openapi.CreateMessageParams{}
	params.SetFrom("+15005550006")
	params.SetTo("+79003223232")
	params.SetBody("10")

	_, err := client.Api.CreateMessage(params)
	require.NoError(t, err)
}

Exception/Log

=== RUN   TestR
    leaks.go:78: found unexpected goroutines:
        [Goroutine 36 in state IO wait, with internal/poll.runtime_pollWait on top of the stack:
        goroutine 36 [IO wait]:
        internal/poll.runtime_pollWait(0x9f627f8, 0x72)
                /usr/local/opt/go/libexec/src/runtime/netpoll.go:234 +0x89
        internal/poll.(*pollDesc).wait(0xc000192398, 0xc0000c6000, 0x0)
                /usr/local/opt/go/libexec/src/internal/poll/fd_poll_runtime.go:84 +0xbd
        internal/poll.(*pollDesc).waitRead(...)
                /usr/local/opt/go/libexec/src/internal/poll/fd_poll_runtime.go:89
        internal/poll.(*FD).Read(0xc000192380, {0xc0000c6000, 0x12cc, 0x12cc})
                /usr/local/opt/go/libexec/src/internal/poll/fd_unix.go:167 +0x419
        net.(*netFD).Read(0xc000192380, {0xc0000c6000, 0x12cc, 0x12cc})
                /usr/local/opt/go/libexec/src/net/fd_posix.go:56 +0x51
        net.(*conn).Read(0xc000094000, {0xc0000c6000, 0x12cc, 0x12cc})
                /usr/local/opt/go/libexec/src/net/net.go:183 +0xb1
        crypto/tls.(*atLeastReader).Read(0xc00038e060, {0xc0000c6000, 0x12cc, 0x12cc})
                /usr/local/opt/go/libexec/src/crypto/tls/conn.go:777 +0x86
        bytes.(*Buffer).ReadFrom(0xc000098278, {0x14f13a0, 0xc00038e060})
                /usr/local/opt/go/libexec/src/bytes/buffer.go:204 +0x113
        crypto/tls.(*Conn).readFromUntil(0xc000098000, {0x9ef5100, 0xc000094000}, 0x5)
                /usr/local/opt/go/libexec/src/crypto/tls/conn.go:799 +0x1df
        crypto/tls.(*Conn).readRecordOrCCS(0xc000098000, 0x0)
                /usr/local/opt/go/libexec/src/crypto/tls/conn.go:606 +0x3fe
        crypto/tls.(*Conn).readRecord(...)
                /usr/local/opt/go/libexec/src/crypto/tls/conn.go:574
        crypto/tls.(*Conn).Read(0xc000098000, {0xc00034c000, 0x1000, 0x0})
                /usr/local/opt/go/libexec/src/crypto/tls/conn.go:1277 +0x29c
        net/http.(*persistConn).Read(0xc00015aa20, {0xc00034c000, 0x1000, 0x1000})
                /usr/local/opt/go/libexec/src/net/http/transport.go:1926 +0x110
        bufio.(*Reader).fill(0xc000300c00)
                /usr/local/opt/go/libexec/src/bufio/bufio.go:101 +0x294
        bufio.(*Reader).Peek(0xc000300c00, 0x1)
                /usr/local/opt/go/libexec/src/bufio/bufio.go:139 +0xcc
        net/http.(*persistConn).readLoop(0xc00015aa20)
                /usr/local/opt/go/libexec/src/net/http/transport.go:2087 +0x2db
        created by net/http.(*Transport).dialConn
                /usr/local/opt/go/libexec/src/net/http/transport.go:1747 +0x2ef8
        
         Goroutine 37 in state select, with net/http.(*persistConn).writeLoop on top of the stack:
        goroutine 37 [select]:
        net/http.(*persistConn).writeLoop(0xc00015aa20)
                /usr/local/opt/go/libexec/src/net/http/transport.go:2386 +0x1a9
        created by net/http.(*Transport).dialConn
                /usr/local/opt/go/libexec/src/net/http/transport.go:1748 +0x2f8b
        ]
--- FAIL: TestR (1.47s)

Technical details:

  • twilio-go version: 0.26.0
  • go version: 1.17

`PathAccountSid` in `CreateMessageParams`

Issue Summary

Ambiguity regarding the expected behaviour of PathAccountSid parameter on the CreateMessageParams struct.
The Twilio client is initialized on application startup, using our organization's Account SID and Auth Token.

Our application requires us to be able to send messages from other accounts as well, which have different phone numbers, Account SIDs and Auth Tokens.

I tried passing the Account SID of the From phone number as the PathAccountSid field, thinking that was the logical thing to do, but since the credentials with which the client was created are different, the Twilio REST API throws an authentication error.
The only way I've found to deal with this is to create a new client with the desired Account SID and Auth Token.
Since I've found this to be the case so far, I'm unsure as to what the PathAccountSid field is supposed to do.

Steps to Reproduce

  1. Have multiple Twilio accounts (let's say A and B).
  2. Create a REST client with A account's Auth token and Account SID
  3. Try to send SMS from B account's phone number, passing B's account SID as PathAccountSid.
  4. Send request using the client created in step 2

Code Snippet

func NewTwilioClient(username, password string) *TwilioClient {
	twilioClient := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: username,
		Password: password,
	})
	return &TwilioClient{Twilio: twilioClient}
}

This creates a REST client some account's SID and auth token.

func (r *TwilioClient) CreateTwilioMessage(targetNumber, fromNumber, message string) (*openapi.ApiV2010Message, error) {
	statusCallback := configuration.ServiceURL.Message + "/status"
	otherSid := "xxxx"
	params := &openapi.CreateMessageParams{
		PathAccountSid: &otherSid,
		Body:           &message,
		From:           &fromNumber,
		To:             &targetNumber,
		StatusCallback: &statusCallback,
	}

	messages, err := r.Twilio.Api.CreateMessage(params)
	if err != nil {
		logs.Error("Error while creating message:", err.Error())
		return nil, err
	}
	return messages, nil
}

This tries to create a message using other account's phone number.

Exception/Log

https://www.twilio.com/docs/api/errors/20003

ConversationsV1.PageConversation does not work except for the first call

Issue Summary

ConversationsV1.PageConversation does not work when trying to fetch next page with a pageToken and pageNumber. It always return an empty result.

Cause of the problem: Conversations api returns a pageToken like PTclosed_2024-01-18T03:17:17.005Z_CHa09ace6334284f0aa7f988ebad3e231a while other endpoints return a hashed token like this ENZXlKbGRtVnVkRjlrWVhSbElqb3hOekEyTlRBek1qVTJNREF3TENKemFXUWlPaUpCUlRFek5tVXpOekJpTXpoak1tTTRPR1ptTVRRMU1EWXhNMk15TVRNME1HTXhJbjA9

The .005 inside Conversation pageToken will be eliminated in the SendRequest method in client.go which breaks the token.

Steps to Reproduce

1, call PageConversation method with empty pageNumber and pageToken
2, parse the response and get pageNumber and pageToken for next page
3, call PageConversation again with pageNumber and pageToken for next page.

Technical details:

  • twilio-go version: 1.17.0
  • go version: 1.21

MockBaseClient broken by 1.20.0 update which changed the function signature of SendRequest

Issue Summary

Version 1.20.0 changed the BaseClient SendRequest method (seen in this pull request) to add body ...byte as a function parameter. The corresponding MockBaseClient was not updated.

Steps to Reproduce

  1. Use twilio-go version 1.20.1
  2. Attempt to use a MockBaseClient (see code below)

Code Snippet

ctrl := gomock.NewController(t)
c := client.NewMockBaseClient(ctrl)
twilioClient := twilio.NewRestClientWithParams(twilio.ClientParams{Client: c})

Exception/Log

cannot use c (variable of type *client.MockBaseClient) as client.BaseClient value in struct literal: *client.MockBaseClient does not implement client.BaseClient (wrong type for method SendRequest)
		have SendRequest(string, string, url.Values, map[string]interface{}) (*http.Response, error)
		want SendRequest(string, string, url.Values, map[string]interface{}, ...byte) (*http.Response, error)compiler[InvalidIfaceAssign](https://pkg.go.dev/golang.org/x/tools/internal/typesinternal#InvalidIfaceAssign)

Technical details:

  • twilio-go version: 1.20.1
  • go version: go version go1.22.2 darwin/arm64

changing base API url

I have to change the base API url in order to send requests to the mock server in tests but apparently, API URLs are hardcoded so I couldn't find a way to send requests to the mock server.

VerifyV2.CreateVerification error

Issue Summary

I am receiving an Invalid parameter (null) error when using the verifyV2.CreateVerification function.

Steps to Reproduce

  1. create verification service
  2. attempt to create verification

Code Snippet

func (v *MobileVerifier) VerifyRequestTest() (err error) {
	p := openapi.CreateVerificationParams{}
	p.SetTo("+{myphonenumber}")
	p.SetChannel("sms")

	log.Printf("v: %#v", v.accountSID)
	log.Printf("p: %#v", *p.To)

	verification, err := v.client.VerifyV2.CreateVerification(v.accountSID, &p)
	if err != nil {
		err = fmt.Errorf("v.client.VerifyV2.CreateVerification: %w", err)
		return
	}
	log.Printf("%+v", verification)
	return
}

Exception/Log

error occurred: v.client.VerifyV2.CreateVerification: Status: 400 - ApiError 60200: Invalid parameter (null) More info: https://www.twilio.com/docs/errors/60200

Technical details:

  • twilio-go version: v0.26.0
  • go version: 1.18

Double check the usability on the README

It's weird that the example for creating a message requires JSON marshaling of the response (??), but the example for creating a call does not.

Also, not an expert but guessing that the message/call examples are going to be relevant to a lot more people than the info on how to set the region or edge, and should maybe go higher up on the page.

Also I guess it's bizarre that errors are being printed and then ignored.

context.Context support is missing

Issue Summary

Not really a bug, but a missing functionality. Expected to see methods with context.Context support. However, currently there is no support for it and this makes it not being possible to do proper cancellation with twilio's API.

Code Snippet

N/A

Exception/Log

N/A

Technical details:

  • twilio-go version: v0.12.0
  • go version: 1.16.5

V1VideoClient - Unable to UpdateRoomRecordingRule

Issue Summary

When calling UpdateRoomRecordingRule on the client.v1Video the error Status: 400 - ApiError 53120: Invalid Recording Rule(s) (null) More info: https://www.twilio.com/docs/errors/53120 is always returned. However, I have confirmed (see screen shot below) that the proper data is being sent and the rules are in fact valid.

Screen Shot 2022-03-21 at 12 21 42 PM

Steps to Reproduce

  1. Create a v1video client
  2. Create an UpdateRoomRecordingRuleParams
  3. Invoke UpdateRoomRecordingRule on the client

Code Snippet

var (
	startRecordingRules = map[string]interface{}{
		"type": "include",
		"all":  true,
	}
)

func (ts *twilioSvc) StartRecording(roomName string) error {
	startRecordRulesReq := &openapi.UpdateRoomRecordingRuleParams{
		Rules: &startRecordingRules,
	}

	_, err := ts.videoClient.UpdateRoomRecordingRule(roomName, startRecordRulesReq)

	return err
}

Exception/Log

Status: 400 - ApiError 53120: Invalid Recording Rule(s) (null) More info: https://www.twilio.com/docs/errors/53120

Technical details:

  • v0.22.0
  • 1.17.2

Passing Custom Code to Verifications Fails

Issue Summary

invalid memory address or nil pointer dereference when passing a custom code.

Steps to Reproduce

Pass a value to setCustomCode. If this line is commented, verifications are created just fine and the SMS is received.

Code Snippet

client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: accountSid,
		Password: authToken,
	})

	params := &verify.CreateVerificationParams{}
	params.SetCustomCode("867530")
	params.SetTo(t_int.Phone)
	params.SetChannel("sms")

	resp, err := client.VerifyV2.CreateVerification(verificationSid, params)
	if err != nil {
		fmt.Println(err.Error())

		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"status": resp.Status,
			"err":    err.Error(),
		})
	} else {
		return c.Status(http.StatusOK).JSON(fiber.Map{
			"status": resp.Status,
		})
	}

Exception/Log

Invalid parameter: Code (null) More info: https://www.twilio.com/docs/errors/60200
runtime error: invalid memory address or nil pointer dereference

Technical details:

  • twilio-go version: github.com/twilio/twilio-go v1.12.0
  • go version: 1.21.0 darwin/arm64

Library Removes waitUrl Attribute When Set to Empty String Contrary to Documentation (<Conference> TwiML)

Issue Summary

In the library, when setting the waitUrl attribute of a Conference TwiML conference to an empty string ('') to prevent any playback while waiting for the conference to start, the attribute is unexpectedly removed from the rendered TwiML. This behavior is inconsistent with the official documentation, which states that setting waitUrl to an empty string should be a valid option for achieving no playback during the wait period.

Steps to Reproduce

  1. Run Code snippet
  2. Check console output

Code Snippet

package main

import (
	"fmt"
	"github.com/twilio/twilio-go/twiml"
)

func main() {
	twimlConference := twiml.VoiceConference{
		Name:                "MyConference",
		WaitUrl: "",
	}

	voice, err := twiml.Voice([]twiml.Element{twimlConference})
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s", voice)
}

Exception/Log

<?xml version="1.0" encoding="UTF-8"?><Response><Conference>MyConference</Conference></Response>

Technical details:

  • twilio-go version: v1.17.0
  • go version: 1.21

MediaExternalLocation is missing in CompositionV1

Issue Summary

The struct CompositionV1 is missing field: MediaExternalLocation
this field is not in the schema: schema issue: twilio/twilio-oai#48

Steps to Reproduce

Schema issue, can't be reproduced.

Code Snippet

# paste code here

Exception/Log

# paste exception/log here

Technical details:

  • twilio-go version:
  • go version:

EOF error response when sending SMS OTP

Issue Summary

I received an ambiguous error response below when calling function VerifyV2.CreateVerification

Post "https://verify.twilio.com/v2/Services/xxxxxxx/Verifications/": EOF

Strange thing is it happened very random, like it was poping out once in thousands of success SMS OTP that were sent by my service.

I did a bit of research and maybe this is what happen:
https://stackoverflow.com/questions/28046100/golang-http-concurrent-requests-post-eof

Is there any way to workaround this?

Technical details:

  • twilio-go version: v1.7.0
  • go version: 1.19

TwiML Reponse API

It would be nice if twilio-go provides an API to generate a TwiML response. Almost all Twilio's Server-side Helper Libraries provide an API to do so. although I can use encoding/xml to generate TwiML response.

Add ShortenUrls CreateMessageParam

Issue Summary

Hi!
I may have missed it but I believe the ShortenUrl param is missing from CreateMessageParams. This may be intentional as the API docs state that Link Shortening is in Public Beta.
I would like to contribute a PR if you do want to add the param.

https://www.twilio.com/docs/sms/api/message-resource#create-a-message-resource-with-shortened-link

I propose the following addition to the CreateMessage parameters:

Name Type Description
ShortenUrls bool Indicates your intent to shorten links in a message. Set the value to true to enable Link Shortening. You will need to set up your domain and Messaging Services to use Link Shortening. Get started here. This parameter is false by default.

Example Usage

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	client := twilio.NewRestClient()

	params := &api.CreateMessageParams{}
	params.SetFrom("+15017122661")
	params.SetBody("Click me!\nhttps://my.domain.com/longurl?longparam=didyouknowaurlcanbetwothousandfortyeightcharacterslong%3f!!")
	params.SetTo("+15558675310")
        
	// Proposed method usage
        // Link Shortening only works with a configured Messaging Service
        params.SetMessagingServiceSid(os.Getenv("TWILIO_MESSAGING_SERVICE_SID"))
	params.SetShortenUrls(true)

	resp, err := client.Api.CreateMessage(params)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		if resp.Sid != nil {
			fmt.Println(*resp.Sid)
		} else {
			fmt.Println(resp.Sid)
		}
	}
}

Thanks!

Sidenote

The API docs have a typo here. "ShortenUrl=true" should say "ShortenUrls=true"
https://www.twilio.com/docs/sms/api/message-resource#create-a-message-resource-with-shortened-link

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.