Skip to main content

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