nexmo

package module
v0.12.0-alpha.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 26, 2020 License: MIT Imports: 14 Imported by: 18

README

Nexmo Server SDK For Go

Go Report Card Build Status Coverage GoDoc

Nexmo is now known as Vonage

This is the community-supported Golang library for Nexmo. It has support for most of our APIs, but is still under active development. Issues, pull requests and other input is very welcome.

If you don't already know Nexmo: We make telephony APIs. If you need to make a call, check a phone number, or send an SMS then you are in the right place! If you don't have a Nexmo yet, you can sign up for a Nexmo account and get some free credit to get you started.

Installation

Find current and past releases on the releases page.

Import the package and use it:

import ("github.com/nexmo-community/nexmo-go")

Older versions of Go (<= 1.12)

To install the package, use go get:

go get github.com/nexmo-community/nexmo-go

Or import the package into your project and then do go get ..

Usage

Here are some simple examples to get you started. If there's anything else you'd like to see here, please open an issue and let us know! Be aware that this library is still at an alpha stage so things may change between versions.

Send SMS

To send an SMS, try the code below:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go/nexmo"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	smsClient := nexmo.NewSMSClient(auth)
	response, err := smsClient.Send("NexmoGolang", "44777000777", "This is a message from golang", nexmo.SMSOpts{})

	if err != nil {
		panic(err)
	}

	if response.Messages[0].Status == "0" {
		fmt.Println("Account Balance: " + response.Messages[0].RemainingBalance)
	}
}
Send Unicode SMS

Add Type to the opts parameter and set it to "unicode":

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go/nexmo"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	smsClient := nexmo.NewSMSClient(auth)
	response, err := smsClient.Send("NexmoGolang", "44777000777", "こんにちは世界", nexmo.SMSOpts{Type: "unicode"})

	if err != nil {
		panic(err)
	}

	if response.Messages[0].Status == "0" {
		fmt.Println("Account Balance: " + response.Messages[0].RemainingBalance)
	}
}
Receive SMS

To receive an SMS, you will need to run a local webserver and expose the URL publicly (you can use a tool such as ngrok.

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {

	http.HandleFunc("/webhooks/inbound-sms", func(w http.ResponseWriter, r *http.Request) {
		params := r.URL.Query()
		fmt.Println("SMS from " + params["msisdn"][0] + ": " + string(params["text"][0]))
	})

	http.ListenAndServe(":8080", nil)
}
Verify a User's Phone Number

This is a multi-step process. First: request that the number be verified and state what "brand" is asking.

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	verifyClient := nexmo.NewVerifyClient(auth)

    response, errResp, err := verifyClient.Request("447846810475", "GoTest", nexmo.VerifyOpts{CodeLength: 6, Lg: "es-es", WorkflowId: 4})

    if err != nil {
        fmt.Printf("%#v\n", err)
    } else if response.Status != "0" {
        fmt.Println("Error status " + errResp.Status + ": " + errResp.ErrorText)
    } else {
        fmt.Println("Request started: " + response.RequestId)
    }
}

Copy the request ID; the user will receive a PIN code and when they have it, you can check the code (see next section)

Check Verification Code

When a request is in progress, use the requestId and the PIN code sent by the user to check if it is correct:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	verifyClient := nexmo.NewVerifyClient(auth)

	response, errResp, err := verifyClient.Check(REQUEST_ID, PIN_CODE)

	if err != nil {
		fmt.Printf("%#v\n", err)
	} else if response.Status != "0" {
		fmt.Println("Error status " + errResp.Status + ": " + errResp.ErrorText)
	} else {
		// all good
		fmt.Println("Request complete: " + response.RequestId)
	}
}

If status is zero, the code was correct and you have confirmed the user owns the number

Cancel a Verification

If you have a verification in progress, and no longer wish to proceed, you can cancel it. This can be done from 30 seconds after the verification was requested, until the second event occurs.

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	verifyClient := nexmo.NewVerifyClient(auth)
   	response, errResp, err := verifyClient.Cancel(REQUEST_ID)

	if err != nil {
		fmt.Printf("%#v\n", err)
	} else if response.Status != "0" {
		fmt.Println("Error status " + errResp.Status + ": " + errResp.ErrorText)
	} else {
		// all good
		fmt.Println("Request cancelled: " + response.RequestId)
	}
}
Trigger the Next Event in a Verification

