NAME
WWW::Vonage::API
VERSION
version 0.003
SYNOPSIS
use WWW::Vonage::API;
my $vonage = WWW::Vonage::API->new(
API_Key => 'ABC12345...',
API_Secret => '1234567...'
);
## Send an SMS
my $payload = {
to => '+6725550002',
from => '+6725550001',
channel => "sms",
message_type => "text",
text => 'There is a storm coming!',
};
my $response = $vonage->POST( 'messages', $payload );
print $response->{content};
DESCRIPTION
WWW::Vonage::API aims to make connecting to and making REST calls on the Vonage API easy, reliable, and enjoyable.
NAME
WWW::Vonage::API - Accessing Vonage's REST API with Perl
Vonage API
The Vonage API documentation is found here: https://developer.vonage.com/en/home
The Vonage Communications API is a cloud-based platform that allows developers to embed programmable communication channels like SMS, voice, video, and social messaging directly into their applications, websites, and business systems.
Core API Offerings
The ecosystem is generally categorized into the following core products:
- 1. Messaging APIs
-
Includes the Messages API (multi-channel support for SMS, WhatsApp, etc.) and the dedicated SMS API.
- 2. Voice and Video APIs
-
Voice API for programmatically controlling phone calls and Video API (formerly Tokbox) for interactive video sessions.
- 3. Verify (Identity & Security)
-
A specialized tool for Two-Factor Authentication (2FA) that manages the entire verification workflow.
- 4. Identity & Network Insights
-
Includes Identity Insights and Number Insight API for fraud prevention and number validation.
- 5. Management and Enablement APIs
-
Helper APIs for managing accounts, purchasing numbers, and auditing usage.
Domain Host Version
In true large corporation fashion, not all Vonage APIs share the same domain or versioning scheme.
API Endpoint Mapping
+--------------------+----------------------+---------+
| API Name | Domain/Host | Version |
+--------------------+----------------------+---------+
| Account API | rest.nexmo.com | none |
| Application API | api.nexmo.com | v2 |
| Messages API | api.nexmo.com | v1 |
| Number Insight API | api.nexmo.com | none |
| Numbers API | rest.nexmo.com | none |
| Pricing API | api.nexmo.com | v2 |
| Redact API | api.nexmo.com | v1 |
| Reports API | api.nexmo.com | v2 |
| SMS API | rest.nexmo.com | none |
| Verify API | api.nexmo.com | v2 |
| Video API | video.api.vonage.com | v2 |
| Voice API | api.nexmo.com | v1 |
+--------------------+----------------------+---------+
Additionally, some of the domains that start with 'api' are also available with a region-specific domain. Within some of the APIs, you can have more than one version of an API call, and the version may vary by API call. Finally, some APIs do not use or have a version number.
Using WWW::Vonage::API
In theory, all features should work with this module. However, some features require JSON Web Tokens (JWT). At this time, only Basic Authentication (API Key and Secret) is implemented.
Basic Call
my $payload = {
to => '+6725550002',
from => '+6725550001',
channel => "sms",
message_type => "text",
text => 'There is a storm coming!',
};
my $response = $vonage->POST( 'messages',$payload );
In the above example, the "Messages" API is being invoked following the Vonage API documentation (https://developer.vonage.com/en/api/messages?source=messages). For context, a snippet of the documentation follows:
Messages API
Available Operations:
Post Send a message to the given channel
Send an SMS message
POST https://{api-region}.nexmo.com/v1/messages
Server Variables
Api-region:
one of api, api-eu, api-us, api-ac
Authentication:
JWT or Basic
Body:
Required key-value pairs in request body for SMS
+--------------+-----------------------+
| Key | value |
+--------------+-----------------------+
| channel | sms |
| message_type | text |
| from | the sender phone # |
| to | the recipient phone # |
| text | up to 1000 characters |
+--------------+-----------------------+
Responses:
202 Accepted
401 Authentication failure
402 Payment Required
404 Not Found
422 Unprocessable Entity
429 Too Many Requests
500 Internal error
METHODS
new
Creates a new Vonage object.
my $vonage = WWW::Vonage::API->new(
API_Key => 'YOUR_KEY',
API_Secret => 'YOUR_SECRET',
);
Available Parameters:
- API_Key (Required)
-
Your Vonage API Key.
- API_Secret (Required)
-
Your Vonage API Secret.
- API_Domain
-
Defaults to 'nexmo.com'. There is one production API that uses a different domain as well as a number of 'beta' APIs. Simply use this parameter with the value of the domain you wish to access.
- API_Version
-
Defaults to 'v1'. This value will change by API and even within an API; see Vonage documentation for details. For example, the 'Reports' API uses 'v2', and some calls in that API use 'v3'. Use 'none' for APIs that do not utilize a version string in the URL.
- API_Region
-
Defaults to 'api'. Use this parameter when the API documentation calls for something other than 'api'. The documented ones are 'api-eu', 'api-us', 'api-ac', 'rest', and 'video.api'.
- DEBUG
-
Sets an internal flag and will dump debug information to STDERR.
Option Examples:
my $vonage = new WWW::Vonage::API(
API_Key => 'AC...',
API_Secret => '...',
);
would create the following url: https://api.nexmo.com/v1/
my $vonage = new WWW::Vonage::API(
API_Key => 'AC...',
API_Secret => '...',
API_Version => 'v2'
);
would create the following url: https://api.nexmo.com/v2/
my $vonage = new WWW::Vonage::API(
API_Key => 'AC...',
API_Secret => '...',
API_Version => 'none',
API_Region => 'rest'
);
would create the following url: https://rest.nexmo.com/
my $vonage = new WWW::Vonage::API(
API_Key => 'AC...',
API_Secret => '...',
API_Domain => 'vonage.com',
API_Version => 'v2',
API_Region => 'video.api'
);
would create the following url: https://video.api.vonage.com/v2/
Vonage API calls
As Vonage is designed to be a RESTful API, there is an expectation of a certain resource/entity path pattern for a given HTTP verb. For the most part, Vonage follows the standard REST path pattern of:
'resource'
for the POST and some GET verbs
'resource/:entity_id'
for the DELETE, PATCH, and PUT verbs and some GET verbs.
There are also a few APIs that include parent-child calls in this pattern:
'resource/:entity_id/:child_entity'
for the POST verb and some GET and PATCH verbs. For the DELETE, PATCH, and PUT verbs and some GET verbs, the child_id is also included:
'resource/:entity_id/:child_entity/:child_entity_id'
There are a few that also include an extra resource in the path:
'resource_1/:entity_id/:child_entity/:child_entity_id/resource_2'
As a final note, API resource names can be either case-sensitive or case-insensitive, whereas API entity IDs are strictly case-sensitive. Please consult the individual Vonage API documentation for specific details on how each works.
All API calls are of the form:
VONAGE->METHOD(PATH, PAYLOAD, OPTIONS);
METHOD
The method is one of the following HTTP verbs: GET, POST, PATCH, DELETE, and PUT.
- GET
-
Requests a representation of a specific entity within a Vonage API. It is used to retrieve data without modifying it. If the request has a 'PAYLOAD', it is encoded on the query string of the URL.
- POST
-
Sends data to a server to create a new entity, and in some Vonage APIs, it is used to initiate a specialized process. If the request has a 'PAYLOAD', it is encoded in JSON in the body of the request.
- PATCH
-
Applies partial modifications to an existing entity rather than replacing it. If the request has a 'PAYLOAD', it is encoded in JSON in the body of the request.
- DELETE
-
Removes the specified entity from the server. Normally there is no 'PAYLOAD', and the entity_id is included in the request 'PATH'.
- PUT
-
Replaces the current target entity with the payload. In some Vonage APIs, it will create the entity if it doesn't exist. If the request has a 'PAYLOAD', it is encoded in JSON in the body of the request.
PATH
This is the Vonage API resource that is being invoked. Normally it is just a single resource, but that varies from API to API. This software expects that the full resource/entity path is included. For example, a call with the PATCH verb of the 'project' resource requires this path pattern:
'resource_1/:entity_id/:child_entity/:child_id/resource_2'
and so the PATCH call to an entity would look like this:
$vonage->PATCH('project/999902/archive/19900/streams',$payload,...)
where 'project' is the resource, '999902' the entity id, 'archive' the child entity, '19900' the child_id, and 'streams' the secondary resource.
PAYLOAD
A hash-ref of key-value pairs. For the POST, PATCH, and PUT verbs, it is encoded as JSON in the request body. For GET, it is encoded on the query string.
OPTIONS
You can override API_Version, API_Domain, API_Region, or DEBUG options on a per-call basis without creating a new instance. Note that these option values are sticky and will remain with a VONAGE instance until overwritten.
API Response
Each of GET, POST, PATCH, PUT, and DELETE returns a hashref with the call results, the most important of which is the content element. This is the untouched, raw response of the Vonage API server, suitable for you to do whatever you want with it. Normally it is a JSON object, as in the example below:
my $payload = {
date_start => '2026-04-18',
date_end => '2026-04-23',
product => 'sms',
direction => 'outbound'
};
$response = $Vonage->GET('reports/records',$payload,API_Version=>'v2');
...
and the $response hash-ref will look like this:
{
content =>'{"message_uuid": "aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab",
"workflow_id": "3TcNjguHxr2vcCZ9Ddsnq6tw8yQUpZ9rMHv9QXSxLan5ibMxqSzLdx9"}',
code =>'202',
message =>'Accepted',
}
The elements in the response are:
- content
-
Contains the JSON response from the server.
- code
-
Contains the HTTP status code. Successful responses will be in the '200' range. Make sure you check the Vonage API documentation to see what is the correct success code for the API you are invoking.
- message
-
A brief HTTP status message, corresponding to the status code. For 200 codes, the message will be "OK". For 202 codes, the message will be "Accepted". For "400" codes, the message will be "Bad Request", and so forth. Again, check the Vonage API documentation to see what the correct message and code are for the API you are invoking.
Example:
$response = $vonage->POST( 'messages',$payload );
$response is a hashref that looks like this:
{
content =>'{"message_uuid": "aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab",
"workflow_id": "3TcNjguHxr2vcCZ9Ddsnq6tw8yQUpZ9rMHv9QXSxLan5ibMxqSzLdx9"}',
code =>'202',
message =>'Accepted',
}
API Examples
Vonage is a rather large API, so here are some examples that will cover most of the basics.
Get API calls
Reports API
In this example, a report on 'SMS' outbound messages for a date range is required. The 'Reports API' is going to be invoked to fulfill this requirement. The resource that will be invoked is 'reports', and the entity is 'records'. According to the API documentation, these four parameters start date, end date, product, and direction are required to be encoded on the URL Query String.
First, the payload is created:
my $payload = {
date_start => '2026-04-18',
date_end => '2026-04-23',
product => 'sms',
direction => 'outbound'
};
Next, a Vonage API instance is required:
my $Vonage = WWW::Vonage::API->new(API_Key => 'ABC12345...',
API_Secret => '1234567...');
Then, the API is invoked with this line:
my $response = $Vonage->GET('reports/records',$payload,API_Version=>'v2');
The response is a hashref that would look like this:
{ code =>'200',
message =>'OK',
content =>'{
"_links": {
"self": {
"href": "https://api.nexmo.com/v2/reports/sms/records?product=SMS&direction=outbound&date_start=2024-02-01T00:00:00Z&date_end=2024-02-02T00:00:00Z"
},
"next": {
"href": "https://api.nexmo.com/v2/reports/sms/records?product=SMS&direction=outbound&cursor=MTY0OTQ3ODAwMDAwMA"
}
},
...
Notes:
As the API_Version parameter was not included when creating the Vonage instance, 'v1' is used as the default. According to the API documentation, 'v2' is required, so to invoke the correct version, the API_Version param is used.
Account API
In this example, the current balance of the account is required. To get this value, the Accounts API must be used. So the 'account' resource is used in conjunction with the 'get-balance' entity.
In this case, there is no payload, only a call to the API.
Starting with a new Vonage instance:
my $Vonage = WWW::Vonage::API->new(API_Key => 'ABC12345...',
API_Secret => '1234567...',
API_Region => 'rest');
Then, the GET call to the resource:
my $response = $Vonage->GET('account/get-balance',undef,API_Version=>'none');
The response is a hashref that would look like this:
{ code =>'200',
message =>'OK',
content =>'{"value": 10.28,"autoReload": false}'
}
Notes:
The API_Region param is used to set the first part of the URL to 'rest' when invoking the Vonage instance. The 'PAYLOAD' is set to 'undef' as there is no payload, and finally, the API_Version param is used with a value of 'none' to drop the version number from the URL.
POST API call
Account API
In this example, a transaction notice needs to be sent to Vonage to update the balance of an account. The 'Accounts API' is again used to set this value using the 'POST' verb and the 'top-up' entity. The 'trx' param is required, and it is encoded in the body of the POST:
my $response = $Vonage->POST('account/top-up',{trx=>'8ef2...'});
The response in this case would be a hashref:
{ code =>'200',
message =>'success',
content =>''
}
Notes:
In the above example, it is assumed the Vonage object is being reused from the previous example, so it will maintain the option values of API_Region and API_Version for its call.
More examples of using the params to set the path of an API call can be found in the .t files.
SEE ALSO
LWP::UserAgent, https://developer.vonage.com/
AUTHOR
John Scoles, <byterock@hotmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2026 by John Scoles
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
AUTHOR
John Scoles <byterock@hotmail.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by John Scoles.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.