WWW::Vonage::API(3)

NAME
WWW::Vonage::API - Accessing Vonage's REST API with Perl

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.

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      |
  +--------------------+----------------------+---------+

As well some of the domains that start with 'api' are also available with a region specific domain and within some of the APIs you can have more than one version of an API call and 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.

1. 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'.

  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 supposed 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 verb and some GET and PATCH verbs and

    'resource/:entity_id'

for the DELETE, PATCH, PUT verbs and some GET verbs.

There are also a few APIs where there are parent-child calls as well in this pattern:

    'resource/:entity_id/:child_entity'

for the POST verb and some GET and PATCH verbs and for the DELETE, PATCH, 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'

Consult the individual Vonage API documents for details on how each works.

  All API calls are of the form:
    VONAGE->METHOD(PATH, PAYLOAD, OPTIONS);

METHOD

Method is one of following HTTP verbs GET, POST, PATCH, DELETE and PUT.

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 here; 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 POST, PATCH, and PUT, this is encoded as JSON in the request body. For GET, it is encoded on a query string.

OPTIONS

You can override "API_Version", "API_Domain", or "API_Region" on a per-call basis without creating a new instance.

API Response

Each of GET, POST, PATCH, PUT and DELETE return 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 this 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 B<$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 is 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 basic 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 for the report to work.

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 in the new call, 'v1' is used as the default. According to the API document '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 conjuction 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',
                                     API_Version  => 'none');

then the 'GET' call to the resource:

  my $response = $Vonage->GET('account/get-balance');

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' and the API_Version param with a value of 'nono' is used to drop the version number from the URL.

POST API calls

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->GET('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 was assumed the Vonage object is being reused from the previous example so it will maintain the 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.

POD ERRORS
Hey! The above document had some coding errors, which are explained below:

Around line 281:
    Non-ASCII character seen before =encoding in 'channels—like'. Assuming UTF-8

Around line 369:
    You forgot a '=back' before '=head3'

Around line 407:
    =back without =over