If for example, an SMS has been sent, and you'd immediately like to have the user get a TTS call (depending on the workflow in use), it's possible to make the next event happen on demand:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	verifyClient := nexmo.NewVerifyClient(auth)
   	response, errResp, err := verifyClient.TriggerNextEvent(REQUEST_ID)

	if err != nil {
		fmt.Printf("%#v\n", err)
	} else if response.Status != "0" {
		fmt.Println("Error status " + errResp.Status + ": " + errResp.ErrorText)
	} else {
		// all good
		fmt.Println("Next event triggered for request: " + response.RequestId)
	}
}
Search for a Verification

You can check on an in-progress or completely (either successfully or not) verification by its request ID:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	verifyClient := nexmo.NewVerifyClient(auth)
   	response, errResp, err := verifyClient.Search(REQUEST_ID)

	if err != nil {
		fmt.Printf("%#v\n", err)
	} else if response.Status != "0" {
		fmt.Println("Error status " + errResp.Status + ": " + errResp.ErrorText)
	} else {
		// all good
		fmt.Println("Next event triggered for request: " + response.RequestId)
	}
}
List the Numbers You Own

To check on the numbers already associated with your account:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	numbersClient := nexmo.NewNumbersClient(auth)
	response, err := numbersClient.List(nexmo.NumbersOpts{})

	if err != nil {
		panic(err)
	}

	for _, number := range response.Numbers {
		fmt.Println("Number: " + number.Msisdn + " (" + number.Country + ") with: " + strings.Join(number.Features, ", "))
	}
}

You can also filter by which applications a number is linked to (set the ApplicationId param) or as in the example below, by whether it is linked to an application at all:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	numbersClient := nexmo.NewNumbersClient(auth)
	response, err := numbersClient.List(nexmo.NumbersOpts{HasApplication: "false"})

	if err != nil {
		panic(err)
	}

	for _, number := range response.Numbers {
		fmt.Println("Number: " + number.Msisdn + " (" + number.Country + ") with: " + strings.Join(number.Features, ", "))
	}
}
Search for a number to buy

You can programmatically add numbers to your account:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	numbersClient := nexmo.NewNumbersClient(auth)
    response, respErr, err := numbersClient.Search("GB", nexmo.NumberSearchOpts{Size: 10})
    if err != nil {
        panic(err)
    }
    if respErr.ErrorCode != "" {
        fmt.Println("Error " + respErr.ErrorCode + ": " + respErr.ErrorCodeLabel)
    }
    for _, number := range response.Numbers {
        fmt.Println("Number: " + number.Msisdn + " (" + number.Country + ") with: " + strings.Join(number.Features, ", "))
    }
}
Buy a number

Use the search to find a number that suits your needs (see the previous example), then buy it:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	numbersClient := nexmo.NewNumbersClient(auth)

    response, resp, err := numbersClient.Buy("GB", "44777000777", nexmo.NumberBuyOpts{})
    if err != nil {
        panic(err)
    }
    fmt.Printf("%#v\n", response)
}

Failures in this action can indicate that more information is needed when buying the number. If you get a 420 status code, try buying via the dashboard https://developer.nexmo.com.

Update number configuration

This endpoint is how you configure the number behaviour. There are a few properties you can set, they are named to match the Number API Reference.

  • MoHTTPURL - The URL for incoming ("mobile originated", hence the name) SMS API webhooks.
  • AppID - The application ID to use for configuration (this is the most common setup for most apps)
  • VoiceCallbackType - Can be tel or sip
  • VoiceCallbackValue - The value f telephone number or sip connection as appropriate
package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	numbersClient := nexmo.NewNumbersClient(auth)
	response, resp, err := numbersClient.Update("GB", "44777000777", nexmo.NumberUpdateOpts{AppID: " aaaaaaaa-bbbb-cccc-dddd-0123456789abc"})

	fmt.Printf("%#v\n", response)
}
Cancel a bought number

If you don't need a number any more, you can cancel it and stop paying the rental for it:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go"
)

func main() {
	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	numbersClient := nexmo.NewNumbersClient(auth)

    response, resp, err := numbersClient.Cancel("GB", "44777000777", nexmo.NumberCancelOpts{})
    if err != nil {
        panic(err)
    }
    fmt.Printf("%#v\n", response)
}
Generate a Basic JWT

