Skip to Content
ExamplesJava Spring Examples

Java Spring Examples

VerifNow provides an official Spring Boot SDK to simplify integration. You can also call the API directly with RestTemplate or WebClient.

Official SDK: 📦 verifnow-spring  — Spring Boot starter for VerifNow 📖 Full example project  — A complete working example


Add the dependency

<!-- pom.xml --> <dependency> <groupId>io.verifnow</groupId> <artifactId>verifnow-spring</artifactId> <version>2.1.0</version> </dependency>

Configure your API key

# application.properties verifnow.api-key=${VERIFNOW_API_KEY}

Use it in your service

The SDK provides auto-configured beans that you can inject directly. See the full documentation and usage examples at:


Option 2: Direct API call with RestTemplate

If you prefer not to use the SDK, you can call the API directly.

Configuration

Add your API key to application.properties:

# application.properties verifnow.api-key=${VERIFNOW_API_KEY} verifnow.base-url=https://api.verifnow.io/api/v1/validate

Model classes

// ValidationResult.java package io.verifnow.client.model; import com.fasterxml.jackson.annotation.JsonProperty; public class ValidationResult { private boolean valid; private String message; @JsonProperty("normalizedValue") private String normalizedValue; @JsonProperty("originalValue") private String originalValue; @JsonProperty("validationLevel") private String validationLevel; @JsonProperty("emailDetails") private EmailDetails emailDetails; public boolean isValid() { return valid; } public String getMessage() { return message; } public String getNormalizedValue() { return normalizedValue; } public String getOriginalValue() { return originalValue; } public String getValidationLevel() { return validationLevel; } public EmailDetails getEmailDetails() { return emailDetails; } }
// EmailDetails.java package io.verifnow.client.model; import com.fasterxml.jackson.annotation.JsonProperty; public class EmailDetails { private EmailSignals signals; @JsonProperty("risk_score") private int riskScore; @JsonProperty("risk_level") private String riskLevel; private String deliverability; @JsonProperty("applied_level") private String appliedLevel; public EmailSignals getSignals() { return signals; } public int getRiskScore() { return riskScore; } public String getRiskLevel() { return riskLevel; } public String getDeliverability() { return deliverability; } }
// EmailSignals.java package io.verifnow.client.model; import com.fasterxml.jackson.annotation.JsonProperty; public class EmailSignals { @JsonProperty("syntax_valid") private boolean syntaxValid; @JsonProperty("mx_valid") private boolean mxValid; @JsonProperty("typo_detected") private boolean typoDetected; @JsonProperty("suggested_domain") private String suggestedDomain; private boolean disposable; @JsonProperty("role_based") private boolean roleBased; @JsonProperty("free_provider") private boolean freeProvider; @JsonProperty("domain_age_days") private Integer domainAgeDays; @JsonProperty("mx_provider") private String mxProvider; @JsonProperty("mx_quality_score") private double mxQualityScore; public boolean isDisposable() { return disposable; } public boolean isTypoDetected() { return typoDetected; } public String getSuggestedDomain() { return suggestedDomain; } public boolean isRoleBased() { return roleBased; } public boolean isFreeProvider() { return freeProvider; } public boolean isSyntaxValid() { return syntaxValid; } public boolean isMxValid() { return mxValid; } }

Service

// VerifNowService.java package io.verifnow.client.service; import io.verifnow.client.model.ValidationResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import java.util.Map; @Service public class VerifNowService { private static final Logger logger = LoggerFactory.getLogger(VerifNowService.class); private final RestTemplate restTemplate; @Value("${verifnow.api-key}") private String apiKey; @Value("${verifnow.base-url}") private String baseUrl; public VerifNowService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @Retryable( retryFor = { HttpClientErrorException.TooManyRequests.class }, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2) ) public ValidationResult validateEmail(String email) { HttpHeaders headers = new HttpHeaders(); headers.set("X-API-KEY", apiKey); headers.setContentType(MediaType.APPLICATION_JSON); Map<String, String> body = Map.of("value", email); HttpEntity<Map<String, String>> request = new HttpEntity<>(body, headers); try { ResponseEntity<ValidationResult> response = restTemplate.postForEntity( baseUrl + "/email", request, ValidationResult.class ); return response.getBody(); } catch (HttpClientErrorException.Unauthorized e) { throw new RuntimeException("Invalid VerifNow API key. Check VERIFNOW_API_KEY.", e); } catch (HttpClientErrorException.TooManyRequests e) { logger.warn("VerifNow quota exceeded, retrying..."); throw e; // Let @Retryable handle it } catch (HttpClientErrorException e) { logger.error("VerifNow API error: {} {}", e.getStatusCode(), e.getMessage()); throw new RuntimeException("VerifNow validation failed: " + e.getMessage(), e); } } }

RestTemplate configuration

// AppConfig.java package io.verifnow.client.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.retry.annotation.EnableRetry; import org.springframework.web.client.RestTemplate; @Configuration @EnableRetry public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }

Controller integration

// UserController.java package io.verifnow.client.controller; import io.verifnow.client.model.ValidationResult; import io.verifnow.client.service.VerifNowService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Map; @RestController @RequestMapping("/api/users") public class UserController { private final VerifNowService verifNowService; public UserController(VerifNowService verifNowService) { this.verifNowService = verifNowService; } @PostMapping("/register") public ResponseEntity<?> register(@RequestBody Map<String, String> payload) { String email = payload.get("email"); ValidationResult validation; try { validation = verifNowService.validateEmail(email); } catch (Exception e) { // Fail open: don't block registration if VerifNow is unreachable return continueRegistration(email); } if (!validation.isValid()) { String suggestion = ""; if (validation.getEmailDetails() != null && validation.getEmailDetails().getSignals() != null && validation.getEmailDetails().getSignals().getSuggestedDomain() != null) { suggestion = validation.getEmailDetails().getSignals().getSuggestedDomain(); } return ResponseEntity.badRequest().body( Map.of( "error", "Please provide a valid, reachable email address.", "suggestion", suggestion ) ); } if (validation.getEmailDetails() != null && validation.getEmailDetails().getSignals() != null && validation.getEmailDetails().getSignals().isDisposable()) { return ResponseEntity.badRequest().body( Map.of("error", "Disposable email addresses are not allowed.") ); } return continueRegistration(email); } private ResponseEntity<?> continueRegistration(String email) { // Your actual user creation logic here return ResponseEntity.ok(Map.of("message", "Registration successful", "email", email)); } }

Reactive WebClient (Spring WebFlux)

For non-blocking, reactive applications:

// VerifNowReactiveService.java package io.verifnow.client.service; import io.verifnow.client.model.ValidationResult; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; import java.util.Map; @Service public class VerifNowReactiveService { private final WebClient webClient; public VerifNowReactiveService( @Value("${verifnow.api-key}") String apiKey, @Value("${verifnow.base-url}") String baseUrl ) { this.webClient = WebClient.builder() .baseUrl(baseUrl) .defaultHeader("X-API-KEY", apiKey) .defaultHeader("Content-Type", "application/json") .build(); } public Mono<ValidationResult> validateEmail(String email) { return webClient.post() .uri("/email") .bodyValue(Map.of("value", email)) .retrieve() .onStatus( status -> status.value() == 429, response -> Mono.error(new RuntimeException("Quota exceeded")) ) .bodyToMono(ValidationResult.class); } }
Last updated on