Installation
Add the EnviaAI SDK to your project using Maven or Gradle.<dependency>
<groupId>com.enviaai</groupId>
<artifactId>enviaai-java</artifactId>
<version>1.0.0</version>
</dependency>
Requirements
- Java 11 or higher
- Gson (included as dependency)
Quick Start
import com.enviaai.EnviaAI;
import com.enviaai.models.*;
public class QuickStart {
public static void main(String[] args) {
// Initialize client
EnviaAI client = new EnviaAI("your-api-key");
// Send a message
SendMessageResponse response = client.messages().send(
SendMessageRequest.builder()
.instanceId("inst_abc123")
.to("5511999999999")
.text("Hello from EnviaAI!")
.build()
);
System.out.println("Message sent: " + response.getMessageId());
}
}
Configuration
Basic Configuration
// Simple initialization with API key
EnviaAI client = new EnviaAI("your-api-key");
Advanced Configuration
// Using the builder pattern
EnviaAI client = EnviaAI.builder()
.apiKey("your-api-key")
.baseUrl("https://api.enviaai.app") // Optional
.timeout(60000) // 60 seconds
.addHeader("X-Custom-Header", "value")
.build();
Environment Variables
// Load API key from environment
String apiKey = System.getenv("ENVIAAI_API_KEY");
EnviaAI client = new EnviaAI(apiKey);
Sending Messages
Text Message
SendMessageResponse response = client.messages().send(
SendMessageRequest.builder()
.instanceId("inst_abc123")
.to("5511999999999")
.text("Hello! How can I help you?")
.build()
);
System.out.println("Message ID: " + response.getMessageId());
System.out.println("Status: " + response.getStatus());
Image Message
SendMessageResponse response = client.messages().send(
SendMessageRequest.builder()
.instanceId("inst_abc123")
.to("5511999999999")
.mediaUrl("https://example.com/image.jpg")
.mediaType(MessageType.IMAGE)
.caption("Check out our product!")
.build()
);
Document
SendMessageResponse response = client.messages().send(
SendMessageRequest.builder()
.instanceId("inst_abc123")
.to("5511999999999")
.mediaUrl("https://example.com/invoice.pdf")
.mediaType(MessageType.DOCUMENT)
.filename("Invoice-2026-001.pdf")
.caption("Here is your invoice")
.build()
);
Reply to Message
SendMessageResponse response = client.messages().send(
SendMessageRequest.builder()
.instanceId("inst_abc123")
.to("5511999999999")
.text("Thanks for your question!")
.quotedMessageId("msg_original123")
.build()
);
Managing Instances
List Instances
import java.util.List;
List<Instance> instances = client.instances().list();
for (Instance instance : instances) {
System.out.printf("%s: %s (%s)%n",
instance.getId(),
instance.getName(),
instance.getStatus()
);
}
Filter by Status
List<Instance> connected = client.instances().list(
InstanceStatus.CONNECTED
);
Get Instance Status
InstanceStatusResponse status = client.instances().getStatus("inst_abc123");
System.out.println("Status: " + status.getStatus());
System.out.println("Phone: " + status.getPhone());
if (status.getStats() != null) {
System.out.println("Messages sent today: " + status.getStats().getMessagesSent());
System.out.println("Messages received: " + status.getStats().getMessagesReceived());
}
Connect Instance (QR Code)
QRCodeResponse qr = client.instances().connect("inst_abc123");
if (qr.getQrCode() != null) {
System.out.println("Scan QR code: " + qr.getQrCode());
System.out.println("Expires at: " + qr.getExpiresAt());
}
Disconnect Instance
client.instances().disconnect("inst_abc123");
Chat History
List Chats
import java.util.List;
List<Chat> chats = client.messages().getChats("inst_abc123");
for (Chat chat : chats) {
System.out.printf("%s - %s (Unread: %d)%n",
chat.getPhone(),
chat.getContactName(),
chat.getUnreadCount()
);
}
Get Messages from Chat
List<Message> messages = client.messages().getMessages(
"inst_abc123",
"5511999999999",
50 // limit
);
for (Message msg : messages) {
String direction = msg.getDirection() == MessageDirection.INBOUND ? "←" : "→";
System.out.printf("%s %s: %s%n",
direction,
msg.getTimestamp(),
msg.getContent()
);
}
Error Handling
Exception Types
import com.enviaai.EnviaAIException;
try {
client.messages().send(request);
} catch (EnviaAIException.AuthenticationException e) {
System.err.println("Invalid API key: " + e.getMessage());
} catch (EnviaAIException.RateLimitException e) {
System.err.println("Rate limited. Retry after: " + e.getRetryAfter() + "s");
} catch (EnviaAIException.ValidationException e) {
System.err.println("Invalid request: " + e.getMessage());
} catch (EnviaAIException.NotFoundException e) {
System.err.println("Resource not found: " + e.getMessage());
} catch (EnviaAIException.ServerException e) {
System.err.println("Server error: " + e.getMessage());
} catch (EnviaAIException e) {
System.err.println("API error: " + e.getCode() + " - " + e.getMessage());
}
Error Response Structure
try {
client.messages().send(request);
} catch (EnviaAIException e) {
System.err.println("Error code: " + e.getCode());
System.err.println("Message: " + e.getMessage());
System.err.println("Request ID: " + e.getRequestId());
System.err.println("HTTP Status: " + e.getStatusCode());
}
Webhook Handler
Spring Boot
import org.springframework.web.bind.annotation.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.HexFormat;
@RestController
@RequestMapping("/webhooks")
public class WebhookController {
private static final String WEBHOOK_SECRET = System.getenv("WEBHOOK_SECRET");
@PostMapping("/enviaai")
public ResponseEntity<String> handleWebhook(
@RequestBody String payload,
@RequestHeader("X-EnviaAI-Signature") String signature) {
// Verify signature
if (!verifySignature(payload, signature)) {
return ResponseEntity.status(401).body("Invalid signature");
}
// Parse event
WebhookEvent event = parseEvent(payload);
// Process asynchronously
processEventAsync(event);
// Respond quickly
return ResponseEntity.ok("OK");
}
private boolean verifySignature(String payload, String signature) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(WEBHOOK_SECRET.getBytes(), "HmacSHA256"));
String expected = "sha256=" + HexFormat.of().formatHex(mac.doFinal(payload.getBytes()));
return signature.equals(expected);
} catch (Exception e) {
return false;
}
}
}
Jakarta EE / JAX-RS
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
@Path("/webhooks")
public class WebhookResource {
@POST
@Path("/enviaai")
@Consumes("application/json")
public Response handleWebhook(
String payload,
@HeaderParam("X-EnviaAI-Signature") String signature) {
if (!verifySignature(payload, signature)) {
return Response.status(401).entity("Invalid signature").build();
}
// Process event
processEvent(payload);
return Response.ok("OK").build();
}
}
Async Operations
CompletableFuture (Manual)
import java.util.concurrent.CompletableFuture;
CompletableFuture.supplyAsync(() -> {
return client.messages().send(request);
}).thenAccept(response -> {
System.out.println("Message sent: " + response.getMessageId());
}).exceptionally(e -> {
System.err.println("Failed: " + e.getMessage());
return null;
});
Bulk Messaging
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
List<String> recipients = List.of(
"5511999999991",
"5511999999992",
"5511999999993"
);
List<CompletableFuture<SendMessageResponse>> futures = recipients.stream()
.map(phone -> CompletableFuture.supplyAsync(() -> {
return client.messages().send(
SendMessageRequest.builder()
.instanceId("inst_abc123")
.to(phone)
.text("Hello! Special offer just for you.")
.build()
);
}))
.collect(Collectors.toList());
// Wait for all to complete
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// Get results
for (CompletableFuture<SendMessageResponse> future : futures) {
try {
SendMessageResponse response = future.get();
System.out.println("Sent: " + response.getMessageId());
} catch (Exception e) {
System.err.println("Failed: " + e.getMessage());
}
}
Best Practices
Use Environment Variables
Never hardcode API keys. Use environment variables or secret managers.
Handle Errors Gracefully
Implement proper error handling with retries for rate limits.
Use Connection Pooling
The SDK uses connection pooling internally. Reuse the client instance.
Verify Webhooks
Always verify webhook signatures before processing events.
Singleton Pattern
public class EnviaAIClient {
private static volatile EnviaAI instance;
public static EnviaAI getInstance() {
if (instance == null) {
synchronized (EnviaAIClient.class) {
if (instance == null) {
instance = new EnviaAI(System.getenv("ENVIAAI_API_KEY"));
}
}
}
return instance;
}
}
// Usage
EnviaAI client = EnviaAIClient.getInstance();
Resources
GitHub Repository
Source code and examples
JavaDoc
Full API documentation
Maven Central
Package releases
Report Issues
Bug reports and feature requests