Java client for 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 jsonapi-converter for JSON:API serialization and deserialization.
Read more https://doc.didww.com/api
This SDK sends the X-DIDWW-API-Version: 2026-04-16 header with every request by default.
| SDK Version | Branch | DIDWW API Version |
|---|---|---|
| 3.x | main |
2026-04-16 |
| 2.x | 2022-05-10 |
2022-05-10 |
- Java 11+
This SDK is distributed via JitPack. JitPack builds the library directly from GitHub, so no manual publishing is required.
Browse all available versions (tags, branches, commits): https://jitpack.io/#didww/didww-api-3-java-sdk
repositories {
maven("https://jitpack.io")
}
dependencies {
implementation("com.github.didww:didww-api-3-java-sdk:2.4.0")
}<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.didww</groupId>
<artifactId>didww-api-3-java-sdk</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>You can also consume the SDK from a specific branch or commit via JitPack:
dependencies {
// specific branch (append -SNAPSHOT)
implementation("com.github.didww:didww-api-3-java-sdk:main-SNAPSHOT")
// specific commit hash
// implementation("com.github.didww:didww-api-3-java-sdk:<commit-hash>")
}import com.didww.sdk.*;
import com.didww.sdk.resource.*;
import com.didww.sdk.http.QueryParams;
DidwwClient client = DidwwClient.builder()
.credentials(new DidwwCredentials("YOUR_API_KEY", DidwwEnvironment.SANDBOX))
.build();
// Check balance
Balance balance = client.balance().find().getData();
System.out.println("Balance: " + balance.getTotalBalance());
// List DID groups with stock keeping units
QueryParams params = QueryParams.builder()
.include("stock_keeping_units")
.filter("area_name", "Acapulco")
.build();
List<DidGroup> didGroups = client.didGroups().list(params).getData();For more examples visit examples.
For details on obtaining your API key please visit https://doc.didww.com/api3/configuration.html
- Source code: examples/src/main/java/com/didww/examples
- How to run: examples/README.md
import java.time.Duration;
DidwwClient client = DidwwClient.builder()
.credentials(new DidwwCredentials("YOUR_API_KEY", DidwwEnvironment.PRODUCTION))
.connectTimeout(Duration.ofSeconds(10))
.readTimeout(Duration.ofSeconds(30))
.build();You can pass a custom OkHttpClient.Builder for advanced configuration such as proxy support:
import java.net.InetSocketAddress;
import java.net.Proxy;
import okhttp3.OkHttpClient;
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder()
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080)));
DidwwClient client = DidwwClient.builder()
.credentials(new DidwwCredentials("YOUR_API_KEY", DidwwEnvironment.PRODUCTION))
.httpClientBuilder(httpBuilder)
.build();The API key interceptor is added automatically. Any other OkHttp settings (timeouts, SSL, interceptors, connection pools) can be configured on the builder.
| Environment | Base URL |
|---|---|
DidwwEnvironment.PRODUCTION |
https://api.didww.com/v3 |
DidwwEnvironment.SANDBOX |
https://sandbox-api.didww.com/v3 |
import com.didww.sdk.*;
import com.didww.sdk.resource.*;
import com.didww.sdk.http.QueryParams;
DidwwClient client = DidwwClient.builder()
.credentials(new DidwwCredentials("YOUR_API_KEY", DidwwEnvironment.SANDBOX))
.build();
// Countries
List<Country> countries = client.countries().list().getData();
Country country = client.countries().find("uuid").getData();
// Regions
List<Region> regions = client.regions().list().getData();
// Cities
List<City> cities = client.cities().list().getData();
// Areas
List<Area> areas = client.areas().list().getData();
// NANPA Prefixes
List<NanpaPrefix> prefixes = client.nanpaPrefixes().list().getData();
// POPs (Points of Presence)
List<Pop> pops = client.pops().list().getData();
// DID Group Types
List<DidGroupType> types = client.didGroupTypes().list().getData();
// DID Groups (with stock keeping units)
QueryParams dgParams = QueryParams.builder().include("stock_keeping_units").build();
List<DidGroup> groups = client.didGroups().list(dgParams).getData();
// Available DIDs (with DID group and stock keeping units)
QueryParams adParams = QueryParams.builder().include("did_group.stock_keeping_units").build();
List<AvailableDid> available = client.availableDids().list(adParams).getData();
// Proof Types
List<ProofType> proofTypes = client.proofTypes().list().getData();
// Public Keys
List<PublicKey> publicKeys = client.publicKeys().list().getData();
// Address Requirements
List<AddressRequirement> requirements = client.addressRequirements().list().getData();
// Supporting Document Templates
List<SupportingDocumentTemplate> templates = client.supportingDocumentTemplates().list().getData();
// Balance (singleton)
Balance balance = client.balance().find().getData();// List DIDs
List<Did> dids = client.dids().list().getData();
// Update DID - assign trunk and capacity
Did did = client.dids().find("uuid").getData();
did.setDescription("Updated");
did.setCapacityLimit(20);
did.setVoiceInTrunk(trunk);
client.dids().update(did);import com.didww.sdk.resource.configuration.*;
import com.didww.sdk.resource.enums.*;
// Create SIP trunk
VoiceInTrunk trunk = new VoiceInTrunk();
trunk.setName("My SIP Trunk");
trunk.setPriority(1);
trunk.setWeight(100);
trunk.setCliFormat(CliFormat.E164);
trunk.setRingingTimeout(30);
SipConfiguration sip = new SipConfiguration();
sip.setHost("sip.example.com");
sip.setPort(5060);
sip.setCodecIds(Arrays.asList(Codec.PCMU, Codec.PCMA));
sip.setTransportProtocolId(TransportProtocol.UDP);
trunk.setConfiguration(sip);
VoiceInTrunk created = client.voiceInTrunks().create(trunk).getData();
// Update trunk
created.setDescription("Updated");
client.voiceInTrunks().update(created);
// Delete trunk
client.voiceInTrunks().delete(created.getId());VoiceInTrunkGroup group = new VoiceInTrunkGroup();
group.setName("Primary Group");
group.setCapacityLimit(50);
VoiceInTrunkGroup created = client.voiceInTrunkGroups().create(group).getData();Note: Voice Out Trunks require additional account configuration. Contact DIDWW support to enable. The
REPLACE_CLIandRANDOMIZE_CLIvalues ofOnCliMismatchActionalso require account configuration.
Voice Out Trunks use a polymorphic authenticationMethod (2026-04-16). Three types are supported:
credentials_and_ip-- default method;usernameandpasswordare server-generated and returned in the response.twilio-- requires atwilioAccountSid.ip_only-- read-only; can only be configured by DIDWW staff upon request. Cannot be set via the API.
import com.didww.sdk.resource.enums.DefaultDstAction;
import com.didww.sdk.resource.enums.OnCliMismatchAction;
import com.didww.sdk.resource.authenticationmethod.CredentialsAndIpAuthenticationMethod;
// NOTE: 203.0.113.0/24 is RFC 5737 TEST-NET-3 documentation space.
// Replace with the real CIDR of your SIP infrastructure.
CredentialsAndIpAuthenticationMethod auth = new CredentialsAndIpAuthenticationMethod();
auth.setAllowedSipIps(Collections.singletonList("203.0.113.0/24"));
VoiceOutTrunk voTrunk = new VoiceOutTrunk();
voTrunk.setName("My Outbound Trunk");
voTrunk.setAuthenticationMethod(auth);
voTrunk.setDefaultDstAction(DefaultDstAction.ALLOW_ALL);
voTrunk.setOnCliMismatchAction(OnCliMismatchAction.REJECT_CALL);
VoiceOutTrunk created = client.voiceOutTrunks().create(voTrunk).getData();
// created.getAuthenticationMethod().getUsername() -- server-generated
// created.getAuthenticationMethod().getPassword() -- server-generatedimport com.didww.sdk.resource.orderitem.*;
// Order by SKU
Order order = new Order();
DidOrderItem item = new DidOrderItem();
item.setSkuId("sku-uuid");
item.setQty(2);
order.setItems(Arrays.asList(item));
Order created = client.orders().create(order).getData();
// Order available DID
AvailableDidOrderItem availableItem = new AvailableDidOrderItem();
availableItem.setAvailableDidId("available-did-uuid");
availableItem.setSkuId("sku-uuid");
// Order reserved DID
ReservationDidOrderItem reservationItem = new ReservationDidOrderItem();
reservationItem.setDidReservationId("reservation-uuid");
reservationItem.setSkuId("sku-uuid");
// Order capacity
CapacityOrderItem capacityItem = new CapacityOrderItem();
capacityItem.setCapacityPoolId("pool-uuid");
capacityItem.setQty(1);DidReservation reservation = new DidReservation();
reservation.setDescription("Reserved for client");
reservation.setAvailableDid(availableDid);
DidReservation created = client.didReservations().create(reservation).getData();
// Delete reservation
client.didReservations().delete(created.getId());SharedCapacityGroup scg = new SharedCapacityGroup();
scg.setName("Shared Group");
scg.setSharedChannelsCount(20);
scg.setCapacityPool(capacityPool);
SharedCapacityGroup created = client.sharedCapacityGroups().create(scg).getData();import com.didww.sdk.resource.enums.IdentityType;
Identity identity = new Identity();
identity.setFirstName("John");
identity.setLastName("Doe");
identity.setPhoneNumber("12125551234");
identity.setIdentityType(IdentityType.PERSONAL);
identity.setCountry(country);
Identity created = client.identities().create(identity).getData();Address address = new Address();
address.setCityName("New York");
address.setPostalCode("10001");
address.setAddress("123 Main St");
address.setIdentity(identity);
address.setCountry(country);
Address created = client.addresses().create(address).getData();AddressVerification verification = new AddressVerification();
verification.setCallbackUrl("http://example.com/callback");
verification.setCallbackMethod(CallbackMethod.GET);
AddressVerification created = client.addressVerifications().create(verification).getData();import java.nio.file.Path;
import com.didww.sdk.resource.enums.ExportType;
Export export = new Export();
export.setExportType(ExportType.CDR_IN);
export.setFilters(Map.of("from", "2025-01-01T00:00:00Z", "to", "2025-02-01T00:00:00Z"));
Export created = client.exports().create(export).getData();
// Download the export when completed
client.downloadExport(created.getUrl(), Path.of("/tmp/export.csv"));// List emergency requirements
List<EmergencyRequirement> emergReqs = client.emergencyRequirements().list().getData();
// Create emergency verification
EmergencyVerification emergVerification = new EmergencyVerification();
emergVerification.setCallbackUrl("https://example.com/callback");
emergVerification.setCallbackMethod(CallbackMethod.POST);
emergVerification.setAddress(address);
emergVerification.setDids(Arrays.asList(did));
EmergencyVerification created = client.emergencyVerifications().create(emergVerification).getData();
// List emergency calling services
List<EmergencyCallingService> emergServices = client.emergencyCallingServices().list().getData();// List DID history
List<DidHistory> history = client.didHistory().list().getData();
for (DidHistory entry : history) {
System.out.println(entry.getAction() + " " + entry.getCreatedAt());
}The SDK tracks which fields have been modified and sends only those fields in PATCH requests. This avoids overwriting server-side values that your code hasn't touched.
When you fetch a resource and modify it, only the changed fields are sent:
Did did = client.dids().find("uuid").getData();
did.setDescription("Updated description");
// PATCH payload includes only "description", not all attributes
client.dids().update(did);Use withId(id) to create a lightweight resource for PATCH without fetching first:
VoiceInTrunk trunk = new VoiceInTrunk().withId("trunk-uuid");
trunk.setName("New name");
// PATCH payload includes only "name"
client.voiceInTrunks().update(trunk);Calling a setter with null marks the field as dirty and includes an explicit null in the payload, which clears the server-side value:
Did did = new Did().withId("uuid");
did.setDescription(null);
// PATCH payload includes "description": null
client.dids().update(did);Calling a relationship setter with null sends "data": null for to-one or "data": [] for to-many relationships:
Did did = new Did().withId("uuid");
did.setVoiceInTrunk(null);
// PATCH payload includes: "relationships": { "voice_in_trunk": { "data": null } }
client.dids().update(did);Dirty tracking is automatically enabled on included (sideloaded) resources, so you can fetch with includes and update a related resource directly:
Did did = client.dids().find("uuid", QueryParams.builder().include("voice_in_trunk").build()).getData();
VoiceInTrunk trunk = did.getVoiceInTrunk();
trunk.setDescription("Updated via include");
client.voiceInTrunks().update(trunk);import com.didww.sdk.http.QueryParams;
QueryParams params = QueryParams.builder()
.filter("country.id", "uuid")
.filter("name", "Arizona")
.include("country")
.sort("name")
.page(1, 25)
.build();
List<Region> regions = client.regions().list(params).getData();The SDK provides an Encrypt utility for encrypting files before upload, using RSA-OAEP + AES-256-CBC (matching DIDWW's encryption requirements).
import com.didww.sdk.Encrypt;
// Instance-based: fetches public keys from the API
Encrypt enc = new Encrypt(client);
String fingerprint = enc.getFingerprint();
byte[] encrypted = enc.encrypt(fileBytes);
// Static: provide your own public keys
byte[] encrypted = Encrypt.encryptWithKeys(fileBytes, publicKeyPems);
String fingerprint = Encrypt.calculateFingerprint(publicKeyPems);Upload encrypted file:
List<String> encryptedFileIds = client.uploadEncryptedFile(
encrypted, // encrypted bytes
"document.pdf.enc", // uploaded file name
fingerprint, // Encrypt#getFingerprint()
"document.pdf" // description
);Validate incoming webhook callbacks from DIDWW using HMAC-SHA1 signature verification.
import com.didww.sdk.callback.RequestValidator;
RequestValidator validator = new RequestValidator("YOUR_API_KEY");
// In your webhook handler:
boolean valid = validator.validate(
requestUrl, // full original URL
payloadMap, // Map<String, String> of payload key-value pairs
signature // value of X-DIDWW-Signature header
);The signature header name is available as RequestValidator.HEADER_NAME.
import com.didww.sdk.exception.*;
try {
client.voiceInTrunks().find("nonexistent");
} catch (DidwwApiException e) {
System.out.println("HTTP Status: " + e.getHttpStatus());
for (DidwwApiException.ApiError error : e.getErrors()) {
System.out.println("Error: " + error.getDetail());
}
} catch (DidwwClientException e) {
System.out.println("Client error: " + e.getMessage());
}| Type | Class |
|---|---|
| SIP | SipConfiguration |
| PSTN | PstnConfiguration |
| Type | Class |
|---|---|
| DID | DidOrderItem |
| Available DID | AvailableDidOrderItem |
| Reservation DID | ReservationDidOrderItem |
| Capacity | CapacityOrderItem |
| Generic | GenericOrderItem |
| Resource | Repository | Operations |
|---|---|---|
| Country | client.countries() |
list, find |
| Region | client.regions() |
list, find |
| City | client.cities() |
list, find |
| Area | client.areas() |
list, find |
| NanpaPrefix | client.nanpaPrefixes() |
list, find |
| Pop | client.pops() |
list, find |
| DidGroupType | client.didGroupTypes() |
list, find |
| DidGroup | client.didGroups() |
list, find |
| AvailableDid | client.availableDids() |
list, find |
| ProofType | client.proofTypes() |
list, find |
| PublicKey | client.publicKeys() |
list, find |
| AddressRequirement | client.addressRequirements() |
list, find |
| SupportingDocumentTemplate | client.supportingDocumentTemplates() |
list, find |
| Balance | client.balance() |
find |
| Did | client.dids() |
list, find, update, delete |
| VoiceInTrunk | client.voiceInTrunks() |
list, find, create, update, delete |
| VoiceInTrunkGroup | client.voiceInTrunkGroups() |
list, find, create, update, delete |
| VoiceOutTrunk | client.voiceOutTrunks() |
list, find, create, update, delete |
| VoiceOutTrunkRegenerateCredential | client.voiceOutTrunkRegenerateCredentials() |
create |
| DidReservation | client.didReservations() |
list, find, create, delete |
| CapacityPool | client.capacityPools() |
list, find, update |
| SharedCapacityGroup | client.sharedCapacityGroups() |
list, find, create, update, delete |
| Order | client.orders() |
list, find, create, delete |
| Export | client.exports() |
list, find, create, update |
| Address | client.addresses() |
list, find, create, update, delete |
| AddressVerification | client.addressVerifications() |
list, find, create, update |
| Identity | client.identities() |
list, find, create, update, delete |
| EncryptedFile | client.encryptedFiles() |
list, find, delete |
| PermanentSupportingDocument | client.permanentSupportingDocuments() |
create |
| Proof | client.proofs() |
create |
| AddressRequirementValidation | client.addressRequirementValidations() |
create |
| DidHistory | client.didHistory() |
list |
| EmergencyRequirement | client.emergencyRequirements() |
list, find |
| EmergencyRequirementValidation | client.emergencyRequirementValidations() |
create |
| EmergencyCallingService | client.emergencyCallingServices() |
list, find, create, update, delete |
| EmergencyVerification | client.emergencyVerifications() |
list, find, create, update |
| StockKeepingUnit | include on didGroups |
— |
| QtyBasedPricing | include on capacityPools |
— |
Note:
StockKeepingUnitandQtyBasedPricinghave no standalone API endpoints. Access them viaincludeondidGroupsandcapacityPoolsrespectively.
The SDK distinguishes between date-only and datetime fields:
- Datetime fields — deserialized as
OffsetDateTime:getCreatedAt()— present on most resourcesgetExpiresAt()—Did,DidReservation,Proof,EncryptedFile(nullable)getActivatedAt()—EmergencyCallingService(nullable)getCanceledAt()—EmergencyCallingService(nullable)
- Date-only fields — deserialized as
LocalDate:Identity.getBirthDate()
- Date-only fields kept as strings — remain as
String:CapacityPool.getRenewDate(),EmergencyCallingService.getRenewDate()—"YYYY-MM-DD"(nullable)DidOrderItem.getBilledFrom(),DidOrderItem.getBilledTo()
- String fields (not numeric):
EmergencyRequirement.getEstimateSetupTime()— e.g."7-14 days","1"EmergencyRequirement.getRequirementRestrictionMessage()— nullable
Important changes from previous API versions:
getExpireAt()renamed togetExpiresAt()onDidReservationandEncryptedFilegetRenewDate()returns a date-only string, NOT anOffsetDateTimegetEstimateSetupTime()returns aString, NOT an integer
Did did = client.dids().find("uuid").getData();
System.out.println(did.getCreatedAt()); // 2024-01-15T10:00:00Z (OffsetDateTime)
System.out.println(did.getExpiresAt()); // null or 2025-01-15T10:00:00Z
Identity identity = client.identities().find("uuid").getData();
System.out.println(identity.getBirthDate()); // 1990-05-20 (LocalDate)The SDK provides enum classes in com.didww.sdk.resource.enums:
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 account configuration.
- Update
versioninbuild.gradle.ktsto the new version (e.g."4.0.0") - Commit and push to
main - Create and push a git tag matching the version:
git tag 4.0.0 git push origin 4.0.0
- JitPack will automatically build and publish the new version from the tag
Bug reports and pull requests are welcome on GitHub at https://github.com/didww/didww-api-3-java-sdk
The package is available as open source under the terms of the MIT License.