Generate a JSON Web Token (JWT) for the APIs that use that. You usually won't need to do this if you're using the library but if you need to make a custom request or want to use a JWT for something else, you can use this.

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go/jwt"
)

func main() {
    privateKey, _ := ioutil.ReadFile(PATH_TO_PRIVATE_KEY_FILE)
    g := jwt.NewGenerator(APPLICATION_ID, privateKey)

    token, _ := g.GenerateToken()
    fmt.Println(token)
}
Generate a JWT with more options

You can also set up the generator with the options needed on your token, such as expiry time or ACLs.

    privateKey, _ := ioutil.ReadFile(PATH_TO_PRIVATE_KEY_FILE)
    g := jwt.Generator{
        ApplicationID: APPLICATION_ID,
        PrivateKey:    privateKey,
        TTL:           time.Minute * time.Duration(90),
    }
	g.AddPath(jwt.Path{Path: "/*/users/**"})

    token, _ := g.GenerateToken()
    fmt.Println(token)

Tips, Tricks and Troubleshooting

Changing the Base URL

If you want to point your API calls to an alternative endpoint (for geographical or local testing reasons this can be useful) try this:

package main

import (
	"fmt"

	"github.com/nexmo-community/nexmo-go/nexmo"
)

func main() {
	fmt.Println("Hello")

	auth := nexmo.CreateAuthFromKeySecret(API_KEY, API_SECRET)
	smsClient := nexmo.NewSMSClient(auth)
    smsClient.Config.BasePath = "http://localhost:4010"

	response, err := smsClient.Send("NexmoGolang", "44777000777", "This is a message from golang", nexmo.SMSOpts{})

	if err != nil {
		panic(err)
	}

	if response.Messages[0].Status == "0" {
		fmt.Println("Account Balance: " + response.Messages[0].RemainingBalance)
	}
}

(The example above shows using the library with Prism, which we find useful at development time)

The fields for configuration are:

  • BasePath (shown in the example above) overrides where the requests should be sent to
  • DefaultHeader is a map, add any custom headers you need here
  • HTTPClient is a pointer to an httpClient if you need to change any networking settings

Getting Help

We love to hear from you so if you have questions, comments or find a bug in the project, let us know! You can either:

Further Reading

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APITransport

type APITransport struct {
	APISecret string

	// Transport is the underlying HTTP transport to use when making requests.
	// It will default to http.DefaultTransport if nil.
	Transport http.RoundTripper
}

APITransport lets us add extra HTTP features and pass them around elegantly

func (*APITransport) Client

func (t *APITransport) Client() *http.Client

Client is our HTTP Client with custom rountripper set

func (*APITransport) RoundTrip

