The official Java client for the VoiceTel REST API β provision numbers, place orders, validate e911, send messages, and manage your account, with strongly-typed records and modern java.net.http.
- Features
- Installation
- Quickstart
- Authentication
- Resource Reference
- Error Handling
- Rate Limits
- Development
- API Documentation
- Contributors
- Sponsors
- License
- Java 17 records for every one of the 73 API operations β request bodies, response payloads, and entity types.
- Jackson-databind serialization with
@JsonIgnoreProperties(ignoreUnknown = true)so server-side field additions never break clients. - No generated code, no annotation processors. Hand-written, navigable in any IDE.
- Built on the standard
java.net.http.HttpClient(Java 11+). No OkHttp, no Apache HttpClient. - Zero non-Jackson dependencies. Slim transitive footprint for downstream apps.
- Compatible with Java 17 LTS through 25.
- Automatic retry with exponential backoff on 429 / 5xx β honors
Retry-Afterheaders, capped at 8s. - Configurable per-request timeout via
ClientOptions. Default 30 seconds. - Bearer auth managed for you; the passwordβkey exchange is one
client.login()call. ApiErrorwith a typedErrorKindenum, so you canswitch (err.getKind()) { case RATE_LIMIT: ... }without parsing HTTP status codes.
- Numbers β list, get, add, remove, route, translate, CNAM, LIDB, fax, forward, SMS, messaging campaigns, port-out PIN, account moves.
- Account β profile, sub-accounts, CDRs, credits, payments, MRC, registration, password recovery.
- e911 β record provisioning, address validation, lookup, removal.
- Gateways β list, create, update, delete, view bound numbers.
- Messaging β SMS & MMS sending, message history, 10DLC brand and campaign registration, per-number messaging state.
- Lookups β CNAM and LRN dips.
- iNumbering β inventory search, coverage queries, number orders, port-in submissions, port-out availability checks.
- Support β ticket create / read / update / delete, threaded messages, replies.
- ACL β IP allowlist management with structured 409 conflict bodies.
- Authentication β switch between Digest, IP-only, or hybrid modes; rotate passwords.
- In-process
HttpServertests exercise the real transport (headers, retry, error mapping) without external mocks. - JaCoCo coverage reports on every CI run.
- Builds and tests on JDK 17 and 21 in CI.
<dependency>
<groupId>com.voicetel</groupId>
<artifactId>voicetel-sdk</artifactId>
<version>2.2.10</version>
</dependency>dependencies {
implementation("com.voicetel:voicetel-sdk:2.2.10")
}Requires Java 17 or later.
import com.voicetel.sdk.VoiceTelClient;
import com.voicetel.sdk.models.Account;
public class Example {
public static void main(String[] args) {
VoiceTelClient client = new VoiceTelClient();
// Exchange username + password for an API key (one-time per session)
client.login(1000000001, "hunter2");
// Typed responses β your IDE knows the shape of `me`.
Account.Data me = client.account().get();
System.out.printf("Balance: $%.2f | Caller ID: %s%n", me.cash(), me.callerId());
// List your numbers
client.numbers().list().numbers().forEach(n ->
System.out.printf("%s route=%d cnam=%b sms=%b%n",
n.number(), n.route(), n.cnam(), n.smsEnabled())
);
}
}Or, if you already have an API key:
import com.voicetel.sdk.ClientOptions;
VoiceTelClient client = new VoiceTelClient(
ClientOptions.builder().apiKey("32hex...").build());
var coverage = client.iNumbering().coverage(
new INumberingService.CoverageQuery().state("NJ"));
coverage.coverage().forEach(b ->
System.out.printf("%s-%s: %d TNs available%n", b.npa(), b.nxx(), b.count()));Every endpoint requires Authorization: Bearer <apikey> except POST /v2.2/account/api-key, which exchanges username + password for a fresh key. client.login() handles the exchange and installs the returned key on the transport.
Re-fetch the API key after any password change β the old one is invalidated.
Don't have credentials yet? Get them at voicetel.com/docs/api/v2.2/credentials.
VoiceTelClient client = new VoiceTelClient();
String key = client.login(1000000001, "hunter2");
// `key` is the new 32-hex bearer; the client already has it installed.| Resource | Accessor | Example |
|---|---|---|
| Account | client.account() |
client.account().cdr(start, end) |
| ACL | client.acl() |
client.acl().add(new Acl.ModifyRequest(...)) |
| Authentication | client.authentication() |
client.authentication().update(new Authentication.PutRequest(1, null)) |
| e911 | client.e911() |
client.e911().validate(new E911.AddressRequest(...)) |
| Gateways | client.gateways() |
client.gateways().list() |
| iNumbering | client.iNumbering() |
client.iNumbering().searchInventory(new InventoryQuery().npa(201)) |
| Lookups | client.lookups() |
client.lookups().lrn("2015551234", "2012548000") |
| Messaging | client.messaging() |
client.messaging().send(new Messaging.SendRequest(from, to, text)) |
| Numbers | client.numbers() |
client.numbers().assignCampaign("2015551234", new Numbers.CampaignAssignRequest("C1")) |
| Support | client.support() |
client.support().create(new Support.CreateRequest("subject", "body")) |
All HTTP errors throw ApiError (a RuntimeException) with a typed ErrorKind:
ErrorKind |
HTTP status |
|---|---|
BAD_REQUEST |
400 |
AUTHENTICATION |
401 |
PERMISSION_DENIED |
403 |
NOT_FOUND |
404 |
CONFLICT |
409 |
RATE_LIMIT |
429 |
SERVER |
5xx |
UNKNOWN |
other / transport |
try {
var n = client.numbers().get("9999999999");
} catch (ApiError e) {
if (e.isNotFound()) {
System.out.println("That number isn't on your account.");
} else if (e.isRateLimit()) {
System.out.println("Slow down β backoff and retry.");
} else {
throw e;
}
}For 409 conflicts on ACL or auth, the structured failure payload is on e.getBody().
These endpoints are limited to 6 requests per hour per IP:
account/infoaccount/mrc(client.account().recurringCharges())account/cdr(client.account().cdr(...))account/api-key(client.login(...))
The SDK automatically retries 429 responses with Retry-After honored, up to maxRetries (default 2). To bump it:
new VoiceTelClient(
ClientOptions.builder()
.apiKey(System.getenv("VOICETEL_API_KEY"))
.maxRetries(4)
.timeout(Duration.ofSeconds(60))
.build()
);git clone https://github.com/voicetel/java-sdk
cd java-sdk
# Build + test + coverage
mvn verify
# Just tests
mvn test
# Build the jar
mvn package- Reference docs: voicetel.com/docs/api/v2.2/
- Interactive playground: voicetel.com/docs/api/v2.2/playground/ β try the API in your browser without writing any code
- API credentials: voicetel.com/docs/api/v2.2/credentials/
- Michael Mavroudis β Lead Developer
Contributions welcome. Open an issue describing the change, or send a pull request against main.
| Sponsor | Contribution |
|---|---|
| VoiceTel Communications | Primary development and production hosting |
This project is licensed under the MIT License β see the LICENSE file for details.