Ruby client for DIDWW API v3.
About DIDWW API v3
The DIDWW API provides a simple yet powerful interface that allows you to fully integrate your own applications with DIDWW services. An extensive set of actions may be performed using this API, such as ordering and configuring phone numbers, setting capacity, creating SIP trunks and retrieving CDRs and other operational data.
The DIDWW API v3 is a fully compliant implementation of the JSON API specification.
This SDK uses json_api_client for JSON:API serialization and deserialization.
Read more https://doc.didww.com/api
API Version
This SDK sends the X-DIDWW-API-Version: 2026-04-16 header with every request by default.
| Gem Version | Branch | DIDWW API Version |
|---|---|---|
| 6.x | master |
2026-04-16 |
| 5.x | 2022-05-10 |
2022-05-10 |
| 3.x | release-3 |
2021-12-15 |
| 2.x | release-2 |
2021-04-19 |
| 1.x | release-1 |
2017-09-18 |
Installation
Add this line to your application's Gemfile:
gem 'didww-v3'
And then execute:
$ bundle
Or install it yourself as:
$ gem install didww-v3
Requirements
- Ruby 3.3+
Quick Start
require 'didww'
DIDWW::Client.configure do |config|
config.api_key = 'YOUR_API_KEY'
config.api_mode = :sandbox
end
# Check balance
balance = DIDWW::Client.balance
puts "Balance: #{balance.total_balance}"
# List DID groups with stock keeping units
did_groups = DIDWW::Client.did_groups.all(
include: 'stock_keeping_units',
filter: { area_name: 'Acapulco' }
)
puts "DID groups: #{did_groups.count}"
For details on obtaining your API key please visit https://doc.didww.com/api3/configuration.html
Examples
- Rails integration sample: https://github.com/didww/didww-v3-rails-sample
Configuration
require 'didww'
# Sandbox
DIDWW::Client.configure do |config|
config.api_key = 'YOUR_API_KEY'
config.api_mode = :sandbox
end
# Production
DIDWW::Client.configure do |config|
config.api_key = 'YOUR_API_KEY'
config.api_mode = :production
end
Environments
| Environment | Base URL |
|---|---|
:production |
https://api.didww.com/v3/ |
:sandbox |
https://sandbox-api.didww.com/v3/ |
Connection Customization
Use customize_connection to customize the underlying Faraday connection, for example to configure a proxy or add custom middleware:
# Using a proxy
DIDWW::Client.configure do |config|
config.api_key = 'YOUR_API_KEY'
config.api_mode = :production
config.customize_connection do |conn|
# conn is a JsonApiClient::Connection instance
conn.faraday.proxy = 'http://proxy.example.com:8080'
end
end
# Adding custom middleware and timeouts
DIDWW::Client.configure do |config|
config.api_key = 'YOUR_API_KEY'
config.api_mode = :production
config.customize_connection do |conn|
# conn is a JsonApiClient::Connection instance
conn.use MyCustomMiddleware
conn.faraday..timeout = 30
conn.faraday..open_timeout = 10
end
end
API Version
The SDK sends X-DIDWW-API-Version: 2026-04-16 by default. You can override it per block (e.g., to pin to a previous API version during migration):
DIDWW::Client.with_api_version('2022-05-10') do
DIDWW::Client.countries.all
end
Resources
Read-Only Resources
# Countries
countries = DIDWW::Client.countries.all
country = DIDWW::Client.countries.find('uuid')
# Regions, Cities, Areas, POPs
regions = DIDWW::Client.regions.all
cities = DIDWW::Client.cities.all
areas = DIDWW::Client.areas.all
pops = DIDWW::Client.pops.all
# DID Group Types
types = DIDWW::Client.did_group_types.all
# DID Groups (with stock keeping units)
did_groups = DIDWW::Client.did_groups.all(include: 'stock_keeping_units')
# Available DIDs (with DID group and stock keeping units)
available_dids = DIDWW::Client.available_dids.all(include: 'did_group.stock_keeping_units')
# Public Keys
public_keys = DIDWW::Client.public_keys.all
# Requirements
requirements = DIDWW::Client.requirements.all
# Balance (singleton)
balance = DIDWW::Client.balance
DIDs
# List DIDs
dids = DIDWW::Client.dids.all
# Update DID
did = DIDWW::Client.dids.find('uuid')
did.description = 'Updated'
did.capacity_limit = 20
did.save
Voice In Trunks
trunk = DIDWW::Client.voice_in_trunks.new(
name: 'My SIP Trunk',
configuration: {
type: 'sip_configurations',
username: '{DID}',
host: 'sip.example.com',
port: 5060
}
)
trunk.save
Voice Out Trunks
Voice Out Trunks use a polymorphic authentication_method (2026-04-16). Three types are supported:
credentials_and_ip-- default method;usernameandpasswordare server-generated and returned in the response.twilio-- requires atwilio_account_sid.ip_only-- read-only; can only be configured by DIDWW staff upon request. Cannot be set via the API.
# NOTE: 203.0.113.0/24 is RFC 5737 TEST-NET-3 documentation space.
# Replace with the real CIDR of your SIP infrastructure.
trunk = DIDWW::Client.voice_out_trunks.new(
name: 'My Outbound Trunk',
on_cli_mismatch_action: 'reject_call',
authentication_method: DIDWW::ComplexObject::AuthenticationMethod::CredentialsAndIp.new(
allowed_sip_ips: ['203.0.113.0/24']
)
)
trunk.save
# trunk.authentication_method.username -- server-generated
# trunk.authentication_method.password -- server-generated
Orders
order = DIDWW::Client.orders.new(
items: [
{
type: 'did_order_items',
sku_id: 'sku-uuid',
qty: 2
}
]
)
order.save
Emergency Services
# List emergency requirements with filters
requirements = DIDWW::Client.emergency_requirements
.includes(:country, :did_group_type)
.all
# Filter by country
requirements = DIDWW::Client.emergency_requirements
.where('country.id': 'country-uuid')
.all
requirements.each do |req|
puts req.identity_type
puts req.address_area_level
puts req.estimate_setup_time # e.g. "7-14 days"
puts req.
end
# Create an emergency verification
verification = DIDWW::Client.emergency_verifications.new(
address: DIDWW::Resource::Address.load(id: 'address-uuid'),
emergency_calling_service:
DIDWW::Resource::EmergencyCallingService.load(id: 'ecs-uuid'),
dids: [DIDWW::Resource::Did.load(id: 'did-uuid')],
external_reference_id: 'my-ref-123'
)
if verification.save
puts "Created: #{verification.id} (status: #{verification.status})"
else
puts "Errors: #{verification.errors.}"
end
# List emergency calling services
services = DIDWW::Client.emergency_calling_services
.includes(:country, :did_group_type, :dids)
.all
services.each do |svc|
puts "#{svc.name} — #{svc.status}"
end
# Cancel (destroy) an emergency calling service
svc = DIDWW::Client.emergency_calling_services.find('uuid').first
svc.destroy
DID History
# List recent DID history events (retained for the last 90 days)
events = DIDWW::Client.did_history.all
events.each do |event|
puts "#{event.created_at.iso8601} #{event.did_number} #{event.action} via #{event.method}"
end
# Filter by action
assigned = DIDWW::Client.did_history
.where(action: DIDWW::Resource::DidHistory::ACTION_ASSIGNED)
.all
# Filter by DID number
per_number = DIDWW::Client.did_history
.where(did_number: '12125551234')
.all
# Filter by date range
seven_days_ago = (Time.now - 7 * 24 * 60 * 60).iso8601
recent = DIDWW::Client.did_history
.where(created_at_gteq: seven_days_ago)
.all
Error Handling
The SDK uses json_api_client which raises exceptions for HTTP-level errors. Validation errors from the API are returned on the resource's errors collection after a failed save.
# Validation errors (422 Unprocessable Entity)
trunk = DIDWW::Client.voice_in_trunks.new(name: '')
unless trunk.save
trunk.errors..each do |msg|
puts "Validation error: #{msg}"
end
end
# HTTP errors (404, 401, 500, etc.)
begin
DIDWW::Client.dids.find('nonexistent-uuid')
rescue JsonApiClient::Errors::NotFound => e
puts "Not found: #{e.}"
rescue JsonApiClient::Errors::AccessDenied => e
puts "Access denied: #{e.}"
rescue JsonApiClient::Errors::ServerError => e
puts "Server error: #{e.}"
rescue JsonApiClient::Errors::ConnectionError => e
puts "Connection error: #{e.}"
end
Dirty Tracking
The SDK (via json_api_client) tracks which attributes have been modified. When you call save on a fetched resource, the resulting PATCH request sends only the changed attributes, avoiding unintended overwrites of server-side values.
did = DIDWW::Client.dids.find('uuid').first
did.description = 'Updated'
did.save
# PATCH payload includes only "description", not all attributes
Date and Datetime Fields
The SDK distinguishes between date-only and datetime fields:
- Datetime fields — deserialized as
Time:created_at— present on most resourcesexpires_at—Did,DidReservation,Proof,EncryptedFile(nullable)activated_at—EmergencyCallingService(nullable)canceled_at—EmergencyCallingService(nullable)
- Date-only fields — deserialized as
Date:Identity#birth_date
- Date-only fields kept as strings — remain as
String:CapacityPool#renew_date,EmergencyCallingService#renew_date—"YYYY-MM-DD"(nullable)
- String fields (not numeric):
EmergencyRequirement#estimate_setup_time— e.g."7-14 days","1"EmergencyRequirement#requirement_restriction_message— nullable
Important changes from previous API versions:
expire_atrenamed toexpires_atonDidReservationandEncryptedFilerenew_dateis a date-only string, NOT a datetimeestimate_setup_timeis a string, NOT an integer
did = DIDWW::Client.dids.find("uuid").first
puts did.created_at # => 2024-01-15 10:00:00 UTC (Time)
puts did.expires_at # => nil or 2025-01-15 10:00:00 UTC (Time)
identity = DIDWW::Client.identities.find("uuid").first
puts identity.birth_date # => 1990-05-20 (Date)
Resource Relationships
See docs/resource_relationships.md for a Mermaid ER diagram showing all has_one, has_many, and belongs_to relationships between resources.
Webhook Signature Validation
Validate incoming webhook callbacks from DIDWW using HMAC-SHA1 signature verification.
require 'didww/callback/request_validator'
validator = DIDWW::Callback::RequestValidator.new("YOUR_API_KEY")
# In your webhook handler:
valid = validator.validate(
request_url, # full original URL
payload_params, # Hash of payload key-value pairs
signature # value of X-DIDWW-Signature header
)
The signature header name is available as the constant DIDWW::Callback::RequestValidator::HEADER.
Rails Example
class WebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
def create
validator = DIDWW::Callback::RequestValidator.new("YOUR_API_KEY")
signature = request.headers[DIDWW::Callback::RequestValidator::HEADER]
params_hash = request.POST
if validator.validate(request.original_url, params_hash, signature)
# Process the webhook
head :ok
else
head :forbidden
end
end
end
Enums
The SDK provides constants for all API option fields. These are defined as constants on their respective modules/classes:
CallbackMethod, IdentityType, OrderStatus, ExportType, ExportStatus, CliFormat,
OnCliMismatchAction*, MediaEncryptionMode, DefaultDstAction, VoiceOutTrunkStatus,
EmergencyCallingServiceStatus, EmergencyVerificationStatus, DiversionRelayPolicy,
TransportProtocol, Codec, RxDtmfFormat, TxDtmfFormat, SstRefreshMethod,
ReroutingDisconnectCode, Feature, AreaLevel, AddressVerificationStatus, StirShakenMode
* REPLACE_CLI and RANDOMIZE_CLI require additional account configuration. Contact DIDWW support to enable these values.
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/didww/didww-v3-ruby.
License
The gem is available as open source under the terms of the MIT License.