func (t *APITransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements the RoundTripper interface.

type Action

type Action interface {
	// contains filtered or unexported methods
}

Action is an interface to ensure all Actions have a prepare()

type Auth

type Auth interface {
	GetCreds() []string
}

Auth types are various but support a common interface

type CallFrom

type CallFrom struct {
	Type       string
	Number     string
	DtmfAnswer string
}

CallFrom details of the caller

type CallTo

type CallTo struct {
	Type        string
	Number      string
	DtmfAnswer  string
	Uri         string
	Extension   string
	ContentType string
	Headers     map[string]string
}

CallTo details of the callee

type CreateCallOpts

type CreateCallOpts struct {
	From CallFrom
	To   CallTo
	Ncco Ncco
}

CreateCallOpts: Options for creating a call

type JWTAuth

type JWTAuth struct {
	JWT string
}

JWTAuth is an Auth type to represent a JWT token

func CreateAuthFromAppPrivateKey

func CreateAuthFromAppPrivateKey(appID string, privateKey []byte) (*JWTAuth, error)

CreateAuthFromAppPrivateKey is a helper method to generate auth from an Application ID and a []byte of the private key (use with ioutil.ReadFile)

func CreateAuthFromJwtTokenGenerator

func CreateAuthFromJwtTokenGenerator(generator jwt.Generator) *JWTAuth

CreateAuthFromJwtTokenGenerator accepts a token generator struct, use this to set more of the options on the generator.

func (*JWTAuth) GetCreds

func (auth *JWTAuth) GetCreds() []string

GetCreds returns an array of strings, this time just one element which is the JWT token

type KeySecretAuth

type KeySecretAuth struct {
	// contains filtered or unexported fields
}

KeySecretAuth is an Auth type to represent the API key and API secret combination

func CreateAuthFromKeySecret

func CreateAuthFromKeySecret(apiKey string, apiSecret string) *KeySecretAuth

CreateAuthFromKeySecret returns an Auth type given an API key and API secret

func (*KeySecretAuth) GetCreds

func (auth *KeySecretAuth) GetCreds() []string

GetCreds gives an array of credential strings

type Ncco

type Ncco struct {
	// contains filtered or unexported fields
}

Ncco is a parent type to hold the actions

func (*Ncco) AddAction

func (n *Ncco) AddAction(action Action)

AddAction to add a next action, in sequence, to the Ncco

func (*Ncco) GetActions

func (n *Ncco) GetActions() []interface{}

GetActions to get all the actions

type NotifyAction

type NotifyAction struct {
	Action      string            `json:"action,omitempty"`
	Payload     map[string]string `json:"payload,omitempty"`
	EventUrl    []string          `json:"eventUrl,omitempty"`
	EventMethod string            `json:"eventMethod,omitempty"`
}

NotifyAction to represent a Notify Action

type NumberBuyOpts

type NumberBuyOpts struct {
	TargetAPIKey string
}

NumberBuyOpts enables users to set the Target API Key (and any future params)

type NumberCancelOpts

type NumberCancelOpts struct {
	TargetAPIKey string
}

NumberCancelOpts enables users to set the Target API Key (and any future params)

type NumberSearchOpts

type NumberSearchOpts struct {
	Type          string
	Features      string
	Pattern       string
	SearchPattern int32
	Size          int32
	Index         int32
}

NumberSearchOpts sets the optional values in the Search method

type NumberUpdateOpts

type NumberUpdateOpts struct {
	AppID                 string
	MoHTTPURL             string
	VoiceCallbackType     string
	VoiceCallbackValue    string
	VoiceStatusCallback   string
	MessagesCallbackType  string
	MessagesCallbackValue string
}

NumberUpdateOpts sets all the various fields for the number config

type NumbersClient

type NumbersClient struct {
	Config *numbers.Configuration
	// contains filtered or unexported fields
}

NumbersClient for working with the Numbers API

func NewNumbersClient

func NewNumbersClient(Auth Auth) *NumbersClient

NewNumbersClient Creates a new Numbers Client, supplying an Auth to work with

func (*NumbersClient) Buy

func (client *NumbersClient) Buy(country string, msisdn string, opts NumberBuyOpts) (numbers.Response, NumbersErrorResponse, error)

Buy the best phone number to use in your app

func (*NumbersClient) Cancel

func (client *NumbersClient) Cancel(country string, msisdn string, opts NumberCancelOpts) (numbers.Response, NumbersErrorResponse, error)

Cancel a number already in your account

func (*NumbersClient) List

func (client *NumbersClient) List(opts NumbersOpts) (numbers.InboundNumbers, error)

List shows the numbers you already own, filters and pagination are available

func (*NumbersClient) Search

func (client *NumbersClient) Search(country string, opts NumberSearchOpts) (numbers.AvailableNumbers, error)

Search lets you find a great phone number to use in your application

func (*NumbersClient) Update

func (client *NumbersClient) Update(country string, msisdn string, opts NumberUpdateOpts) (numbers.Response, NumbersErrorResponse, error)

Update the configuration for your number

type NumbersErrorResponse

type NumbersErrorResponse struct {
	ErrorCode      string `json:"error-code,omitempty"`
	ErrorCodeLabel string `json:"error-code-label,omitempty"`
}

NumbersErrorResponse is the error format for the Numbers API

type NumbersOpts

type NumbersOpts struct {
	ApplicationID  string
	HasApplication string // string because it's tri-state, not boolean
	Country        string
	Pattern        string
	SearchPattern  int32
	Size           int32
	Index          int32
}

NumbersOpts sets the options to use in finding the numbers already in the user's account

type SMSClient

type SMSClient struct {
	Config *sms.Configuration
	// contains filtered or unexported fields
}

SMSClient for working with the SMS API

func NewSMSClient

func NewSMSClient(Auth Auth) *SMSClient

NewSMSClient Creates a new SMS Client, supplying an Auth to work with

func (*SMSClient) Send

func (client *SMSClient) Send(from string, to string, text string, opts SMSOpts) (sms.Sms, error)

Send an SMS. Give some text to send and the number to send to - there are some restrictions on what you can send from, to be safe try using a Nexmo number associated with your account

type SMSOpts

type SMSOpts struct {
	StatusReportReq bool
	Callback        string
	Type            string
	ClientRef       string
}

SMSOpts holds all the optional values that can be set when sending an SMS, check the https://developer.nexmo.com/api/sms API reference for more information

type TalkAction

type TalkAction struct {
	Action              string `json:"action,omitempty"`
	Text                string `json:"text"`
	Loop                string `json:"-"`
	BargeIn             bool   `json:"bargeIn"`
	Level               int    `json:"level"`
	VoiceName           string `json:"voiceName,omitempty"`
	CalculatedLoopValue int    `json:"loop"`
}

TalkAction is a text-to-speech feature. Beware that the "Loop" field is a string here, and the CalculatedLoopValue is used to assemble the correct value when sending

type VerifyClient

type VerifyClient struct {
	Config *verify.Configuration
	// contains filtered or unexported fields
}

VerifyClient for working with the Verify API

func NewVerifyClient

func NewVerifyClient(Auth Auth) *VerifyClient

NewVerifyClient Creates a new Verify Client, supplying an Auth to work with

func (*VerifyClient) Cancel

Cancel an in-progress request (check API docs for when this is possible)

func (*VerifyClient) Check

func (client *VerifyClient) Check(requestID string, code string) (verify.CheckResponse, verify.CheckErrorResponse, error)

Check the user-supplied code for this request ID

func (*VerifyClient) Request

func (client *VerifyClient) Request(number string, brand string, opts VerifyOpts) (verify.RequestResponse, verify.RequestErrorResponse, error)

Request a number is verified for ownership

func (*VerifyClient) Search

Search for an earlier request by id

func (*VerifyClient) TriggerNextEvent

func (client *VerifyClient) TriggerNextEvent(requestID string) (verify.ControlResponse, verify.ControlErrorResponse, error)

TriggerNextEvent moves on to the next event in the workflow

type VerifyOpts

type VerifyOpts struct {
	Country       string
	SenderID      string
	CodeLength    int32
	Lg            string
	PinExpiry     int32
	NextEventWait int32
	WorkflowID    int32
}

VerifyOpts holds all the optional arguments for the verify request function

type VoiceClient

type VoiceClient struct {
	Config *voice.Configuration
	JWT    string
}

VoiceClient for working with the Voice API

func NewVoiceClient

func NewVoiceClient(Auth Auth) *VoiceClient

NewVoiceClient Creates a new Voice Client, supplying an Auth to work with

func (*VoiceClient) CreateCall

CreateCall Makes a phone call given the from/to details and either an AnswerURL or an NCCO

func (*VoiceClient) GetCalls

List your calls

type VoiceErrorGeneralResponse

type VoiceErrorGeneralResponse struct {
	Type  string `json:"type, omitempty"`
	Title string `json:"error_title, omitempty"`
}

VoiceErrorGeneralResponse covers some common error types that come from the webserver/gateway rather than the API itself

type VoiceErrorInvalidParamsResponse

type VoiceErrorInvalidParamsResponse struct {
	Type              int                 `json:"type, omitempty"`
	Title             string              `json:"title, omitempty"`
	Detail            string              `json:"detail, omitempty"`
	Instance          string              `json:"instance, omitempty"`
	InvalidParameters []map[string]string `json:"invalid_parameters, omitempty"`
}

VoiceErrorInvalidParamsResponse can come with a 400 response if it is caused by some invalid_parameters

type VoiceErrorResponse

type VoiceErrorResponse struct {
	Error interface{}
}

VoiceErrorResponse is a container for error types since we can get more than one type of error back and they have incompatible data types

Directories

Path Synopsis
examples
cli/vongo command
cli/vongo/cmd
Package cmd is an example app Package cmd is an example app Package cmd is an example app Package cmd is an example app
Package cmd is an example app Package cmd is an example app Package cmd is an example app Package cmd is an example app

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL